|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)if_uba.c 7.9 (Berkeley) 5/24/88
7: */
8:
9: #include "param.h"
10: #include "systm.h"
11: #include "mbuf.h"
12: #include "map.h"
13: #include "buf.h"
14: #include "cmap.h"
15: #include "vmmac.h"
16: #include "socket.h"
17: #include "syslog.h"
18: #include "malloc.h"
19:
20: #include "../net/if.h"
21:
22: #include "../vax/pte.h"
23: #include "../vax/mtpr.h"
24: #include "if_uba.h"
25: #include "../vaxuba/ubareg.h"
26: #include "../vaxuba/ubavar.h"
27:
28: /*
29: * Routines supporting UNIBUS network interfaces.
30: *
31: * TODO:
32: * Support interfaces using only one BDP statically.
33: */
34:
35: /*
36: * Init UNIBUS for interface on uban whose headers of size hlen are to
37: * end on a page boundary. We allocate a UNIBUS map register for the page
38: * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
39: * doing this once for each read and once for each write buffer. We also
40: * allocate page frames in the mbuffer pool for these pages.
41: */
42: if_ubaminit(ifu, uban, hlen, nmr, ifr, nr, ifw, nw)
43: register struct ifubinfo *ifu;
44: int uban, hlen, nmr, nr, nw;
45: register struct ifrw *ifr;
46: register struct ifxmt *ifw;
47: {
48: register caddr_t p;
49: caddr_t cp;
50: int i, nclbytes, off;
51:
52: if (hlen)
53: off = CLBYTES - hlen;
54: else
55: off = 0;
56: nclbytes = CLBYTES * (clrnd(nmr) / CLSIZE);
57: if (hlen)
58: nclbytes += CLBYTES;
59: if (ifr[0].ifrw_addr)
60: cp = ifr[0].ifrw_addr - off;
61: else {
62: cp = (caddr_t)malloc((u_long)((nr + nw) * nclbytes), M_DEVBUF,
63: M_NOWAIT);
64: if (cp == 0)
65: return (0);
66: p = cp;
67: for (i = 0; i < nr; i++) {
68: ifr[i].ifrw_addr = p + off;
69: p += nclbytes;
70: }
71: for (i = 0; i < nw; i++) {
72: ifw[i].ifw_base = p;
73: ifw[i].ifw_addr = p + off;
74: p += nclbytes;
75: }
76: ifu->iff_hlen = hlen;
77: ifu->iff_uban = uban;
78: ifu->iff_uba = uba_hd[uban].uh_uba;
79: ifu->iff_ubamr = uba_hd[uban].uh_mr;
80: }
81: for (i = 0; i < nr; i++)
82: if (if_ubaalloc(ifu, &ifr[i], nmr) == 0) {
83: nr = i;
84: nw = 0;
85: goto bad;
86: }
87: for (i = 0; i < nw; i++)
88: if (if_ubaalloc(ifu, &ifw[i].ifrw, nmr) == 0) {
89: nw = i;
90: goto bad;
91: }
92: while (--nw >= 0) {
93: for (i = 0; i < nmr; i++)
94: ifw[nw].ifw_wmap[i] = ifw[nw].ifw_mr[i];
95: ifw[nw].ifw_xswapd = 0;
96: ifw[nw].ifw_flags = IFRW_W;
97: ifw[nw].ifw_nmr = nmr;
98: }
99: return (1);
100: bad:
101: while (--nw >= 0)
102: ubarelse(ifu->iff_uban, &ifw[nw].ifw_info);
103: while (--nr >= 0)
104: ubarelse(ifu->iff_uban, &ifr[nr].ifrw_info);
105: free(cp, M_DEVBUF);
106: ifr[0].ifrw_addr = 0;
107: return (0);
108: }
109:
110: /*
111: * Setup an ifrw structure by allocating UNIBUS map registers,
112: * possibly a buffered data path, and initializing the fields of
113: * the ifrw structure to minimize run-time overhead.
114: */
115: static
116: if_ubaalloc(ifu, ifrw, nmr)
117: struct ifubinfo *ifu;
118: register struct ifrw *ifrw;
119: int nmr;
120: {
121: register int info;
122:
123: info =
124: uballoc(ifu->iff_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->iff_hlen,
125: ifu->iff_flags);
126: if (info == 0)
127: return (0);
128: ifrw->ifrw_info = info;
129: ifrw->ifrw_bdp = UBAI_BDP(info);
130: ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
131: ifrw->ifrw_mr = &ifu->iff_ubamr[UBAI_MR(info) + (ifu->iff_hlen? 1 : 0)];
132: return (1);
133: }
134:
135: /*
136: * Pull read data off a interface.
137: * Len is length of data, with local net header stripped.
138: * Off is non-zero if a trailer protocol was used, and
139: * gives the offset of the trailer information.
140: * We copy the trailer information and then all the normal
141: * data into mbufs. When full cluster sized units are present
142: * on the interface on cluster boundaries we can get them more
143: * easily by remapping, and take advantage of this here.
144: * Prepend a pointer to the interface structure,
145: * so that protocols can determine where incoming packets arrived.
146: * Note: we may be called to receive from a transmit buffer by some
147: * devices. In that case, we must force normal mapping of the buffer,
148: * so that the correct data will appear (only unibus maps are
149: * changed when remapping the transmit buffers).
150: */
151: struct mbuf *
152: if_ubaget(ifu, ifr, totlen, off0, ifp)
153: struct ifubinfo *ifu;
154: register struct ifrw *ifr;
155: int totlen, off0;
156: struct ifnet *ifp;
157: {
158: struct mbuf *top, **mp;
159: register struct mbuf *m;
160: int off = off0, len;
161: register caddr_t cp = ifr->ifrw_addr + ifu->iff_hlen, pp;
162:
163: top = 0;
164: mp = ⊤
165: if (ifr->ifrw_flags & IFRW_W)
166: rcv_xmtbuf((struct ifxmt *)ifr);
167: while (totlen > 0) {
168: MGET(m, M_DONTWAIT, MT_DATA);
169: if (m == 0) {
170: m_freem(top);
171: top = 0;
172: goto out;
173: }
174: if (off) {
175: len = totlen - off;
176: cp = ifr->ifrw_addr + ifu->iff_hlen + off;
177: } else
178: len = totlen;
179: if (len >= CLBYTES/2) {
180: struct pte *cpte, *ppte;
181: int x, *ip, i;
182:
183: /*
184: * If doing the first mbuf and
185: * the interface pointer hasn't been put in,
186: * put it in a separate mbuf to preserve alignment.
187: */
188: if (ifp) {
189: len = 0;
190: goto nopage;
191: }
192: MCLGET(m);
193: if (m->m_len != CLBYTES)
194: goto nopage;
195: m->m_len = MIN(len, CLBYTES);
196: if (!claligned(cp))
197: goto copy;
198:
199: /*
200: * Switch pages mapped to UNIBUS with new page pp,
201: * as quick form of copy. Remap UNIBUS and invalidate.
202: */
203: pp = mtod(m, char *);
204: cpte = kvtopte(cp);
205: ppte = kvtopte(pp);
206: x = btop(cp - ifr->ifrw_addr);
207: ip = (int *)&ifr->ifrw_mr[x];
208: for (i = 0; i < CLSIZE; i++) {
209: struct pte t;
210: t = *ppte; *ppte++ = *cpte; *cpte = t;
211: *ip++ = cpte++->pg_pfnum|ifr->ifrw_proto;
212: mtpr(TBIS, cp);
213: cp += NBPG;
214: mtpr(TBIS, (caddr_t)pp);
215: pp += NBPG;
216: }
217: goto nocopy;
218: }
219: nopage:
220: m->m_off = MMINOFF;
221: if (ifp) {
222: /*
223: * Leave room for ifp.
224: */
225: m->m_len = MIN(MLEN - sizeof(ifp), len);
226: m->m_off += sizeof(ifp);
227: } else
228: m->m_len = MIN(MLEN, len);
229: copy:
230: bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
231: cp += m->m_len;
232: nocopy:
233: *mp = m;
234: mp = &m->m_next;
235: if (off) {
236: /* sort of an ALGOL-W style for statement... */
237: off += m->m_len;
238: if (off == totlen) {
239: cp = ifr->ifrw_addr + ifu->iff_hlen;
240: off = 0;
241: totlen = off0;
242: }
243: } else
244: totlen -= m->m_len;
245: if (ifp) {
246: /*
247: * Prepend interface pointer to first mbuf.
248: */
249: m->m_len += sizeof(ifp);
250: m->m_off -= sizeof(ifp);
251: *(mtod(m, struct ifnet **)) = ifp;
252: ifp = (struct ifnet *)0;
253: }
254: }
255: out:
256: if (ifr->ifrw_flags & IFRW_W)
257: restor_xmtbuf((struct ifxmt *)ifr);
258: return (top);
259: }
260:
261: /*
262: * Change the mapping on a transmit buffer so that if_ubaget may
263: * receive from that buffer. Copy data from any pages mapped to Unibus
264: * into the pages mapped to normal kernel virtual memory, so that
265: * they can be accessed and swapped as usual. We take advantage
266: * of the fact that clusters are placed on the xtofree list
267: * in inverse order, finding the last one.
268: */
269: static
270: rcv_xmtbuf(ifw)
271: register struct ifxmt *ifw;
272: {
273: register struct mbuf *m;
274: struct mbuf **mprev;
275: register i;
276: char *cp;
277:
278: while (i = ffs((long)ifw->ifw_xswapd)) {
279: cp = ifw->ifw_base + i * CLBYTES;
280: i--;
281: ifw->ifw_xswapd &= ~(1<<i);
282: mprev = &ifw->ifw_xtofree;
283: for (m = ifw->ifw_xtofree; m && m->m_next; m = m->m_next)
284: mprev = &m->m_next;
285: if (m == NULL)
286: break;
287: bcopy(mtod(m, caddr_t), cp, CLBYTES);
288: (void) m_free(m);
289: *mprev = NULL;
290: }
291: ifw->ifw_xswapd = 0;
292: for (i = 0; i < ifw->ifw_nmr; i++)
293: ifw->ifw_mr[i] = ifw->ifw_wmap[i];
294: }
295:
296: /*
297: * Put a transmit buffer back together after doing an if_ubaget on it,
298: * which may have swapped pages.
299: */
300: static
301: restor_xmtbuf(ifw)
302: register struct ifxmt *ifw;
303: {
304: register i;
305:
306: for (i = 0; i < ifw->ifw_nmr; i++)
307: ifw->ifw_wmap[i] = ifw->ifw_mr[i];
308: }
309:
310: /*
311: * Map a chain of mbufs onto a network interface
312: * in preparation for an i/o operation.
313: * The argument chain of mbufs includes the local network
314: * header which is copied to be in the mapped, aligned
315: * i/o space.
316: */
317: if_ubaput(ifu, ifw, m)
318: struct ifubinfo *ifu;
319: register struct ifxmt *ifw;
320: register struct mbuf *m;
321: {
322: register struct mbuf *mp;
323: register caddr_t cp, dp;
324: register int i;
325: int xswapd = 0;
326: int x, cc, t;
327:
328: cp = ifw->ifw_addr;
329: while (m) {
330: dp = mtod(m, char *);
331: if (claligned(cp) && claligned(dp) &&
332: (m->m_len == CLBYTES || m->m_next == (struct mbuf *)0)) {
333: struct pte *pte;
334: int *ip;
335:
336: pte = kvtopte(dp);
337: x = btop(cp - ifw->ifw_addr);
338: ip = (int *)&ifw->ifw_mr[x];
339: for (i = 0; i < CLSIZE; i++)
340: *ip++ = ifw->ifw_proto | pte++->pg_pfnum;
341: xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT));
342: mp = m->m_next;
343: m->m_next = ifw->ifw_xtofree;
344: ifw->ifw_xtofree = m;
345: cp += m->m_len;
346: } else {
347: bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
348: cp += m->m_len;
349: MFREE(m, mp);
350: }
351: m = mp;
352: }
353:
354: /*
355: * Xswapd is the set of clusters we just mapped out. Ifu->iff_xswapd
356: * is the set of clusters mapped out from before. We compute
357: * the number of clusters involved in this operation in x.
358: * Clusters mapped out before and involved in this operation
359: * should be unmapped so original pages will be accessed by the device.
360: */
361: cc = cp - ifw->ifw_addr;
362: x = ((cc - ifu->iff_hlen) + CLBYTES - 1) >> CLSHIFT;
363: ifw->ifw_xswapd &= ~xswapd;
364: while (i = ffs((long)ifw->ifw_xswapd)) {
365: i--;
366: if (i >= x)
367: break;
368: ifw->ifw_xswapd &= ~(1<<i);
369: i *= CLSIZE;
370: for (t = 0; t < CLSIZE; t++) {
371: ifw->ifw_mr[i] = ifw->ifw_wmap[i];
372: i++;
373: }
374: }
375: ifw->ifw_xswapd |= xswapd;
376: return (cc);
377: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.