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