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