conversion to start written in C
[unix-history] / usr / src / sys / vax / if / if_uba.c
CommitLineData
8a13b737 1/* if_uba.c 4.2 81/11/26 */
0468e5fa
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/mbuf.h"
6#include "../h/map.h"
7#include "../h/pte.h"
8a13b737 8#include "../h/buf.h"
0468e5fa
BJ
9#include "../h/ubareg.h"
10#include "../h/ubavar.h"
11#include "../h/cmap.h"
12#include "../h/mtpr.h"
8a13b737
BJ
13#include "../h/vmmac.h"
14#include "../net/in.h"
15#include "../net/in_systm.h"
16#include "../net/if.h"
0468e5fa
BJ
17#include "../net/if_uba.h"
18
19/*
20 * Routines supporting UNIBUS network interfaces.
21 *
22 * TODO:
23 * Support interfaces using only one BDP statically.
24 */
25
26/*
27 * Init UNIBUS for interface on uban whose headers of size hlen are to
28 * end on a page boundary. We allocate a UNIBUS map register for the page
29 * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
30 * doing this twice: once for reading and once for writing. We also
31 * allocate page frames in the mbuffer pool for these pages.
32 */
33if_ubainit(ifu, uban, hlen, nmr)
34 register struct ifuba *ifu;
35 int uban, hlen, nmr;
36{
8a13b737
BJ
37 register caddr_t cp = (caddr_t)m_pgalloc(2 * (nmr + 1));
38 int i;
0468e5fa 39
8a13b737 40COUNT(IF_UBAINIT);
0468e5fa
BJ
41 if (cp == 0)
42 return (0);
8a13b737
BJ
43 ifu->ifu_uban = uban;
44 ifu->ifu_uba = uba_hd[uban].uh_uba;
45 ifu->ifu_r.ifrw_addr = cp + NBPG - hlen;
46 ifu->ifu_w.ifrw_addr = ifu->ifu_r.ifrw_addr + (nmr + 1) * NBPG;
47 if (if_ubaalloc(ifu, &ifu->ifu_r) == 0)
0468e5fa 48 goto bad;
8a13b737 49 if (if_ubaalloc(ifu, &ifu->ifu_w) == 0)
0468e5fa
BJ
50 goto bad2;
51 for (i = 0; i < IF_NUBAMR; i++)
8a13b737
BJ
52 ifu->ifu_wmap[i] = ifu->ifu_w.ifrw_mr[i+1];
53 ifu->ifu_xswapd = 0;
0468e5fa
BJ
54 return (1);
55bad2:
8a13b737 56 ubarelse(ifu->ifu_uban, &ifu->ifu_r.ifrw_info);
0468e5fa
BJ
57bad:
58 m_pgfree(cp, 2 * (nmr + 1));
59 return (0);
60}
61
62/*
63 * Setup either a ifrw structure by allocating UNIBUS map registers,
64 * a buffered data path, and initializing the fields of the ifrw structure
65 * to minimize run-time overhead.
66 */
67static
68if_ubaalloc(ifu, ifrw)
69 struct ifuba *ifu;
70 register struct ifrw *ifrw;
71{
72 register int info;
73
8a13b737 74COUNT(IF_UBAALLOC);
0468e5fa 75 info =
8a13b737 76 uballoc(ifu->ifu_uban, ifrw->ifrw_addr, IF_NUBAMR*NBPG + ifu->ifu_hlen,
0468e5fa
BJ
77 UBA_NEED16|UBA_NEEDBDP);
78 if (info == 0)
8a13b737 79 return (0);
0468e5fa
BJ
80 ifrw->ifrw_info = info;
81 ifrw->ifrw_bdp = UBAI_BDP(info);
8a13b737
BJ
82 ifrw->ifrw_proto = UBAMR_MRV | (UBAI_MR(info) << UBAMR_DPSHIFT);
83 ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1];
84 return (1);
0468e5fa
BJ
85}
86
87/*
88 * Pull read data off a interface, given length.
89 * Map the header into a mbuf, and then copy or
90 * remap the data into a chain of mbufs.
91 * Return 0 if there is no space, or a pointer
92 * to the assembled mbuf chain.
93 */
94struct mbuf *
95if_rubaget(ifu, len)
96 register struct ifuba *ifu;
97 int len;
98{
99 register struct mbuf *m;
100 register caddr_t cp;
101 struct mbuf *mp, *p, *top;
102
8a13b737 103COUNT(IF_RUBAGET);
0468e5fa
BJ
104 /*
105 * First pull local net header off into a mbuf.
106 */
107 MGET(m, 0);
108 if (m == 0)
109 return (0);
110 m->m_off = MMINOFF;
8a13b737 111 m->m_len = ifu->ifu_hlen;
0468e5fa
BJ
112 top = m;
113 cp = ifu->ifu_r.ifrw_addr;
8a13b737
BJ
114 bcopy(cp, mtod(m, caddr_t), ifu->ifu_hlen);
115 len -= ifu->ifu_hlen;
116 cp += ifu->ifu_hlen;
0468e5fa
BJ
117
118 /*
119 * Now pull data off. If whole pages
120 * are there, pull into pages if possible,
121 * otherwise copy small blocks into mbufs.
122 */
123 mp = m;
124 while (len > 0) {
125 MGET(m, 0);
126 if (m == 0)
8a13b737 127 goto bad;
0468e5fa
BJ
128 if (len >= CLSIZE) {
129 struct pte *cpte, *ppte;
130 int i, x, *ip;
131
132 MCLGET(p, 1);
133 if (p == 0)
134 goto nopage;
135 m->m_len = CLSIZE;
136 m->m_off = (int)p - (int)m;
137 if ((int)cp & CLOFF)
138 goto copy;
139
140 /*
141 * Cluster size data on cluster size boundary.
142 * Input by remapping newly allocated pages to
143 * UNIBUS, and taking pages with data already
144 * in them.
145 *
146 * Cpte is the pte of the virtual memory which
147 * is mapped to the UNIBUS, and ppte is the pte
148 * for the fresh pages. We switch the memory
149 * copies of these pte's, to make the allocated
150 * virtual memory contain the data (using the old
151 * physical pages). We have to rewrite
152 * the UNIBUS map so that the newly allocated
153 * pages will be used for the next UNIBUS read,
154 * and invalidate the kernel translations
155 * for the virtual addresses of the pages
156 * we are flipping.
157 *
158 * The idea here is that this is supposed
159 * to take less time than copying the data.
160 */
161 cpte = &Mbmap[mtocl(cp)];
162 ppte = &Mbmap[mtocl(p)];
8a13b737 163 x = btop(cp - ifu->ifu_r.ifrw_addr);
0468e5fa
BJ
164 ip = (int *)&ifu->ifu_r.ifrw_mr[x+1];
165 for (i = 0; i < CLSIZE; i++) {
166 struct pte t;
167 t = *ppte; *ppte = *cpte; *cpte = t;
168 *ip++ =
8a13b737 169 cpte++->pg_pfnum|ifu->ifu_r.ifrw_proto;
0468e5fa 170 mtpr(TBIS, cp);
8a13b737 171 cp += NBPG;
0468e5fa 172 mtpr(TBIS, (caddr_t)p);
8a13b737 173 p += NBPG / sizeof (*p);
0468e5fa
BJ
174 }
175 goto nocopy;
176 }
177nopage:
178 m->m_len = MIN(MLEN, len);
179 m->m_off = MMINOFF;
180copy:
181 bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
182 cp += m->m_len;
183nocopy:
184 len -= m->m_len;
185 mp->m_next = m;
186 mp = m;
187 }
188 return (top);
189bad:
190 m_freem(top);
191 return (0);
192}
193
194/*
195 * Map a chain of mbufs onto a network interface
196 * in preparation for an i/o operation.
197 * The argument chain of mbufs includes the local network
198 * header which is copied to be in the mapped, aligned
199 * i/o space.
200 */
201if_wubaput(ifu, m)
202 register struct ifuba *ifu;
203 register struct mbuf *m;
204{
205 register struct mbuf *mp;
206 register caddr_t cp, dp;
207 register int i;
208 int xswapd = ifu->ifu_xswapd;
209 int x;
210
8a13b737 211COUNT(IF_WUBAPUT);
0468e5fa
BJ
212 ifu->ifu_xswapd = 0;
213 cp = ifu->ifu_w.ifrw_addr;
214 while (m) {
215 dp = mtod(m, char *);
216 if (claligned(cp) && claligned(dp)) {
217 struct pte *pte; int *ip;
218 pte = &Mbmap[mtocl(dp)];
219 x = btop(cp - ifu->ifu_w.ifrw_addr);
8a13b737 220 ip = (int *)&ifu->ifu_w.ifrw_mr[x + 1];
0468e5fa
BJ
221 for (i = 0; i < CLSIZE; i++)
222 *ip++ =
223 ifu->ifu_w.ifrw_proto | pte++->pg_pfnum;
224 ifu->ifu_xswapd |= 1 << (x>>CLSHIFT);
225 } else
226 bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
227 cp += m->m_len;
228 MFREE(m, mp); /* XXX too soon! */
229 m = mp;
230 }
231 xswapd &= ~ifu->ifu_xswapd;
232 if (xswapd)
233 while (i = ffs(xswapd)) {
234 i--;
235 xswapd &= ~(1<<i);
236 i <<= CLSHIFT;
237 for (x = 0; x < CLSIZE; x++) {
8a13b737 238 ifu->ifu_w.ifrw_mr[i] = ifu->ifu_wmap[i];
0468e5fa
BJ
239 i++;
240 }
241 }
242}