[BACK]Return to if_uba.c CVS log [TXT][DIR] Up to [local] / sys / arch / vax / if

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