diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/net/via-rhine.c linux-2.5/drivers/net/via-rhine.c --- bk-linus/drivers/net/via-rhine.c 2002-11-21 02:16:33.000000000 +0000 +++ linux-2.5/drivers/net/via-rhine.c 2002-11-21 17:59:34.000000000 +0000 @@ -95,6 +95,10 @@ so normal interrupts will not trigger the message (src: Donald Becker) (Roger Lahti) - cosmetic cleanups, remove 3 unused members of struct netdev_private + (Roger Luethi) + - show confused chip where to continue after Tx error + - location of collision counter is chip specific + - allow selecting backoff algorithm (module parameter) */ @@ -113,6 +117,9 @@ static int max_interrupt_work = 20; Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; +/* Select a backoff algorithm (Ethernet capture effect) */ +static int backoff; + /* Used to pass the media type, etc. Both 'options[]' and 'full_duplex[]' should exist for driver interoperability. @@ -215,11 +222,13 @@ MODULE_LICENSE("GPL"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(backoff, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm"); MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)"); @@ -236,7 +245,8 @@ II. Board-specific settings Boards with this chip are functional only in a bus-master PCI slot. Many operational settings are loaded from the EEPROM to the Config word at -offset 0x78. This driver assumes that they are correct. +offset 0x78. For most of these settings, this driver assumes that they are +correct. If this driver is compiled to use PCI memory space operations the EEPROM must be configured to enable memory ops. @@ -359,9 +369,9 @@ static struct via_rhine_chip_info via_rh { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL }, { "VIA VT6105M Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL }, }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = @@ -369,7 +379,7 @@ static struct pci_device_id via_rhine_pc {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, - {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, + {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, {0,} /* terminate list */ }; MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); @@ -388,9 +398,10 @@ enum register_offsets { StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC, }; -/* Bits in ConfigD (select backoff algorithm (Ethernet capture effect)) */ +/* Bits in ConfigD */ enum backoff_bits { - BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08 + BackOptional=0x01, BackModify=0x02, + BackCaptureEffect=0x04, BackRandom=0x08 }; #ifdef USE_MEM @@ -404,7 +415,7 @@ int mmio_verify_registers[] = { /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, - IntrTxDone=0x0002, IntrTxAbort=0x0008, IntrTxUnderrun=0x0010, + IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0010, IntrPCIErr=0x0040, IntrStatsMax=0x0080, IntrRxEarly=0x0100, IntrMIIChange=0x0200, IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, @@ -430,24 +441,27 @@ enum mii_status_bits { /* The Rx and Tx buffer descriptors. */ struct rx_desc { s32 rx_status; - u32 desc_length; + u32 desc_length; /* Chain flag, Buffer/frame length */ u32 addr; u32 next_desc; }; struct tx_desc { s32 tx_status; - u32 desc_length; + u32 desc_length; /* Chain flag, Tx Config, Frame length */ u32 addr; u32 next_desc; }; +/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */ +#define TXDESC 0x00e08000 + enum rx_status_bits { RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F }; -/* Bits in *_desc.status */ +/* Bits in *_desc.*_status */ enum desc_status_bits { - DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000, + DescOwn=0x80000000 }; /* Bits in ChipCmd. */ @@ -519,6 +533,7 @@ static struct net_device_stats *via_rhin static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int via_rhine_close(struct net_device *dev); static inline void clear_tally_counters(long ioaddr); +static inline void via_restart_tx(struct net_device *dev); static void wait_for_reset(struct net_device *dev, int chip_id, char *name) { @@ -705,6 +720,11 @@ static int __devinit via_rhine_init_one writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); } + /* Select backoff algorithm */ + if (backoff) + writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff), + ioaddr + ConfigD); + dev->irq = pdev->irq; np = dev->priv; @@ -941,7 +961,7 @@ static void alloc_tbufs(struct net_devic for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].desc_length = cpu_to_le32(TXDESC); next += sizeof(struct tx_desc); np->tx_ring[i].next_desc = cpu_to_le32(next); np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ]; @@ -957,7 +977,7 @@ static void free_tbufs(struct net_device for (i = 0; i < TX_RING_SIZE; i++) { np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].desc_length = cpu_to_le32(TXDESC); np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (np->tx_skbuff[i]) { if (np->tx_skbuff_dma[i]) { @@ -982,7 +1002,7 @@ static void init_registers(struct net_de writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers. */ - writew(0x0006, ioaddr + PCIBusConfig); /* Store & forward */ + writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ /* Configure initial FIFO thresholds. */ writeb(0x20, ioaddr + TxConfig); np->tx_thresh = 0x20; @@ -997,8 +1017,9 @@ static void init_registers(struct net_de via_rhine_set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ - writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| - IntrTxDone | IntrTxAbort | IntrTxUnderrun | + writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | + IntrRxDropped | IntrRxNoBuf | IntrTxAborted | + IntrTxDone | IntrTxError | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange, ioaddr + IntrEnable); @@ -1241,7 +1262,7 @@ static int via_rhine_start_tx(struct sk_ } np->tx_ring[entry].desc_length = - cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); /* lock eth irq */ spin_lock_irq (&np->lock); @@ -1293,13 +1314,14 @@ static void via_rhine_interrupt(int irq, IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) via_rhine_rx(dev); - if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun | + if (intr_status & (IntrTxDone | IntrTxError | IntrTxUnderrun | IntrTxAborted)) via_rhine_tx(dev); /* Abnormal error summary/uncommon events handlers. */ if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange | - IntrStatsMax | IntrTxAbort | IntrTxUnderrun)) + IntrStatsMax | IntrTxError | IntrTxAborted | + IntrTxUnderrun)) via_rhine_error(dev, intr_status); if (--boguscnt < 0) { @@ -1311,7 +1333,7 @@ static void via_rhine_interrupt(int irq, } if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + printk(KERN_DEBUG "%s: exiting interrupt, status=%4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); } @@ -1327,11 +1349,11 @@ static void via_rhine_tx(struct net_devi /* find and cleanup dirty tx descriptors */ while (np->dirty_tx != np->cur_tx) { txstatus = le32_to_cpu(np->tx_ring[entry].tx_status); - if (txstatus & DescOwn) - break; if (debug > 6) printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n", entry, txstatus); + if (txstatus & DescOwn) + break; if (txstatus & 0x8000) { if (debug > 1) printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", @@ -1341,10 +1363,22 @@ static void via_rhine_tx(struct net_devi if (txstatus & 0x0200) np->stats.tx_window_errors++; if (txstatus & 0x0100) np->stats.tx_aborted_errors++; if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++; - if (txstatus & 0x0002) np->stats.tx_fifo_errors++; + if (((np->chip_id == VT86C100A) && txstatus & 0x0002) || + (txstatus & 0x0800) || (txstatus & 0x1000)) { + np->stats.tx_fifo_errors++; + np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); + break; /* Keep the skb - we try again */ + } /* Transmitter restarted in 'abnormal' handler. */ } else { - np->stats.collisions += (txstatus >> 3) & 15; + if (np->chip_id == VT86C100A) + np->stats.collisions += (txstatus >> 3) & 0x0F; + else + np->stats.collisions += txstatus & 0x0F; + if (debug > 6) + printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", + (txstatus >> 3) & 0xF, + txstatus & 0xF); np->stats.tx_bytes += np->tx_skbuff[entry]->len; np->stats.tx_packets++; } @@ -1480,6 +1514,17 @@ static void via_rhine_rx(struct net_devi writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd); } +static inline void via_restart_tx(struct net_device *dev) { + struct netdev_private *np = dev->priv; + int entry = np->dirty_tx % TX_RING_SIZE; + + /* We know better than the chip where it should continue */ + writel(np->tx_ring_dma + entry * sizeof(struct tx_desc), + dev->base_addr + TxRingPtr); + + writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); +} + static void via_rhine_error(struct net_device *dev, int intr_status) { struct netdev_private *np = dev->priv; @@ -1505,19 +1550,23 @@ static void via_rhine_error(struct net_d np->stats.rx_missed_errors += readw(ioaddr + RxMissed); clear_tally_counters(ioaddr); } - if (intr_status & IntrTxAbort) { - /* Stats counted in Tx-done handler, just restart Tx. */ - writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); + if (intr_status & IntrTxError) { + if (debug > 1) + printk(KERN_INFO "%s: Abort %4.4x, frame dropped.\n", + dev->name, intr_status); + via_restart_tx(dev); } if (intr_status & IntrTxUnderrun) { if (np->tx_thresh < 0xE0) writeb(np->tx_thresh += 0x20, ioaddr + TxConfig); if (debug > 1) - printk(KERN_INFO "%s: Transmitter underrun, increasing Tx " - "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); + printk(KERN_INFO "%s: Transmitter underrun, Tx " + "threshold now %2.2x.\n", + dev->name, np->tx_thresh); + via_restart_tx(dev); } if (intr_status & ~( IntrLinkChange | IntrStatsMax | - IntrTxAbort | IntrTxAborted | IntrNormalSummary)) { + IntrTxError | IntrTxAborted | IntrNormalSummary)) { if (debug > 1) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status);