Annotation of sys/arch/vax/if/if_uba.c, Revision 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