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