diff -urNX diff_kernel_excludes /usr/src/local/linux-2.4.vanilla/drivers/net/starfire.c linux-2.4/drivers/net/starfire.c --- /usr/src/local/linux-2.4.vanilla/drivers/net/starfire.c Fri Aug 11 15:57:58 2000 +++ linux-2.4/drivers/net/starfire.c Sat Jan 27 12:44:35 2001 @@ -34,6 +34,10 @@ LK1.1.4 (jgarzik): - Merge Becker version 1.03 + + LK1.2.0 (Ion Badulescu ) + - Support hardware Rx/Tx checksumming + - Add GFP firmware taken from Adaptec's Netware driver */ /* These identify the driver base version and may not be removed. */ @@ -43,11 +47,17 @@ " Updates and info at http://www.scyld.com/network/starfire.html\n"; static const char version3[] = -" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n"; +" (unofficial 2.4.x kernel port, version 1.2.0, January 25, 2001)\n"; /* The user-configurable values. These may be modified when a driver module is loaded.*/ +/* + * The current frame processor firmware fails to checksum a fragment + * of length 1. If and when this is fixed, the #define below can be removed. + */ +#define HAS_BROKEN_FIRMWARE + /* Used for tuning interrupt latency vs. overhead. */ static int interrupt_mitigation = 0x0; @@ -117,12 +127,15 @@ #include #include +#include "starfire_firmware.h" + MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(mtu, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(interrupt_mitigation, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); @@ -256,19 +269,31 @@ TxThreshold=0x500B0, CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8, RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0, - CompletionQConsumerIdx=0x500C4, + CompletionQConsumerIdx=0x500C4, RxDMACtrl=0x500D0, RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0, RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4, - TxMode=0x55000, + TxMode=0x55000, TxGfpMem=0x58000, RxGfpMem=0x5a000, }; /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { - IntrNormalSummary=0x8000, IntrAbnormalSummary=0x02000000, - IntrRxDone=0x0300, IntrRxEmpty=0x10040, IntrRxPCIErr=0x80000, - IntrTxDone=0x4000, IntrTxEmpty=0x1000, IntrTxPCIErr=0x80000, - StatsMax=0x08000000, LinkChange=0xf0000000, - IntrTxDataLow=0x00040000, + IntrLinkChange=0xf0000000, IntrStatsMax=0x08000000, + IntrAbnormalSummary=0x02000000, IntrGeneralTimer=0x01000000, + IntrSoftware=0x800000, IntrRxComplQ1Low=0x400000, + IntrTxComplQLow=0x200000, IntrPCI=0x100000, + IntrDMAErr=0x080000, IntrTxDataLow=0x040000, + IntrRxComplQ2Low=0x020000, IntrRxDescQ1Low=0x010000, + IntrNormalSummary=0x8000, IntrTxDone=0x4000, + IntrTxDMADone=0x2000, IntrTxEmpty=0x1000, + IntrEarlyRxQ2=0x0800, IntrEarlyRxQ1=0x0400, + IntrRxQ2Done=0x0200, IntrRxQ1Done=0x0100, + IntrRxGFPDead=0x80, IntrRxDescQ2Low=0x40, + IntrNoTxCsum=0x20, IntrTxBadID=0x10, + IntrHiPriTxBadID=0x08, IntrRxGfp=0x04, + IntrTxGfp=0x02, IntrPCIPad=0x01, + /* not quite bits */ + IntrRxDone=IntrRxQ2Done | IntrRxQ1Done, + IntrRxEmpty=IntrRxDescQ1Low | IntrRxDescQ2Low, }; /* Bits in the RxFilterMode register. */ @@ -277,6 +302,37 @@ AcceptMulticast=0x10, AcceptMyPhys=0xE040, }; +/* Bits in the TxDescCtrl register. */ +enum tx_ctrl_bits { + TxDescSpaceUnlim=0x00, TxDescSpace32=0x10, TxDescSpace64=0x20, + TxDescSpace128=0x30, TxDescSpace256=0x40, + TxDescType0=0x00, TxDescType1=0x01, TxDescType2=0x02, + TxDescType3=0x03, TxDescType4=0x04, + TxNoDMACompletion=0x08, TxDescQ64bit=0x80, + TxHiPriFIFOThreshShift=24, TxPadLenShift=16, + TxDMABurstSizeShift=8, +}; + +/* Bits in the RxDescQCtrl register. */ +enum rx_ctrl_bits { + RxBufferLenShift=16, RxMinDescrThreshShift=0, + RxPrefetchMode=0x8000, Rx2048QEntries=0x4000, + RxVariableQ=0x2000, RxDesc64bit=0x1000, + RxDescQAddr64bit=0x0100, + RxDescSpace4=0x000, RxDescSpace8=0x100, + RxDescSpace16=0x200, RxDescSpace32=0x300, + RxDescSpace64=0x400, RxDescSpace128=0x500, + RxConsumerWrEn=0x80, +}; + +/* Bits in the RxCompletionAddr register */ +enum rx_compl_bits { + RxComplQAddr64bit=0x80, TxComplProducerWrEn=0x40, + RxComplType0=0x00, RxComplType1=0x10, + RxComplType2=0x20, RxComplType3=0x30, + RxComplThreshShift=0, +}; + /* The Rx and Tx buffer descriptors. */ struct starfire_rx_desc { u32 rxaddr; /* Optionally 64 bits. */ @@ -288,8 +344,12 @@ /* Completion queue entry. You must update the page allocation, init_ring and the shift count in rx() if using a larger format. */ +#define csum_rx_status struct rx_done_desc { u32 status; /* Low 16 bits is length. */ +#ifdef csum_rx_status + u32 status2; /* Low 16 bits is csum */ +#endif #ifdef full_rx_status u32 status2; u16 vlanid; @@ -301,14 +361,24 @@ RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000, }; -/* Type 1 Tx descriptor. */ +/* Type 0 Tx descriptor. */ +/* If more fragments are needed, don't forget to change the + descriptor spacing as well! */ struct starfire_tx_desc { - u32 status; /* Upper bits are status, lower 16 length. */ - u32 addr; + u32 status; + u32 nbufs; + u32 first_addr; + u16 first_len; + u16 total_len; + struct { + u32 addr; + u32 len; + } frag[6]; }; enum tx_desc_bits { - TxDescID=0xB1010000, /* Also marks single fragment, add CRC. */ - TxDescIntr=0x08000000, TxRingWrap=0x04000000, + TxDescID=0xB0000000, + TxCRCEn=0x01000000, TxDescIntr=0x08000000, + TxRingWrap=0x04000000, TxCalTCP=0x02000000, }; struct tx_done_report { u32 status; /* timestamp, index. */ @@ -318,10 +388,15 @@ }; #define PRIV_ALIGN 15 /* Required alignment mask */ -struct ring_info { +struct rx_ring_info { struct sk_buff *skb; dma_addr_t mapping; }; +struct tx_ring_info { + struct sk_buff *skb; + dma_addr_t first_mapping; + dma_addr_t frag_mapping[6]; +}; struct netdev_private { /* Descriptor rings first for alignment. */ @@ -330,8 +405,8 @@ dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; /* The addresses of rx/tx-in-place skbuffs. */ - struct ring_info rx_info[RX_RING_SIZE]; - struct ring_info tx_info[TX_RING_SIZE]; + struct rx_ring_info rx_info[RX_RING_SIZE]; + struct tx_ring_info tx_info[TX_RING_SIZE]; /* Pointers to completion queues (full pages). I should cache line pad..*/ u8 pad0[100]; struct rx_done_desc *rx_done_q; @@ -390,16 +465,17 @@ static int card_idx = -1; static int printed_version = 0; long ioaddr; - int drv_flags, io_size = netdrv_tbl[chip_idx].io_size; + int drv_flags, io_size; card_idx++; option = card_idx < MAX_UNITS ? options[card_idx] : 0; - + if (!printed_version++) printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", version1, version2, version3); ioaddr = pci_resource_start (pdev, 0); + io_size = pci_resource_len (pdev, 0); if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) { printk (KERN_ERR "starfire %d: no PCI MEM resources, aborting\n", card_idx); return -ENODEV; @@ -410,6 +486,7 @@ printk (KERN_ERR "starfire %d: cannot alloc etherdev, aborting\n", card_idx); return -ENOMEM; } + SET_MODULE_OWNER(dev); irq = pdev->irq; @@ -434,6 +511,9 @@ printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, netdrv_tbl[chip_idx].name, ioaddr); + /* Starfire can do SG and TCP/UDP checksumming */ + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + /* Serial EEPROM reads are hidden by the hardware. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i); @@ -546,13 +626,9 @@ /* Do we ever need to reset the chip??? */ - MOD_INC_USE_COUNT; - retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); - if (retval) { - MOD_DEC_USE_COUNT; + if (retval) return retval; - } /* Disable the Rx and Tx, and reset the chip. */ writel(0, ioaddr + GenCtrl); @@ -564,7 +640,7 @@ if (np->tx_done_q == 0) np->tx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_done_q_dma); if (np->rx_done_q == 0) - np->rx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_done_q_dma); + np->rx_done_q = pci_alloc_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, &np->rx_done_q_dma); if (np->tx_ring == 0) np->tx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_ring_dma); if (np->rx_ring == 0) @@ -575,7 +651,7 @@ pci_free_consistent(np->pci_dev, PAGE_SIZE, np->tx_done_q, np->tx_done_q_dma); if (np->rx_done_q) - pci_free_consistent(np->pci_dev, PAGE_SIZE, + pci_free_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, np->rx_done_q, np->rx_done_q_dma); if (np->tx_ring) pci_free_consistent(np->pci_dev, PAGE_SIZE, @@ -583,16 +659,23 @@ if (np->rx_ring) pci_free_consistent(np->pci_dev, PAGE_SIZE, np->rx_ring, np->rx_ring_dma); - MOD_DEC_USE_COUNT; return -ENOMEM; } init_ring(dev); /* Set the size of the Rx buffers. */ - writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl); - - /* Set Tx descriptor to type 1 and padding to 0 bytes. */ - writel(0x02000401, ioaddr + TxDescCtrl); + writel((np->rx_buf_sz << RxBufferLenShift) | + (0 << RxMinDescrThreshShift) | + RxPrefetchMode | RxVariableQ | + RxDescSpace4, + ioaddr + RxDescQCtrl); + + /* Set Tx descriptor to type 0 and spacing to 64 bytes. */ + writel((2 << TxHiPriFIFOThreshShift) | + (0 << TxPadLenShift) | + (4 << TxDMABurstSizeShift) | + TxDescSpace64 | TxDescType0, + ioaddr + TxDescCtrl); #if defined(ADDR_64BITS) && defined(__alpha__) /* XXX We really need a 64-bit PCI dma interfaces too... -DaveM */ @@ -607,7 +690,24 @@ writel(np->tx_ring_dma, ioaddr + TxRingPtr); writel(np->tx_done_q_dma, ioaddr + TxCompletionAddr); - writel(np->rx_done_q_dma, ioaddr + RxCompletionAddr); +#ifdef full_rx_status + writel(np->rx_done_q_dma | + RxComplType3 | + (0 << RxComplThreshShift), + ioaddr + RxCompletionAddr); +#else +#ifdef csum_rx_status + writel(np->rx_done_q_dma | + RxComplType2 | + (0 << RxComplThreshShift), + ioaddr + RxCompletionAddr); +#else + writel(np->rx_done_q_dma | + RxComplType0 | + (0 << RxComplThreshShift), + ioaddr + RxCompletionAddr); +#endif +#endif if (debug > 1) printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name); @@ -643,15 +743,21 @@ check_duplex(dev, 1); /* Set the interrupt mask and enable PCI interrupts. */ - writel(IntrRxDone | IntrRxEmpty | IntrRxPCIErr | - IntrTxDone | IntrTxEmpty | IntrTxPCIErr | - StatsMax | LinkChange | IntrNormalSummary | IntrAbnormalSummary - | 0x0010 , ioaddr + IntrEnable); + writel(IntrRxDone | IntrRxEmpty | IntrDMAErr | + IntrTxDone | IntrStatsMax | IntrLinkChange | + IntrNormalSummary | IntrAbnormalSummary | + IntrRxGFPDead | IntrNoTxCsum | IntrTxBadID, + ioaddr + IntrEnable); writel(0x00800000 | readl(ioaddr + PCIDeviceConfig), ioaddr + PCIDeviceConfig); - /* Enable the Rx and Tx units. */ - writel(0x000F, ioaddr + GenCtrl); + /* Load Rx/Tx firmware into the frame processors */ + for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++) + writel(cpu_to_le32(firmware_rx[i]), ioaddr + RxGfpMem + i * 4); + for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++) + writel(cpu_to_le32(firmware_tx[i]), ioaddr + TxGfpMem + i * 4); + /* Enable the Rx and Tx units, and the Rx/Tx frame processors. */ + writel(0x003F, ioaddr + GenCtrl); if (debug > 2) printk(KERN_DEBUG "%s: Done netdev_open().\n", @@ -765,7 +871,7 @@ static void init_ring(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; - int i; + int i, j; np->tx_full = 0; np->cur_rx = np->cur_tx = 0; @@ -804,7 +910,9 @@ for (i = 0; i < TX_RING_SIZE; i++) { np->tx_info[i].skb = NULL; - np->tx_info[i].mapping = 0; + np->tx_info[i].first_mapping = 0; + for (j = 0; j < 6; j++) + np->tx_info[i].frag_mapping[j] = 0; np->tx_ring[i].status = 0; } return; @@ -814,6 +922,7 @@ { struct netdev_private *np = (struct netdev_private *)dev->priv; unsigned entry; + int i; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -821,42 +930,87 @@ /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; +#ifdef HAS_BROKEN_FIRMWARE + { + int has_bad_length = 0; + + if (skb_headlen(skb) == 1) + has_bad_length = 1; + else { + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + if (skb_shinfo(skb)->frags[i].size == 1) { + has_bad_length = 1; + break; + } + } + + if (has_bad_length) + skb_checksum_help(skb); + } +#endif /* HAS_BROKEN_FIRMWARE */ + np->tx_info[entry].skb = skb; - np->tx_info[entry].mapping = - pci_map_single(np->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + np->tx_info[entry].first_mapping = + pci_map_single(np->pci_dev, skb->data, skb_headlen(skb), PCI_DMA_TODEVICE); - np->tx_ring[entry].addr = cpu_to_le32(np->tx_info[entry].mapping); + np->tx_ring[entry].first_addr = cpu_to_le32(np->tx_info[entry].first_mapping); + np->tx_ring[entry].first_len = cpu_to_le32(skb_headlen(skb)); + np->tx_ring[entry].total_len = cpu_to_le32(skb->len); /* Add "| TxDescIntr" to generate Tx-done interrupts. */ - np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID); + np->tx_ring[entry].status = cpu_to_le32(TxDescID | TxCRCEn); + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr); + np->tx_ring[entry].nbufs = cpu_to_le32(skb_shinfo(skb)->nr_frags + 1); + + if (skb->ip_summed == CHECKSUM_HW) + np->tx_ring[entry].status |= cpu_to_le32(TxCalTCP); + if (debug > 5) { - printk(KERN_DEBUG "%s: Tx #%d slot %d %8.8x %8.8x.\n", + printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x nbufs %d len %4.4x/%4.4x.\n", dev->name, np->cur_tx, entry, le32_to_cpu(np->tx_ring[entry].status), - le32_to_cpu(np->tx_ring[entry].addr)); + le32_to_cpu(np->tx_ring[entry].nbufs), + le32_to_cpu(np->tx_ring[entry].first_len), + le32_to_cpu(np->tx_ring[entry].total_len)); + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i]; + + /* we already have the proper value in entry */ + np->tx_info[entry].frag_mapping[i] = + pci_map_single(np->pci_dev, page_address(this_frag->page) + this_frag->page_offset, this_frag->size, PCI_DMA_TODEVICE); + + np->tx_ring[entry].frag[i].addr = cpu_to_le32(np->tx_info[entry].frag_mapping[i]); + np->tx_ring[entry].frag[i].len = cpu_to_le32(this_frag->size); + if (debug > 5) { + printk(KERN_DEBUG "%s: Tx #%d frag %d len %4.4x.\n", + dev->name, np->cur_tx, i, + le32_to_cpu(np->tx_ring[entry].frag[i].len)); + } } + np->cur_tx++; -#if 1 - if (entry >= TX_RING_SIZE-1) { /* Wrap ring */ - np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr); + + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ entry = -1; - } -#endif + entry++; /* Non-x86: explicitly flush descriptor cache lines here. */ + /* Ensure everything is written back above before the transmit is + initiated. - Jes */ + wmb(); /* Update the producer index. */ - writel(++entry, dev->base_addr + TxProducerIdx); + writel(entry * (sizeof(struct starfire_tx_desc) / 8), dev->base_addr + TxProducerIdx); if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) { np->tx_full = 1; netif_stop_queue(dev); } + dev->trans_start = jiffies; - if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, np->cur_tx, entry); - } return 0; } @@ -919,18 +1073,29 @@ np->stats.tx_packets++; } else if ((tx_status & 0xe0000000) == 0x80000000) { struct sk_buff *skb; + int i; u16 entry = tx_status; /* Implicit truncate */ - entry >>= 3; + entry /= sizeof(struct starfire_tx_desc); skb = np->tx_info[entry].skb; + np->tx_info[entry].skb = NULL; pci_unmap_single(np->pci_dev, - np->tx_info[entry].mapping, - skb->len, PCI_DMA_TODEVICE); + np->tx_info[entry].first_mapping, + skb_headlen(skb), + PCI_DMA_TODEVICE); + np->tx_info[entry].first_mapping = 0; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + pci_unmap_single(np->pci_dev, + np->tx_info[entry].frag_mapping[i], + skb_shinfo(skb)->frags[i].size, + PCI_DMA_TODEVICE); + np->tx_info[entry].frag_mapping[i] = 0; + } /* Scavenge the descriptor. */ dev_kfree_skb_irq(skb); - np->tx_info[entry].skb = NULL; - np->tx_info[entry].mapping = 0; + np->dirty_tx++; } np->tx_done_q[np->tx_done].status = 0; @@ -1037,14 +1202,6 @@ temp = skb_put(skb, pkt_len); np->rx_info[entry].skb = NULL; np->rx_info[entry].mapping = 0; -#ifndef final_version /* Remove after testing. */ - if (le32_to_cpu(np->rx_ring[entry].rxaddr & ~3) != ((unsigned long) temp)) - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in netdev_rx: %d vs. %p / %p.\n", - dev->name, - le32_to_cpu(np->rx_ring[entry].rxaddr), - skb->head, temp); -#endif } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ @@ -1060,9 +1217,23 @@ skb->data[17]); #endif skb->protocol = eth_type_trans(skb, dev); -#ifdef full_rx_status - if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) +#if defined(full_rx_status) || defined(csum_rx_status) + if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) { skb->ip_summed = CHECKSUM_UNNECESSARY; + } + /* + * This feature doesn't seem to be working, at least + * with the two firmware versions I have. If the GFP sees + * a fragment, it either ignores it completely, or reports + * "bad checksum" on it. + * + * Maybe I missed something -- corrections are welcome. -Ion + */ + else if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x00400000) { + skb->ip_summed = CHECKSUM_HW; + skb->csum = le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0xffff; + printk(KERN_DEBUG "%s: checksum_hw, status2 = %x\n", dev->name, np->rx_done_q[np->rx_done].status2); + } #endif netif_rx(skb); dev->last_rx = jiffies; @@ -1109,28 +1280,26 @@ { struct netdev_private *np = (struct netdev_private *)dev->priv; - if (intr_status & LinkChange) { + if (intr_status & IntrLinkChange) { printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" " %4.4x partner %4.4x.\n", dev->name, mdio_read(dev, np->phys[0], 4), mdio_read(dev, np->phys[0], 5)); check_duplex(dev, 0); } - if (intr_status & StatsMax) { + if (intr_status & IntrStatsMax) { get_stats(dev); } /* Came close to underrunning the Tx FIFO, increase threshold. */ if (intr_status & IntrTxDataLow) writel(++np->tx_threshold, dev->base_addr + TxThreshold); if ((intr_status & - ~(IntrAbnormalSummary|LinkChange|StatsMax|IntrTxDataLow|1)) && debug) + ~(IntrAbnormalSummary|IntrLinkChange|IntrStatsMax|IntrTxDataLow|1)) && debug) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); - /* Hmmmmm, it's not clear how to recover from PCI faults. */ - if (intr_status & IntrTxPCIErr) + /* Hmmmmm, it's not clear how to recover from DMA faults. */ + if (intr_status & IntrDMAErr) np->stats.tx_fifo_errors++; - if (intr_status & IntrRxPCIErr) - np->stats.rx_fifo_errors++; } static struct net_device_stats *get_stats(struct net_device *dev) @@ -1280,7 +1449,7 @@ { long ioaddr = dev->base_addr; struct netdev_private *np = (struct netdev_private *)dev->priv; - int i; + int i, j; netif_stop_queue(dev); @@ -1305,7 +1474,7 @@ for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++) printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n", i, le32_to_cpu(np->tx_ring[i].status), - le32_to_cpu(np->tx_ring[i].addr), + le32_to_cpu(np->tx_ring[i].first_addr), le32_to_cpu(np->tx_done_q[i].status)); printk(KERN_DEBUG " Rx ring at %8.8x -> %p:\n", np->rx_ring_dma, np->rx_done_q); @@ -1333,16 +1502,23 @@ struct sk_buff *skb = np->tx_info[i].skb; if (skb != NULL) { pci_unmap_single(np->pci_dev, - np->tx_info[i].mapping, - skb->len, PCI_DMA_TODEVICE); + np->tx_info[i].first_mapping, + skb_headlen(skb), PCI_DMA_TODEVICE); + np->tx_info[i].first_mapping = 0; dev_kfree_skb(skb); + np->tx_info[i].skb = NULL; + for (j = 0; j < 6; j++) + if (np->tx_info[i].frag_mapping[j]) { + pci_unmap_single(np->pci_dev, + np->tx_info[i].frag_mapping[j], + skb_shinfo(skb)->frags[j].size, + PCI_DMA_TODEVICE); + np->tx_info[i].frag_mapping[j] = 0; + } else + break; } - np->tx_info[i].skb = NULL; - np->tx_info[i].mapping = 0; } - MOD_DEC_USE_COUNT; - return 0; } @@ -1359,6 +1535,9 @@ unregister_netdev(dev); iounmap((char *)dev->base_addr); + + release_mem_region(pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); if (np->tx_done_q) pci_free_consistent(np->pci_dev, PAGE_SIZE, diff -urNX diff_kernel_excludes /usr/src/local/linux-2.4.vanilla/drivers/net/starfire_firmware.h linux-2.4/drivers/net/starfire_firmware.h --- /usr/src/local/linux-2.4.vanilla/drivers/net/starfire_firmware.h Wed Dec 31 16:00:00 1969 +++ linux-2.4/drivers/net/starfire_firmware.h Sat Jan 27 13:03:06 2001 @@ -0,0 +1,215 @@ +static u32 firmware_rx[] = { + 0x010003dc, 0x00000000, + 0x04000421, 0x00000086, + 0x80000015, 0x0000180e, + 0x81000015, 0x00006664, + 0x1a0040ab, 0x00000b06, + 0x14200011, 0x00000000, + 0x14204022, 0x0000aaaa, + 0x14204022, 0x00000300, + 0x14204022, 0x00000000, + 0x1a0040ab, 0x00000b14, + 0x14200011, 0x00000000, + 0x83000015, 0x00000002, + 0x04000021, 0x00000000, + 0x00000010, 0x00000000, + 0x04000421, 0x00000087, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x00008015, 0x00000000, + 0x0000003e, 0x00000000, + 0x00000010, 0x00000000, + 0x82000015, 0x00004000, + 0x009e8050, 0x00000000, + 0x03008015, 0x00000000, + 0x86008015, 0x00000000, + 0x82000015, 0x00008000, + 0x0100001c, 0x00000000, + 0x000050a0, 0x0000010c, + 0x4e20d011, 0x00006008, + 0x1420d012, 0x00004008, + 0x0000f090, 0x00007000, + 0x0000c8b0, 0x00003000, + 0x00004040, 0x00000000, + 0x00108015, 0x00000000, + 0x00a2c150, 0x00004000, + 0x00a400b0, 0x00000014, + 0x00000020, 0x00000000, + 0x2500400d, 0x00002525, + 0x00047220, 0x00003100, + 0x00934070, 0x00000000, + 0x00000020, 0x00000000, + 0x00924460, 0x00000184, + 0x2b20c011, 0x00000000, + 0x0000c420, 0x00000540, + 0x36014018, 0x0000422d, + 0x14200011, 0x00000000, + 0x00924460, 0x00000183, + 0x3200001f, 0x00000034, + 0x02ac0015, 0x00000002, + 0x00a60110, 0x00000008, + 0x42200011, 0x00000000, + 0x00924060, 0x00000103, + 0x0000001e, 0x00000000, + 0x00000020, 0x00000100, + 0x0000001e, 0x00000000, + 0x00924460, 0x00000086, + 0x00004080, 0x00000000, + 0x0092c070, 0x00000000, + 0x00924060, 0x00000100, + 0x0000c890, 0x00005000, + 0x00a6c110, 0x00000000, + 0x00b0c090, 0x00000012, + 0x021c0015, 0x00000000, + 0x3200001f, 0x00000034, + 0x00924460, 0x00000510, + 0x44210011, 0x00000000, + 0x42000011, 0x00000000, + 0x83000015, 0x00000040, + 0x00924460, 0x00000508, + 0x45014018, 0x00004545, + 0x00808050, 0x00000000, + 0x62208012, 0x00000000, + 0x82000015, 0x00000800, + 0x15200011, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x80000015, 0x0000eea4, + 0x81000015, 0x0000005f, + 0x00000060, 0x00000000, + 0x00004120, 0x00000000, + 0x00004a00, 0x00004000, + 0x00924460, 0x00000190, + 0x5601401a, 0x00005956, + 0x14000011, 0x00000000, + 0x00934050, 0x00000018, + 0x00930050, 0x00000018, + 0x3601403a, 0x0000002d, + 0x000643a9, 0x00000000, + 0x0000c420, 0x00000140, + 0x5601401a, 0x00005956, + 0x14000011, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x000642a9, 0x00000000, + 0x00024420, 0x00000183, + 0x5601401a, 0x00005956, + 0x82000015, 0x00002000, + 0x15200011, 0x00000000, + 0x82000015, 0x00000010, + 0x15200011, 0x00000000, + 0x82000015, 0x00000010, + 0x15200011, 0x00000000, +}; /* 104 Rx instructions */ +#define FIRMWARE_RX_SIZE 104 + +static u32 firmware_tx[] = { + 0x010003dc, 0x00000000, + 0x04000421, 0x00000086, + 0x80000015, 0x0000180e, + 0x81000015, 0x00006664, + 0x1a0040ab, 0x00000b06, + 0x14200011, 0x00000000, + 0x14204022, 0x0000aaaa, + 0x14204022, 0x00000300, + 0x14204022, 0x00000000, + 0x1a0040ab, 0x00000b14, + 0x14200011, 0x00000000, + 0x83000015, 0x00000002, + 0x04000021, 0x00000000, + 0x00000010, 0x00000000, + 0x04000421, 0x00000087, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x00008015, 0x00000000, + 0x0000003e, 0x00000000, + 0x00000010, 0x00000000, + 0x82000015, 0x00004000, + 0x009e8050, 0x00000000, + 0x03008015, 0x00000000, + 0x86008015, 0x00000000, + 0x82000015, 0x00008000, + 0x0100001c, 0x00000000, + 0x000050a0, 0x0000010c, + 0x4e20d011, 0x00006008, + 0x1420d012, 0x00004008, + 0x0000f090, 0x00007000, + 0x0000c8b0, 0x00003000, + 0x00004040, 0x00000000, + 0x00108015, 0x00000000, + 0x00a2c150, 0x00004000, + 0x00a400b0, 0x00000014, + 0x00000020, 0x00000000, + 0x2500400d, 0x00002525, + 0x00047220, 0x00003100, + 0x00934070, 0x00000000, + 0x00000020, 0x00000000, + 0x00924460, 0x00000184, + 0x2b20c011, 0x00000000, + 0x0000c420, 0x00000540, + 0x36014018, 0x0000422d, + 0x14200011, 0x00000000, + 0x00924460, 0x00000183, + 0x3200001f, 0x00000034, + 0x02ac0015, 0x00000002, + 0x00a60110, 0x00000008, + 0x42200011, 0x00000000, + 0x00924060, 0x00000103, + 0x0000001e, 0x00000000, + 0x00000020, 0x00000100, + 0x0000001e, 0x00000000, + 0x00924460, 0x00000086, + 0x00004080, 0x00000000, + 0x0092c070, 0x00000000, + 0x00924060, 0x00000100, + 0x0000c890, 0x00005000, + 0x00a6c110, 0x00000000, + 0x00b0c090, 0x00000012, + 0x021c0015, 0x00000000, + 0x3200001f, 0x00000034, + 0x00924460, 0x00000510, + 0x44210011, 0x00000000, + 0x42000011, 0x00000000, + 0x83000015, 0x00000040, + 0x00924460, 0x00000508, + 0x45014018, 0x00004545, + 0x00808050, 0x00000000, + 0x62208012, 0x00000000, + 0x82000015, 0x00000800, + 0x15200011, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x80000015, 0x0000eea4, + 0x81000015, 0x0000005f, + 0x00000060, 0x00000000, + 0x00004120, 0x00000000, + 0x00004a00, 0x00004000, + 0x00924460, 0x00000190, + 0x5601401a, 0x00005956, + 0x14000011, 0x00000000, + 0x00934050, 0x00000018, + 0x00930050, 0x00000018, + 0x3601403a, 0x0000002d, + 0x000643a9, 0x00000000, + 0x0000c420, 0x00000140, + 0x5601401a, 0x00005956, + 0x14000011, 0x00000000, + 0x00000010, 0x00000000, + 0x00000010, 0x00000000, + 0x000642a9, 0x00000000, + 0x00024420, 0x00000183, + 0x5601401a, 0x00005956, + 0x82000015, 0x00002000, + 0x15200011, 0x00000000, + 0x82000015, 0x00000010, + 0x15200011, 0x00000000, + 0x82000015, 0x00000010, + 0x15200011, 0x00000000, +}; /* 104 Tx instructions */ +#define FIRMWARE_TX_SIZE 104 diff -urNX diff_kernel_excludes /usr/src/local/linux-2.4.vanilla/drivers/net/starfire_firmware.pl linux-2.4/drivers/net/starfire_firmware.pl --- /usr/src/local/linux-2.4.vanilla/drivers/net/starfire_firmware.pl Wed Dec 31 16:00:00 1969 +++ linux-2.4/drivers/net/starfire_firmware.pl Thu Jan 25 21:43:27 2001 @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +# This script can be used to generate a new starfire_firmware.h +# from GFP_RX.DAT and GFP_TX.DAT, files included with the DDK +# and also with the Novell drivers. + +open FW, "GFP_RX.DAT" || die; +open FWH, ">starfire_firmware.h" || die; + +printf(FWH "static u32 firmware_rx[] = {\n"); +$counter = 0; +while ($foo = ) { + chomp; + printf(FWH " 0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4)); + $counter++; +} + +close FW; +open FW, "GFP_TX.DAT" || die; + +printf(FWH "};\t/* %d Rx instructions */\n#define FIRMWARE_RX_SIZE %d\n\nstatic u32 firmware_tx[] = {\n", $counter, $counter); +$counter = 0; +while ($foo = ) { + chomp; + printf(FWH " 0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4)); + $counter++; +} + +close FW; +printf(FWH "};\t/* %d Tx instructions */\n#define FIRMWARE_TX_SIZE %d\n", $counter, $counter); +close(FWH);