Annotation of Net2/arch/i386/isa/if_ec.c, revision 1.1

1.1     ! root        1: #include "ec.h"
        !             2: #if NEC > 0
        !             3: /*-
        !             4:  * Copyright (c) 1990 The Regents of the University of California.
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * This code is derived from software contributed to Berkeley by
        !             8:  * Tim L. Tucker.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *     This product includes software developed by the University of
        !            21:  *     California, Berkeley and its contributors.
        !            22:  * 4. Neither the name of the University nor the names of its contributors
        !            23:  *    may be used to endorse or promote products derived from this software
        !            24:  *    without specific prior written permission.
        !            25:  *
        !            26:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            27:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            29:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            30:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            31:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            32:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            33:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            34:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            35:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            36:  * SUCH DAMAGE.
        !            37:  *
        !            38:  */
        !            39: /*
        !            40:  * A driver for the 3Com 3C503 (Etherlink II) ethernet adaptor.
        !            41:  *
        !            42:  *   Written by Herb Peyerl ([email protected]) on 04/25/92.
        !            43:  *   (This is my first ever device driver and I couldn't have done
        !            44:  *    it without the consumption of many "Brock Gummy Bears" so a
        !            45:  *    big thanx to the "Brock Candy Company" of Chattanooga TN)
        !            46:  *
        !            47:  *   This driver uses the Western Digital 8003 driver for a template
        !            48:  *   since the two cards use the DP8390 chip by National.  Everything
        !            49:  *   is fairly similar except that the nic on the wd8003 appears to
        !            50:  *   to see shared memory at 0x0000 and on the 3com, the nic sees it 
        !            51:  *   at 0x2000.  Also, the 3c503 has it's own ASIC for controlling 
        !            52:  *   things like the IRQ level in software and whether to use the
        !            53:  *   onboard xceiver or not.  Since the Clarkson drivers do a very
        !            54:  *   good rendition of a 3c503, I also scavenged a lot of ideas from
        !            55:  *   there.
        !            56:  *
        !            57:  * Kludges:
        !            58:  *   Since I couldn't really think of any non-creative way (other than
        !            59:  *   using a #define) of configuring the board to use the onboard xceiver,
        !            60:  *   I kludged the isa_device->unit to contain this information.  Simply
        !            61:  *   put, if bit-7 of isa_device->unit is set (>127) then the driver
        !            62:  *   configures that unit to onboard-xceiver (BNC) and if <128 it assumes
        !            63:  *   AUI.  ec_attach informs the user of this on bootup.  Also, ec_probe
        !            64:  *   repairs this bit after obtaining it's information since I didn't know
        !            65:  *   what else within the depths of the kernel would freak out if I left it.
        !            66:  */
        !            67: #include "param.h"
        !            68: #include "mbuf.h"
        !            69: #include "socket.h"
        !            70: #include "ioctl.h"
        !            71: #include "errno.h"
        !            72: #include "syslog.h"
        !            73: #include "net/if.h"
        !            74: #include "net/netisr.h"
        !            75: #ifdef INET
        !            76: #include "netinet/in.h"
        !            77: #include "netinet/in_systm.h"
        !            78: #include "netinet/in_var.h"
        !            79: #include "netinet/ip.h"
        !            80: #include "netinet/if_ether.h"
        !            81: #endif
        !            82: #ifdef NS
        !            83: #include "netns/ns.h"
        !            84: #include "netns/ns_if.h"
        !            85: #endif
        !            86: #include "i386/isa/isa_device.h"
        !            87: #include "i386/isa/if_ec.h"
        !            88: 
        !            89: /*
        !            90:  * Ethernet software status per interface.
        !            91:  *
        !            92:  * Each interface is referenced by a network interface structure,
        !            93:  * qe_if, which the routing code uses to locate the interface.
        !            94:  * This structure contains the output queue for the interface, its address, ...
        !            95:  */
        !            96: struct ec_softc {
        !            97:        struct  arpcom ec_ac;           /* Ethernet common part         */
        !            98: #define        ec_if   ec_ac.ac_if             /* network-visible interface    */
        !            99: #define        ec_addr ec_ac.ac_enaddr         /* hardware Ethernet address    */
        !           100: 
        !           101:        u_char  ec_flags;               /* software state               */
        !           102: #define        EC_RUNNING      0x01
        !           103: #define EC_TXBUSY      0x02
        !           104: 
        !           105:        u_char  ec_type;                /* interface type code          */
        !           106:        u_short ec_vector;              /* interrupt vector             */
        !           107:        short   ec_io_ctl_addr;         /* i/o bus address, control     */
        !           108:        short   ec_io_nic_addr;         /* i/o bus address, DS8390      */
        !           109:        short   thick_or_thin;          /* thick=0;thin=2               */
        !           110: 
        !           111:        caddr_t ec_vmem_addr;           /* card RAM virtual memory base */
        !           112:        u_long  ec_vmem_size;           /* card RAM bytes               */
        !           113:        caddr_t ec_vmem_ring;           /* receive ring RAM vaddress    */
        !           114:        caddr_t ec_vmem_end;            /* receive ring RAM end */
        !           115: } ec_softc[NEC];
        !           116: 
        !           117: #define PAGE0  outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0);
        !           118: #define PAGE1  outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE1);
        !           119: static Bdry;
        !           120: 
        !           121: int ether_output(),
        !           122:     ecprobe(),
        !           123:     ecattach(),
        !           124:     ecintr(),
        !           125:     ec_init(),
        !           126:     ec_ioctl(),
        !           127:     ec_reset(),
        !           128:     ec_watchdog(),
        !           129:     ec_start_output();
        !           130: 
        !           131: struct isa_driver ecdriver = {
        !           132:        ecprobe, 
        !           133:         ecattach,
        !           134:         "ec",
        !           135: };
        !           136: 
        !           137: ecprobe(is)
        !           138: struct isa_device *is;
        !           139: {
        !           140:        register struct ec_softc *sc = &ec_softc[is->id_unit&127];
        !           141:        int i, sum; 
        !           142: /*
        !           143:  * Set up the softc structure with card specific info.
        !           144:  * The 3Com asic is at base+0x400
        !           145:  */
        !           146:        sc->ec_io_ctl_addr = is->id_iobase + 0x400;
        !           147:        sc->ec_io_nic_addr = is->id_iobase;
        !           148:        sc->ec_vector = is->id_irq;
        !           149:        sc->ec_vmem_addr = (caddr_t)is->id_maddr;
        !           150:        sc->ec_vmem_size = is->id_msize;
        !           151:        sc->ec_vmem_ring = sc->ec_vmem_addr + (EC_PAGE_SIZE * EC_TXBUF_SIZE);
        !           152:        sc->ec_vmem_end = sc->ec_vmem_addr + is->id_msize;
        !           153: /* 
        !           154:  * Now we get the MAC address. Assume thin ethernet unless told otherwise later.
        !           155:  */
        !           156:        outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_RESET|2);  /* Toggle reset bit on*/
        !           157:        DELAY(100);
        !           158:        outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2);       /* Toggle reset bit off */
        !           159:        DELAY(100);
        !           160:        outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_SAPROM|2); /* Map SA_PROM */
        !           161:        for (i=0;i<ETHER_ADDR_LEN; ++i)
        !           162:                sc->ec_addr[i] = inb(sc->ec_io_nic_addr + i);
        !           163:        outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2);   /* Disable SA_PROM */
        !           164:        outb(sc->ec_io_ctl_addr + E33G_GACFR, EGACFR_IRQOFF);   /* tcm, rsel, mbs0, nim */
        !           165: /*
        !           166:  * Stop the chip just in case.
        !           167:  */
        !           168:        DELAY(1000);
        !           169:        PAGE0
        !           170:        outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
        !           171:        DELAY(1000);
        !           172: 
        !           173:        /* Check cmd reg and fail if not right */
        !           174:        if ((i=inb(sc->ec_io_nic_addr + EN_CCMD)) != (ENC_NODMA|ENC_STOP))
        !           175:                return(0);
        !           176: 
        !           177: /*
        !           178:  * Test the shared memory.
        !           179:  */
        !           180:        for(i = 0 ; i < sc->ec_vmem_size ; ++i)
        !           181:                sc->ec_vmem_addr[i] = 0x0;
        !           182:        for(sum=0, i=0; i<sc->ec_vmem_size; ++i)
        !           183:                sum += sc->ec_vmem_addr[i];
        !           184:        if(sum)
        !           185:        {
        !           186:                printf("ec%d: shared memory error (device conflict?)\n",
        !           187:                        is->id_unit);
        !           188:                return(0);
        !           189:        }
        !           190: /*
        !           191:  *  All done. 
        !           192:  */
        !           193:        return(1);
        !           194: }
        !           195: 
        !           196: ecattach(is)
        !           197: struct isa_device *is;
        !           198: {
        !           199:        register struct ec_softc *sc = &ec_softc[is->id_unit];
        !           200:        register struct ifnet *ifp = &sc->ec_if;
        !           201: 
        !           202: /**
        !           203:  ** Initialize the ASIC in same order as Clarkson driver.
        !           204:  **/
        !           205: 
        !           206: 
        !           207: /*
        !           208:  * Point vector pointer registers off into boonies.
        !           209:  */
        !           210:        outb(sc->ec_io_ctl_addr + E33G_VP2, 0xff);
        !           211:        outb(sc->ec_io_ctl_addr + E33G_VP1, 0xff);
        !           212:        outb(sc->ec_io_ctl_addr + E33G_VP0, 0x0);
        !           213: /*
        !           214:  * Set up control of shared memory, buffer ring, etc.
        !           215:  */
        !           216:        outb(sc->ec_io_ctl_addr + E33G_STARTPG, EC_RXBUF_OFFSET);
        !           217:        outb(sc->ec_io_ctl_addr + E33G_STOPPG, EC_RXBUF_END);
        !           218: /*
        !           219:  * Set up the IRQ  and NBURST on the board.
        !           220:  *  ( Not sure why we set up NBURST since we don't use DMA.) 
        !           221:  *
        !           222:  * Normally we would is->id_irq<<2 but IRQ2 is defined as 0x200
        !           223:  * in icu.h so it's a special case.
        !           224:  */
        !           225:        if(is->id_irq == 0x200)
        !           226:                outb(sc->ec_io_ctl_addr + E33G_IDCFR, 0x10);
        !           227:        else
        !           228:                outb(sc->ec_io_ctl_addr + E33G_IDCFR, is->id_irq << 2);
        !           229:         outb(sc->ec_io_ctl_addr + E33G_NBURST, 0x08);     /* Set Burst to 8 */
        !           230:        outb(sc->ec_io_ctl_addr + E33G_DMAAH, 0x20);
        !           231:        outb(sc->ec_io_ctl_addr + E33G_DMAAL, 0x0);
        !           232: /*
        !           233:  * Fill in the ifnet structure.
        !           234:  */
        !           235:        ifp->if_unit = is->id_unit;
        !           236:        ifp->if_name = "ec" ;
        !           237:        ifp->if_mtu = ETHERMTU;
        !           238:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
        !           239:        ifp->if_init = ec_init;
        !           240:        ifp->if_output = ether_output;
        !           241:        ifp->if_start = ec_start_output;
        !           242:        ifp->if_ioctl = ec_ioctl;
        !           243:        ifp->if_reset = ec_reset;
        !           244:        ifp->if_watchdog = ec_watchdog;
        !           245: /*
        !           246:  * Attach the interface to something. Have to figure this out later.
        !           247:  */
        !           248:        if_attach(ifp);
        !           249: /*
        !           250:  * Weeee.. We get to tell people we exist...
        !           251:  */
        !           252:        printf(" address %s", ether_sprintf(sc->ec_addr));
        !           253: }
        !           254: 
        !           255: ec_init(unit)
        !           256: int unit;
        !           257: {
        !           258:        register struct ec_softc *sc = &ec_softc[unit];
        !           259:        register struct ifnet *ifp = &sc->ec_if;
        !           260:        int i, s;
        !           261:        u_short   ax, cx;
        !           262: 
        !           263:        Bdry=0;
        !           264: printf("ecinit");
        !           265: /*
        !           266:  * Address not known.
        !           267:  */
        !           268:        if(ifp->if_addrlist == (struct ifaddr *) 0)
        !           269:                return;
        !           270: 
        !           271:        /*
        !           272:         * XXX (untested)
        !           273:         * select thick (e.g. AUI connector) if LLC0 bit is set
        !           274:         */
        !           275:        if (ifp->if_flags & IFF_LLC0)
        !           276:                outb(sc->ec_io_ctl_addr + E33G_CNTRL, 0);
        !           277:        else
        !           278:                outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2);
        !           279: 
        !           280: /*
        !           281:  * Set up the 8390 chip.
        !           282:  *   (Use sequence recommended by 3Com. )
        !           283:  */
        !           284:        s=splhigh();
        !           285:        PAGE0
        !           286:        outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0|ENC_STOP);
        !           287:        outb(sc->ec_io_nic_addr + EN0_DCFG, ENDCFG_BM8);
        !           288:        outb(sc->ec_io_nic_addr + EN0_RCNTLO, 0x0);
        !           289:        outb(sc->ec_io_nic_addr + EN0_RCNTHI, 0x0);
        !           290:        outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_MON );
        !           291:        outb(sc->ec_io_nic_addr + EN0_TXCR, 0x02);
        !           292:        outb(sc->ec_io_nic_addr + EN0_BOUNDARY, EC_RXBUF_OFFSET);
        !           293:        outb(sc->ec_io_nic_addr + EN0_TPSR, 0x20);
        !           294:        outb(sc->ec_io_nic_addr + EN0_STARTPG, EC_RXBUF_OFFSET);
        !           295:        outb(sc->ec_io_nic_addr + EN0_STOPPG, EC_RXBUF_END);
        !           296:        outb(sc->ec_io_nic_addr + EN0_ISR, 0xff);
        !           297:        outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f);
        !           298: /*
        !           299:  * Copy Ethernet address from SA_PROM into 8390 chip registers.
        !           300:  */
        !           301:        PAGE1
        !           302:        for(i=0;i<6;i++)
        !           303:                outb(sc->ec_io_nic_addr + EN1_PHYS+i, sc->ec_addr[i]);
        !           304: /*
        !           305:  * Set multicast filter mask bits in case promiscuous rcv wanted (???)
        !           306:  *   (set to 0xff as in if_we.c)
        !           307:  */
        !           308:        for(i=0;i<8;i++)
        !           309:                outb(sc->ec_io_nic_addr + EN1_MULT+i, 0xff);
        !           310: /*
        !           311:  * Set current shared page for RX to work on.
        !           312:  */
        !           313:        outb(sc->ec_io_nic_addr + EN1_CURPAG, EC_RXBUF_OFFSET);
        !           314: /*
        !           315:  * Start the 8390. Clear Interrupt Status reg, and accept Broadcast
        !           316:  * packets.
        !           317:  */
        !           318:        outb(sc->ec_io_nic_addr + EN_CCMD, ENC_START|ENC_PAGE0|ENC_NODMA);
        !           319:        outb(sc->ec_io_nic_addr + EN0_ISR, 0xff);
        !           320:        outb(sc->ec_io_nic_addr + EN0_TXCR, 0x0);
        !           321:        outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_BCST);
        !           322: /*
        !           323:  * Take interface out of reset, program the vector,
        !           324:  * enable interrupts, and tell the world we are up.
        !           325:  */
        !           326:        ifp->if_flags |= IFF_RUNNING;
        !           327:        outb(sc->ec_io_ctl_addr + E33G_GACFR, EGACFR_NORM);  /* tcm, rsel, mbs0 */
        !           328:        (void) splx(s);
        !           329:        sc->ec_flags &= ~EC_TXBUSY;
        !           330:        ec_start_output(ifp);
        !           331: }
        !           332: 
        !           333: ec_start_output(ifp)
        !           334: struct ifnet *ifp;
        !           335: {
        !           336:        register struct ec_softc *sc = &ec_softc[ifp->if_unit];
        !           337:        struct mbuf *m0, *m;
        !           338:        register caddr_t buffer;
        !           339:        int len, s;
        !           340:        int ec_cmd_reg;
        !           341: 
        !           342: /*
        !           343:  * The DS8390 only has one transmit buffer, if it is busy we
        !           344:  * must wait until the transmit interrupt completes.
        !           345:  */
        !           346:        s=splhigh();
        !           347:        if(sc->ec_flags & EC_TXBUSY)
        !           348:        {
        !           349:                (void) splx(s);
        !           350:                return;
        !           351:        }
        !           352:        IF_DEQUEUE(&sc->ec_if.if_snd, m);
        !           353:        if(m == 0)
        !           354:        {
        !           355:                (void) splx(s);
        !           356:                return;
        !           357:        }
        !           358:        sc->ec_flags |= EC_TXBUSY;
        !           359:        (void) splx(s);
        !           360: 
        !           361: /*
        !           362:  * Copy the mbuf chain into the transmit buffer
        !           363:  */
        !           364:        buffer = sc->ec_vmem_addr;
        !           365:        len = 0;
        !           366:        for(m0 = m; m!= 0; m = m->m_next)
        !           367:        {
        !           368:                bcopy(mtod(m, caddr_t), buffer, m->m_len);
        !           369:                buffer += m->m_len;
        !           370:                len  += m->m_len;
        !           371:        }
        !           372:        m_freem(m0);
        !           373: 
        !           374: /*
        !           375:  * Init transmit length registers and set transmit start flag.
        !           376:  */
        !           377:        s=splhigh();
        !           378:        len = MAX(len, ETHER_MIN_LEN);
        !           379:        PAGE0
        !           380:        outb(sc->ec_io_nic_addr + EN0_TCNTLO, len & 0xff);
        !           381:        outb(sc->ec_io_nic_addr + EN0_TCNTHI, len >> 8);
        !           382:        ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
        !           383:        outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg|ENC_TRANS);
        !           384:        (void) splx(s);
        !           385: }
        !           386: 
        !           387:        int ec_cmd_reg, ec_sts_reg;
        !           388: /*
        !           389:  * Interrupt handler.
        !           390:  */
        !           391: ecintr(unit)
        !           392: int unit;
        !           393: {
        !           394:        register struct ec_softc *sc = &ec_softc[unit];
        !           395: 
        !           396:        unit = 0;
        !           397: 
        !           398: /*
        !           399:  * Get current command register and interrupt status.
        !           400:  * Turn off interrupts while we take care of things.
        !           401:  */
        !           402:        ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
        !           403:        PAGE0
        !           404:        ec_sts_reg = inb(sc->ec_io_nic_addr + EN0_ISR);
        !           405:        outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
        !           406: loop:
        !           407:        outb(sc->ec_io_nic_addr + EN0_ISR, ec_sts_reg);
        !           408:        /*
        !           409:         * have we lost ourselves somewhere?
        !           410:         */
        !           411:        if (ec_sts_reg == 0xff)
        !           412:                ec_watchdog(unit);
        !           413: /*
        !           414:  * Transmit error
        !           415:  */
        !           416:        if(ec_sts_reg & ENISR_TX_ERR)
        !           417:        {
        !           418:                sc->ec_if.if_collisions += inb(sc->ec_io_nic_addr + EN0_TCNTLO);
        !           419:                ++sc->ec_if.if_oerrors;
        !           420:        }
        !           421: /*
        !           422:  * Receive Error
        !           423:  */
        !           424:        if(ec_sts_reg & ENISR_RX_ERR)
        !           425:        {
        !           426:                (void) inb(sc->ec_io_nic_addr + 0xD);
        !           427:                (void) inb(sc->ec_io_nic_addr + 0xE);
        !           428:                (void) inb(sc->ec_io_nic_addr + 0xF);
        !           429:                ++sc->ec_if.if_ierrors;
        !           430:        }
        !           431: /*
        !           432:  * Normal transmit complete.
        !           433:  */
        !           434:        if(ec_sts_reg&ENISR_TX || ec_sts_reg&ENISR_TX_ERR) 
        !           435:                ectint(unit);
        !           436: /*
        !           437:  * Normal receive notification
        !           438:  */
        !           439:        if(ec_sts_reg&(ENISR_RX|ENISR_RX_ERR)) 
        !           440:                ecrint(unit);
        !           441: 
        !           442: /*
        !           443:  * Try to start transmit
        !           444:  */
        !           445:        ec_start_output(&sc->ec_if);
        !           446: /*
        !           447:  * Reenable  onboard interrupts.
        !           448:  */
        !           449:        /*PAGE0*/
        !           450:        outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg);
        !           451:        outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f);
        !           452:        if(ec_sts_reg=inb(sc->ec_io_nic_addr + EN0_ISR))
        !           453:                goto loop;
        !           454: }
        !           455: 
        !           456: /*
        !           457:  * Transmit interrupt
        !           458:  */
        !           459: ectint(unit)
        !           460: int unit;
        !           461: {
        !           462:        register struct ec_softc *sc = &ec_softc[unit];
        !           463: /*
        !           464:  * Do some statistics.
        !           465:  */
        !           466:        PAGE0
        !           467:        sc->ec_flags &= ~EC_TXBUSY;
        !           468:        sc->ec_if.if_timer = 0;
        !           469:        ++sc->ec_if.if_opackets;
        !           470:        sc->ec_if.if_collisions += inb(sc->ec_io_nic_addr + EN0_TCNTLO);
        !           471: }
        !           472: 
        !           473: /*
        !           474:  * Receive interrupt.
        !           475:  * (This gave me the most trouble so excuse the mess.)
        !           476:  */
        !           477: ecrint(unit)
        !           478: int unit;
        !           479: {
        !           480:        register struct ec_softc *sc = &ec_softc[unit];
        !           481:        u_char bnry, curr;
        !           482:        int len;
        !           483:        struct ec_ring *ecr;
        !           484:  
        !           485:        /*
        !           486:         * Traverse the receive ring looking for packets to pass back.
        !           487:         * The search is complete when we find a descriptor not in use.
        !           488:         */
        !           489:        PAGE0
        !           490:        bnry = inb(sc->ec_io_nic_addr + EN0_BOUNDARY);
        !           491:        PAGE1
        !           492:        curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
        !           493: if(Bdry)
        !           494:        bnry =Bdry;
        !           495: 
        !           496:        while (bnry != curr)
        !           497:        {
        !           498:                /* get pointer to this buffer header structure */
        !           499:                ecr = (struct ec_ring *)(sc->ec_vmem_addr + ((bnry-EC_VMEM_OFFSET) << 8));
        !           500: 
        !           501:                /* count includes CRC */
        !           502:                len = ecr->ec_count - 4;
        !           503:                /*if (len > 30 && len <= ETHERMTU+100) */
        !           504:                        ecread(sc, (caddr_t)(ecr + 1), len);
        !           505:                /*else printf("reject:%x bnry:%x curr:%x", len, bnry, curr);*/
        !           506: outofbufs:
        !           507:                PAGE0
        !           508:                /* advance on chip Boundry register */
        !           509:                if((caddr_t) ecr + EC_PAGE_SIZE - 1 > sc->ec_vmem_end) {
        !           510:                        bnry = EC_RXBUF_OFFSET;
        !           511:                        outb(sc->ec_io_nic_addr + EN0_BOUNDARY,
        !           512:                                (sc->ec_vmem_size / EC_PAGE_SIZE) - 1 - EC_VMEM_OFFSET); 
        !           513:                } else {
        !           514:                        if (len > 30 && len <= ETHERMTU+100)
        !           515:                                bnry = ecr->ec_next_packet;
        !           516:                        else bnry = curr;
        !           517: 
        !           518:                        /* watch out for NIC overflow, reset Boundry if invalid */
        !           519:                        if ((bnry - 1) < EC_RXBUF_OFFSET) {
        !           520:                                outb(sc->ec_io_nic_addr + EN0_BOUNDARY, 
        !           521:                                        (sc->ec_vmem_size / EC_PAGE_SIZE) - 1 - EC_VMEM_OFFSET);
        !           522:                                bnry = EC_RXBUF_OFFSET;
        !           523:                        } else
        !           524:                                outb(sc->ec_io_nic_addr + EN0_BOUNDARY, bnry-1);
        !           525:                }
        !           526: 
        !           527:                /* refresh our copy of CURR */
        !           528:                PAGE1
        !           529:                curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
        !           530:        }
        !           531:        Bdry = bnry;
        !           532:        PAGE0
        !           533: }
        !           534: 
        !           535: #define        ecdataaddr(sc, eh, off, type) \
        !           536:        ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->ec_vmem_end) ? \
        !           537:                (((caddr_t)((eh)+1)+(off))) - (sc)->ec_vmem_end \
        !           538:                + (sc)->ec_vmem_ring: \
        !           539:                ((caddr_t)((eh)+1)+(off)))
        !           540: 
        !           541: ecread(sc, buf, len)
        !           542: register struct ec_softc *sc;
        !           543: char *buf;
        !           544: int len;
        !           545: {
        !           546:        register struct ether_header *eh;
        !           547:        struct mbuf *m, *ecget();
        !           548:        int off, resid;
        !           549: 
        !           550:        /*
        !           551:         * Deal with trailer protocol: if type is trailer type
        !           552:         * get true type from first 16-bit word past data.
        !           553:         * Remember that type was trailer by setting off.
        !           554:         */
        !           555:        eh = (struct ether_header *)buf;
        !           556:        eh->ether_type = ntohs((u_short)eh->ether_type);
        !           557:        if (eh->ether_type >= ETHERTYPE_TRAIL &&
        !           558:            eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
        !           559:                off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
        !           560:                if (off >= ETHERMTU) return;            /* sanity */
        !           561:                eh->ether_type = ntohs(*ecdataaddr(sc, eh, off, u_short *));
        !           562:                resid = ntohs(*(ecdataaddr(sc, eh, off+2, u_short *)));
        !           563:                if (off + resid > len) return;          /* sanity */
        !           564:                len = off + resid;
        !           565:        } else  off = 0;
        !           566: 
        !           567:        len -= sizeof(struct ether_header);
        !           568:        if (len <= 0) return;
        !           569: 
        !           570:        /*
        !           571:         * Pull packet off interface.  Off is nonzero if packet
        !           572:         * has trailing header; neget will then force this header
        !           573:         * information to be at the front, but we still have to drop
        !           574:         * the type and length which are at the front of any trailer data.
        !           575:         */
        !           576:        m = ecget(buf, len, off, &sc->ec_if, sc);
        !           577:        if (m == 0) return;
        !           578:        ether_input(&sc->ec_if, eh, m);
        !           579: }
        !           580: ec_ioctl(ifp, cmd, data)
        !           581: register struct ifnet *ifp;
        !           582: int cmd;
        !           583: caddr_t data;
        !           584: {
        !           585:        register struct ifaddr *ifa = (struct ifaddr *)data;
        !           586:        struct ec_softc *sc = &ec_softc[ifp->if_unit];
        !           587:        struct ifreq *ifr = (struct ifreq *)data;
        !           588:        int s=splimp(), error=0;
        !           589:        switch(cmd){
        !           590:        case SIOCSIFADDR:
        !           591:                ifp->if_flags |= IFF_UP;
        !           592:                switch (ifa->ifa_addr->sa_family) {
        !           593: #ifdef INET
        !           594:                case AF_INET:
        !           595:                        ec_init(ifp->if_unit);  /* before arpwhohas */
        !           596:                        ((struct arpcom *)ifp)->ac_ipaddr =
        !           597:                                IA_SIN(ifa)->sin_addr;
        !           598:                        arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
        !           599:                        break;
        !           600: #endif
        !           601: #ifdef NS
        !           602:                case AF_NS:
        !           603:                    {
        !           604:                        register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
        !           605: 
        !           606:                        if (ns_nullhost(*ina))
        !           607:                                ina->x_host = *(union ns_host *)(sc->ns_addr);
        !           608:                        else {
        !           609:                                /* 
        !           610:                                 * The manual says we can't change the address 
        !           611:                                 * while the receiver is armed,
        !           612:                                 * so reset everything
        !           613:                                 */
        !           614:                                ifp->if_flags &= ~IFF_RUNNING; 
        !           615:                                bcopy((caddr_t)ina->x_host.c_host,
        !           616:                                    (caddr_t)sc->ns_addr, sizeof(sc->ns_addr));
        !           617:                        }
        !           618:                        ec_init(ifp->if_unit); /* does ne_setaddr() */
        !           619:                        break;
        !           620:                    }
        !           621: #endif
        !           622:                default:
        !           623:                        ec_init(ifp->if_unit);
        !           624:                        break;
        !           625:                }
        !           626:                break;
        !           627: 
        !           628:        case SIOCSIFFLAGS:
        !           629:                if ((ifp->if_flags & IFF_UP) == 0 &&
        !           630:                    ifp->if_flags & IFF_RUNNING) {
        !           631:                        ifp->if_flags &= ~IFF_RUNNING;
        !           632:                        ec_stop(ifp->if_unit);
        !           633:                } else if (ifp->if_flags & IFF_UP &&
        !           634:                    (ifp->if_flags & IFF_RUNNING) == 0)
        !           635:                        ec_init(ifp->if_unit);
        !           636:                break;
        !           637: 
        !           638: #ifdef notdef
        !           639:        case SIOCGHWADDR:
        !           640:                bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
        !           641:                        sizeof(sc->sc_addr));
        !           642:                break;
        !           643: #endif
        !           644: 
        !           645:        default:
        !           646:                error = EINVAL;
        !           647:        }
        !           648:        splx(s);
        !           649:        return (error);
        !           650: }
        !           651: 
        !           652: ec_reset(unit)
        !           653: int unit;
        !           654: {
        !           655:        if(unit >= NEC)
        !           656:                return;
        !           657:        printf("ec%d: reset\n", unit);
        !           658:        ec_init(unit);
        !           659: }
        !           660: 
        !           661: ec_watchdog(unit)
        !           662: int unit;
        !           663: {
        !           664:        log(LOG_WARNING, "ec%d: soft reset\n", unit);
        !           665:        ec_stop(unit);
        !           666:        ec_init(unit);
        !           667: }
        !           668: 
        !           669: ec_stop(unit)
        !           670: int unit;
        !           671: {
        !           672:        register struct ec_softc *sc = &ec_softc[unit];
        !           673:        int s;
        !           674: 
        !           675:        s=splimp();
        !           676:        PAGE0
        !           677:        outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
        !           678:        outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
        !           679:        sc->ec_flags &= ~EC_RUNNING;
        !           680: /*
        !           681:  * Shutdown the 8390.
        !           682:  */
        !           683:        (void) splx(s);
        !           684: }
        !           685: 
        !           686: /*
        !           687:  * Pull read data off a interface.
        !           688:  * Len is length of data, with local net header stripped.
        !           689:  * Off is non-zero if a trailer protocol was used, and
        !           690:  * gives the offset of the trailer information.
        !           691:  * We copy the trailer information and then all the normal
        !           692:  * data into mbufs.  When full cluster sized units are present
        !           693:  * we copy into clusters.
        !           694:  */
        !           695: struct mbuf *
        !           696: ecget(buf, totlen, off0, ifp, sc)
        !           697:        caddr_t buf;
        !           698:        int totlen, off0;
        !           699:        struct ifnet *ifp;
        !           700:        struct ec_softc *sc;
        !           701: {
        !           702:        struct mbuf *top, **mp, *m, *p;
        !           703:        int off = off0, len;
        !           704:        register caddr_t cp = buf;
        !           705:        char *epkt;
        !           706:        int tc =totlen;
        !           707: 
        !           708:        buf += sizeof(struct ether_header);
        !           709:        cp = buf;
        !           710:        epkt = cp + totlen;
        !           711: 
        !           712:        if (off) {
        !           713:                cp += off + 2 * sizeof(u_short);
        !           714:                totlen -= 2 * sizeof(u_short);
        !           715:        }
        !           716: 
        !           717:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           718:        if (m == 0)
        !           719:                return (0);
        !           720:        m->m_pkthdr.rcvif = ifp;
        !           721:        m->m_pkthdr.len = totlen;
        !           722:        m->m_len = MHLEN;
        !           723: 
        !           724:        top = 0;
        !           725:        mp = &top;
        !           726:        while (totlen > 0) {
        !           727:                if (top) {
        !           728:                        MGET(m, M_DONTWAIT, MT_DATA);
        !           729:                        if (m == 0) {
        !           730:                                m_freem(top);
        !           731:                                return (0);
        !           732:                        }
        !           733:                        m->m_len = MLEN;
        !           734:                }
        !           735:                len = min(totlen, epkt - cp);
        !           736:                if (len >= MINCLSIZE) {
        !           737:                        MCLGET(m, M_DONTWAIT);
        !           738:                        if (m->m_flags & M_EXT)
        !           739:                                m->m_len = len = min(len, MCLBYTES);
        !           740:                        else
        !           741:                                len = m->m_len;
        !           742:                } else {
        !           743:                        /*
        !           744:                         * Place initial small packet/header at end of mbuf.
        !           745:                         */
        !           746:                        if (len < m->m_len) {
        !           747:                                if (top == 0 && len + max_linkhdr <= m->m_len)
        !           748:                                        m->m_data += max_linkhdr;
        !           749:                                m->m_len = len;
        !           750:                        } else
        !           751:                                len = m->m_len;
        !           752:                }
        !           753: 
        !           754:                totlen -= len;
        !           755:                /* only do up to end of buffer */
        !           756:                if (cp+len > sc->ec_vmem_end) {
        !           757:                        unsigned toend = sc->ec_vmem_end - cp;
        !           758: 
        !           759:                        bcopy(cp, mtod(m, caddr_t), toend);
        !           760:                        cp = sc->ec_vmem_ring;
        !           761:                        bcopy(cp, mtod(m, caddr_t)+toend, len - toend);
        !           762:                        cp += len - toend;
        !           763:                        epkt = cp + totlen;
        !           764:                } else {
        !           765:                        bcopy(cp, mtod(m, caddr_t), (unsigned)len);
        !           766:                        cp += len;
        !           767:                }
        !           768:                *mp = m;
        !           769:                mp = &m->m_next;
        !           770:                if (cp == epkt) {
        !           771:                        cp = buf;
        !           772:                        epkt = cp + tc;
        !           773:                }
        !           774:        }
        !           775:        return (top);
        !           776: }
        !           777: #endif /* NEC > 0 */

unix.superglobalmegacorp.com

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