Annotation of qemu/roms/ipxe/src/drivers/net/natsemi.c, revision 1.1

1.1     ! root        1: /* 
        !             2:    natsemi.c - iPXE driver for the NatSemi DP8381x series.
        !             3:  
        !             4:    Based on:
        !             5: 
        !             6:    natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
        !             7: 
        !             8:    Copyright (C) 2001 Entity Cyber, Inc.
        !             9:    
        !            10:    This development of this Etherboot driver was funded by 
        !            11:    
        !            12:       Sicom Systems: http://www.sicompos.com/
        !            13:    
        !            14:    Author: Marty Connor <[email protected]>
        !            15:    Adapted from a Linux driver which was written by Donald Becker
        !            16:    
        !            17:    This software may be used and distributed according to the terms
        !            18:    of the GNU Public License (GPL), incorporated herein by reference.
        !            19:    
        !            20:    Original Copyright Notice:
        !            21:    
        !            22:    Written/copyright 1999-2001 by Donald Becker.
        !            23:    
        !            24:    This software may be used and distributed according to the terms of
        !            25:    the GNU General Public License (GPL), incorporated herein by reference.
        !            26:    Drivers based on or derived from this code fall under the GPL and must
        !            27:    retain the authorship, copyright and license notice.  This file is not
        !            28:    a complete program and may only be used when the entire operating
        !            29:    system is licensed under the GPL.  License for under other terms may be
        !            30:    available.  Contact the original author for details.
        !            31:    
        !            32:    The original author may be reached as [email protected], or at
        !            33:    Scyld Computing Corporation
        !            34:    410 Severn Ave., Suite 210
        !            35:    Annapolis MD 21403
        !            36:    
        !            37:    Support information and updates available at
        !            38:    http://www.scyld.com/network/netsemi.html
        !            39:    
        !            40:    References:
        !            41:    
        !            42:    http://www.scyld.com/expert/100mbps.html
        !            43:    http://www.scyld.com/expert/NWay.html
        !            44:    Datasheet is available from:
        !            45:    http://www.national.com/pf/DP/DP83815.html
        !            46: 
        !            47: */
        !            48: 
        !            49: FILE_LICENCE ( GPL_ANY );
        !            50: 
        !            51: /* Revision History */
        !            52: 
        !            53: /*
        !            54:   02 Jul 2007  Udayan Kumar     1.2 ported the driver from etherboot to iPXE API.
        !            55:                                     Fully rewritten,adapting the old driver.
        !            56:                                     Added a circular buffer for transmit and receive.
        !            57:                                     transmit routine will not wait for transmission to finish.
        !            58:                                     poll routine deals with it.
        !            59:   13 Dec 2003  Tim Legge         1.1 Enabled Multicast Support
        !            60:   29 May 2001  Marty Connor     1.0 Initial Release. Tested with Netgear FA311 and FA312 boards
        !            61: */
        !            62: 
        !            63: #include <stdint.h>
        !            64: #include <stdlib.h>
        !            65: #include <stdio.h>
        !            66: #include <string.h>
        !            67: #include <ipxe/io.h>
        !            68: #include <errno.h>
        !            69: #include <byteswap.h>
        !            70: #include <unistd.h>
        !            71: #include <ipxe/pci.h>
        !            72: #include <ipxe/if_ether.h>
        !            73: #include <ipxe/ethernet.h>
        !            74: #include <ipxe/iobuf.h>
        !            75: #include <ipxe/netdevice.h>
        !            76: #include <ipxe/spi_bit.h>
        !            77: #include <ipxe/threewire.h>
        !            78: #include <ipxe/nvo.h>
        !            79: #include "natsemi.h"
        !            80: 
        !            81: /*  Function Prototypes: */
        !            82:  
        !            83: static int natsemi_spi_read_bit ( struct bit_basher *, unsigned int );
        !            84: static void natsemi_spi_write_bit ( struct bit_basher *,unsigned int, unsigned long ); 
        !            85: static void natsemi_init_eeprom ( struct natsemi_private * ); 
        !            86: static int natsemi_probe (struct pci_device *pci);
        !            87: static void natsemi_reset (struct net_device *netdev);
        !            88: static int natsemi_open (struct net_device *netdev);
        !            89: static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf);
        !            90: static void natsemi_poll (struct net_device *netdev);
        !            91: static void natsemi_close (struct net_device *netdev);
        !            92: static void natsemi_irq (struct net_device *netdev, int enable);
        !            93: static void natsemi_remove (struct pci_device *pci);
        !            94: 
        !            95: /** natsemi net device operations */
        !            96: static struct net_device_operations natsemi_operations = {
        !            97:         .open           = natsemi_open,
        !            98:         .close          = natsemi_close,
        !            99:         .transmit       = natsemi_transmit,
        !           100:         .poll           = natsemi_poll,
        !           101:        .irq            = natsemi_irq,
        !           102: };
        !           103: 
        !           104: static int natsemi_spi_read_bit ( struct bit_basher *basher,
        !           105:                              unsigned int bit_id ) {
        !           106:        struct natsemi_private *np = container_of ( basher, struct natsemi_private,
        !           107:                                                 spibit.basher );
        !           108:        uint8_t mask = natsemi_ee_bits[bit_id];
        !           109:        uint8_t eereg;
        !           110: 
        !           111:        eereg = inb ( np->ioaddr + EE_REG );
        !           112:        return ( eereg & mask );
        !           113: }
        !           114: 
        !           115: static void natsemi_spi_write_bit ( struct bit_basher *basher,
        !           116:                                unsigned int bit_id, unsigned long data ) {
        !           117:        struct natsemi_private *np = container_of ( basher, struct natsemi_private,
        !           118:                                                 spibit.basher );
        !           119:        uint8_t mask = natsemi_ee_bits[bit_id];
        !           120:        uint8_t eereg;
        !           121: 
        !           122:        eereg = inb ( np->ioaddr + EE_REG );
        !           123:        eereg &= ~mask;
        !           124:        eereg |= ( data & mask );
        !           125:        outb ( eereg, np->ioaddr + EE_REG );
        !           126: }
        !           127: 
        !           128: static struct bit_basher_operations natsemi_basher_ops = {
        !           129:        .read = natsemi_spi_read_bit,
        !           130:        .write = natsemi_spi_write_bit,
        !           131: };
        !           132: 
        !           133: /*
        !           134:  * Set up for EEPROM access
        !           135:  *
        !           136:  * @v NAT              NATSEMI NIC
        !           137:  */
        !           138: static void natsemi_init_eeprom ( struct natsemi_private *np ) {
        !           139: 
        !           140:        /* Initialise three-wire bus 
        !           141:         */
        !           142:        np->spibit.basher.op = &natsemi_basher_ops;
        !           143:        np->spibit.bus.mode = SPI_MODE_THREEWIRE;
        !           144:        np->spibit.endianness = SPI_BIT_LITTLE_ENDIAN;
        !           145:        init_spi_bit_basher ( &np->spibit );
        !           146: 
        !           147:        /*natsemi DP 83815 only supports at93c46
        !           148:         */
        !           149:        init_at93c46 ( &np->eeprom, 16 );
        !           150:        np->eeprom.bus = &np->spibit.bus;
        !           151: 
        !           152:        /* It looks that this portion of EEPROM can be used for
        !           153:         * non-volatile stored options. Data sheet does not talk about
        !           154:         * this region.  Currently it is not working. But with some
        !           155:         * efforts it can.
        !           156:         */
        !           157:        nvo_init ( &np->nvo, &np->eeprom.nvs, 0x0c, 0x68, NULL, NULL );
        !           158: }
        !           159: 
        !           160: /**
        !           161:  * Probe PCI device
        !           162:  *
        !           163:  * @v pci      PCI device
        !           164:  * @v id       PCI ID
        !           165:  * @ret rc     Return status code
        !           166:  */
        !           167: static int natsemi_probe (struct pci_device *pci) {
        !           168:        struct net_device *netdev;
        !           169:        struct natsemi_private *np = NULL;
        !           170:        uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN];
        !           171:        uint8_t last=0,last1=0;
        !           172:        uint8_t prev_bytes[2];
        !           173:        int i;
        !           174:        int rc;
        !           175: 
        !           176:        /* Allocate net device 
        !           177:         */
        !           178:        netdev = alloc_etherdev (sizeof (*np));
        !           179:        if (! netdev) 
        !           180:                return -ENOMEM;
        !           181: 
        !           182:        netdev_init (netdev, &natsemi_operations);
        !           183:        np = netdev->priv;
        !           184:        pci_set_drvdata (pci, netdev);
        !           185:        netdev->dev = &pci->dev;
        !           186:        memset (np, 0, sizeof (*np));
        !           187:        np->ioaddr = pci->ioaddr;
        !           188: 
        !           189:        adjust_pci_device (pci);
        !           190: 
        !           191:        natsemi_reset (netdev);
        !           192:        natsemi_init_eeprom ( np );
        !           193:        nvs_read ( &np->eeprom.nvs, EE_MAC-1, prev_bytes, 1 );
        !           194:        nvs_read ( &np->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN );
        !           195: 
        !           196:        /* decoding the MAC address read from NVS 
        !           197:         * and save it in netdev->ll_addr
        !           198:          */
        !           199:        last = prev_bytes[1] >> 7;
        !           200:        for ( i = 0 ; i < ETH_ALEN ; i++ ) {
        !           201:                last1 = ll_addr_encoded[i] >> 7;
        !           202:                netdev->hw_addr[i] = ll_addr_encoded[i] << 1 | last;
        !           203:                last = last1;
        !           204:        }
        !           205: 
        !           206:        if ((rc = register_netdev (netdev)) != 0)
        !           207:                goto err_register_netdev;
        !           208: 
        !           209:        /* Mark as link up; we don't yet handle link state */
        !           210:        netdev_link_up ( netdev );
        !           211: 
        !           212:        return 0;
        !           213: 
        !           214: err_register_netdev:
        !           215: 
        !           216:        natsemi_reset (netdev);
        !           217:        netdev_put (netdev);
        !           218:        return rc;
        !           219: }
        !           220: 
        !           221: /**
        !           222:  * Remove PCI device
        !           223:  *
        !           224:  * @v pci      PCI device
        !           225:  */
        !           226: static void natsemi_remove (struct pci_device *pci) {
        !           227:        struct net_device *netdev = pci_get_drvdata (pci);
        !           228:  
        !           229:        unregister_netdev (netdev);
        !           230:        natsemi_reset (netdev);
        !           231:        netdev_nullify ( netdev );
        !           232:        netdev_put (netdev);
        !           233: }
        !           234: 
        !           235: /**
        !           236:  * Reset NIC
        !           237:  *
        !           238:  * @v          NATSEMI NIC
        !           239:  *
        !           240:  * Issues a hardware reset and waits for the reset to complete.
        !           241:  */
        !           242: static void natsemi_reset (struct net_device *netdev) 
        !           243: {
        !           244:        struct natsemi_private *np = netdev->priv;
        !           245:        int i;
        !           246:         u32 cfg;
        !           247:         u32 wcsr;
        !           248:         u32 rfcr;
        !           249:         u16 pmatch[3];
        !           250:         u16 sopass[3];
        !           251: 
        !           252:        natsemi_irq (netdev, 0);
        !           253: 
        !           254:         /*
        !           255:          * Resetting the chip causes some registers to be lost.
        !           256:          * Natsemi suggests NOT reloading the EEPROM while live, so instead
        !           257:          * we save the state that would have been loaded from EEPROM
        !           258:          * on a normal power-up (see the spec EEPROM map).
        !           259:          */
        !           260: 
        !           261:         /* CFG */
        !           262:         cfg = inl (np->ioaddr + ChipConfig) & CFG_RESET_SAVE;
        !           263: 
        !           264:         /* WCSR */
        !           265:         wcsr = inl (np->ioaddr + WOLCmd) & WCSR_RESET_SAVE;
        !           266: 
        !           267:         /* RFCR */
        !           268:         rfcr = inl (np->ioaddr + RxFilterAddr) & RFCR_RESET_SAVE;
        !           269: 
        !           270:         /* PMATCH */
        !           271:         for (i = 0; i < 3; i++) {
        !           272:                outl(i*2, np->ioaddr + RxFilterAddr);
        !           273:                pmatch[i] = inw(np->ioaddr + RxFilterData);
        !           274:         }
        !           275: 
        !           276:         /* SOPAS */
        !           277:         for (i = 0; i < 3; i++) {
        !           278:                outl(0xa+(i*2), np->ioaddr + RxFilterAddr);
        !           279:                sopass[i] = inw(np->ioaddr + RxFilterData);
        !           280:         }
        !           281: 
        !           282:         /* now whack the chip */
        !           283:         outl(ChipReset, np->ioaddr + ChipCmd);
        !           284:         for (i=0; i<NATSEMI_HW_TIMEOUT; i++) {
        !           285:                if (! (inl (np->ioaddr + ChipCmd) & ChipReset))
        !           286:                       break;
        !           287:                udelay(5);
        !           288:         }
        !           289:         if (i == NATSEMI_HW_TIMEOUT) {
        !           290:                DBG ("natsemi_reset: reset did not complete in %d usec.\n", i*5);
        !           291:         }
        !           292: 
        !           293:         /* restore CFG */
        !           294:         cfg |= inl(np->ioaddr + ChipConfig) & ~CFG_RESET_SAVE;
        !           295:        cfg &= ~(CfgExtPhy | CfgPhyDis);
        !           296:         outl (cfg, np->ioaddr + ChipConfig);
        !           297: 
        !           298:         /* restore WCSR */
        !           299:         wcsr |= inl (np->ioaddr + WOLCmd) & ~WCSR_RESET_SAVE;
        !           300:         outl (wcsr, np->ioaddr + WOLCmd);
        !           301: 
        !           302:         /* read RFCR */
        !           303:         rfcr |= inl (np->ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE;
        !           304: 
        !           305:         /* restore PMATCH */
        !           306:         for (i = 0; i < 3; i++) {
        !           307:                outl (i*2, np->ioaddr + RxFilterAddr);
        !           308:                outw (pmatch[i], np->ioaddr + RxFilterData);
        !           309:         }
        !           310:         for (i = 0; i < 3; i++) {
        !           311:                outl (0xa+(i*2), np->ioaddr + RxFilterAddr);
        !           312:                outw (sopass[i], np->ioaddr + RxFilterData);
        !           313:         }
        !           314:         /* restore RFCR */
        !           315:         outl (rfcr, np->ioaddr + RxFilterAddr);
        !           316: }
        !           317: 
        !           318: /**
        !           319:  * Open NIC
        !           320:  *
        !           321:  * @v netdev           Net device
        !           322:  * @ret rc             Return status code
        !           323:  */
        !           324: static int natsemi_open (struct net_device *netdev)
        !           325: {
        !           326:        struct natsemi_private *np = netdev->priv;
        !           327:        uint32_t tx_config, rx_config;
        !           328:        int i;
        !           329:        
        !           330:        /* Disable PME:
        !           331:          * The PME bit is initialized from the EEPROM contents.
        !           332:          * PCI cards probably have PME disabled, but motherboard
        !           333:          * implementations may have PME set to enable WakeOnLan. 
        !           334:          * With PME set the chip will scan incoming packets but
        !           335:          * nothing will be written to memory. 
        !           336:          */
        !           337:         outl (inl (np->ioaddr + ClkRun) & ~0x100, np->ioaddr + ClkRun);
        !           338: 
        !           339:        /* Set MAC address in NIC
        !           340:         */
        !           341:        for (i = 0 ; i < ETH_ALEN ; i+=2) {
        !           342:                outl (i, np->ioaddr + RxFilterAddr);
        !           343:                outw (netdev->ll_addr[i] + (netdev->ll_addr[i + 1] << 8),
        !           344:                       np->ioaddr + RxFilterData);
        !           345:        }
        !           346: 
        !           347:        /* Setup Tx Ring 
        !           348:         */
        !           349:        np->tx_cur = 0;
        !           350:        np->tx_dirty = 0;
        !           351:        for (i = 0 ; i < TX_RING_SIZE ; i++) {
        !           352:                np->tx[i].link   = virt_to_bus ((i + 1 < TX_RING_SIZE) ? &np->tx[i + 1] : &np->tx[0]);
        !           353:                np->tx[i].cmdsts = 0;
        !           354:                np->tx[i].bufptr = 0;
        !           355:        }
        !           356:        outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr);
        !           357: 
        !           358:        DBG ("Natsemi Tx descriptor loaded with: %#08x\n",
        !           359:             inl (np->ioaddr + TxRingPtr));
        !           360: 
        !           361:        /* Setup RX ring
        !           362:         */
        !           363:        np->rx_cur = 0;
        !           364:        for (i = 0 ; i < NUM_RX_DESC ; i++) {
        !           365:                np->iobuf[i] = alloc_iob (RX_BUF_SIZE);
        !           366:                if (! np->iobuf[i])
        !           367:                        goto memory_alloc_err;
        !           368:                np->rx[i].link   = virt_to_bus ((i + 1 < NUM_RX_DESC) 
        !           369:                                                ? &np->rx[i + 1] : &np->rx[0]);
        !           370:                np->rx[i].cmdsts = RX_BUF_SIZE;
        !           371:                np->rx[i].bufptr = virt_to_bus (np->iobuf[i]->data);
        !           372:                DBG (" Address of iobuf [%d] = %p and iobuf->data = %p \n", i, 
        !           373:                      &np->iobuf[i],  &np->iobuf[i]->data);
        !           374:        }
        !           375:        outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr);
        !           376: 
        !           377:        DBG ("Natsemi Rx descriptor loaded with: %#08x\n",
        !           378:              inl (np->ioaddr + RxRingPtr));            
        !           379: 
        !           380:        /* Setup RX Filter 
        !           381:         */
        !           382:        outl (RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys,
        !           383:              np->ioaddr + RxFilterAddr);
        !           384: 
        !           385:        /* Initialize other registers. 
        !           386:         * Configure the PCI bus bursts and FIFO thresholds. 
        !           387:         * Configure for standard, in-spec Ethernet. 
        !           388:         */
        !           389:        if (inl (np->ioaddr + ChipConfig) & 0x20000000) {       /* Full duplex */
        !           390:                DBG ("Full duplex\n");
        !           391:                tx_config = 0xD0801002 |  0xC0000000;
        !           392:                rx_config = 0x10000020 |  0x10000000;
        !           393:        } else {
        !           394:                DBG ("Half duplex\n");
        !           395:                tx_config = 0x10801002 & ~0xC0000000;
        !           396:                rx_config = 0x00000020 & ~0x10000000;
        !           397:        }
        !           398:        outl (tx_config, np->ioaddr + TxConfig);
        !           399:        outl (rx_config, np->ioaddr + RxConfig);
        !           400: 
        !           401:        DBG ("Tx config register = %#08x Rx config register = %#08x\n", 
        !           402:                inl (np->ioaddr + TxConfig),
        !           403:               inl (np->ioaddr + RxConfig));
        !           404: 
        !           405:        /*Set the Interrupt Mask register
        !           406:         */
        !           407:        outl((RxOk|RxErr|TxOk|TxErr),np->ioaddr + IntrMask);
        !           408:        /*start the receiver 
        !           409:         */
        !           410:         outl (RxOn, np->ioaddr + ChipCmd);
        !           411:        
        !           412:        return 0;
        !           413:                       
        !           414: memory_alloc_err:
        !           415: 
        !           416:        /* Frees any allocated buffers when memory
        !           417:         * for all buffers requested is not available
        !           418:         */
        !           419:        i = 0;
        !           420:        while (np->rx[i].cmdsts == RX_BUF_SIZE) {
        !           421:                free_iob (np->iobuf[i]);
        !           422:                i++;
        !           423:        }
        !           424:        return -ENOMEM; 
        !           425: }
        !           426: 
        !           427: /**
        !           428:  * Close NIC
        !           429:  *
        !           430:  * @v netdev           Net device
        !           431:  */
        !           432: static void natsemi_close (struct net_device *netdev) 
        !           433: {
        !           434:        struct natsemi_private *np = netdev->priv;
        !           435:        int i;
        !           436: 
        !           437:        natsemi_reset (netdev);
        !           438: 
        !           439:        for (i = 0; i < NUM_RX_DESC ; i++) {
        !           440:                free_iob (np->iobuf[i]);
        !           441:        }
        !           442: }
        !           443: 
        !           444: /** 
        !           445:  * Transmit packet
        !           446:  *
        !           447:  * @v netdev   Network device
        !           448:  * @v iobuf    I/O buffer
        !           449:  * @ret rc     Return status code
        !           450:  */
        !           451: static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf)
        !           452: {
        !           453:        struct natsemi_private *np = netdev->priv;
        !           454: 
        !           455:        if (np->tx[np->tx_cur].cmdsts != 0) {
        !           456:                DBG ("TX overflow\n");
        !           457:                return -ENOBUFS;
        !           458:        }
        !           459: 
        !           460:        /* Used by netdev_tx_complete ()
        !           461:         */
        !           462:        np->tx_iobuf[np->tx_cur] = iobuf;
        !           463: 
        !           464:        /* Pad and align packet has not been used because its not required 
        !           465:         * by the hardware.
        !           466:         *      iob_pad (iobuf, ETH_ZLEN); 
        !           467:         * can be used to achieve it, if required
        !           468:         */
        !           469: 
        !           470:        /* Add the packet to TX ring
        !           471:         */
        !           472:        np->tx[np->tx_cur].bufptr = virt_to_bus (iobuf->data);
        !           473:        np->tx[np->tx_cur].cmdsts = iob_len (iobuf) | OWN;
        !           474: 
        !           475:        DBG ("TX id %d at %#08lx + %#08zx\n", np->tx_cur,
        !           476:             virt_to_bus (&iobuf->data), iob_len (iobuf));
        !           477: 
        !           478:        /* increment the circular buffer pointer to the next buffer location
        !           479:         */
        !           480:        np->tx_cur = (np->tx_cur + 1) % TX_RING_SIZE;
        !           481: 
        !           482:        /*start the transmitter 
        !           483:         */
        !           484:         outl (TxOn, np->ioaddr + ChipCmd);
        !           485: 
        !           486:        return 0;
        !           487: }
        !           488: 
        !           489: /** 
        !           490:  * Poll for received packets
        !           491:  *
        !           492:  * @v netdev   Network device
        !           493:  */
        !           494: static void natsemi_poll (struct net_device *netdev)
        !           495: {
        !           496:        struct natsemi_private *np = netdev->priv;
        !           497:        unsigned int tx_status;
        !           498:        unsigned int rx_status;
        !           499:        unsigned int intr_status;
        !           500:        unsigned int rx_len;
        !           501:        struct io_buffer *rx_iob;
        !           502:        int i;
        !           503:        
        !           504:        /* read the interrupt register
        !           505:         */
        !           506:        intr_status = inl (np->ioaddr + IntrStatus);
        !           507: 
        !           508:        if (!intr_status)
        !           509:                goto end;
        !           510: 
        !           511:         DBG ("natsemi_poll: intr_status = %#08x\n", intr_status);
        !           512: 
        !           513:        /* Check status of transmitted packets
        !           514:         */
        !           515:        i = np->tx_dirty;
        !           516:        while (i != np->tx_cur) {
        !           517:                tx_status = np->tx[np->tx_dirty].cmdsts;
        !           518: 
        !           519:                DBG ("tx_dirty = %d tx_cur=%d tx_status=%#08x\n",
        !           520:                     np->tx_dirty, np->tx_cur, tx_status);
        !           521:                
        !           522:                if (tx_status & OWN) 
        !           523:                        break;
        !           524: 
        !           525:                if (! (tx_status & DescPktOK)) {
        !           526:                        netdev_tx_complete_err (netdev,np->tx_iobuf[np->tx_dirty],-EINVAL);
        !           527:                        DBG ("Error transmitting packet, tx_status: %#08x\n",
        !           528:                             tx_status);
        !           529:                } else {
        !           530:                        netdev_tx_complete (netdev, np->tx_iobuf[np->tx_dirty]);
        !           531:                        DBG ("Success transmitting packet\n");
        !           532:                }
        !           533: 
        !           534:                np->tx[np->tx_dirty].cmdsts = 0;
        !           535:                np->tx_dirty = (np->tx_dirty + 1) % TX_RING_SIZE;
        !           536:                i = (i + 1) % TX_RING_SIZE;
        !           537:        }
        !           538:        
        !           539:        /* Process received packets 
        !           540:         */
        !           541:        rx_status = (unsigned int) np->rx[np->rx_cur].cmdsts; 
        !           542:        while ((rx_status & OWN)) {
        !           543:                rx_len = (rx_status & DSIZE) - CRC_SIZE;
        !           544: 
        !           545:                 DBG ("Received packet, rx_curr = %d, rx_status = %#08x, rx_len = %d\n",
        !           546:                      np->rx_cur, rx_status, rx_len);
        !           547:                 
        !           548:                if ((rx_status & (DescMore | DescPktOK | RxTooLong)) != DescPktOK) {
        !           549:                        netdev_rx_err (netdev, NULL, -EINVAL);
        !           550: 
        !           551:                        DBG ("natsemi_poll: Corrupted packet received!"
        !           552:                             " Status = %#08x\n",
        !           553:                              np->rx[np->rx_cur].cmdsts);
        !           554: 
        !           555:                } else  {
        !           556: 
        !           557: 
        !           558:                        /* If unable allocate space for this packet,
        !           559:                         *  try again next poll
        !           560:                         */
        !           561:                        rx_iob = alloc_iob (rx_len);
        !           562:                        if (! rx_iob) 
        !           563:                                goto end;
        !           564:                        memcpy (iob_put (rx_iob, rx_len), 
        !           565:                                np->iobuf[np->rx_cur]->data, rx_len);
        !           566:                        /* Add this packet to the receive queue. 
        !           567:                         */
        !           568:                        netdev_rx (netdev, rx_iob);
        !           569:                }
        !           570:                np->rx[np->rx_cur].cmdsts = RX_BUF_SIZE;
        !           571:                np->rx_cur = (np->rx_cur + 1) % NUM_RX_DESC;
        !           572:                rx_status = np->rx[np->rx_cur].cmdsts; 
        !           573:        }
        !           574: end:
        !           575:        /* re-enable the potentially idle receive state machine 
        !           576:         */
        !           577:        outl (RxOn, np->ioaddr + ChipCmd);      
        !           578: }                              
        !           579: 
        !           580: /**
        !           581:  * Enable/disable interrupts
        !           582:  *
        !           583:  * @v netdev    Network device
        !           584:  * @v enable    Non-zero for enable, zero for disable
        !           585:  */
        !           586: static void natsemi_irq (struct net_device *netdev, int enable)
        !           587: {
        !           588:         struct natsemi_private *np = netdev->priv;
        !           589: 
        !           590:        outl ((enable ? (RxOk | RxErr | TxOk|TxErr) : 0),
        !           591:              np->ioaddr + IntrMask); 
        !           592:        outl ((enable ? 1 : 0), np->ioaddr + IntrEnable);
        !           593: }
        !           594: 
        !           595: static struct pci_device_id natsemi_nics[] = {
        !           596:        PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815", 0),
        !           597: };
        !           598: 
        !           599: struct pci_driver natsemi_driver __pci_driver = {
        !           600:        .ids = natsemi_nics,
        !           601:        .id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])),
        !           602:        .probe = natsemi_probe,
        !           603:        .remove = natsemi_remove,
        !           604: };

unix.superglobalmegacorp.com

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