|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: * ! 6: * @(#)if_uba.c 7.9 (Berkeley) 5/24/88 ! 7: */ ! 8: ! 9: #include "param.h" ! 10: #include "systm.h" ! 11: #include "mbuf.h" ! 12: #include "map.h" ! 13: #include "buf.h" ! 14: #include "cmap.h" ! 15: #include "vmmac.h" ! 16: #include "socket.h" ! 17: #include "syslog.h" ! 18: #include "malloc.h" ! 19: ! 20: #include "../net/if.h" ! 21: ! 22: #include "../vax/pte.h" ! 23: #include "../vax/mtpr.h" ! 24: #include "if_uba.h" ! 25: #include "../vaxuba/ubareg.h" ! 26: #include "../vaxuba/ubavar.h" ! 27: ! 28: /* ! 29: * Routines supporting UNIBUS network interfaces. ! 30: * ! 31: * TODO: ! 32: * Support interfaces using only one BDP statically. ! 33: */ ! 34: ! 35: /* ! 36: * Init UNIBUS for interface on uban whose headers of size hlen are to ! 37: * end on a page boundary. We allocate a UNIBUS map register for the page ! 38: * with the header, and nmr more UNIBUS map registers for i/o on the adapter, ! 39: * doing this once for each read and once for each write buffer. We also ! 40: * allocate page frames in the mbuffer pool for these pages. ! 41: */ ! 42: if_ubaminit(ifu, uban, hlen, nmr, ifr, nr, ifw, nw) ! 43: register struct ifubinfo *ifu; ! 44: int uban, hlen, nmr, nr, nw; ! 45: register struct ifrw *ifr; ! 46: register struct ifxmt *ifw; ! 47: { ! 48: register caddr_t p; ! 49: caddr_t cp; ! 50: int i, nclbytes, off; ! 51: ! 52: if (hlen) ! 53: off = CLBYTES - hlen; ! 54: else ! 55: off = 0; ! 56: nclbytes = CLBYTES * (clrnd(nmr) / CLSIZE); ! 57: if (hlen) ! 58: nclbytes += CLBYTES; ! 59: if (ifr[0].ifrw_addr) ! 60: cp = ifr[0].ifrw_addr - off; ! 61: else { ! 62: cp = (caddr_t)malloc((u_long)((nr + nw) * nclbytes), M_DEVBUF, ! 63: M_NOWAIT); ! 64: if (cp == 0) ! 65: return (0); ! 66: p = cp; ! 67: for (i = 0; i < nr; i++) { ! 68: ifr[i].ifrw_addr = p + off; ! 69: p += nclbytes; ! 70: } ! 71: for (i = 0; i < nw; i++) { ! 72: ifw[i].ifw_base = p; ! 73: ifw[i].ifw_addr = p + off; ! 74: p += nclbytes; ! 75: } ! 76: ifu->iff_hlen = hlen; ! 77: ifu->iff_uban = uban; ! 78: ifu->iff_uba = uba_hd[uban].uh_uba; ! 79: ifu->iff_ubamr = uba_hd[uban].uh_mr; ! 80: } ! 81: for (i = 0; i < nr; i++) ! 82: if (if_ubaalloc(ifu, &ifr[i], nmr) == 0) { ! 83: nr = i; ! 84: nw = 0; ! 85: goto bad; ! 86: } ! 87: for (i = 0; i < nw; i++) ! 88: if (if_ubaalloc(ifu, &ifw[i].ifrw, nmr) == 0) { ! 89: nw = i; ! 90: goto bad; ! 91: } ! 92: while (--nw >= 0) { ! 93: for (i = 0; i < nmr; i++) ! 94: ifw[nw].ifw_wmap[i] = ifw[nw].ifw_mr[i]; ! 95: ifw[nw].ifw_xswapd = 0; ! 96: ifw[nw].ifw_flags = IFRW_W; ! 97: ifw[nw].ifw_nmr = nmr; ! 98: } ! 99: return (1); ! 100: bad: ! 101: while (--nw >= 0) ! 102: ubarelse(ifu->iff_uban, &ifw[nw].ifw_info); ! 103: while (--nr >= 0) ! 104: ubarelse(ifu->iff_uban, &ifr[nr].ifrw_info); ! 105: free(cp, M_DEVBUF); ! 106: ifr[0].ifrw_addr = 0; ! 107: return (0); ! 108: } ! 109: ! 110: /* ! 111: * Setup an ifrw structure by allocating UNIBUS map registers, ! 112: * possibly a buffered data path, and initializing the fields of ! 113: * the ifrw structure to minimize run-time overhead. ! 114: */ ! 115: static ! 116: if_ubaalloc(ifu, ifrw, nmr) ! 117: struct ifubinfo *ifu; ! 118: register struct ifrw *ifrw; ! 119: int nmr; ! 120: { ! 121: register int info; ! 122: ! 123: info = ! 124: uballoc(ifu->iff_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->iff_hlen, ! 125: ifu->iff_flags); ! 126: if (info == 0) ! 127: return (0); ! 128: ifrw->ifrw_info = info; ! 129: ifrw->ifrw_bdp = UBAI_BDP(info); ! 130: ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT); ! 131: ifrw->ifrw_mr = &ifu->iff_ubamr[UBAI_MR(info) + (ifu->iff_hlen? 1 : 0)]; ! 132: return (1); ! 133: } ! 134: ! 135: /* ! 136: * Pull read data off a interface. ! 137: * Len is length of data, with local net header stripped. ! 138: * Off is non-zero if a trailer protocol was used, and ! 139: * gives the offset of the trailer information. ! 140: * We copy the trailer information and then all the normal ! 141: * data into mbufs. When full cluster sized units are present ! 142: * on the interface on cluster boundaries we can get them more ! 143: * easily by remapping, and take advantage of this here. ! 144: * Prepend a pointer to the interface structure, ! 145: * so that protocols can determine where incoming packets arrived. ! 146: * Note: we may be called to receive from a transmit buffer by some ! 147: * devices. In that case, we must force normal mapping of the buffer, ! 148: * so that the correct data will appear (only unibus maps are ! 149: * changed when remapping the transmit buffers). ! 150: */ ! 151: struct mbuf * ! 152: if_ubaget(ifu, ifr, totlen, off0, ifp) ! 153: struct ifubinfo *ifu; ! 154: register struct ifrw *ifr; ! 155: int totlen, off0; ! 156: struct ifnet *ifp; ! 157: { ! 158: struct mbuf *top, **mp; ! 159: register struct mbuf *m; ! 160: int off = off0, len; ! 161: register caddr_t cp = ifr->ifrw_addr + ifu->iff_hlen, pp; ! 162: ! 163: top = 0; ! 164: mp = ⊤ ! 165: if (ifr->ifrw_flags & IFRW_W) ! 166: rcv_xmtbuf((struct ifxmt *)ifr); ! 167: while (totlen > 0) { ! 168: MGET(m, M_DONTWAIT, MT_DATA); ! 169: if (m == 0) { ! 170: m_freem(top); ! 171: top = 0; ! 172: goto out; ! 173: } ! 174: if (off) { ! 175: len = totlen - off; ! 176: cp = ifr->ifrw_addr + ifu->iff_hlen + off; ! 177: } else ! 178: len = totlen; ! 179: if (len >= CLBYTES/2) { ! 180: struct pte *cpte, *ppte; ! 181: int x, *ip, i; ! 182: ! 183: /* ! 184: * If doing the first mbuf and ! 185: * the interface pointer hasn't been put in, ! 186: * put it in a separate mbuf to preserve alignment. ! 187: */ ! 188: if (ifp) { ! 189: len = 0; ! 190: goto nopage; ! 191: } ! 192: MCLGET(m); ! 193: if (m->m_len != CLBYTES) ! 194: goto nopage; ! 195: m->m_len = MIN(len, CLBYTES); ! 196: if (!claligned(cp)) ! 197: goto copy; ! 198: ! 199: /* ! 200: * Switch pages mapped to UNIBUS with new page pp, ! 201: * as quick form of copy. Remap UNIBUS and invalidate. ! 202: */ ! 203: pp = mtod(m, char *); ! 204: cpte = kvtopte(cp); ! 205: ppte = kvtopte(pp); ! 206: x = btop(cp - ifr->ifrw_addr); ! 207: ip = (int *)&ifr->ifrw_mr[x]; ! 208: for (i = 0; i < CLSIZE; i++) { ! 209: struct pte t; ! 210: t = *ppte; *ppte++ = *cpte; *cpte = t; ! 211: *ip++ = cpte++->pg_pfnum|ifr->ifrw_proto; ! 212: mtpr(TBIS, cp); ! 213: cp += NBPG; ! 214: mtpr(TBIS, (caddr_t)pp); ! 215: pp += NBPG; ! 216: } ! 217: goto nocopy; ! 218: } ! 219: nopage: ! 220: m->m_off = MMINOFF; ! 221: if (ifp) { ! 222: /* ! 223: * Leave room for ifp. ! 224: */ ! 225: m->m_len = MIN(MLEN - sizeof(ifp), len); ! 226: m->m_off += sizeof(ifp); ! 227: } else ! 228: m->m_len = MIN(MLEN, len); ! 229: copy: ! 230: bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len); ! 231: cp += m->m_len; ! 232: nocopy: ! 233: *mp = m; ! 234: mp = &m->m_next; ! 235: if (off) { ! 236: /* sort of an ALGOL-W style for statement... */ ! 237: off += m->m_len; ! 238: if (off == totlen) { ! 239: cp = ifr->ifrw_addr + ifu->iff_hlen; ! 240: off = 0; ! 241: totlen = off0; ! 242: } ! 243: } else ! 244: totlen -= m->m_len; ! 245: if (ifp) { ! 246: /* ! 247: * Prepend interface pointer to first mbuf. ! 248: */ ! 249: m->m_len += sizeof(ifp); ! 250: m->m_off -= sizeof(ifp); ! 251: *(mtod(m, struct ifnet **)) = ifp; ! 252: ifp = (struct ifnet *)0; ! 253: } ! 254: } ! 255: out: ! 256: if (ifr->ifrw_flags & IFRW_W) ! 257: restor_xmtbuf((struct ifxmt *)ifr); ! 258: return (top); ! 259: } ! 260: ! 261: /* ! 262: * Change the mapping on a transmit buffer so that if_ubaget may ! 263: * receive from that buffer. Copy data from any pages mapped to Unibus ! 264: * into the pages mapped to normal kernel virtual memory, so that ! 265: * they can be accessed and swapped as usual. We take advantage ! 266: * of the fact that clusters are placed on the xtofree list ! 267: * in inverse order, finding the last one. ! 268: */ ! 269: static ! 270: rcv_xmtbuf(ifw) ! 271: register struct ifxmt *ifw; ! 272: { ! 273: register struct mbuf *m; ! 274: struct mbuf **mprev; ! 275: register i; ! 276: char *cp; ! 277: ! 278: while (i = ffs((long)ifw->ifw_xswapd)) { ! 279: cp = ifw->ifw_base + i * CLBYTES; ! 280: i--; ! 281: ifw->ifw_xswapd &= ~(1<<i); ! 282: mprev = &ifw->ifw_xtofree; ! 283: for (m = ifw->ifw_xtofree; m && m->m_next; m = m->m_next) ! 284: mprev = &m->m_next; ! 285: if (m == NULL) ! 286: break; ! 287: bcopy(mtod(m, caddr_t), cp, CLBYTES); ! 288: (void) m_free(m); ! 289: *mprev = NULL; ! 290: } ! 291: ifw->ifw_xswapd = 0; ! 292: for (i = 0; i < ifw->ifw_nmr; i++) ! 293: ifw->ifw_mr[i] = ifw->ifw_wmap[i]; ! 294: } ! 295: ! 296: /* ! 297: * Put a transmit buffer back together after doing an if_ubaget on it, ! 298: * which may have swapped pages. ! 299: */ ! 300: static ! 301: restor_xmtbuf(ifw) ! 302: register struct ifxmt *ifw; ! 303: { ! 304: register i; ! 305: ! 306: for (i = 0; i < ifw->ifw_nmr; i++) ! 307: ifw->ifw_wmap[i] = ifw->ifw_mr[i]; ! 308: } ! 309: ! 310: /* ! 311: * Map a chain of mbufs onto a network interface ! 312: * in preparation for an i/o operation. ! 313: * The argument chain of mbufs includes the local network ! 314: * header which is copied to be in the mapped, aligned ! 315: * i/o space. ! 316: */ ! 317: if_ubaput(ifu, ifw, m) ! 318: struct ifubinfo *ifu; ! 319: register struct ifxmt *ifw; ! 320: register struct mbuf *m; ! 321: { ! 322: register struct mbuf *mp; ! 323: register caddr_t cp, dp; ! 324: register int i; ! 325: int xswapd = 0; ! 326: int x, cc, t; ! 327: ! 328: cp = ifw->ifw_addr; ! 329: while (m) { ! 330: dp = mtod(m, char *); ! 331: if (claligned(cp) && claligned(dp) && ! 332: (m->m_len == CLBYTES || m->m_next == (struct mbuf *)0)) { ! 333: struct pte *pte; ! 334: int *ip; ! 335: ! 336: pte = kvtopte(dp); ! 337: x = btop(cp - ifw->ifw_addr); ! 338: ip = (int *)&ifw->ifw_mr[x]; ! 339: for (i = 0; i < CLSIZE; i++) ! 340: *ip++ = ifw->ifw_proto | pte++->pg_pfnum; ! 341: xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT)); ! 342: mp = m->m_next; ! 343: m->m_next = ifw->ifw_xtofree; ! 344: ifw->ifw_xtofree = m; ! 345: cp += m->m_len; ! 346: } else { ! 347: bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); ! 348: cp += m->m_len; ! 349: MFREE(m, mp); ! 350: } ! 351: m = mp; ! 352: } ! 353: ! 354: /* ! 355: * Xswapd is the set of clusters we just mapped out. Ifu->iff_xswapd ! 356: * is the set of clusters mapped out from before. We compute ! 357: * the number of clusters involved in this operation in x. ! 358: * Clusters mapped out before and involved in this operation ! 359: * should be unmapped so original pages will be accessed by the device. ! 360: */ ! 361: cc = cp - ifw->ifw_addr; ! 362: x = ((cc - ifu->iff_hlen) + CLBYTES - 1) >> CLSHIFT; ! 363: ifw->ifw_xswapd &= ~xswapd; ! 364: while (i = ffs((long)ifw->ifw_xswapd)) { ! 365: i--; ! 366: if (i >= x) ! 367: break; ! 368: ifw->ifw_xswapd &= ~(1<<i); ! 369: i *= CLSIZE; ! 370: for (t = 0; t < CLSIZE; t++) { ! 371: ifw->ifw_mr[i] = ifw->ifw_wmap[i]; ! 372: i++; ! 373: } ! 374: } ! 375: ifw->ifw_xswapd |= xswapd; ! 376: return (cc); ! 377: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.