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

1.1       root        1: /*-
                      2:  * Copyright (c) 1990 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * Tim L. Tucker.
                      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. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  *
                     36:  */
                     37: /*
                     38:  * A driver for the 3Com 3C503 (Etherlink II) ethernet adaptor.
                     39:  *
                     40:  *   Written by Herb Peyerl ([email protected]) on 04/25/92.
                     41:  *   (This is my first ever device driver and I couldn't have done
                     42:  *    it without the consumption of many "Brock Gummy Bears" so a
                     43:  *    big thanx to the "Brock Candy Company" of Chattanooga TN)
                     44:  *
                     45:  *   This driver uses the Western Digital 8003 driver for a template
                     46:  *   since the two cards use the DP8390 chip by National.  Everything
                     47:  *   is fairly similar except that the nic on the wd8003 appears to
                     48:  *   to see shared memory at 0x0000 and on the 3com, the nic sees it 
                     49:  *   at 0x2000.  Also, the 3c503 has it's own ASIC for controlling 
                     50:  *   things like the IRQ level in software and whether to use the
                     51:  *   onboard xceiver or not.  Since the Clarkson drivers do a very
                     52:  *   good rendition of a 3c503, I also scavenged a lot of ideas from
                     53:  *   there.
                     54:  *
                     55:  * Kludges:
                     56:  *   Since I couldn't really think of any non-creative way (other than
                     57:  *   using a #define) of configuring the board to use the onboard xceiver,
                     58:  *   I kludged the isa_device->unit to contain this information.  Simply
                     59:  *   put, if bit-7 of isa_device->unit is set (>127) then the driver
                     60:  *   configures that unit to onboard-xceiver (BNC) and if <128 it assumes
                     61:  *   AUI.  ec_attach informs the user of this on bootup.  Also, ec_probe
                     62:  *   repairs this bit after obtaining it's information since I didn't know
                     63:  *   what else within the depths of the kernel would freak out if I left it.
                     64:  */
                     65: #include "param.h"
                     66: #include "mbuf.h"
                     67: #include "socket.h"
                     68: #include "ioctl.h"
                     69: #include "errno.h"
                     70: #include "syslog.h"
                     71: #include "net/if.h"
                     72: #include "net/netisr.h"
                     73: #ifdef INET
                     74: #include "netinet/in.h"
                     75: #include "netinet/in_systm.h"
                     76: #include "netinet/in_var.h"
                     77: #include "netinet/ip.h"
                     78: #include "netinet/if_ether.h"
                     79: #endif
                     80: #ifdef NS
                     81: #include "netns/ns.h"
                     82: #include "netns/ns_if.h"
                     83: #endif
                     84: #include "i386/isa/isa_device.h"
                     85: #include "i386/isa/if_ec.h"
                     86: 
1.1.1.2 ! root       87: #include "ec.h"
        !            88: 
1.1       root       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    */
1.1.1.2 ! root      100: #define ns_addrp ec_ac.ac_enaddr       /* hardware Ethernet address (for ns)*/
1.1       root      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))
1.1.1.2 ! root      607:                                ina->x_host = *(union ns_host *)(sc->ns_addrp);
1.1       root      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,
1.1.1.2 ! root      616:                                    (caddr_t)sc->ns_addrp, sizeof(sc->ns_addrp));
1.1       root      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: }

unix.superglobalmegacorp.com

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