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