PATCH: 8139too fixes for testing

From: Jeff Garzik (jgarzik@mandrakesoft.com)
Date: Fri Jun 08 2001 - 23:37:14 EST


Testing requested, especially if you had problems with 8139too in recent
2.4.x kernels.

-- 
Jeff Garzik      | Andre the Giant has a posse.
Building 1024    |
MandrakeSoft     |

Index: linux_2_4/drivers/net/8139too.c diff -u linux_2_4/drivers/net/8139too.c:1.1.1.39 linux_2_4/drivers/net/8139too.c:1.1.1.39.2.3 --- linux_2_4/drivers/net/8139too.c:1.1.1.39 Fri Jun 8 15:40:33 2001 +++ linux_2_4/drivers/net/8139too.c Fri Jun 8 21:22:43 2001 @@ -136,6 +136,10 @@ */ +#define DRV_NAME "8139too" +#define DRV_VERSION "0.9.18-pre1" + + #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -146,13 +150,13 @@ #include <linux/etherdevice.h> #include <linux/rtnetlink.h> #include <linux/delay.h> +#include <linux/ethtool.h> #include <asm/io.h> +#include <asm/uaccess.h> -#define RTL8139_VERSION "0.9.17" -#define MODNAME "8139too" -#define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION -#define PFX MODNAME ": " +#define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION +#define PFX DRV_NAME ": " /* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */ @@ -363,7 +367,10 @@ TxOK = 0x04, RxErr = 0x02, RxOK = 0x01, + + RxAckBits = RxFIFOOver | RxOverflow | RxOK, }; + enum TxStatusBits { TxHostOwns = 0x2000, TxUnderrun = 0x4000, @@ -542,6 +549,11 @@ }; +struct rtl_extra_stats { + unsigned long early_rx; + unsigned long tx_buf_mapped; + unsigned long tx_timeouts; +}; struct rtl8139_private { void *mmio_addr; @@ -560,7 +572,6 @@ dma_addr_t rx_ring_dma; dma_addr_t tx_bufs_dma; signed char phys[4]; /* MII device addresses. */ - u16 advertising; /* NWay media advertisement */ char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; @@ -574,6 +585,7 @@ wait_queue_head_t thr_wait; struct semaphore thr_exited; u32 rx_config; + struct rtl_extra_stats xstats; }; MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>"); @@ -582,6 +594,10 @@ MODULE_PARM (max_interrupt_work, "i"); MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses"); +MODULE_PARM_DESC (max_interrupt_work, "8139too maximum events handled per interrupt"); +MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps"); +MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)"); static int read_eeprom (void *ioaddr, int location, int addr_len); static int rtl8139_open (struct net_device *dev); @@ -596,7 +612,7 @@ static void rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static int rtl8139_close (struct net_device *dev); -static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); static inline u32 ether_crc (int length, unsigned char *data); static void rtl8139_set_rx_mode (struct net_device *dev); @@ -938,7 +954,7 @@ dev->stop = rtl8139_close; dev->get_stats = rtl8139_get_stats; dev->set_multicast_list = rtl8139_set_rx_mode; - dev->do_ioctl = mii_ioctl; + dev->do_ioctl = netdev_ioctl; dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -984,11 +1000,11 @@ for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { + u16 advertising = mdio_read(dev, phy, 4); tp->phys[phy_idx++] = phy; - tp->advertising = mdio_read(dev, phy, 4); printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " "advertising %4.4x.\n", - dev->name, phy, mii_status, tp->advertising); + dev->name, phy, mii_status, advertising); } } if (phy_idx == 0) { @@ -1331,16 +1347,16 @@ rtl8139_chip_reset (ioaddr); /* unlock Config[01234] and BMCR register writes */ - RTL_W8 (Cfg9346, Cfg9346_Unlock); + RTL_W8_F (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); - RTL_W32 (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); + RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); /* Must enable Tx/Rx before setting transfer thresholds! */ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys; - RTL_W32 (RxConfig, rtl8139_rx_config); + RTL_W32 (RxConfig, tp->rx_config); /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); @@ -1357,24 +1373,15 @@ else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040) tp->full_duplex = 1; - if (mii_reg5) { - printk(KERN_INFO"%s: Setting %s%s-duplex based on" - " auto-negotiated partner ability %4.4x.\n", dev->name, - mii_reg5 == 0 ? "" : - (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", - tp->full_duplex ? "full" : "half", mii_reg5); - } else { - printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", - dev->name); - } + + printk (KERN_INFO"%s: Setting %s%s-duplex based on" + " auto-negotiated partner ability %4.4x.\n", + dev->name, mii_reg5 == 0 ? "" : + (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", + tp->full_duplex ? "full" : "half", mii_reg5); } if (tp->chipset >= CH_8139B) { - tmp = RTL_R8 (Config4) & ~(1<<2); - /* chip will clear Rx FIFO overflow automatically */ - tmp |= (1<<7); - RTL_W8 (Config4, tmp); - /* disable magic packet scanning, which is enabled * when PM is enabled in Config1 */ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); @@ -1654,6 +1661,8 @@ RTL_R16 (IntrStatus), RTL_R8 (MediaStatus)); + tp->xstats.tx_timeouts++; + /* disable Tx ASAP, if not already */ tmp8 = RTL_R8 (ChipCmd); if (tmp8 & CmdTxEnb) @@ -1704,6 +1713,7 @@ RTL_W32 (TxAddr0 + (entry * 4), tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs)); } else { + tp->xstats.tx_buf_mapped++; tp->tx_info[entry].mapping = pci_map_single (tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); @@ -1760,7 +1770,7 @@ tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; - RTL_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); + RTL_W32_F (TxConfig, TxClearAbt); } if (txstatus & TxCarrierLost) tp->stats.tx_carrier_errors++; @@ -1865,11 +1875,10 @@ static void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp, void *ioaddr, - u16 status) + struct rtl8139_private *tp, void *ioaddr) { unsigned char *rx_ring; - u16 cur_rx, ackstat; + u16 cur_rx; assert (dev != NULL); assert (tp != NULL); @@ -1883,11 +1892,6 @@ RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); - if (status & RxFIFOOver) - status = RxOverflow | RxOK; - else - status = RxOK; - while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { int ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; @@ -1895,8 +1899,6 @@ unsigned int pkt_size; struct sk_buff *skb; - mb(); - /* read size+status of next frame from DMA ring buffer */ rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); rx_size = rx_status >> 16; @@ -1916,8 +1918,10 @@ } #endif - if (rx_size == 0xfff0) /* Early Rx in progress */ + if (rx_size == 0xfff0) { /* Early Rx in progress */ + tp->xstats.early_rx++; break; + } /* If Rx err or invalid rx_size/rx_status received * (which happens if we get lost in the ring), @@ -1963,9 +1967,8 @@ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; RTL_W16 (RxBufPtr, cur_rx - 16); - ackstat = RTL_R16 (IntrStatus) & status; - if (ackstat) - RTL_W16 (IntrStatus, ackstat); + if (RTL_R16 (IntrStatus) & RxAckBits) + RTL_W16_F (IntrStatus, RxAckBits); } DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," @@ -1975,11 +1978,9 @@ tp->cur_rx = cur_rx; - if (RTL_R8 (ChipCmd) & RxBufEmpty) { - ackstat = RTL_R16 (IntrStatus) & status; - if (ackstat) - RTL_W16_F (IntrStatus, ackstat); - } + if ((RTL_R8 (ChipCmd) & RxBufEmpty) && + (RTL_R16 (IntrStatus) & RxAckBits)) + RTL_W16_F (IntrStatus, RxAckBits); } @@ -2059,26 +2060,10 @@ if (status & RxUnderrun) link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; - /* E. Gill */ - /* In case of an RxFIFOOver we must also clear the RxOverflow - bit to avoid dropping frames for ever. Believe me, I got a - lot of troubles copying huge data (approximately 2 RxFIFOOver - errors per 1GB data transfer). - The following is written in the 'p-guide.pdf' file (RTL8139(A/B) - Programming guide V0.1, from 1999/1/15) on page 9 from REALTEC. - ----------------------------------------------------------- - 2. RxFIFOOvw handling: - When RxFIFOOvw occurs, all incoming packets are discarded. - Clear ISR(RxFIFOOvw) doesn't dismiss RxFIFOOvw event. To - dismiss RxFIFOOvw event, the ISR(RxBufOvw) must be written - with a '1'. - ----------------------------------------------------------- - Unfortunately I was not able to find any reason for the - RxFIFOOver error (I got the feeling this depends on the - CPU speed, lower CPU speed --> more errors). - After clearing the RxOverflow bit the transfer of the - packet was repeated and all data are error free transferred */ - ackstat = status & ~(RxFIFOOver | RxOverflow | RxOK); + /* The chip takes special action when we clear RxAckBits, + * so we clear them later in rtl8139_rx_interrupt + */ + ackstat = status & ~RxAckBits; RTL_W16 (IntrStatus, ackstat); DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", @@ -2089,9 +2074,8 @@ RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) break; - if (netif_running (dev) && - status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ - rtl8139_rx_interrupt (dev, tp, ioaddr, status); + if (netif_running (dev) && (status & RxAckBits)) + rtl8139_rx_interrupt (dev, tp, ioaddr); /* Check uncommon events with one test. */ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | @@ -2099,8 +2083,7 @@ rtl8139_weird_interrupt (dev, tp, ioaddr, status, link_changed); - if (netif_running (dev) && - status & (TxOK | TxErr)) { + if (netif_running (dev) && (status & (TxOK | TxErr))) { spin_lock (&tp->lock); rtl8139_tx_interrupt (dev, tp, ioaddr); spin_unlock (&tp->lock); @@ -2110,10 +2093,8 @@ } while (boguscnt > 0); if (boguscnt <= 0) { - printk (KERN_WARNING - "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", dev->name, - status); + printk (KERN_WARNING "%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", dev->name, status); /* Clear all interrupt sources. */ RTL_W16 (IntrStatus, 0xffff); @@ -2183,8 +2164,32 @@ return 0; } + +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct rtl8139_private *np = dev->priv; + u32 ethcmd; + + if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + strcpy(info.bus_info, np->pci_dev->slot_name); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + } + + return -EOPNOTSUPP; +} -static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct rtl8139_private *tp = dev->priv; u16 *data = (u16 *) & rq->ifr_data; @@ -2193,6 +2198,8 @@ DPRINTK ("ENTER\n"); switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = tp->phys[0] & 0x3f; /* Fall Through */ @@ -2216,7 +2223,7 @@ if (tp->medialock) tp->full_duplex = (value & 0x0100) ? 1 : 0; break; - case 4: tp->advertising = value; break; + case 4: /* tp->advertising = value; */ break; } } mdio_write(dev, data[0], data[1] & 0x1f, data[2]); @@ -2323,7 +2330,7 @@ tp->rx_config = tmp; } RTL_W32_F (MAR0 + 0, mc_filter[0]); - RTL_W32 (MAR0 + 4, mc_filter[1]); + RTL_W32_F (MAR0 + 4, mc_filter[1]); spin_unlock_irqrestore (&tp->lock, flags); @@ -2369,7 +2376,7 @@ static struct pci_driver rtl8139_pci_driver = { - name: MODNAME, + name: DRV_NAME, id_table: rtl8139_pci_tbl, probe: rtl8139_init_one, remove: rtl8139_remove_one,

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Jun 15 2001 - 21:00:10 EST