forcedeth: minor fixes for stats, rmmod, sparse
Subsystems (3)
v5 cover forcedeth: minor fixes for stats, rmmod, sparse
This is a minor update over v4, re-adding a patch I left aside to study it.
Changes since v4:
- added patch 1/5 fixing a rmmod race (see description for test details)
- all other patches identical to v4
Changes since v3:
- removed feature additions, this leaves minor sparse and stats fixes. Feature additions shipped previously will go to net-next
Changes since v2:
- removed "Fix a race during rmmod of forcedeth" from the series (will look at it separately with original author)
- added "remove unneeded stats updates" and "64-bit stats"
- reordered patches
Changes since v1:
- rebased on top of netdev tip
- do not repeat name of device in netdev_dbg
- do not completely mute TX timeout messages when debug_tx_timeout is not set
- make debug_tx_timeout writable in /sys/module
Note: I am re-submitting "expose module parameters in /sys/module" as
it can be useful in production and I was assured it doesn't add much memory overhead by the sysfs maintainers.
Tested:
16-way x86_64 SMP, dual forcedeth ->
RX bytes:7244556582 (7.2 GB) TX bytes:181904254 (181.9 MB)
############################################
# Patch Set Summary:
David Decotigny (3):
forcedeth: fix race when unloading module
forcedeth: remove unneeded stats updates
forcedeth: fix a few sparse warnings (variable shadowing)
Mandeep Baines (1):
forcedeth: Improve stats counters
Mike Ditto (1):
forcedeth: Acknowledge only interrupts that are being processed
drivers/net/ethernet/nvidia/forcedeth.c | 88 +++++++++++-------------------- 1 files changed, 31 insertions(+), 57 deletions(-)
Signature · 1 line
1.7.3.1
PATCH v5 1/5 forcedeth: fix race when unloading module
When forcedeth module is unloaded, there exists a path that can lead to mod_timer() after del_timer_sync(), causing an oops. This patch short-circuits this unneeded path, which originates in nv_get_ethtool_stats().
Tested:
x86_64 16-way + 3 ethtool -S infinite loops + 100Mbps incoming traffic
+ rmmod/modprobe/ifconfig in a loop
Initial-Author: Salman Qazi <[email protected]>
Discussion: http://patchwork.ozlabs.org/patch/123548/
--- drivers/net/ethernet/nvidia/forcedeth.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/net/ethernet/nvidia/forcedeth.c +1 -1
@@ -4566,7 +4566,7 @@ static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estruct fe_priv *np =netdev_priv (dev);/* update stats */ -nv_do_stats_poll ((unsigned long )dev); +nv_get_hw_stats (dev);memcpy (buffer, &np->estats,nv_get_sset_count (dev,ETH_SS_STATS )*sizeof (u64)); }
Signature · 1 line
1.7.3.1
PATCH v5 2/5 forcedeth: Acknowledge only interrupts that are being processed
In reply to David DecotignyFrom: Mike Ditto <[email protected]>
This is to avoid a race, accidentally acknowledging an interrupt that we didn't notice and won't immediately process. This is based solely on code inspection; it is not known if there was an actual bug here.
--- drivers/net/ethernet/nvidia/forcedeth.c | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-)
drivers/net/ethernet/nvidia/forcedeth.c +8 -5
@@ -3398,7 +3398,8 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)for (i =0 ;; i++) { events =readl (base + NvRegMSIXIrqStatus) &NVREG_IRQ_TX_ALL ; -writel (NVREG_IRQ_TX_ALL , base + NvRegMSIXIrqStatus); +writel (events, base + NvRegMSIXIrqStatus); +netdev_dbg (dev,"tx irq events: %08x\n" , events);if (!(events & np->irqmask))break ;
@@ -3509,7 +3510,8 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)for (i =0 ;; i++) { events =readl (base + NvRegMSIXIrqStatus) &NVREG_IRQ_RX_ALL ; -writel (NVREG_IRQ_RX_ALL , base + NvRegMSIXIrqStatus); +writel (events, base + NvRegMSIXIrqStatus); +netdev_dbg (dev,"rx irq events: %08x\n" , events);if (!(events & np->irqmask))break ;
@@ -3553,7 +3555,8 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)for (i =0 ;; i++) { events =readl (base + NvRegMSIXIrqStatus) &NVREG_IRQ_OTHER ; -writel (NVREG_IRQ_OTHER , base + NvRegMSIXIrqStatus); +writel (events, base + NvRegMSIXIrqStatus); +netdev_dbg (dev,"irq events: %08x\n" , events);if (!(events & np->irqmask))break ;
@@ -3617,10 +3620,10 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data)if (!(np->msi_flags &NV_MSI_X_ENABLED )) { events =readl (base + NvRegIrqStatus) &NVREG_IRQSTAT_MASK ; -writel (NVREG_IRQ_TIMER , base + NvRegIrqStatus); +writel (events &NVREG_IRQ_TIMER , base + NvRegIrqStatus); }else { events =readl (base + NvRegMSIXIrqStatus) &NVREG_IRQSTAT_MASK ; -writel (NVREG_IRQ_TIMER , base + NvRegMSIXIrqStatus); +writel (events &NVREG_IRQ_TIMER , base + NvRegMSIXIrqStatus); }pci_push (base);if (!(events &NVREG_IRQ_TIMER ))
Signature · 1 line
1.7.3.1
PATCH v5 3/5 forcedeth: remove unneeded stats updates
In reply to David DecotignyFunction ndo_get_stats() updates most of the stats from hardware registers, making the manual updates un-needed. This change removes these manual updates. Main exception is rx_missed_errors which needs manual update.
Another exception is rx_packets, still updated manually in this commit to make sure this patch doesn't change behavior of driver. This will be addressed by a future patch.
--- drivers/net/ethernet/nvidia/forcedeth.c | 35 +------------------------------ 1 files changed, 1 insertions(+), 34 deletions(-)
drivers/net/ethernet/nvidia/forcedeth.c +1 -34
@@ -2374,16 +2374,8 @@ static int nv_tx_done(struct net_device *dev, int limit)if (np->desc_ver ==DESC_VER_1 ) {if (flags &NV_TX_LASTPACKET ) {if (flags &NV_TX_ERROR ) { -if (flags &NV_TX_UNDERFLOW ) - dev->stats.tx_fifo_errors++; -if (flags &NV_TX_CARRIERLOST ) - dev->stats.tx_carrier_errors++;if ((flags &NV_TX_RETRYERROR ) && !(flags &NV_TX_RETRYCOUNT_MASK ))nv_legacybackoff_reseed (dev); - dev->stats.tx_errors++; - }else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += np->get_tx_ctx->skb->len; }dev_kfree_skb_any (np->get_tx_ctx->skb); np->get_tx_ctx->skb =NULL ;
@@ -2392,16 +2384,8 @@ static int nv_tx_done(struct net_device *dev, int limit) }else {if (flags &NV_TX2_LASTPACKET ) {if (flags &NV_TX2_ERROR ) { -if (flags &NV_TX2_UNDERFLOW ) - dev->stats.tx_fifo_errors++; -if (flags &NV_TX2_CARRIERLOST ) - dev->stats.tx_carrier_errors++;if ((flags &NV_TX2_RETRYERROR ) && !(flags &NV_TX2_RETRYCOUNT_MASK ))nv_legacybackoff_reseed (dev); - dev->stats.tx_errors++; - }else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += np->get_tx_ctx->skb->len; }dev_kfree_skb_any (np->get_tx_ctx->skb); np->get_tx_ctx->skb =NULL ;
@@ -2434,9 +2418,7 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)nv_unmap_txskb (np, np->get_tx_ctx);if (flags &NV_TX2_LASTPACKET ) { -if (!(flags &NV_TX2_ERROR )) - dev->stats.tx_packets++; -else { +if (flags &NV_TX2_ERROR ) {if ((flags &NV_TX2_RETRYERROR ) && !(flags &NV_TX2_RETRYCOUNT_MASK )) {if (np->driver_data &DEV_HAS_GEAR_MODE )nv_gear_backoff_reseed (dev);
@@ -2636,7 +2618,6 @@ static int nv_rx_process(struct net_device *dev, int limit)if ((flags &NV_RX_ERROR_MASK ) ==NV_RX_ERROR4 ) { len =nv_getlen (dev, skb->data, len);if (len <0 ) { - dev->stats.rx_errors++;dev_kfree_skb (skb); goto next_pkt; }
@@ -2650,11 +2631,6 @@ static int nv_rx_process(struct net_device *dev, int limit)else {if (flags &NV_RX_MISSEDFRAME ) dev->stats.rx_missed_errors++; -if (flags &NV_RX_CRCERR ) - dev->stats.rx_crc_errors++; -if (flags &NV_RX_OVERFLOW ) - dev->stats.rx_over_errors++; - dev->stats.rx_errors++;dev_kfree_skb (skb); goto next_pkt; }
@@ -2670,7 +2646,6 @@ static int nv_rx_process(struct net_device *dev, int limit)if ((flags &NV_RX2_ERROR_MASK ) ==NV_RX2_ERROR4 ) { len =nv_getlen (dev, skb->data, len);if (len <0 ) { - dev->stats.rx_errors++;dev_kfree_skb (skb); goto next_pkt; }
@@ -2682,11 +2657,6 @@ static int nv_rx_process(struct net_device *dev, int limit) }/* the rest are hard errors */ else { -if (flags &NV_RX2_CRCERR ) - dev->stats.rx_crc_errors++; -if (flags &NV_RX2_OVERFLOW ) - dev->stats.rx_over_errors++; - dev->stats.rx_errors++;dev_kfree_skb (skb); goto next_pkt; }
@@ -2704,7 +2674,6 @@ static int nv_rx_process(struct net_device *dev, int limit) skb->protocol =eth_type_trans (skb, dev);napi_gro_receive (&np->napi, skb); dev->stats.rx_packets++; - dev->stats.rx_bytes += len; next_pkt:if (unlikely (np->get_rx.orig++ == np->last_rx.orig)) np->get_rx.orig = np->first_rx.orig;
@@ -2787,9 +2756,7 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)__vlan_hwaccel_put_tag (skb, vid); }napi_gro_receive (&np->napi, skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; }else {dev_kfree_skb (skb); }
Signature · 1 line
1.7.3.1
PATCH v5 5/5 forcedeth: fix a few sparse warnings (variable shadowing)
In reply to David DecotignyThis fixes the following sparse warnings:drivers/net/ethernet/nvidia/forcedeth.c:2113:7: warning: symbol 'size' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2102:6: originally declared here drivers/net/ethernet/nvidia/forcedeth.c:2155:7: warning: symbol 'size' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2102:6: originally declared here drivers/net/ethernet/nvidia/forcedeth.c:2227:7: warning: symbol 'size' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2215:6: originally declared here drivers/net/ethernet/nvidia/forcedeth.c:2271:7: warning: symbol 'size' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2215:6: originally declared here drivers/net/ethernet/nvidia/forcedeth.c:2986:20: warning: symbol 'addr' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2963:6: originally declared here
--- drivers/net/ethernet/nvidia/forcedeth.c | 34 +++++++++++++++--------------- 1 files changed, 17 insertions(+), 17 deletions(-)
drivers/net/ethernet/nvidia/forcedeth.c +17 -17
@@ -2103,10 +2103,10 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)/* add fragments to entries count */ for (i =0 ; i < fragments; i++) { -u32 size =skb_frag_size (&skb_shinfo (skb)->frags[i]); +u32 frag_size =skb_frag_size (&skb_shinfo (skb)->frags[i]); - entries += (size >>NV_TX2_TSO_MAX_SHIFT ) + - ((size & (NV_TX2_TSO_MAX_SIZE -1 )) ?1 :0 ); + entries += (frag_size >>NV_TX2_TSO_MAX_SHIFT ) + + ((frag_size & (NV_TX2_TSO_MAX_SIZE -1 )) ?1 :0 ); }spin_lock_irqsave (&np->lock, flags);
@@ -2145,13 +2145,13 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) /* setup the fragments */ for (i = 0; i < fragments; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 size = skb_frag_size(frag); + u32 frag_size = skb_frag_size(frag); offset = 0; do { prev_tx = put_tx; prev_tx_ctx = np->put_tx_ctx; - bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; np->put_tx_ctx->dma = skb_frag_dma_map( &np->pci_dev->dev, frag, offset,
@@ -2163,12 +2163,12 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) put_tx->flaglen =cpu_to_le32 ((bcnt-1 ) | tx_flags); offset += bcnt; - size -= bcnt; + frag_size -= bcnt;if (unlikely (put_tx++ == np->last_tx.orig)) put_tx = np->first_tx.orig;if (unlikely (np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; - }while (size); + }while (frag_size); }/* set last fragment flag */
@@ -2217,10 +2217,10 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,/* add fragments to entries count */ for (i =0 ; i < fragments; i++) { -u32 size =skb_frag_size (&skb_shinfo (skb)->frags[i]); +u32 frag_size =skb_frag_size (&skb_shinfo (skb)->frags[i]); - entries += (size >>NV_TX2_TSO_MAX_SHIFT ) + - ((size & (NV_TX2_TSO_MAX_SIZE -1 )) ?1 :0 ); + entries += (frag_size >>NV_TX2_TSO_MAX_SHIFT ) + + ((frag_size & (NV_TX2_TSO_MAX_SIZE -1 )) ?1 :0 ); }spin_lock_irqsave (&np->lock, flags);
@@ -2261,13 +2261,13 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, /* setup the fragments */ for (i = 0; i < fragments; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 size = skb_frag_size(frag); + u32 frag_size = skb_frag_size(frag); offset = 0; do { prev_tx = put_tx; prev_tx_ctx = np->put_tx_ctx; - bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; np->put_tx_ctx->dma = skb_frag_dma_map( &np->pci_dev->dev, frag, offset,
@@ -2280,12 +2280,12 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, put_tx->flaglen =cpu_to_le32 ((bcnt-1 ) | tx_flags); offset += bcnt; - size -= bcnt; + frag_size -= bcnt;if (unlikely (put_tx++ == np->last_tx.ex)) put_tx = np->first_tx.ex;if (unlikely (np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; - }while (size); + }while (frag_size); }/* set last fragment flag */
@@ -2933,11 +2933,11 @@ static void nv_set_multicast(struct net_device *dev)struct netdev_hw_addr *ha;netdev_for_each_mc_addr (ha, dev) { -unsigned char *addr = ha->addr; +unsigned char *hw_addr = ha->addr;u32 a, b; - a =le32_to_cpu (*(__le32 *) addr); - b =le16_to_cpu (*(__le16 *) (&addr[4 ])); + a =le32_to_cpu (*(__le32 *) hw_addr); + b =le16_to_cpu (*(__le16 *) (&hw_addr[4 ])); alwaysOn[0 ] &= a; alwaysOff[0 ] &= ~a; alwaysOn[1 ] &= b;
Signature · 1 line
1.7.3.1
PATCH v5 4/5 forcedeth: Improve stats counters
In reply to David DecotignyFrom: Mandeep Baines <[email protected]>
Rx byte count was off; instead use the hardware's count. Tx packet count was counting pre-TSO packets; instead count on-the-wire packets. Report hardware dropped frame count as rx_fifo_errors.
- The count of transmitted packets reported by the forcedeth driver reports pre-TSO (TCP Segmentation Offload) packet counts and not the count of the number of packets sent on the wire. This change fixes the forcedeth driver to report the correct count. Fixed the code by copying the count stored in the NIC H/W to the value reported by the driver.
- Count rx_drop_frame errors as rx_fifo_errors:
We see a lot of rx_drop_frame errors if we disable the rx bottom-halves for too long. Normally, rx_fifo_errors would be counted in this case. The rx_drop_frame error count is private to forcedeth and is not reported by ifconfig or sysfs. The rx_fifo_errors count is currently unused in the forcedeth driver. It is reported by ifconfig as overruns. This change reports rx_drop_frame errors as rx_fifo_errors.
--- drivers/net/ethernet/nvidia/forcedeth.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
drivers/net/ethernet/nvidia/forcedeth.c +4 -0
@@ -1682,6 +1682,7 @@ static void nv_get_hw_stats(struct net_device *dev) np->estats.tx_pause +=readl (base + NvRegTxPause); np->estats.rx_pause +=readl (base + NvRegRxPause); np->estats.rx_drop_frame +=readl (base + NvRegRxDropFrame); + np->estats.rx_errors_total += np->estats.rx_drop_frame; }if (np->driver_data &DEV_HAS_STATISTICS_V3 ) {
@@ -1706,11 +1707,14 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)nv_get_hw_stats (dev);/* copy to net_device stats */ + dev->stats.tx_packets = np->estats.tx_packets; + dev->stats.rx_bytes = np->estats.rx_bytes; dev->stats.tx_bytes = np->estats.tx_bytes; dev->stats.tx_fifo_errors = np->estats.tx_fifo_errors; dev->stats.tx_carrier_errors = np->estats.tx_carrier_errors; dev->stats.rx_crc_errors = np->estats.rx_crc_errors; dev->stats.rx_over_errors = np->estats.rx_over_errors; + dev->stats.rx_fifo_errors = np->estats.rx_drop_frame; dev->stats.rx_errors = np->estats.rx_errors_total; dev->stats.tx_errors = np->estats.tx_errors_total; }
Signature · 1 line
1.7.3.1
David Miller
maintainerFrom: David Decotigny <[email protected]>
Date: Sat, 5 Nov 2011 17:38:19 -0700
Quoted 2 lines
This is a minor update over v4, re-adding a patch I left aside to study it.
All applied, thanks.