|
|
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.