From 126fa4b9ca5d9d7cb7d46f779ad3bd3631ca387c Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 12 May 2005 20:09:17 -0400 Subject: [PATCH] r8169: incoming frame length check The size of the incoming frame is not correctly checked. The RxMaxSize register (0xDA) does not work as expected and incoming frames whose size exceeds the MTU actually end spanning multiple descriptors. The first Rx descriptor contains the size of the whole frame (or some garbage in its place). The driver does not expect something above the space allocated to the current skb and crashes loudly when it issues a skb_put. The fix contains two parts: - disable hardware Rx size filtering: so far it only proved to be able to trigger some new fancy errors; - drop multi-descriptors frame: as the driver allocates MTU sized Rx buffers, it provides an adequate filtering. As a bonus, wrong descriptors were not returned to the asic after their processing. Signed-off-by: Francois Romieu Signed-off-by: Jeff Garzik --- drivers/net/r8169.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c59507f8a76b..b3768d844747 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev) RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(EarlyTxThres, EarlyTxThld); - /* For gigabit rtl8169, MTU + header + CRC + VLAN */ - RTL_W16(RxMaxSize, tp->rx_buf_sz); + /* Low hurts. Let's disable the filtering. */ + RTL_W16(RxMaxSize, 16383); /* Set Rx Config register */ i = rtl8169_rx_config | @@ -2127,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp, } } +static inline int rtl8169_fragmented_frame(u32 status) +{ + return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag); +} + static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc) { u32 opts1 = le32_to_cpu(desc->opts1); @@ -2177,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, while (rx_left > 0) { unsigned int entry = cur_rx % NUM_RX_DESC; + struct RxDesc *desc = tp->RxDescArray + entry; u32 status; rmb(); - status = le32_to_cpu(tp->RxDescArray[entry].opts1); + status = le32_to_cpu(desc->opts1); if (status & DescOwn) break; if (status & RxRES) { - printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); + printk(KERN_INFO "%s: Rx ERROR. status = %08x\n", + dev->name, status); tp->stats.rx_errors++; if (status & (RxRWT | RxRUNT)) tp->stats.rx_length_errors++; if (status & RxCRC) tp->stats.rx_crc_errors++; + rtl8169_mark_to_asic(desc, tp->rx_buf_sz); } else { - struct RxDesc *desc = tp->RxDescArray + entry; struct sk_buff *skb = tp->Rx_skbuff[entry]; int pkt_size = (status & 0x00001FFF) - 4; void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int) = pci_dma_sync_single_for_device; + /* + * The driver does not support incoming fragmented + * frames. They are seen as a symptom of over-mtu + * sized frames. + */ + if (unlikely(rtl8169_fragmented_frame(status))) { + tp->stats.rx_dropped++; + tp->stats.rx_length_errors++; + rtl8169_mark_to_asic(desc, tp->rx_buf_sz); + goto move_on; + } + rtl8169_rx_csum(skb, desc); pci_dma_sync_single_for_cpu(tp->pci_dev, @@ -2224,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; } - +move_on: cur_rx++; rx_left--; } -- cgit v1.2.3 From a7b6459de19c85432f791728317089459316da32 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Fri, 27 May 2005 21:11:33 +0200 Subject: [PATCH] r8169: new PCI id The USR 997902 is based on the 8169 chipset. The value has been extracted from the sources of the driver which comes with the manufacturer's cdrom. Heads-up and test by TommyDrum . Signed-off-by: Francois Romieu --- drivers/net/r8169.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b3768d844747..d064b5b0d192 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -176,6 +176,7 @@ const static struct { static struct pci_device_id rtl8169_pci_tbl[] = { {0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x1186, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x16ec, 0x0116, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,}, }; -- cgit v1.2.3 From 53456f607a7ec02905823dc92a94c7e36d4ded1a Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Fri, 27 May 2005 21:11:37 +0200 Subject: [PATCH] r8169: de-obfuscate supported PCI ID De-obfuscate supported PCI ID Signed-off-by: Francois Romieu --- drivers/net/r8169.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index d064b5b0d192..0f1f81b50c4a 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -174,9 +174,9 @@ const static struct { #undef _R static struct pci_device_id rtl8169_pci_tbl[] = { - {0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x1186, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x16ec, 0x0116, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), }, + { PCI_DEVICE(0x16ec, 0x0116), }, {0,}, }; -- cgit v1.2.3 From f7ccf420e5d5553d2cb25d21f8bb77e7747f1c35 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 27 May 2005 21:11:41 +0200 Subject: [PATCH] r8169: identify the napi version To tell if driver is configured for NAPI or not, put -NAPI on driver version. Remove the NAPI printk since the complete version information is displayed once in the pci probe routine or returned via ethtool. Signed-off-by: Stephen Hemminger Signed-off-by: Francois Romieu --- drivers/net/r8169.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 0f1f81b50c4a..e9592f523507 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -69,7 +69,13 @@ VERSION 2.2LK <2005/01/25> #include #include -#define RTL8169_VERSION "2.2LK" +#ifdef CONFIG_R8169_NAPI +#define NAPI_SUFFIX "-NAPI" +#else +#define NAPI_SUFFIX "" +#endif + +#define RTL8169_VERSION "2.2LK" NAPI_SUFFIX #define MODULENAME "r8169" #define PFX MODULENAME ": " @@ -1367,7 +1373,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_R8169_NAPI dev->poll = rtl8169_poll; dev->weight = R8169_NAPI_WEIGHT; - printk(KERN_INFO PFX "NAPI enabled\n"); #endif #ifdef CONFIG_R8169_VLAN -- cgit v1.2.3 From 1b7efd58bb2c89f408118888b659b51ff66c47b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 27 May 2005 21:11:45 +0200 Subject: [PATCH] r8169: add module parameter (copybreak) Add module parameter description for copybreak. Signed-off-by: Stephen Hemminger Signed-off-by: Francois Romieu --- drivers/net/r8169.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index e9592f523507..bf4bd3909763 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -426,6 +426,7 @@ MODULE_AUTHOR("Realtek and the Linux r8169 crew "); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); module_param_array(media, int, &num_media, 0); module_param(rx_copybreak, int, 0); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); module_param(use_dac, int, 0); MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From df0a1bf63403c2decec2c11cdd1b304363174e90 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Fri, 27 May 2005 21:11:49 +0200 Subject: [PATCH] r8169: add module parameter (media) Add module parameter description for the media option. Signed-off-by: Francois Romieu --- drivers/net/r8169.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index bf4bd3909763..6f3b1383788f 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -425,6 +425,7 @@ struct rtl8169_private { MODULE_AUTHOR("Realtek and the Linux r8169 crew "); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); module_param_array(media, int, &num_media, 0); +MODULE_PARM_DESC(media, "force phy operation. Deprecated by ethtool (8)."); module_param(rx_copybreak, int, 0); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); module_param(use_dac, int, 0); -- cgit v1.2.3 From b57b7e5a11c4e45565cf34d786d74ad35483fe83 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 27 May 2005 21:11:52 +0200 Subject: [PATCH] r8169: ethtool message level control support Also: - ratelimit the too much work at interrupt message, so if under massive packet load the console doesn't get flooded; - removal of a few PFX used in contexts where dev->name is available; - s/->slot_name/pci_name/; - printed_version is redundant with the debug option. Remove it and let the user decide. Signed-off-by: Stephen Hemminger Signed-off-by: Francois Romieu --- drivers/net/r8169.c | 191 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 135 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 6f3b1383788f..d795b31649f3 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -91,6 +91,10 @@ VERSION 2.2LK <2005/01/25> #define dprintk(fmt, args...) do {} while (0) #endif /* RTL8169_DEBUG */ +#define R8169_MSG_DEFAULT \ + (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFUP | \ + NETIF_MSG_IFDOWN) + #define TX_BUFFS_AVAIL(tp) \ (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1) @@ -190,6 +194,9 @@ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); static int rx_copybreak = 200; static int use_dac; +static struct { + u32 msg_enable; +} debug = { -1 }; enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ @@ -392,6 +399,7 @@ struct rtl8169_private { struct pci_dev *pci_dev; /* Index of PCI device */ struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ + u32 msg_enable; int chipset; int mac_version; int phy_version; @@ -430,6 +438,8 @@ module_param(rx_copybreak, int, 0); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); module_param(use_dac, int, 0); MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); +module_param_named(debug, debug.msg_enable, int, 0); +MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); MODULE_LICENSE("GPL"); MODULE_VERSION(RTL8169_VERSION); @@ -552,9 +562,13 @@ static void rtl8169_check_link_status(struct net_device *dev, spin_lock_irqsave(&tp->lock, flags); if (tp->link_ok(ioaddr)) { netif_carrier_on(dev); - printk(KERN_INFO PFX "%s: link up\n", dev->name); - } else + if (netif_msg_ifup(tp)) + printk(KERN_INFO PFX "%s: link up\n", dev->name); + } else { + if (netif_msg_ifdown(tp)) + printk(KERN_INFO PFX "%s: link down\n", dev->name); netif_carrier_off(dev); + } spin_unlock_irqrestore(&tp->lock, flags); } @@ -578,7 +592,7 @@ static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex) option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff; - if ((option != 0xff) && !idx) + if ((option != 0xff) && !idx && netif_msg_drv(&debug)) printk(KERN_WARNING PFX "media option is deprecated.\n"); for (p = link_settings; p->media != 0xff; p++) { @@ -620,9 +634,11 @@ static int rtl8169_set_speed_tbi(struct net_device *dev, } else if (autoneg == AUTONEG_ENABLE) RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); else { - printk(KERN_WARNING PFX - "%s: incorrect speed setting refused in TBI mode\n", - dev->name); + if (netif_msg_link(tp)) { + printk(KERN_WARNING "%s: " + "incorrect speed setting refused in TBI mode\n", + dev->name); + } ret = -EOPNOTSUPP; } @@ -880,12 +896,28 @@ static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs, spin_unlock_irqrestore(&tp->lock, flags); } +static u32 rtl8169_get_msglevel(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + return tp->msg_enable; +} + +static void rtl8169_set_msglevel(struct net_device *dev, u32 value) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + tp->msg_enable = value; +} + static struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, .get_link = ethtool_op_get_link, .get_settings = rtl8169_get_settings, .set_settings = rtl8169_set_settings, + .get_msglevel = rtl8169_get_msglevel, + .set_msglevel = rtl8169_set_msglevel, .get_rx_csum = rtl8169_get_rx_csum, .set_rx_csum = rtl8169_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, @@ -1100,7 +1132,8 @@ static void rtl8169_phy_timer(unsigned long __opaque) if (tp->link_ok(ioaddr)) goto out_unlock; - printk(KERN_WARNING PFX "%s: PHY reset until link up\n", dev->name); + if (netif_msg_link(tp)) + printk(KERN_WARNING "%s: PHY reset until link up\n", dev->name); tp->phy_reset_enable(ioaddr); @@ -1178,18 +1211,23 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, /* dev zeroed in alloc_etherdev */ dev = alloc_etherdev(sizeof (*tp)); if (dev == NULL) { - printk(KERN_ERR PFX "unable to alloc new ethernet\n"); + if (netif_msg_drv(&debug)) + printk(KERN_ERR PFX "unable to alloc new ethernet\n"); goto err_out; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); + tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); /* enable device (incl. PCI PM wakeup and hotplug setup) */ rc = pci_enable_device(pdev); - if (rc) { - printk(KERN_ERR PFX "%s: enable failure\n", pci_name(pdev)); + if (rc < 0) { + if (netif_msg_probe(tp)) { + printk(KERN_ERR PFX "%s: enable failure\n", + pci_name(pdev)); + } goto err_out_free_dev; } @@ -1205,29 +1243,39 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command); acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; } else { - printk(KERN_ERR PFX - "Cannot find PowerManagement capability, aborting.\n"); + if (netif_msg_probe(tp)) { + printk(KERN_ERR PFX + "Cannot find PowerManagement capability. " + "Aborting.\n"); + } goto err_out_mwi; } /* make sure PCI base addr 1 is MMIO */ if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX - "region #1 not an MMIO resource, aborting\n"); + if (netif_msg_probe(tp)) { + printk(KERN_ERR PFX + "region #1 not an MMIO resource, aborting\n"); + } rc = -ENODEV; goto err_out_mwi; } /* check for weird/broken PCI region reporting */ if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) { - printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); + if (netif_msg_probe(tp)) { + printk(KERN_ERR PFX + "Invalid PCI region size(s), aborting\n"); + } rc = -ENODEV; goto err_out_mwi; } rc = pci_request_regions(pdev, MODULENAME); - if (rc) { - printk(KERN_ERR PFX "%s: could not request regions.\n", - pci_name(pdev)); + if (rc < 0) { + if (netif_msg_probe(tp)) { + printk(KERN_ERR PFX "%s: could not request regions.\n", + pci_name(pdev)); + } goto err_out_mwi; } @@ -1240,7 +1288,10 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, } else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc < 0) { - printk(KERN_ERR PFX "DMA configuration failed.\n"); + if (netif_msg_probe(tp)) { + printk(KERN_ERR PFX + "DMA configuration failed.\n"); + } goto err_out_free_res; } } @@ -1250,7 +1301,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, /* ioremap MMIO region */ ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE); if (ioaddr == NULL) { - printk(KERN_ERR PFX "cannot remap MMIO, aborting\n"); + if (netif_msg_probe(tp)) + printk(KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; goto err_out_free_res; } @@ -1281,9 +1333,11 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, } if (i < 0) { /* Unknown chip: assume array element #0, original RTL-8169 */ - printk(KERN_DEBUG PFX - "PCI device %s: unknown chip version, assuming %s\n", - pci_name(pdev), rtl_chip_info[0].name); + if (netif_msg_probe(tp)) { + printk(KERN_DEBUG PFX "PCI device %s: " + "unknown chip version, assuming %s\n", + pci_name(pdev), rtl_chip_info[0].name); + } i++; } tp->chipset = i; @@ -1317,7 +1371,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct rtl8169_private *tp; void __iomem *ioaddr = NULL; static int board_idx = -1; - static int printed_version = 0; u8 autoneg, duplex; u16 speed; int i, rc; @@ -1327,10 +1380,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) board_idx++; - if (!printed_version) { + if (netif_msg_drv(&debug)) { printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n", MODULENAME, RTL8169_VERSION); - printed_version = 1; } rc = rtl8169_init_board(pdev, &dev, &ioaddr); @@ -1399,20 +1451,24 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } - printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name, - rtl_chip_info[tp->chipset].name); + if (netif_msg_probe(tp)) { + printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", + dev->name, rtl_chip_info[tp->chipset].name); + } pci_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "IRQ %d\n", - dev->name, - rtl_chip_info[ent->driver_data].name, - dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], dev->irq); + if (netif_msg_probe(tp)) { + printk(KERN_INFO "%s: %s at 0x%lx, " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "IRQ %d\n", + dev->name, + rtl_chip_info[ent->driver_data].name, + dev->base_addr, + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5], dev->irq); + } rtl8169_hw_phy_config(dev); @@ -1435,7 +1491,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl8169_set_speed(dev, autoneg, speed, duplex); - if (RTL_R8(PHYstatus) & TBI_Enable) + if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp)) printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name); return 0; @@ -1868,8 +1924,13 @@ static void rtl8169_reinit_task(void *_data) ret = rtl8169_open(dev); if (unlikely(ret < 0)) { if (net_ratelimit()) { - printk(PFX KERN_ERR "%s: reinit failure (status = %d)." - " Rescheduling.\n", dev->name, ret); + struct rtl8169_private *tp = netdev_priv(dev); + + if (netif_msg_drv(tp)) { + printk(PFX KERN_ERR + "%s: reinit failure (status = %d)." + " Rescheduling.\n", dev->name, ret); + } } rtl8169_schedule_work(dev, rtl8169_reinit_task); } @@ -1894,8 +1955,12 @@ static void rtl8169_reset_task(void *_data) netif_wake_queue(dev); } else { if (net_ratelimit()) { - printk(PFX KERN_EMERG "%s: Rx buffers shortage\n", - dev->name); + struct rtl8169_private *tp = netdev_priv(dev); + + if (netif_msg_intr(tp)) { + printk(PFX KERN_EMERG + "%s: Rx buffers shortage\n", dev->name); + } } rtl8169_schedule_work(dev, rtl8169_reset_task); } @@ -1981,8 +2046,11 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) int ret = 0; if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { - printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", - dev->name); + if (netif_msg_drv(tp)) { + printk(KERN_ERR + "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); + } goto err_stop; } @@ -2057,8 +2125,11 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev) pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); pci_read_config_word(pdev, PCI_STATUS, &pci_status); - printk(KERN_ERR PFX "%s: PCI error (cmd = 0x%04x, status = 0x%04x).\n", - dev->name, pci_cmd, pci_status); + if (netif_msg_intr(tp)) { + printk(KERN_ERR + "%s: PCI error (cmd = 0x%04x, status = 0x%04x).\n", + dev->name, pci_cmd, pci_status); + } /* * The recovery sequence below admits a very elaborated explanation: @@ -2077,7 +2148,8 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev) /* The infamous DAC f*ckup only happens at boot time */ if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) { - printk(KERN_INFO PFX "%s: disabling PCI DAC.\n", dev->name); + if (netif_msg_intr(tp)) + printk(KERN_INFO "%s: disabling PCI DAC.\n", dev->name); tp->cp_cmd &= ~PCIDAC; RTL_W16(CPlusCmd, tp->cp_cmd); dev->features &= ~NETIF_F_HIGHDMA; @@ -2199,8 +2271,11 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, if (status & DescOwn) break; if (status & RxRES) { - printk(KERN_INFO "%s: Rx ERROR. status = %08x\n", - dev->name, status); + if (netif_msg_rx_err(tp)) { + printk(KERN_INFO + "%s: Rx ERROR. status = %08x\n", + dev->name, status); + } tp->stats.rx_errors++; if (status & (RxRWT | RxRUNT)) tp->stats.rx_length_errors++; @@ -2260,7 +2335,7 @@ move_on: tp->cur_rx = cur_rx; delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); - if (!delta && count) + if (!delta && count && netif_msg_intr(tp)) printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); tp->dirty_rx += delta; @@ -2271,7 +2346,7 @@ move_on: * after refill ? * - how do others driver handle this condition (Uh oh...). */ - if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) + if ((tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) && netif_msg_intr(tp)) printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); return count; @@ -2323,7 +2398,7 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs) if (likely(netif_rx_schedule_prep(dev))) __netif_rx_schedule(dev); - else { + else if (netif_msg_intr(tp)) { printk(KERN_INFO "%s: interrupt %04x taken in poll\n", dev->name, status); } @@ -2342,8 +2417,10 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs) } while (boguscnt > 0); if (boguscnt <= 0) { - printk(KERN_WARNING "%s: Too much work at interrupt!\n", - dev->name); + if (net_ratelimit() && netif_msg_intr(tp)) { + printk(KERN_WARNING + "%s: Too much work at interrupt!\n", dev->name); + } /* Clear all interrupt sources. */ RTL_W16(IntrStatus, 0xffff); } @@ -2466,8 +2543,10 @@ rtl8169_set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", - dev->name); + if (netif_msg_link(tp)) { + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", + dev->name); + } rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; -- cgit v1.2.3 From d4a3a0fc9c2d012093cf75a8d95034966c17e71e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 27 May 2005 21:11:56 +0200 Subject: [PATCH] r8169: add ethtool support for dumping the chip statistics There aren't lots of statistics available, but this is what is available according to the RealTek documentation. Signed-off-by: Stephen Hemminger Signed-off-by: Francois Romieu --- drivers/net/r8169.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index d795b31649f3..b30e13867e1e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -201,6 +201,8 @@ static struct { enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ + CounterAddrLow = 0x10, + CounterAddrHigh = 0x14, TxDescStartAddrLow = 0x20, TxDescStartAddrHigh = 0x24, TxHDescStartAddrLow = 0x28, @@ -342,6 +344,9 @@ enum RTL8169_register_content { /* _TBICSRBit */ TBILinkOK = 0x02000000, + + /* DumpCounterCommand */ + CounterDump = 0x8, }; enum _DescStatusBit { @@ -910,6 +915,98 @@ static void rtl8169_set_msglevel(struct net_device *dev, u32 value) tp->msg_enable = value; } +static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = { + "tx_packets", + "rx_packets", + "tx_errors", + "rx_errors", + "rx_missed", + "align_errors", + "tx_single_collisions", + "tx_multi_collisions", + "unicast", + "broadcast", + "multicast", + "tx_aborted", + "tx_underrun", +}; + +struct rtl8169_counters { + u64 tx_packets; + u64 rx_packets; + u64 tx_errors; + u32 rx_errors; + u16 rx_missed; + u16 align_errors; + u32 tx_one_collision; + u32 tx_multi_collision; + u64 rx_unicast; + u64 rx_broadcast; + u32 rx_multicast; + u16 tx_aborted; + u16 tx_underun; +}; + +static int rtl8169_get_stats_count(struct net_device *dev) +{ + return ARRAY_SIZE(rtl8169_gstrings); +} + +static void rtl8169_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + struct rtl8169_counters *counters; + dma_addr_t paddr; + u32 cmd; + + ASSERT_RTNL(); + + counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr); + if (!counters) + return; + + RTL_W32(CounterAddrHigh, (u64)paddr >> 32); + cmd = (u64)paddr & DMA_32BIT_MASK; + RTL_W32(CounterAddrLow, cmd); + RTL_W32(CounterAddrLow, cmd | CounterDump); + + while (RTL_R32(CounterAddrLow) & CounterDump) { + if (msleep_interruptible(1)) + break; + } + + RTL_W32(CounterAddrLow, 0); + RTL_W32(CounterAddrHigh, 0); + + data[0] = le64_to_cpu(counters->tx_packets); + data[1] = le64_to_cpu(counters->rx_packets); + data[2] = le64_to_cpu(counters->tx_errors); + data[3] = le32_to_cpu(counters->rx_errors); + data[4] = le16_to_cpu(counters->rx_missed); + data[5] = le16_to_cpu(counters->align_errors); + data[6] = le32_to_cpu(counters->tx_one_collision); + data[7] = le32_to_cpu(counters->tx_multi_collision); + data[8] = le64_to_cpu(counters->rx_unicast); + data[9] = le64_to_cpu(counters->rx_broadcast); + data[10] = le32_to_cpu(counters->rx_multicast); + data[11] = le16_to_cpu(counters->tx_aborted); + data[12] = le16_to_cpu(counters->tx_underun); + + pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr); +} + +static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + switch(stringset) { + case ETH_SS_STATS: + memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings)); + break; + } +} + + static struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, @@ -927,6 +1024,9 @@ static struct ethtool_ops rtl8169_ethtool_ops = { .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_regs = rtl8169_get_regs, + .get_strings = rtl8169_get_strings, + .get_stats_count = rtl8169_get_stats_count, + .get_ethtool_stats = rtl8169_get_ethtool_stats, }; static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum, -- cgit v1.2.3 From 4dcb7d33770541ae3e65a57351f3875df64e8af6 Mon Sep 17 00:00:00 2001 From: Richard Dawe Date: Fri, 27 May 2005 21:12:00 +0200 Subject: [PATCH] r8169: minor cleanup - more consistent prototypes; - rtl8169_rx_interrupt() o the error condition should be rare; o goto removal. Signed-off-by: Richard Dawe Signed-off-by: Francois Romieu --- drivers/net/r8169.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b30e13867e1e..882c59fe9f8d 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -457,10 +457,10 @@ static void rtl8169_hw_start(struct net_device *dev); static int rtl8169_close(struct net_device *dev); static void rtl8169_set_rx_mode(struct net_device *dev); static void rtl8169_tx_timeout(struct net_device *dev); -static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev); +static struct net_device_stats *rtl8169_get_stats(struct net_device *dev); static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *, void __iomem *); -static int rtl8169_change_mtu(struct net_device *netdev, int new_mtu); +static int rtl8169_change_mtu(struct net_device *dev, int new_mtu); static void rtl8169_down(struct net_device *dev); #ifdef CONFIG_R8169_NAPI @@ -2360,7 +2360,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota); - while (rx_left > 0) { + for (; rx_left > 0; rx_left--, cur_rx++) { unsigned int entry = cur_rx % NUM_RX_DESC; struct RxDesc *desc = tp->RxDescArray + entry; u32 status; @@ -2370,7 +2370,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, if (status & DescOwn) break; - if (status & RxRES) { + if (unlikely(status & RxRES)) { if (netif_msg_rx_err(tp)) { printk(KERN_INFO "%s: Rx ERROR. status = %08x\n", @@ -2397,7 +2397,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, tp->stats.rx_dropped++; tp->stats.rx_length_errors++; rtl8169_mark_to_asic(desc, tp->rx_buf_sz); - goto move_on; + continue; } rtl8169_rx_csum(skb, desc); @@ -2426,9 +2426,6 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; } -move_on: - cur_rx++; - rx_left--; } count = cur_rx - tp->cur_rx; -- cgit v1.2.3