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 <[EMAIL PROTECTED]>");
@@ -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,

Reply via email to