Annotation of Net2/arch/vax/if/if_uba.c, revision 1.1.1.1

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 = &top;
                    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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.