aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/forcedeth.c
diff options
context:
space:
mode:
authorAyaz Abdulla <aabdulla@nvidia.com>2006-10-30 17:32:01 -0500
committerJeff Garzik <jeff@garzik.org>2006-12-02 00:12:01 -0500
commitc5cf9101fefae32df654da5f0e736ffbe28aefdc (patch)
tree0591d2a2b9f3a71dd0a7bece85d74505a25af5ec /drivers/net/forcedeth.c
parent7e680c22c0579f1db7b84a7b155755a2754f9557 (diff)
[PATCH] forcedeth: add recoverable error support
This patch adds support to recover from a previously fatal MAC error. In the past the MAC would be hung on an internal fatal error. On new chipsets, the MAC has the ability to enter a non-fatal state and allow the driver to re-init it. Signed-Off-By: Ayaz Abdulla <aabdulla@nvidia.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/forcedeth.c')
-rw-r--r--drivers/net/forcedeth.c78
1 files changed, 74 insertions, 4 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 5472d12122b4..3b8087159b6d 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -111,6 +111,7 @@
111 * 0.56: 22 Mar 2006: Additional ethtool config and moduleparam support. 111 * 0.56: 22 Mar 2006: Additional ethtool config and moduleparam support.
112 * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections. 112 * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
113 * 0.58: 30 Oct 2006: Added support for sideband management unit. 113 * 0.58: 30 Oct 2006: Added support for sideband management unit.
114 * 0.59: 30 Oct 2006: Added support for recoverable error.
114 * 115 *
115 * Known bugs: 116 * Known bugs:
116 * We suspect that on some hardware no TX done interrupts are generated. 117 * We suspect that on some hardware no TX done interrupts are generated.
@@ -127,7 +128,7 @@
127#else 128#else
128#define DRIVERNAPI 129#define DRIVERNAPI
129#endif 130#endif
130#define FORCEDETH_VERSION "0.58" 131#define FORCEDETH_VERSION "0.59"
131#define DRV_NAME "forcedeth" 132#define DRV_NAME "forcedeth"
132 133
133#include <linux/module.h> 134#include <linux/module.h>
@@ -180,7 +181,7 @@
180enum { 181enum {
181 NvRegIrqStatus = 0x000, 182 NvRegIrqStatus = 0x000,
182#define NVREG_IRQSTAT_MIIEVENT 0x040 183#define NVREG_IRQSTAT_MIIEVENT 0x040
183#define NVREG_IRQSTAT_MASK 0x1ff 184#define NVREG_IRQSTAT_MASK 0x81ff
184 NvRegIrqMask = 0x004, 185 NvRegIrqMask = 0x004,
185#define NVREG_IRQ_RX_ERROR 0x0001 186#define NVREG_IRQ_RX_ERROR 0x0001
186#define NVREG_IRQ_RX 0x0002 187#define NVREG_IRQ_RX 0x0002
@@ -191,15 +192,16 @@ enum {
191#define NVREG_IRQ_LINK 0x0040 192#define NVREG_IRQ_LINK 0x0040
192#define NVREG_IRQ_RX_FORCED 0x0080 193#define NVREG_IRQ_RX_FORCED 0x0080
193#define NVREG_IRQ_TX_FORCED 0x0100 194#define NVREG_IRQ_TX_FORCED 0x0100
195#define NVREG_IRQ_RECOVER_ERROR 0x8000
194#define NVREG_IRQMASK_THROUGHPUT 0x00df 196#define NVREG_IRQMASK_THROUGHPUT 0x00df
195#define NVREG_IRQMASK_CPU 0x0040 197#define NVREG_IRQMASK_CPU 0x0040
196#define NVREG_IRQ_TX_ALL (NVREG_IRQ_TX_ERR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED) 198#define NVREG_IRQ_TX_ALL (NVREG_IRQ_TX_ERR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED)
197#define NVREG_IRQ_RX_ALL (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED) 199#define NVREG_IRQ_RX_ALL (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED)
198#define NVREG_IRQ_OTHER (NVREG_IRQ_TIMER|NVREG_IRQ_LINK) 200#define NVREG_IRQ_OTHER (NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RECOVER_ERROR)
199 201
200#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \ 202#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
201 NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RX_FORCED| \ 203 NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RX_FORCED| \
202 NVREG_IRQ_TX_FORCED)) 204 NVREG_IRQ_TX_FORCED|NVREG_IRQ_RECOVER_ERROR))
203 205
204 NvRegUnknownSetupReg6 = 0x008, 206 NvRegUnknownSetupReg6 = 0x008,
205#define NVREG_UNKSETUP6_VAL 3 207#define NVREG_UNKSETUP6_VAL 3
@@ -718,6 +720,7 @@ struct fe_priv {
718 unsigned int phy_model; 720 unsigned int phy_model;
719 u16 gigabit; 721 u16 gigabit;
720 int intr_test; 722 int intr_test;
723 int recover_error;
721 724
722 /* General data: RO fields */ 725 /* General data: RO fields */
723 dma_addr_t ring_addr; 726 dma_addr_t ring_addr;
@@ -2455,6 +2458,23 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
2455 printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", 2458 printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
2456 dev->name, events); 2459 dev->name, events);
2457 } 2460 }
2461 if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
2462 spin_lock(&np->lock);
2463 /* disable interrupts on the nic */
2464 if (!(np->msi_flags & NV_MSI_X_ENABLED))
2465 writel(0, base + NvRegIrqMask);
2466 else
2467 writel(np->irqmask, base + NvRegIrqMask);
2468 pci_push(base);
2469
2470 if (!np->in_shutdown) {
2471 np->nic_poll_irq = np->irqmask;
2472 np->recover_error = 1;
2473 mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
2474 }
2475 spin_unlock(&np->lock);
2476 break;
2477 }
2458#ifdef CONFIG_FORCEDETH_NAPI 2478#ifdef CONFIG_FORCEDETH_NAPI
2459 if (events & NVREG_IRQ_RX_ALL) { 2479 if (events & NVREG_IRQ_RX_ALL) {
2460 netif_rx_schedule(dev); 2480 netif_rx_schedule(dev);
@@ -2685,6 +2705,20 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
2685 spin_unlock_irqrestore(&np->lock, flags); 2705 spin_unlock_irqrestore(&np->lock, flags);
2686 np->link_timeout = jiffies + LINK_TIMEOUT; 2706 np->link_timeout = jiffies + LINK_TIMEOUT;
2687 } 2707 }
2708 if (events & NVREG_IRQ_RECOVER_ERROR) {
2709 spin_lock_irq(&np->lock);
2710 /* disable interrupts on the nic */
2711 writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
2712 pci_push(base);
2713
2714 if (!np->in_shutdown) {
2715 np->nic_poll_irq |= NVREG_IRQ_OTHER;
2716 np->recover_error = 1;
2717 mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
2718 }
2719 spin_unlock_irq(&np->lock);
2720 break;
2721 }
2688 if (events & (NVREG_IRQ_UNKNOWN)) { 2722 if (events & (NVREG_IRQ_UNKNOWN)) {
2689 printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", 2723 printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
2690 dev->name, events); 2724 dev->name, events);
@@ -2914,6 +2948,42 @@ static void nv_do_nic_poll(unsigned long data)
2914 } 2948 }
2915 np->nic_poll_irq = 0; 2949 np->nic_poll_irq = 0;
2916 2950
2951 if (np->recover_error) {
2952 np->recover_error = 0;
2953 printk(KERN_INFO "forcedeth: MAC in recoverable error state\n");
2954 if (netif_running(dev)) {
2955 netif_tx_lock_bh(dev);
2956 spin_lock(&np->lock);
2957 /* stop engines */
2958 nv_stop_rx(dev);
2959 nv_stop_tx(dev);
2960 nv_txrx_reset(dev);
2961 /* drain rx queue */
2962 nv_drain_rx(dev);
2963 nv_drain_tx(dev);
2964 /* reinit driver view of the rx queue */
2965 set_bufsize(dev);
2966 if (nv_init_ring(dev)) {
2967 if (!np->in_shutdown)
2968 mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
2969 }
2970 /* reinit nic view of the rx queue */
2971 writel(np->rx_buf_sz, base + NvRegOffloadConfig);
2972 setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
2973 writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
2974 base + NvRegRingSizes);
2975 pci_push(base);
2976 writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
2977 pci_push(base);
2978
2979 /* restart rx engine */
2980 nv_start_rx(dev);
2981 nv_start_tx(dev);
2982 spin_unlock(&np->lock);
2983 netif_tx_unlock_bh(dev);
2984 }
2985 }
2986
2917 /* FIXME: Do we need synchronize_irq(dev->irq) here? */ 2987 /* FIXME: Do we need synchronize_irq(dev->irq) here? */
2918 2988
2919 writel(mask, base + NvRegIrqMask); 2989 writel(mask, base + NvRegIrqMask);