Annotation of Gnu-Mach/i386/i386at/gpl/linux/net/tulip.c, revision 1.1

1.1     ! root        1: /* tulip.c: A DEC 21040 ethernet driver for linux. */
        !             2: /*
        !             3:    NOTICE: this version works with kernels 1.1.82 and later only!
        !             4:        Written 1994,1995 by Donald Becker.
        !             5: 
        !             6:        This software may be used and distributed according to the terms
        !             7:        of the GNU Public License, incorporated herein by reference.
        !             8: 
        !             9:        This driver is for the SMC EtherPower PCI ethernet adapter.
        !            10:        It should work with most other DEC 21*40-based ethercards.
        !            11: 
        !            12:        The author may be reached as [email protected], or C/O
        !            13:        Center of Excellence in Space Data and Information Sciences
        !            14:           Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
        !            15: */
        !            16: 
        !            17: static const char *version = "tulip.c:v0.05 1/20/95 [email protected]\n";
        !            18: 
        !            19: #include <linux/module.h>
        !            20: 
        !            21: #include <linux/kernel.h>
        !            22: #include <linux/sched.h>
        !            23: #include <linux/string.h>
        !            24: #include <linux/ptrace.h>
        !            25: #include <linux/errno.h>
        !            26: #include <linux/ioport.h>
        !            27: #include <linux/malloc.h>
        !            28: #include <linux/interrupt.h>
        !            29: #include <linux/pci.h>
        !            30: #include <linux/bios32.h>
        !            31: #include <asm/bitops.h>
        !            32: #include <asm/io.h>
        !            33: #include <asm/dma.h>
        !            34: 
        !            35: #include <linux/netdevice.h>
        !            36: #include <linux/etherdevice.h>
        !            37: #include <linux/skbuff.h>
        !            38: 
        !            39: /* The total size is unusually large: The 21040 aligns each of its 16
        !            40:    longword-wide registers on a quadword boundary. */
        !            41: #define TULIP_TOTAL_SIZE 0x80
        !            42: 
        !            43: #ifdef HAVE_DEVLIST
        !            44: struct netdev_entry tulip_drv =
        !            45: {"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL};
        !            46: #endif
        !            47: 
        !            48: #define TULIP_DEBUG 1
        !            49: #ifdef TULIP_DEBUG
        !            50: int tulip_debug = TULIP_DEBUG;
        !            51: #else
        !            52: int tulip_debug = 1;
        !            53: #endif
        !            54: 
        !            55: /*
        !            56:                                Theory of Operation
        !            57: 
        !            58: I. Board Compatibility
        !            59: 
        !            60: This device driver is designed for the DECchip 21040 "Tulip", Digital's
        !            61: single-chip ethernet controller for PCI, as used on the SMC EtherPower
        !            62: ethernet adapter.
        !            63: 
        !            64: II. Board-specific settings
        !            65: 
        !            66: PCI bus devices are configured by the system at boot time, so no jumpers
        !            67: need to be set on the board.  The system BIOS should be set to assign the
        !            68: PCI INTA signal to an otherwise unused system IRQ line.  While it's
        !            69: physically possible to shared PCI interrupt lines, the kernel doesn't
        !            70: support it. 
        !            71: 
        !            72: III. Driver operation
        !            73: 
        !            74: IIIa. Ring buffers
        !            75: The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
        !            76: The current driver uses a statically allocated Rx ring of descriptors and
        !            77: buffers, and a list of the Tx buffers.
        !            78: 
        !            79: IIIC. Synchronization
        !            80: The driver runs as two independent, single-threaded flows of control.  One
        !            81: is the send-packet routine, which enforces single-threaded use by the
        !            82: dev->tbusy flag.  The other thread is the interrupt handler, which is single
        !            83: threaded by the hardware and other software.
        !            84: 
        !            85: The send packet thread has partial control over the Tx ring and 'dev->tbusy'
        !            86: flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
        !            87: queue slot is empty, it clears the tbusy flag when finished otherwise it sets
        !            88: the 'tp->tx_full' flag.
        !            89: 
        !            90: The interrupt handler has exclusive control over the Rx ring and records stats
        !            91: from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
        !            92: we can't avoid the interrupt overhead by having the Tx routine reap the Tx
        !            93: stats.)         After reaping the stats, it marks the queue entry as empty by setting
        !            94: the 'base' to zero.     Iff the 'tp->tx_full' flag is set, it clears both the
        !            95: tx_full and tbusy flags.
        !            96: 
        !            97: IV. Notes
        !            98: 
        !            99: Thanks to Duke Kamstra of SMC for providing an EtherPower board.
        !           100: 
        !           101: The DEC databook doesn't document which Rx filter settings accept broadcast
        !           102: packets.  Nor does it document how to configure the part to configure the
        !           103: serial subsystem for normal (vs. loopback) operation or how to have it
        !           104: autoswitch between internal 10baseT, SIA and AUI transceivers.
        !           105: 
        !           106: The databook claims that CSR13, CSR14, and CSR15 should each be the last
        !           107: register of the set CSR12-15 written.   Hmmm, now how is that possible?
        !           108: */
        !           109: 
        !           110: #define DEC_VENDOR_ID  0x1011          /* Hex 'D' :-> */
        !           111: #define DEC_21040_ID   0x0002          /* Change for 21140. */
        !           112: 
        !           113: /* Keep the ring sizes a power of two for efficiency. */
        !           114: #define TX_RING_SIZE   4
        !           115: #define RX_RING_SIZE   4
        !           116: #define PKT_BUF_SZ             1536                    /* Size of each temporary Rx buffer.*/
        !           117: 
        !           118: /* Offsets to the Command and Status Registers, "CSRs".  All accesses
        !           119:    must be longword instructions and quadword aligned. */
        !           120: enum tulip_offsets {
        !           121:        CSR0=0,    CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
        !           122:        CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
        !           123:        CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
        !           124: 
        !           125: /* The Tulip Rx and Tx buffer descriptors. */
        !           126: struct tulip_rx_desc {
        !           127:        int status;
        !           128:        int length;
        !           129:        char *buffer1, *buffer2;                        /* We use only buffer 1.  */
        !           130: };
        !           131: 
        !           132: struct tulip_tx_desc {
        !           133:        int status;
        !           134:        int length;
        !           135:        char *buffer1, *buffer2;                        /* We use only buffer 1.  */
        !           136: };
        !           137: 
        !           138: struct tulip_private {
        !           139:        char devname[8];                        /* Used only for kernel debugging. */
        !           140:        struct tulip_rx_desc rx_ring[RX_RING_SIZE];
        !           141:        struct tulip_tx_desc tx_ring[TX_RING_SIZE];
        !           142:        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        !           143:        struct sk_buff* tx_skbuff[TX_RING_SIZE];
        !           144:        long rx_buffs;                          /* Address of temporary Rx buffers. */
        !           145:        struct enet_statistics stats;
        !           146:        int setup_frame[48];            /* Pseudo-Tx frame to init address table. */
        !           147:        unsigned int cur_rx, cur_tx;            /* The next free ring entry */
        !           148:        unsigned int dirty_rx, dirty_tx;        /* The ring entries to be free()ed. */
        !           149:        unsigned int tx_full:1;
        !           150:        int pad0, pad1;                                         /* Used for 8-byte alignment */
        !           151: };
        !           152: 
        !           153: static void tulip_probe1(int ioaddr, int irq);
        !           154: static int tulip_open(struct device *dev);
        !           155: static void tulip_init_ring(struct device *dev);
        !           156: static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
        !           157: static int tulip_rx(struct device *dev);
        !           158: static void tulip_interrupt(int irq, struct pt_regs *regs);
        !           159: static int tulip_close(struct device *dev);
        !           160: static struct enet_statistics *tulip_get_stats(struct device *dev);
        !           161: static void set_multicast_list(struct device *dev);
        !           162: static int set_mac_address(struct device *dev, void *addr);
        !           163: 
        !           164: 
        !           165: 
        !           166: #ifndef MODULE
        !           167: /* This 21040 probe is unlike most other board probes.  We can use memory
        !           168:    efficiently by allocating a large contiguous region and dividing it
        !           169:    ourselves.  This is done by having the initialization occur before
        !           170:    the 'kmalloc()' memory management system is started. */
        !           171: 
        !           172: int dec21040_init(void)
        !           173: {
        !           174: 
        !           175:     if (pcibios_present()) {
        !           176:            int pci_index;
        !           177:                for (pci_index = 0; pci_index < 8; pci_index++) {
        !           178:                        unsigned char pci_bus, pci_device_fn, pci_irq_line;
        !           179:                        unsigned long pci_ioaddr;
        !           180:                
        !           181:                        if (pcibios_find_device (DEC_VENDOR_ID, DEC_21040_ID, pci_index,
        !           182:                                                                         &pci_bus, &pci_device_fn) != 0)
        !           183:                                break;
        !           184:                        pcibios_read_config_byte(pci_bus, pci_device_fn,
        !           185:                                                                         PCI_INTERRUPT_LINE, &pci_irq_line);
        !           186:                        pcibios_read_config_dword(pci_bus, pci_device_fn,
        !           187:                                                                          PCI_BASE_ADDRESS_0, &pci_ioaddr);
        !           188:                        /* Remove I/O space marker in bit 0. */
        !           189:                        pci_ioaddr &= ~3;
        !           190:                        if (tulip_debug > 2)
        !           191:                                printk("Found DEC PCI Tulip at I/O %#lx, IRQ %d.\n",
        !           192:                                           pci_ioaddr, pci_irq_line);
        !           193:                        tulip_probe1(pci_ioaddr, pci_irq_line);
        !           194:                }
        !           195:        }
        !           196: 
        !           197:        return 0;
        !           198: }
        !           199: #endif
        !           200: #ifdef MODULE
        !           201: static int tulip_probe(struct device *dev)
        !           202: {
        !           203:        printk("tulip: This driver does not yet install properly from module!\n");
        !           204:        return -1;
        !           205: }
        !           206: #endif
        !           207: 
        !           208: static void tulip_probe1(int ioaddr, int irq)
        !           209: {
        !           210:        static int did_version = 0;                     /* Already printed version info. */
        !           211:        struct device *dev;
        !           212:        struct tulip_private *tp;
        !           213:        int i;
        !           214: 
        !           215:        if (tulip_debug > 0  &&  did_version++ == 0)
        !           216:                printk(version);
        !           217: 
        !           218:        dev = init_etherdev(0, 0);
        !           219: 
        !           220:        printk("%s: DEC 21040 Tulip at %#3x,", dev->name, ioaddr);
        !           221: 
        !           222:        /* Stop the chip's Tx and Rx processes. */
        !           223:        outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
        !           224:        /* Clear the missed-packet counter. */
        !           225:        inl(ioaddr + CSR8) & 0xffff;
        !           226: 
        !           227:        /* The station address ROM is read byte serially.  The register must
        !           228:           be polled, waiting for the value to be read bit serially from the
        !           229:           EEPROM.
        !           230:           */
        !           231:        outl(0, ioaddr + CSR9);         /* Reset the pointer with a dummy write. */
        !           232:        for (i = 0; i < 6; i++) {
        !           233:                int value, boguscnt = 100000;
        !           234:                do
        !           235:                        value = inl(ioaddr + CSR9);
        !           236:                while (value < 0  && --boguscnt > 0);
        !           237:                printk(" %2.2x", dev->dev_addr[i] = value);
        !           238:        }
        !           239:        printk(", IRQ %d\n", irq);
        !           240: 
        !           241:        /* We do a request_region() only to register /proc/ioports info. */
        !           242:        request_region(ioaddr, TULIP_TOTAL_SIZE, "DEC Tulip Ethernet");
        !           243: 
        !           244:        dev->base_addr = ioaddr;
        !           245:        dev->irq = irq;
        !           246: 
        !           247:        /* Make certain the data structures are quadword aligned. */
        !           248:        tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
        !           249:        dev->priv = tp;
        !           250:        tp->rx_buffs = kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_KERNEL | GFP_DMA);
        !           251: 
        !           252:        /* The Tulip-specific entries in the device structure. */
        !           253:        dev->open = &tulip_open;
        !           254:        dev->hard_start_xmit = &tulip_start_xmit;
        !           255:        dev->stop = &tulip_close;
        !           256:        dev->get_stats = &tulip_get_stats;
        !           257:        dev->set_multicast_list = &set_multicast_list;
        !           258:        dev->set_mac_address = &set_mac_address;
        !           259: 
        !           260:        return;
        !           261: }
        !           262: 
        !           263: 
        !           264: static int
        !           265: tulip_open(struct device *dev)
        !           266: {
        !           267:        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        !           268:        int ioaddr = dev->base_addr;
        !           269: 
        !           270:        /* Reset the chip, holding bit 0 set at least 10 PCI cycles. */
        !           271:        outl(0xfff80001, ioaddr + CSR0);
        !           272:        SLOW_DOWN_IO;
        !           273:        /* Deassert reset.  Set 8 longword cache alignment, 8 longword burst.
        !           274:           Cache alignment bits 15:14        Burst length 13:8
        !           275:        0000    No alignment  0x00000000 unlimited              0800 8 longwords
        !           276:                4000    8  longwords            0100 1 longword         1000 16 longwords
        !           277:                8000    16 longwords            0200 2 longwords        2000 32 longwords
        !           278:                C000    32  longwords           0400 4 longwords
        !           279:           Wait the specified 50 PCI cycles after a reset by initializing
        !           280:           Tx and Rx queues and the address filter list. */
        !           281:        outl(0xfff84800, ioaddr + CSR0);
        !           282: 
        !           283:        if (irq2dev_map[dev->irq] != NULL
        !           284:                || (irq2dev_map[dev->irq] = dev) == NULL
        !           285:                || dev->irq == 0
        !           286:                || request_irq(dev->irq, &tulip_interrupt, 0, "DEC 21040 Tulip")) {
        !           287:                return -EAGAIN;
        !           288:        }
        !           289: 
        !           290:        if (tulip_debug > 1)
        !           291:                printk("%s: tulip_open() irq %d.\n", dev->name, dev->irq);
        !           292: 
        !           293:        tulip_init_ring(dev);
        !           294: 
        !           295:        /* Fill the whole address filter table with our physical address. */
        !           296:        { 
        !           297:                unsigned short *eaddrs = (unsigned short *)dev->dev_addr;
        !           298:                int *setup_frm = tp->setup_frame, i;
        !           299: 
        !           300:                /* You must add the broadcast address when doing perfect filtering! */
        !           301:                *setup_frm++ = 0xffff;
        !           302:                *setup_frm++ = 0xffff;
        !           303:                *setup_frm++ = 0xffff;
        !           304:                /* Fill the rest of the accept table with our physical address. */
        !           305:                for (i = 1; i < 16; i++) {
        !           306:                        *setup_frm++ = eaddrs[0];
        !           307:                        *setup_frm++ = eaddrs[1];
        !           308:                        *setup_frm++ = eaddrs[2];
        !           309:                }
        !           310:                /* Put the setup frame on the Tx list. */
        !           311:                tp->tx_ring[0].length = 0x08000000 | 192;
        !           312:                tp->tx_ring[0].buffer1 = (char *)tp->setup_frame;
        !           313:                tp->tx_ring[0].buffer2 = 0;
        !           314:                tp->tx_ring[0].status = 0x80000000;
        !           315: 
        !           316:                tp->cur_tx++, tp->dirty_tx++;
        !           317:        }
        !           318: 
        !           319:        outl((int)tp->rx_ring, ioaddr + CSR3);
        !           320:        outl((int)tp->tx_ring, ioaddr + CSR4);
        !           321: 
        !           322:        /* Turn on the xcvr interface. */
        !           323:        outl(0x00000000, ioaddr + CSR13);
        !           324:        outl(0x00000004, ioaddr + CSR13);
        !           325: 
        !           326:        /* Start the chip's Tx and Rx processes. */
        !           327:        outl(0xfffe2002, ioaddr + CSR6);
        !           328: 
        !           329:        /* Trigger an immediate transmit demand to process the setup frame. */
        !           330:        outl(0, ioaddr + CSR1);
        !           331: 
        !           332:        dev->tbusy = 0;
        !           333:        dev->interrupt = 0;
        !           334:        dev->start = 1;
        !           335: 
        !           336:        /* Enable interrupts by setting the interrupt mask. */
        !           337:        outl(0xFFFFFFFF, ioaddr + CSR7);
        !           338: 
        !           339:        if (tulip_debug > 2) {
        !           340:                printk("%s: Done tulip_open(), CSR0 %8.8x, CSR13 %8.8x.\n",
        !           341:                           dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR13));
        !           342:        }
        !           343:        MOD_INC_USE_COUNT;
        !           344:        return 0;
        !           345: }
        !           346: 
        !           347: /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
        !           348: static void
        !           349: tulip_init_ring(struct device *dev)
        !           350: {
        !           351:        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        !           352:        int i;
        !           353: 
        !           354:        tp->tx_full = 0;
        !           355:        tp->cur_rx = tp->cur_tx = 0;
        !           356:        tp->dirty_rx = tp->dirty_tx = 0;
        !           357: 
        !           358:        for (i = 0; i < RX_RING_SIZE; i++) {
        !           359:                tp->rx_ring[i].status = 0x80000000;     /* Owned by Tulip chip */
        !           360:                tp->rx_ring[i].length = PKT_BUF_SZ;
        !           361:                tp->rx_ring[i].buffer1 = (char *)(tp->rx_buffs + i*PKT_BUF_SZ);
        !           362:                tp->rx_ring[i].buffer2 = (char *)&tp->rx_ring[i+1];
        !           363:        }
        !           364:        /* Mark the last entry as wrapping the ring. */ 
        !           365:        tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000;
        !           366:        tp->rx_ring[i-1].buffer2 = (char *)&tp->rx_ring[0];
        !           367: 
        !           368:        /* The Tx buffer descriptor is filled in as needed, but we
        !           369:           do need to clear the ownership bit. */
        !           370:        for (i = 0; i < TX_RING_SIZE; i++) {
        !           371:                tp->tx_ring[i].status = 0x00000000;
        !           372:        }
        !           373: }
        !           374: 
        !           375: static int
        !           376: tulip_start_xmit(struct sk_buff *skb, struct device *dev)
        !           377: {
        !           378:        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        !           379:        int ioaddr = dev->base_addr;
        !           380:        int entry;
        !           381: 
        !           382:        /* Transmitter timeout, serious problems. */
        !           383:        if (dev->tbusy) {
        !           384:                int tickssofar = jiffies - dev->trans_start;
        !           385:                int i;
        !           386:                if (tickssofar < 20)
        !           387:                        return 1;
        !           388:                printk("%s: transmit timed out, status %8.8x, SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
        !           389:                           dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
        !           390:                           inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
        !           391:                printk("  Rx ring %8.8x: ", (int)tp->rx_ring);
        !           392:                for (i = 0; i < RX_RING_SIZE; i++)
        !           393:                        printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
        !           394:                printk("\n  Tx ring %8.8x: ", (int)tp->tx_ring);
        !           395:                for (i = 0; i < TX_RING_SIZE; i++)
        !           396:                        printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
        !           397:                printk("\n");
        !           398: 
        !           399:                tp->stats.tx_errors++;
        !           400:                /* We should reinitialize the hardware here. */
        !           401:                dev->tbusy=0;
        !           402:                dev->trans_start = jiffies;
        !           403:                return 0;
        !           404:        }
        !           405: 
        !           406:        if (skb == NULL || skb->len <= 0) {
        !           407:                printk("%s: Obsolete driver layer request made: skbuff==NULL.\n",
        !           408:                           dev->name);
        !           409:                dev_tint(dev);
        !           410:                return 0;
        !           411:        }
        !           412: 
        !           413:        /* Block a timer-based transmit from overlapping.  This could better be
        !           414:           done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
        !           415:           If this ever occurs the queue layer is doing something evil! */
        !           416:        if (set_bit(0, (void*)&dev->tbusy) != 0) {
        !           417:                printk("%s: Transmitter access conflict.\n", dev->name);
        !           418:                return 1;
        !           419:        }
        !           420: 
        !           421:        /* Caution: the write order is important here, set the base address
        !           422:           with the "ownership" bits last. */
        !           423: 
        !           424:        /* Calculate the next Tx descriptor entry. */
        !           425:        entry = tp->cur_tx % TX_RING_SIZE;
        !           426: 
        !           427:        tp->tx_full = 1;
        !           428:        tp->tx_skbuff[entry] = skb;
        !           429:        tp->tx_ring[entry].length = skb->len |
        !           430:                (entry == TX_RING_SIZE-1 ? 0xe2000000 : 0xe0000000);
        !           431:        tp->tx_ring[entry].buffer1 = skb->data;
        !           432:        tp->tx_ring[entry].buffer2 = 0;
        !           433:        tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */
        !           434: 
        !           435:        tp->cur_tx++;
        !           436: 
        !           437:        /* Trigger an immediate transmit demand. */
        !           438:        outl(0, ioaddr + CSR1);
        !           439: 
        !           440:        dev->trans_start = jiffies;
        !           441: 
        !           442:        return 0;
        !           443: }
        !           444: 
        !           445: /* The interrupt handler does all of the Rx thread work and cleans up
        !           446:    after the Tx thread. */
        !           447: static void tulip_interrupt(int irq, struct pt_regs *regs)
        !           448: {
        !           449:        struct device *dev = (struct device *)(irq2dev_map[irq]);
        !           450:        struct tulip_private *lp;
        !           451:        int csr5, ioaddr, boguscnt=10;
        !           452: 
        !           453:        if (dev == NULL) {
        !           454:                printk ("tulip_interrupt(): irq %d for unknown device.\n", irq);
        !           455:                return;
        !           456:        }
        !           457: 
        !           458:        ioaddr = dev->base_addr;
        !           459:        lp = (struct tulip_private *)dev->priv;
        !           460:        if (dev->interrupt)
        !           461:                printk("%s: Re-entering the interrupt handler.\n", dev->name);
        !           462: 
        !           463:        dev->interrupt = 1;
        !           464: 
        !           465:        do {
        !           466:                csr5 = inl(ioaddr + CSR5);
        !           467:                /* Acknowledge all of the current interrupt sources ASAP. */
        !           468:                outl(csr5 & 0x0001ffff, ioaddr + CSR5);
        !           469: 
        !           470:                if (tulip_debug > 4)
        !           471:                        printk("%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
        !           472:                                   dev->name, csr5, inl(dev->base_addr + CSR5));
        !           473: 
        !           474:                if ((csr5 & 0x00018000) == 0)
        !           475:                        break;
        !           476: 
        !           477:                if (csr5 & 0x0040)                      /* Rx interrupt */
        !           478:                        tulip_rx(dev);
        !           479: 
        !           480:                if (csr5 & 0x0001) {            /* Tx-done interrupt */
        !           481:                        int dirty_tx = lp->dirty_tx;
        !           482: 
        !           483:                        while (dirty_tx < lp->cur_tx) {
        !           484:                                int entry = dirty_tx % TX_RING_SIZE;
        !           485:                                int status = lp->tx_ring[entry].status;
        !           486: 
        !           487:                                if (status < 0)
        !           488:                                        break;                  /* It still hasn't been Txed */
        !           489: 
        !           490:                                if (status & 0x8000) {
        !           491:                                        /* There was an major error, log it. */
        !           492:                                        lp->stats.tx_errors++;
        !           493:                                        if (status & 0x4104) lp->stats.tx_aborted_errors++;
        !           494:                                        if (status & 0x0C00) lp->stats.tx_carrier_errors++;
        !           495:                                        if (status & 0x0200) lp->stats.tx_window_errors++;
        !           496:                                        if (status & 0x0002) lp->stats.tx_fifo_errors++;
        !           497:                                        if (status & 0x0080) lp->stats.tx_heartbeat_errors++;
        !           498: #ifdef ETHER_STATS
        !           499:                                        if (status & 0x0100) lp->stats.collisions16++;
        !           500: #endif
        !           501:                                } else {
        !           502: #ifdef ETHER_STATS
        !           503:                                        if (status & 0x0001) lp->stats.tx_deferred++;
        !           504: #endif
        !           505:                                        lp->stats.collisions += (status >> 3) & 15;
        !           506:                                        lp->stats.tx_packets++;
        !           507:                                }
        !           508: 
        !           509:                                /* Free the original skb. */
        !           510:                                dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
        !           511:                                dirty_tx++;
        !           512:                        }
        !           513: 
        !           514: #ifndef final_version
        !           515:                        if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
        !           516:                                printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
        !           517:                                           dirty_tx, lp->cur_tx, lp->tx_full);
        !           518:                                dirty_tx += TX_RING_SIZE;
        !           519:                        }
        !           520: #endif
        !           521: 
        !           522:                        if (lp->tx_full && dev->tbusy
        !           523:                                && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
        !           524:                                /* The ring is no longer full, clear tbusy. */
        !           525:                                lp->tx_full = 0;
        !           526:                                dev->tbusy = 0;
        !           527:                                mark_bh(NET_BH);
        !           528:                        }
        !           529: 
        !           530:                        lp->dirty_tx = dirty_tx;
        !           531:                }
        !           532: 
        !           533:                /* Log errors. */
        !           534:                if (csr5 & 0x8000) {    /* Abnormal error summary bit. */
        !           535:                        if (csr5 & 0x0008) lp->stats.tx_errors++; /* Tx babble. */
        !           536:                        if (csr5 & 0x0100) {            /* Missed a Rx frame. */
        !           537:                                lp->stats.rx_errors++;
        !           538:                                lp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
        !           539:                        }
        !           540:                        if (csr5 & 0x0800) {
        !           541:                                printk("%s: Something Wicked happened! %8.8x.\n",
        !           542:                                           dev->name, csr5);
        !           543:                                /* Hmmmmm, it's not clear what to do here. */
        !           544:                        }
        !           545:                }
        !           546:                if (--boguscnt < 0) {
        !           547:                        printk("%s: Too much work at interrupt, csr5=0x%8.8x.\n",
        !           548:                                   dev->name, csr5);
        !           549:                        /* Clear all interrupt sources. */
        !           550:                        outl(0x0001ffff, ioaddr + CSR5);
        !           551:                        break;
        !           552:                }
        !           553:        } while (1);
        !           554: 
        !           555:        if (tulip_debug > 3)
        !           556:                printk("%s: exiting interrupt, csr5=%#4.4x.\n",
        !           557:                           dev->name, inl(ioaddr + CSR5));
        !           558: 
        !           559:        /* Special code for testing *only*. */
        !           560:        {
        !           561:                static int stopit = 10;
        !           562:                if (dev->start == 0  &&  --stopit < 0) {
        !           563:                        printk("%s: Emergency stop, looping startup interrupt.\n",
        !           564:                                   dev->name);
        !           565:                        free_irq(irq);
        !           566:                }
        !           567:        }
        !           568: 
        !           569:        dev->interrupt = 0;
        !           570:        return;
        !           571: }
        !           572: 
        !           573: static int
        !           574: tulip_rx(struct device *dev)
        !           575: {
        !           576:        struct tulip_private *lp = (struct tulip_private *)dev->priv;
        !           577:        int entry = lp->cur_rx % RX_RING_SIZE;
        !           578:        int i;
        !           579:                
        !           580:        if (tulip_debug > 4)
        !           581:                printk(" In tulip_rx().\n");
        !           582:        /* If we own the next entry, it's a new packet. Send it up. */
        !           583:        while (lp->rx_ring[entry].status >= 0) {
        !           584:                int status = lp->rx_ring[entry].status;
        !           585: 
        !           586:                if (tulip_debug > 4)
        !           587:                        printk("  tulip_rx() status was %8.8x.\n", status);
        !           588:                if ((status & 0x0300) != 0x0300) {
        !           589:                        printk("%s: Ethernet frame spanned multiple buffers, status %8.8x!\n",
        !           590:                                   dev->name, status);
        !           591:                } else if (status & 0x8000) {
        !           592:                        /* There was a fatal error. */
        !           593:                        lp->stats.rx_errors++; /* end of a packet.*/
        !           594:                        if (status & 0x0890) lp->stats.rx_length_errors++;
        !           595:                        if (status & 0x0004) lp->stats.rx_frame_errors++;
        !           596:                        if (status & 0x0002) lp->stats.rx_crc_errors++;
        !           597:                        if (status & 0x0001) lp->stats.rx_fifo_errors++;
        !           598:                } else {
        !           599:                        /* Malloc up new buffer, compatible with net-2e. */
        !           600:                        short pkt_len = lp->rx_ring[entry].status >> 16;
        !           601:                        struct sk_buff *skb;
        !           602: 
        !           603:                        skb = dev_alloc_skb(pkt_len+2);
        !           604:                        if (skb == NULL) {
        !           605:                                printk("%s: Memory squeeze, deferring packet.\n", dev->name);
        !           606:                                /* Check that at least two ring entries are free.
        !           607:                                   If not, free one and mark stats->rx_dropped++. */
        !           608:                                for (i=0; i < RX_RING_SIZE; i++)
        !           609:                                        if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0)
        !           610:                                                break;
        !           611: 
        !           612:                                if (i > RX_RING_SIZE -2) {
        !           613:                                        lp->stats.rx_dropped++;
        !           614:                                        lp->rx_ring[entry].status = 0x80000000;
        !           615:                                        lp->cur_rx++;
        !           616:                                }
        !           617:                                break;
        !           618:                        }
        !           619:                        skb->dev = dev;
        !           620:                        skb_reserve(skb,2);     /* 16 byte align the data fields */
        !           621:                        memcpy(skb_put(skb,pkt_len), lp->rx_ring[entry].buffer1, pkt_len);
        !           622:                        skb->protocol=eth_type_trans(skb,dev);
        !           623:                        netif_rx(skb);
        !           624:                        lp->stats.rx_packets++;
        !           625:                }
        !           626: 
        !           627:                lp->rx_ring[entry].status = 0x80000000;
        !           628:                entry = (++lp->cur_rx) % RX_RING_SIZE;
        !           629:        }
        !           630: 
        !           631:        return 0;
        !           632: }
        !           633: 
        !           634: static int
        !           635: tulip_close(struct device *dev)
        !           636: {
        !           637:        int ioaddr = dev->base_addr;
        !           638:        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        !           639: 
        !           640:        dev->start = 0;
        !           641:        dev->tbusy = 1;
        !           642: 
        !           643:        if (tulip_debug > 1)
        !           644:                printk("%s: Shutting down ethercard, status was %2.2x.\n",
        !           645:                           dev->name, inl(ioaddr + CSR5));
        !           646: 
        !           647:        /* Disable interrupts by clearing the interrupt mask. */
        !           648:        outl(0x00000000, ioaddr + CSR7);
        !           649:        /* Stop the chip's Tx and Rx processes. */
        !           650:        outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
        !           651: 
        !           652:        tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
        !           653: 
        !           654:        free_irq(dev->irq);
        !           655:        irq2dev_map[dev->irq] = 0;
        !           656: 
        !           657:        MOD_DEC_USE_COUNT;
        !           658:        return 0;
        !           659: }
        !           660: 
        !           661: static struct enet_statistics *
        !           662: tulip_get_stats(struct device *dev)
        !           663: {
        !           664:        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        !           665:        short ioaddr = dev->base_addr;
        !           666: 
        !           667:        tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
        !           668: 
        !           669:        return &tp->stats;
        !           670: }
        !           671: 
        !           672: /*
        !           673:  *     Set or clear the multicast filter for this adaptor.
        !           674:  */
        !           675: 
        !           676: static void set_multicast_list(struct device *dev)
        !           677: {
        !           678:        short ioaddr = dev->base_addr;
        !           679:        int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
        !           680: 
        !           681:        if (dev->flags&IFF_PROMISC) 
        !           682:        {                       /* Set promiscuous. */
        !           683:                outl(csr6 | 0x00C0, ioaddr + CSR6);
        !           684:                /* Log any net taps. */
        !           685:                printk("%s: Promiscuous mode enabled.\n", dev->name);
        !           686:        }
        !           687:        else if (dev->mc_count > 15 || (dev->flags&IFF_ALLMULTI)) 
        !           688:        {
        !           689:                /* Too many to filter perfectly -- accept all multicasts. */
        !           690:                outl(csr6 | 0x0080, ioaddr + CSR6);
        !           691:        }
        !           692:        else
        !           693:        {
        !           694:                struct tulip_private *tp = (struct tulip_private *)dev->priv;
        !           695:                struct dev_mc_list *dmi=dev->mc_list;
        !           696:                int *setup_frm = tp->setup_frame;
        !           697:                unsigned short *eaddrs;
        !           698:                int i;
        !           699: 
        !           700:                /* We have <= 15 addresses that we can use the wonderful
        !           701:                   16 address perfect filtering of the Tulip.  Note that only
        !           702:                   the low shortword of setup_frame[] is valid. */
        !           703:                outl(csr6 | 0x0000, ioaddr + CSR6);
        !           704:                i=0;
        !           705:                while(dmi) 
        !           706:                {
        !           707:                        eaddrs=(unsigned short *)dmi->dmi_addr;
        !           708:                        dmi=dmi->next;
        !           709:                        i++;
        !           710:                        *setup_frm++ = *eaddrs++;
        !           711:                        *setup_frm++ = *eaddrs++;
        !           712:                        *setup_frm++ = *eaddrs++;
        !           713:                }
        !           714:                /* Fill the rest of the table with our physical address. */
        !           715:                eaddrs = (unsigned short *)dev->dev_addr;
        !           716:                do {
        !           717:                        *setup_frm++ = eaddrs[0];
        !           718:                        *setup_frm++ = eaddrs[1];
        !           719:                        *setup_frm++ = eaddrs[2];
        !           720:                } while (++i < 16);
        !           721: 
        !           722:                /* Now add this frame to the Tx list. */
        !           723:        }
        !           724: }
        !           725: 
        !           726: static int
        !           727: set_mac_address(struct device *dev, void *addr)
        !           728: {
        !           729:        int i;
        !           730:        struct sockaddr *sa=(struct sockaddr *)addr;
        !           731:        if (dev->start)
        !           732:                return -EBUSY;
        !           733:        printk("%s: Setting MAC address to ", dev->name);
        !           734:        for (i = 0; i < 6; i++)
        !           735:                printk(" %2.2x", dev->dev_addr[i] = sa->sa_data[i]);
        !           736:        printk(".\n");
        !           737:        return 0;
        !           738: }
        !           739: 
        !           740: #ifdef MODULE
        !           741: static char devicename[9] = { 0, };
        !           742: static struct device dev_tulip = {
        !           743:        devicename, /* device name is inserted by linux/drivers/net/net_init.c */
        !           744:        0, 0, 0, 0,
        !           745:        0, 0,
        !           746:        0, 0, 0, NULL, tulip_probe
        !           747: };
        !           748: 
        !           749: static int io = 0;
        !           750: static int irq = 0;
        !           751: 
        !           752: int init_module(void)
        !           753: {
        !           754:        printk("tulip: Sorry, modularization is not completed\n");
        !           755:        return -EIO;
        !           756: #if 0
        !           757:        if (io == 0)
        !           758:          printk("tulip: You should not use auto-probing with insmod!\n");
        !           759:        dev_tulip.base_addr = io;
        !           760:        dev_tulip.irq       = irq;
        !           761:        if (register_netdev(&dev_tulip) != 0) {
        !           762:                printk("tulip: register_netdev() returned non-zero.\n");
        !           763:                return -EIO;
        !           764:        }
        !           765:        return 0;
        !           766: #endif
        !           767: }
        !           768: 
        !           769: void
        !           770: cleanup_module(void)
        !           771: {
        !           772:        unregister_netdev(&dev_tulip);
        !           773: }
        !           774: #endif /* MODULE */
        !           775: 
        !           776: /*
        !           777:  * Local variables:
        !           778:  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c tulip.c"
        !           779:  *  c-indent-level: 4
        !           780:  *  tab-width: 4
        !           781:  * End:
        !           782:  */

unix.superglobalmegacorp.com

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