From 288379f050284087578b77e04f040b57db3db3f8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 19 Jan 2009 16:43:59 -0800 Subject: net: Remove redundant NAPI functions Following the removal of the unused struct net_device * parameter from the NAPI functions named *netif_rx_* in commit 908a7a1, they are exactly equivalent to the corresponding *napi_* functions and are therefore redundant. Signed-off-by: Ben Hutchings Acked-by: Neil Horman Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 5b910cf63740..875509d7d86b 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -1760,7 +1760,7 @@ static void nv_do_rx_refill(unsigned long data) struct fe_priv *np = netdev_priv(dev); /* Just reschedule NAPI rx processing */ - netif_rx_schedule(&np->napi); + napi_schedule(&np->napi); } #else static void nv_do_rx_refill(unsigned long data) @@ -3406,7 +3406,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { spin_lock(&np->lock); - netif_rx_schedule(&np->napi); + napi_schedule(&np->napi); /* Disable furthur receive irq's */ np->irqmask &= ~NVREG_IRQ_RX_ALL; @@ -3523,7 +3523,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { spin_lock(&np->lock); - netif_rx_schedule(&np->napi); + napi_schedule(&np->napi); /* Disable furthur receive irq's */ np->irqmask &= ~NVREG_IRQ_RX_ALL; @@ -3680,7 +3680,7 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) /* re-enable receive interrupts */ spin_lock_irqsave(&np->lock, flags); - __netif_rx_complete(napi); + __napi_complete(napi); np->irqmask |= NVREG_IRQ_RX_ALL; if (np->msi_flags & NV_MSI_X_ENABLED) @@ -3706,7 +3706,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); if (events) { - netif_rx_schedule(&np->napi); + napi_schedule(&np->napi); /* disable receive interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); -- cgit v1.2.1 From ddb213f0768dc8b10cab37a21b85b567f1966d4a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 6 Feb 2009 01:29:23 -0800 Subject: forcedeth: make msi-x different name for rx-tx Impact: make /proc/interrupts could show more info which irq is rx or other for msi-x add three name fields for rx, tx, other Signed-off-by: Yinghai Lu Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 875509d7d86b..3a733a58456a 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -812,6 +812,11 @@ struct fe_priv { /* power saved state */ u32 saved_config_space[NV_PCI_REGSZ_MAX/4]; + + /* for different msi-x irq type */ + char name_rx[IFNAMSIZ + 3]; /* -rx */ + char name_tx[IFNAMSIZ + 3]; /* -tx */ + char name_other[IFNAMSIZ + 6]; /* -other */ }; /* @@ -3918,21 +3923,27 @@ static int nv_request_irq(struct net_device *dev, int intr_test) np->msi_flags |= NV_MSI_X_ENABLED; if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT && !intr_test) { /* Request irq for rx handling */ - if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, IRQF_SHARED, dev->name, dev) != 0) { + sprintf(np->name_rx, "%s-rx", dev->name); + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, + &nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret); pci_disable_msix(np->pci_dev); np->msi_flags &= ~NV_MSI_X_ENABLED; goto out_err; } /* Request irq for tx handling */ - if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, IRQF_SHARED, dev->name, dev) != 0) { + sprintf(np->name_tx, "%s-tx", dev->name); + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, + &nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret); pci_disable_msix(np->pci_dev); np->msi_flags &= ~NV_MSI_X_ENABLED; goto out_free_rx; } /* Request irq for link and timer handling */ - if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, IRQF_SHARED, dev->name, dev) != 0) { + sprintf(np->name_other, "%s-other", dev->name); + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, + &nv_nic_irq_other, IRQF_SHARED, np->name_other, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret); pci_disable_msix(np->pci_dev); np->msi_flags &= ~NV_MSI_X_ENABLED; -- cgit v1.2.1 From 79d30a581fc405fc63322622cb1517d95ed8f5ce Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 6 Feb 2009 01:30:01 -0800 Subject: forcedeth: don't clear nic_poll_irq too early Impact: fix bug for msix, we still need that flag to enable irq respectively Signed-off-by: Yinghai Lu Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 3a733a58456a..2d5f7d42e92a 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4057,8 +4057,6 @@ static void nv_do_nic_poll(unsigned long data) mask |= NVREG_IRQ_OTHER; } } - np->nic_poll_irq = 0; - /* disable_irq() contains synchronize_irq, thus no irq handler can run now */ if (np->recover_error) { @@ -4096,11 +4094,11 @@ static void nv_do_nic_poll(unsigned long data) } } - writel(mask, base + NvRegIrqMask); pci_push(base); if (!using_multi_irqs(dev)) { + np->nic_poll_irq = 0; if (nv_optimized(np)) nv_nic_irq_optimized(0, dev); else @@ -4111,18 +4109,22 @@ static void nv_do_nic_poll(unsigned long data) enable_irq_lockdep(np->pci_dev->irq); } else { if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { + np->nic_poll_irq &= ~NVREG_IRQ_RX_ALL; nv_nic_irq_rx(0, dev); enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); } if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) { + np->nic_poll_irq &= ~NVREG_IRQ_TX_ALL; nv_nic_irq_tx(0, dev); enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); } if (np->nic_poll_irq & NVREG_IRQ_OTHER) { + np->nic_poll_irq &= ~NVREG_IRQ_OTHER; nv_nic_irq_other(0, dev); enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); } } + } #ifdef CONFIG_NET_POLL_CONTROLLER -- cgit v1.2.1 From 0335ef5d59f40931e1b8f0a8be6a09dbc623081b Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 6 Feb 2009 01:30:36 -0800 Subject: forcedeth: disable irq at first before schedule rx Impact: clean up schedule it later after disable it. Signed-off-by: Yinghai Lu Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 2d5f7d42e92a..a7c15715cd83 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3708,13 +3708,13 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) u32 events; events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; - writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); if (events) { - napi_schedule(&np->napi); /* disable receive interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); + writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); + napi_schedule(&np->napi); } return IRQ_HANDLED; } -- cgit v1.2.1 From 033e97b24ad6aaeddbb0180bbd87844513171430 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 6 Feb 2009 01:30:56 -0800 Subject: forcedeth: ck804 and mcp55 doesn't need timerirq Impact: cleanup so get less irq. Signed-off-by: Yinghai Lu Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index a7c15715cd83..f89ea35e448f 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -6070,11 +6070,11 @@ static struct pci_device_id pci_tbl[] = { }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), @@ -6094,11 +6094,11 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), -- cgit v1.2.1 From 394827913e371b058849349c6fc9d52c59c31a3d Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 6 Feb 2009 01:31:12 -0800 Subject: forcedeth: enable msix to default Impact: change default msix and napic can work again Signed-off-by: Yinghai Lu Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index f89ea35e448f..7825be7586f3 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -862,7 +862,7 @@ enum { NV_MSIX_INT_DISABLED, NV_MSIX_INT_ENABLED }; -static int msix = NV_MSIX_INT_DISABLED; +static int msix = NV_MSIX_INT_ENABLED; /* * DMA 64bit -- cgit v1.2.1 From cac1c52c3621b46e3be49cf7887a7cfa393890de Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sat, 7 Feb 2009 00:23:57 -0800 Subject: forcedeth: mgmt unit interface This patch updates the logic used to communicate with the mgmt unit. It also adds a version check for a newer mgmt unit firmware. * Fixed udelay to schedule_timeout_uninterruptible Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 98 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 16 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 7825be7586f3..da7c9ee069b5 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -157,6 +157,9 @@ enum { #define NVREG_XMITCTL_HOST_SEMA_ACQ 0x0000f000 #define NVREG_XMITCTL_HOST_LOADED 0x00004000 #define NVREG_XMITCTL_TX_PATH_EN 0x01000000 +#define NVREG_XMITCTL_DATA_START 0x00100000 +#define NVREG_XMITCTL_DATA_READY 0x00010000 +#define NVREG_XMITCTL_DATA_ERROR 0x00020000 NvRegTransmitterStatus = 0x088, #define NVREG_XMITSTAT_BUSY 0x01 @@ -289,8 +292,10 @@ enum { #define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 #define NVREG_WAKEUPFLAGS_ENABLE 0x1111 - NvRegPatternCRC = 0x204, - NvRegPatternMask = 0x208, + NvRegMgmtUnitGetVersion = 0x204, +#define NVREG_MGMTUNITGETVERSION 0x01 + NvRegMgmtUnitVersion = 0x208, +#define NVREG_MGMTUNITVERSION 0x08 NvRegPowerCap = 0x268, #define NVREG_POWERCAP_D3SUPP (1<<30) #define NVREG_POWERCAP_D2SUPP (1<<26) @@ -303,6 +308,8 @@ enum { #define NVREG_POWERSTATE_D1 0x0001 #define NVREG_POWERSTATE_D2 0x0002 #define NVREG_POWERSTATE_D3 0x0003 + NvRegMgmtUnitControl = 0x278, +#define NVREG_MGMTUNITCONTROL_INUSE 0x20000 NvRegTxCnt = 0x280, NvRegTxZeroReXmt = 0x284, NvRegTxOneReXmt = 0x288, @@ -758,6 +765,8 @@ struct fe_priv { u32 register_size; int rx_csum; u32 mac_in_use; + int mgmt_version; + int mgmt_sema; void __iomem *base; @@ -5182,6 +5191,7 @@ static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) /* The mgmt unit and driver use a semaphore to access the phy during init */ static int nv_mgmt_acquire_sema(struct net_device *dev) { + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int i; u32 tx_ctrl, mgmt_sema; @@ -5204,8 +5214,10 @@ static int nv_mgmt_acquire_sema(struct net_device *dev) /* verify that semaphore was acquired */ tx_ctrl = readl(base + NvRegTransmitterControl); if (((tx_ctrl & NVREG_XMITCTL_HOST_SEMA_MASK) == NVREG_XMITCTL_HOST_SEMA_ACQ) && - ((tx_ctrl & NVREG_XMITCTL_MGMT_SEMA_MASK) == NVREG_XMITCTL_MGMT_SEMA_FREE)) + ((tx_ctrl & NVREG_XMITCTL_MGMT_SEMA_MASK) == NVREG_XMITCTL_MGMT_SEMA_FREE)) { + np->mgmt_sema = 1; return 1; + } else udelay(50); } @@ -5213,6 +5225,51 @@ static int nv_mgmt_acquire_sema(struct net_device *dev) return 0; } +static void nv_mgmt_release_sema(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 tx_ctrl; + + if (np->driver_data & DEV_HAS_MGMT_UNIT) { + if (np->mgmt_sema) { + tx_ctrl = readl(base + NvRegTransmitterControl); + tx_ctrl &= ~NVREG_XMITCTL_HOST_SEMA_ACQ; + writel(tx_ctrl, base + NvRegTransmitterControl); + } + } +} + + +static int nv_mgmt_get_version(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 data_ready = readl(base + NvRegTransmitterControl); + u32 data_ready2 = 0; + unsigned long start; + int ready = 0; + + writel(NVREG_MGMTUNITGETVERSION, base + NvRegMgmtUnitGetVersion); + writel(data_ready ^ NVREG_XMITCTL_DATA_START, base + NvRegTransmitterControl); + start = jiffies; + while (time_before(jiffies, start + 5*HZ)) { + data_ready2 = readl(base + NvRegTransmitterControl); + if ((data_ready & NVREG_XMITCTL_DATA_READY) != (data_ready2 & NVREG_XMITCTL_DATA_READY)) { + ready = 1; + break; + } + schedule_timeout_uninterruptible(1); + } + + if (!ready || (data_ready2 & NVREG_XMITCTL_DATA_ERROR)) + return 0; + + np->mgmt_version = readl(base + NvRegMgmtUnitVersion) & NVREG_MGMTUNITVERSION; + + return 1; +} + static int nv_open(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); @@ -5784,19 +5841,26 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (id->driver_data & DEV_HAS_MGMT_UNIT) { /* management unit running on the mac? */ - if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) { - np->mac_in_use = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST; - dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n", pci_name(pci_dev), np->mac_in_use); - if (nv_mgmt_acquire_sema(dev)) { - /* management unit setup the phy already? */ - if ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) == - NVREG_XMITCTL_SYNC_PHY_INIT) { - /* phy is inited by mgmt unit */ - phyinitialized = 1; - dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n", pci_name(pci_dev)); - } else { - /* we need to init the phy */ - } + if ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST) && + (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) && + nv_mgmt_acquire_sema(dev) && + nv_mgmt_get_version(dev)) { + np->mac_in_use = 1; + if (np->mgmt_version > 0) { + np->mac_in_use = readl(base + NvRegMgmtUnitControl) & NVREG_MGMTUNITCONTROL_INUSE; + } + dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n", + pci_name(pci_dev), np->mac_in_use); + /* management unit setup the phy already? */ + if (np->mac_in_use && + ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) == + NVREG_XMITCTL_SYNC_PHY_INIT)) { + /* phy is inited by mgmt unit */ + phyinitialized = 1; + dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n", + pci_name(pci_dev)); + } else { + /* we need to init the phy */ } } } @@ -5958,6 +6022,8 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) /* restore any phy related changes */ nv_restore_phy(dev); + nv_mgmt_release_sema(dev); + /* free all structures */ free_rings(dev); iounmap(get_hwbase(dev)); -- cgit v1.2.1 From b6e4405bf7241ae91c497e021370066fcfb196c8 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sat, 7 Feb 2009 00:24:15 -0800 Subject: forcedeth: msi interrupt fix This patch fixes an issue with the suspend/resume cycle with msi interrupts. See bugzilla number 10487 for more details. The fix is to re-setup a private msi pci config offset field. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index da7c9ee069b5..47962ed4b04c 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -589,6 +589,9 @@ union ring_type { #define NV_MSI_X_VECTOR_TX 0x1 #define NV_MSI_X_VECTOR_OTHER 0x2 +#define NV_MSI_PRIV_OFFSET 0x68 +#define NV_MSI_PRIV_VALUE 0xffffffff + #define NV_RESTART_TX 0x1 #define NV_RESTART_RX 0x2 @@ -6074,6 +6077,8 @@ static int nv_resume(struct pci_dev *pdev) for (i = 0;i <= np->register_size/sizeof(u32); i++) writel(np->saved_config_space[i], base+i*sizeof(u32)); + pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE); + netif_device_attach(dev); if (netif_running(dev)) { rc = nv_open(dev); -- cgit v1.2.1 From c1086cda7d46885d672d282af04d1273b001442f Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sat, 7 Feb 2009 00:24:39 -0800 Subject: forcedeth: ethtool tx csum fix This patch fixes the ethtool tx csum "set" command. A recent patch was submitted to remove HW_CSUM and use IP_CSUM instead. Therefore, the corresponding ethtool command should also be modified. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 47962ed4b04c..cb41897f286e 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4763,7 +4763,7 @@ static int nv_set_tx_csum(struct net_device *dev, u32 data) struct fe_priv *np = netdev_priv(dev); if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_tx_hw_csum(dev, data); + return ethtool_op_set_tx_csum(dev, data); else return -EOPNOTSUPP; } -- cgit v1.2.1 From daa91a9d2402d33b70b8685dee6fd3e517bf34a9 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sat, 7 Feb 2009 00:25:00 -0800 Subject: forcedeth: recover error support This patch adds another type of recoverable error to the driver. It also modifies the sequence for recovery to include a mac reset and clearing of interrupts. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index cb41897f286e..e32b8e481b31 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -102,7 +102,7 @@ enum { NvRegIrqStatus = 0x000, #define NVREG_IRQSTAT_MIIEVENT 0x040 -#define NVREG_IRQSTAT_MASK 0x81ff +#define NVREG_IRQSTAT_MASK 0x83ff NvRegIrqMask = 0x004, #define NVREG_IRQ_RX_ERROR 0x0001 #define NVREG_IRQ_RX 0x0002 @@ -113,7 +113,7 @@ enum { #define NVREG_IRQ_LINK 0x0040 #define NVREG_IRQ_RX_FORCED 0x0080 #define NVREG_IRQ_TX_FORCED 0x0100 -#define NVREG_IRQ_RECOVER_ERROR 0x8000 +#define NVREG_IRQ_RECOVER_ERROR 0x8200 #define NVREG_IRQMASK_THROUGHPUT 0x00df #define NVREG_IRQMASK_CPU 0x0060 #define NVREG_IRQ_TX_ALL (NVREG_IRQ_TX_ERR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED) @@ -4073,13 +4073,15 @@ static void nv_do_nic_poll(unsigned long data) if (np->recover_error) { np->recover_error = 0; - printk(KERN_INFO "forcedeth: MAC in recoverable error state\n"); + printk(KERN_INFO "%s: MAC in recoverable error state\n", dev->name); if (netif_running(dev)) { netif_tx_lock_bh(dev); netif_addr_lock(dev); spin_lock(&np->lock); /* stop engines */ nv_stop_rxtx(dev); + if (np->driver_data & DEV_HAS_POWER_CNTRL) + nv_mac_reset(dev); nv_txrx_reset(dev); /* drain rx queue */ nv_drain_rxtx(dev); @@ -4097,6 +4099,11 @@ static void nv_do_nic_poll(unsigned long data) pci_push(base); writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(base); + /* clear interrupts */ + if (!(np->msi_flags & NV_MSI_X_ENABLED)) + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + else + writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); /* restart rx engine */ nv_start_rxtx(dev); -- cgit v1.2.1 From 2813ddd1bfd681a2fcc1d95530b399a92da89556 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sat, 7 Feb 2009 00:25:18 -0800 Subject: forcedeth: bump version to 63 This patch bumps the version up to 63 Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index e32b8e481b31..021308f9f0c7 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -39,7 +39,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.62" +#define FORCEDETH_VERSION "0.63" #define DRV_NAME "forcedeth" #include -- cgit v1.2.1 From 6a64cd64c056d46b419bb07b02153b00df97a2c5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Feb 2009 10:19:35 +0000 Subject: forcedeth: fix non-constant printk warnings Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 8b7f8b77e5e0..e3b7305e8b8c 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -940,7 +940,7 @@ static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, delaymax -= delay; if (delaymax < 0) { if (msg) - printk(msg); + printk("%s", msg); return 1; } } while ((readl(base + offset) & mask) != target); -- cgit v1.2.1 From 8ed1454aa8ab6c616f9c457238c6397c0529ceb9 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:01:49 +0000 Subject: forcedeth: fix stats version feature Newer versions of the stats feature would not encompass all older versions. This would result in only retreiving a subset of all available stats in HW. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index e3b7305e8b8c..abe3306855fd 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -87,8 +87,8 @@ #define DEV_HAS_MSI_X 0x000080 /* device supports MSI-X */ #define DEV_HAS_POWER_CNTRL 0x000100 /* device supports power savings */ #define DEV_HAS_STATISTICS_V1 0x000200 /* device supports hw statistics version 1 */ -#define DEV_HAS_STATISTICS_V2 0x000400 /* device supports hw statistics version 2 */ -#define DEV_HAS_STATISTICS_V3 0x000800 /* device supports hw statistics version 3 */ +#define DEV_HAS_STATISTICS_V2 0x000600 /* device supports hw statistics version 2 */ +#define DEV_HAS_STATISTICS_V3 0x000e00 /* device supports hw statistics version 3 */ #define DEV_HAS_TEST_EXTENDED 0x001000 /* device supports extended diagnostic test */ #define DEV_HAS_MGMT_UNIT 0x002000 /* device supports management unit */ #define DEV_HAS_CORRECT_MACADDR 0x004000 /* device supports correct mac address order */ @@ -4796,12 +4796,12 @@ static int nv_get_sset_count(struct net_device *dev, int sset) else return NV_TEST_COUNT_BASE; case ETH_SS_STATS: - if (np->driver_data & DEV_HAS_STATISTICS_V1) - return NV_DEV_STATISTICS_V1_COUNT; + if (np->driver_data & DEV_HAS_STATISTICS_V3) + return NV_DEV_STATISTICS_V3_COUNT; else if (np->driver_data & DEV_HAS_STATISTICS_V2) return NV_DEV_STATISTICS_V2_COUNT; - else if (np->driver_data & DEV_HAS_STATISTICS_V3) - return NV_DEV_STATISTICS_V3_COUNT; + else if (np->driver_data & DEV_HAS_STATISTICS_V1) + return NV_DEV_STATISTICS_V1_COUNT; else return 0; default: -- cgit v1.2.1 From 08d935757440872d46be77f95153972cdbfe550d Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:01:55 +0000 Subject: forcedeth: fix missing napi enable/disable calls This patch adds missing napi enable/disable calls. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index abe3306855fd..5346410aeb6e 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -1069,6 +1069,24 @@ static void nv_disable_hw_interrupts(struct net_device *dev, u32 mask) } } +static void nv_napi_enable(struct net_device *dev) +{ +#ifdef CONFIG_FORCEDETH_NAPI + struct fe_priv *np = get_nvpriv(dev); + + napi_enable(&np->napi); +#endif +} + +static void nv_napi_disable(struct net_device *dev) +{ +#ifdef CONFIG_FORCEDETH_NAPI + struct fe_priv *np = get_nvpriv(dev); + + napi_disable(&np->napi); +#endif +} + #define MII_READ (-1) /* mii_rw: read/write a register on the PHY. * @@ -2924,6 +2942,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) * Changing the MTU is a rare event, it shouldn't matter. */ nv_disable_irq(dev); + nv_napi_disable(dev); netif_tx_lock_bh(dev); netif_addr_lock(dev); spin_lock(&np->lock); @@ -2952,6 +2971,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) spin_unlock(&np->lock); netif_addr_unlock(dev); netif_tx_unlock_bh(dev); + nv_napi_enable(dev); nv_enable_irq(dev); } return 0; @@ -4592,6 +4612,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri if (netif_running(dev)) { nv_disable_irq(dev); + nv_napi_disable(dev); netif_tx_lock_bh(dev); netif_addr_lock(dev); spin_lock(&np->lock); @@ -4644,6 +4665,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri spin_unlock(&np->lock); netif_addr_unlock(dev); netif_tx_unlock_bh(dev); + nv_napi_enable(dev); nv_enable_irq(dev); } return 0; @@ -5070,9 +5092,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 if (test->flags & ETH_TEST_FL_OFFLINE) { if (netif_running(dev)) { netif_stop_queue(dev); -#ifdef CONFIG_FORCEDETH_NAPI - napi_disable(&np->napi); -#endif + nv_napi_disable(dev); netif_tx_lock_bh(dev); netif_addr_lock(dev); spin_lock_irq(&np->lock); @@ -5130,9 +5150,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 /* restart rx engine */ nv_start_rxtx(dev); netif_start_queue(dev); -#ifdef CONFIG_FORCEDETH_NAPI - napi_enable(&np->napi); -#endif + nv_napi_enable(dev); nv_enable_hw_interrupts(dev, np->irqmask); } } @@ -5424,9 +5442,7 @@ static int nv_open(struct net_device *dev) ret = nv_update_linkspeed(dev); nv_start_rxtx(dev); netif_start_queue(dev); -#ifdef CONFIG_FORCEDETH_NAPI - napi_enable(&np->napi); -#endif + nv_napi_enable(dev); if (ret) { netif_carrier_on(dev); @@ -5458,9 +5474,7 @@ static int nv_close(struct net_device *dev) spin_lock_irq(&np->lock); np->in_shutdown = 1; spin_unlock_irq(&np->lock); -#ifdef CONFIG_FORCEDETH_NAPI - napi_disable(&np->napi); -#endif + nv_napi_disable(dev); synchronize_irq(np->pci_dev->irq); del_timer_sync(&np->oom_kick); -- cgit v1.2.1 From d41c628c514bceb33037c26f83585c629594bed5 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:01:59 +0000 Subject: forcedeth: remove msix + napi This patch removes support for msix running in conjunction with napi. There has been reported issues regarding the behaviour of irqmask and generation of interrupts by the HW when in MSIX mode. When running napi, the driver is constantly turning off/on the irqmask. For the time being, I am going to disable it until I can root cause the issue. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 5346410aeb6e..a4f2f146ae68 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3731,26 +3731,6 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) } #endif -#ifdef CONFIG_FORCEDETH_NAPI -static irqreturn_t nv_nic_irq_rx(int foo, void *data) -{ - struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = netdev_priv(dev); - u8 __iomem *base = get_hwbase(dev); - u32 events; - - events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; - - if (events) { - /* disable receive interrupts on the nic */ - writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); - pci_push(base); - writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); - napi_schedule(&np->napi); - } - return IRQ_HANDLED; -} -#else static irqreturn_t nv_nic_irq_rx(int foo, void *data) { struct net_device *dev = (struct net_device *) data; @@ -3797,7 +3777,6 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) return IRQ_RETVAL(i); } -#endif static irqreturn_t nv_nic_irq_other(int foo, void *data) { @@ -5670,7 +5649,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->msi_flags |= NV_MSI_CAPABLE; } if ((id->driver_data & DEV_HAS_MSI_X) && msix) { + /* msix has had reported issues when modifying irqmask + as in the case of napi, therefore, disable for now + */ +#ifndef CONFIG_FORCEDETH_NAPI np->msi_flags |= NV_MSI_X_CAPABLE; +#endif } np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG; -- cgit v1.2.1 From 582806be066bd35dc5d2739b090b561a5efd787a Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:03 +0000 Subject: forcedeth: save irq events for napi processing This patch will save the irq events in the driver's context so that the napi routine knows which interrupts have occurred. Subsequent changes will be moving all interrupt processing into the napi poll routine. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index a4f2f146ae68..37cd23fb9e44 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -759,6 +759,7 @@ struct fe_priv { dma_addr_t ring_addr; struct pci_dev *pci_dev; u32 orig_mac[2]; + u32 events; u32 irqmask; u32 desc_ver; u32 txrxctl_bits; @@ -3417,21 +3418,20 @@ static irqreturn_t nv_nic_irq(int foo, void *data) struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - u32 events; int i; dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name); for (i=0; ; i++) { if (!(np->msi_flags & NV_MSI_X_ENABLED)) { - events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + np->events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); } else { - events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; + np->events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); } - dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); - if (!(events & np->irqmask)) + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); + if (!(np->events & np->irqmask)) break; nv_msi_workaround(np); @@ -3441,7 +3441,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); #ifdef CONFIG_FORCEDETH_NAPI - if (events & NVREG_IRQ_RX_ALL) { + if (np->events & NVREG_IRQ_RX_ALL) { spin_lock(&np->lock); napi_schedule(&np->napi); @@ -3464,7 +3464,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) } } #endif - if (unlikely(events & NVREG_IRQ_LINK)) { + if (unlikely(np->events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); nv_link_irq(dev); spin_unlock(&np->lock); @@ -3475,15 +3475,15 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); np->link_timeout = jiffies + LINK_TIMEOUT; } - if (unlikely(events & (NVREG_IRQ_TX_ERR))) { + if (unlikely(np->events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", - dev->name, events); + dev->name, np->events); } - if (unlikely(events & (NVREG_IRQ_UNKNOWN))) { + if (unlikely(np->events & (NVREG_IRQ_UNKNOWN))) { printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", - dev->name, events); + dev->name, np->events); } - if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) { + if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { spin_lock(&np->lock); /* disable interrupts on the nic */ if (!(np->msi_flags & NV_MSI_X_ENABLED)) @@ -3534,21 +3534,20 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - u32 events; int i; dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name); for (i=0; ; i++) { if (!(np->msi_flags & NV_MSI_X_ENABLED)) { - events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + np->events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); } else { - events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; + np->events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); } - dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); - if (!(events & np->irqmask)) + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); + if (!(np->events & np->irqmask)) break; nv_msi_workaround(np); @@ -3558,7 +3557,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) spin_unlock(&np->lock); #ifdef CONFIG_FORCEDETH_NAPI - if (events & NVREG_IRQ_RX_ALL) { + if (np->events & NVREG_IRQ_RX_ALL) { spin_lock(&np->lock); napi_schedule(&np->napi); @@ -3581,7 +3580,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) } } #endif - if (unlikely(events & NVREG_IRQ_LINK)) { + if (unlikely(np->events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); nv_link_irq(dev); spin_unlock(&np->lock); @@ -3592,15 +3591,15 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) spin_unlock(&np->lock); np->link_timeout = jiffies + LINK_TIMEOUT; } - if (unlikely(events & (NVREG_IRQ_TX_ERR))) { + if (unlikely(np->events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", - dev->name, events); + dev->name, np->events); } - if (unlikely(events & (NVREG_IRQ_UNKNOWN))) { + if (unlikely(np->events & (NVREG_IRQ_UNKNOWN))) { printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", - dev->name, events); + dev->name, np->events); } - if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) { + if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { spin_lock(&np->lock); /* disable interrupts on the nic */ if (!(np->msi_flags & NV_MSI_X_ENABLED)) -- cgit v1.2.1 From 2daac3e8f831beba2012fdefda17770456be9b7e Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:06 +0000 Subject: forcedeth: remove overhead This patch removes unnecessary overhead code. Firstly, there is no nead to mask off unwanted interrupts as we will be checking against the irqmask field anyways. Secondly, there has been no value in last few years from detecting error or unknown interrupts. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 37cd23fb9e44..74511f7e13e9 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -120,10 +120,6 @@ enum { #define NVREG_IRQ_RX_ALL (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED) #define NVREG_IRQ_OTHER (NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RECOVER_ERROR) -#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \ - NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RX_FORCED| \ - NVREG_IRQ_TX_FORCED|NVREG_IRQ_RECOVER_ERROR)) - NvRegUnknownSetupReg6 = 0x008, #define NVREG_UNKSETUP6_VAL 3 @@ -3424,10 +3420,10 @@ static irqreturn_t nv_nic_irq(int foo, void *data) for (i=0; ; i++) { if (!(np->msi_flags & NV_MSI_X_ENABLED)) { - np->events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + np->events = readl(base + NvRegIrqStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); } else { - np->events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; + np->events = readl(base + NvRegMSIXIrqStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); } dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); @@ -3475,14 +3471,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); np->link_timeout = jiffies + LINK_TIMEOUT; } - if (unlikely(np->events & (NVREG_IRQ_TX_ERR))) { - dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", - dev->name, np->events); - } - if (unlikely(np->events & (NVREG_IRQ_UNKNOWN))) { - printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", - dev->name, np->events); - } if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { spin_lock(&np->lock); /* disable interrupts on the nic */ @@ -3540,10 +3528,10 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) for (i=0; ; i++) { if (!(np->msi_flags & NV_MSI_X_ENABLED)) { - np->events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + np->events = readl(base + NvRegIrqStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); } else { - np->events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; + np->events = readl(base + NvRegMSIXIrqStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); } dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); @@ -3591,14 +3579,6 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) spin_unlock(&np->lock); np->link_timeout = jiffies + LINK_TIMEOUT; } - if (unlikely(np->events & (NVREG_IRQ_TX_ERR))) { - dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", - dev->name, np->events); - } - if (unlikely(np->events & (NVREG_IRQ_UNKNOWN))) { - printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", - dev->name, np->events); - } if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { spin_lock(&np->lock); /* disable interrupts on the nic */ @@ -3663,10 +3643,6 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); spin_unlock_irqrestore(&np->lock, flags); - if (unlikely(events & (NVREG_IRQ_TX_ERR))) { - dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", - dev->name, events); - } if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ @@ -3825,10 +3801,6 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) spin_unlock_irq(&np->lock); break; } - if (events & (NVREG_IRQ_UNKNOWN)) { - printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", - dev->name, events); - } if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ -- cgit v1.2.1 From 33912e72d00c3627dbbb7c59463df9535176059f Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:10 +0000 Subject: forcedeth: add/modify tx done with limit There are two tx_done routines to handle tx completion processing. Both these functions now take in a limit value and return the amount of tx completions. This will be used by a future patch to determine the total amount of work done. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 74511f7e13e9..78c2fe185281 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2397,14 +2397,16 @@ static inline void nv_tx_flip_ownership(struct net_device *dev) * * Caller must own np->lock. */ -static void nv_tx_done(struct net_device *dev) +static int nv_tx_done(struct net_device *dev, int limit) { struct fe_priv *np = netdev_priv(dev); u32 flags; + int tx_work = 0; struct ring_desc* orig_get_tx = np->get_tx.orig; while ((np->get_tx.orig != np->put_tx.orig) && - !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) { + !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID) && + (tx_work < limit)) { dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n", dev->name, flags); @@ -2430,6 +2432,7 @@ static void nv_tx_done(struct net_device *dev) } dev_kfree_skb_any(np->get_tx_ctx->skb); np->get_tx_ctx->skb = NULL; + tx_work++; } } else { if (flags & NV_TX2_LASTPACKET) { @@ -2447,6 +2450,7 @@ static void nv_tx_done(struct net_device *dev) } dev_kfree_skb_any(np->get_tx_ctx->skb); np->get_tx_ctx->skb = NULL; + tx_work++; } } if (unlikely(np->get_tx.orig++ == np->last_tx.orig)) @@ -2458,17 +2462,19 @@ static void nv_tx_done(struct net_device *dev) np->tx_stop = 0; netif_wake_queue(dev); } + return tx_work; } -static void nv_tx_done_optimized(struct net_device *dev, int limit) +static int nv_tx_done_optimized(struct net_device *dev, int limit) { struct fe_priv *np = netdev_priv(dev); u32 flags; + int tx_work = 0; struct ring_desc_ex* orig_get_tx = np->get_tx.ex; while ((np->get_tx.ex != np->put_tx.ex) && !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) && - (limit-- > 0)) { + (tx_work < limit)) { dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n", dev->name, flags); @@ -2492,6 +2498,7 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit) dev_kfree_skb_any(np->get_tx_ctx->skb); np->get_tx_ctx->skb = NULL; + tx_work++; if (np->tx_limit) { nv_tx_flip_ownership(dev); @@ -2506,6 +2513,7 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit) np->tx_stop = 0; netif_wake_queue(dev); } + return tx_work; } /* @@ -2578,7 +2586,7 @@ static void nv_tx_timeout(struct net_device *dev) /* 2) check that the packets were not sent already: */ if (!nv_optimized(np)) - nv_tx_done(dev); + nv_tx_done(dev, np->tx_ring_size); else nv_tx_done_optimized(dev, np->tx_ring_size); @@ -3433,7 +3441,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) nv_msi_workaround(np); spin_lock(&np->lock); - nv_tx_done(dev); + nv_tx_done(dev, np->tx_ring_size); spin_unlock(&np->lock); #ifdef CONFIG_FORCEDETH_NAPI -- cgit v1.2.1 From f27e6f39fc37f378f5485b9a0ff905796e789f80 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:14 +0000 Subject: forcedeth: napi - handle all processing The napi poll routine has been modified to handle all interrupt events and process them accordingly. Therefore, the ISR will now only schedule the napi poll and disable all interrupts instead of just disabling rx interrupt. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 98 ++++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 38 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 78c2fe185281..6b6765431eaf 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3440,25 +3440,22 @@ static irqreturn_t nv_nic_irq(int foo, void *data) nv_msi_workaround(np); +#ifdef CONFIG_FORCEDETH_NAPI spin_lock(&np->lock); - nv_tx_done(dev, np->tx_ring_size); - spin_unlock(&np->lock); + napi_schedule(&np->napi); -#ifdef CONFIG_FORCEDETH_NAPI - if (np->events & NVREG_IRQ_RX_ALL) { - spin_lock(&np->lock); - napi_schedule(&np->napi); + /* Disable furthur irq's + (msix not enabled with napi) */ + writel(0, base + NvRegIrqMask); - /* Disable furthur receive irq's */ - np->irqmask &= ~NVREG_IRQ_RX_ALL; + spin_unlock(&np->lock); - if (np->msi_flags & NV_MSI_X_ENABLED) - writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); - else - writel(np->irqmask, base + NvRegIrqMask); - spin_unlock(&np->lock); - } + return IRQ_HANDLED; #else + spin_lock(&np->lock); + nv_tx_done(dev, np->tx_ring_size); + spin_unlock(&np->lock); + if (nv_rx_process(dev, RX_WORK_PER_LOOP)) { if (unlikely(nv_alloc_rx(dev))) { spin_lock(&np->lock); @@ -3467,7 +3464,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); } } -#endif + if (unlikely(np->events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); nv_link_irq(dev); @@ -3513,7 +3510,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); break; } - +#endif } dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name); @@ -3548,25 +3545,22 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) nv_msi_workaround(np); +#ifdef CONFIG_FORCEDETH_NAPI spin_lock(&np->lock); - nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); - spin_unlock(&np->lock); + napi_schedule(&np->napi); -#ifdef CONFIG_FORCEDETH_NAPI - if (np->events & NVREG_IRQ_RX_ALL) { - spin_lock(&np->lock); - napi_schedule(&np->napi); + /* Disable furthur irq's + (msix not enabled with napi) */ + writel(0, base + NvRegIrqMask); - /* Disable furthur receive irq's */ - np->irqmask &= ~NVREG_IRQ_RX_ALL; + spin_unlock(&np->lock); - if (np->msi_flags & NV_MSI_X_ENABLED) - writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); - else - writel(np->irqmask, base + NvRegIrqMask); - spin_unlock(&np->lock); - } + return IRQ_HANDLED; #else + spin_lock(&np->lock); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); + spin_unlock(&np->lock); + if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) { if (unlikely(nv_alloc_rx_optimized(dev))) { spin_lock(&np->lock); @@ -3575,7 +3569,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) spin_unlock(&np->lock); } } -#endif + if (unlikely(np->events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); nv_link_irq(dev); @@ -3622,7 +3616,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); break; } - +#endif } dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name); @@ -3682,9 +3676,17 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) int pkts, retcode; if (!nv_optimized(np)) { + spin_lock_irqsave(&np->lock, flags); + nv_tx_done(dev, np->tx_ring_size); + spin_unlock_irqrestore(&np->lock, flags); + pkts = nv_rx_process(dev, budget); retcode = nv_alloc_rx(dev); } else { + spin_lock_irqsave(&np->lock, flags); + nv_tx_done_optimized(dev, np->tx_ring_size); + spin_unlock_irqrestore(&np->lock, flags); + pkts = nv_rx_process_optimized(dev, budget); retcode = nv_alloc_rx_optimized(dev); } @@ -3696,17 +3698,37 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) spin_unlock_irqrestore(&np->lock, flags); } + if (unlikely(np->events & NVREG_IRQ_LINK)) { + spin_lock_irqsave(&np->lock, flags); + nv_link_irq(dev); + spin_unlock_irqrestore(&np->lock, flags); + } + if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { + spin_lock_irqsave(&np->lock, flags); + nv_linkchange(dev); + spin_unlock_irqrestore(&np->lock, flags); + np->link_timeout = jiffies + LINK_TIMEOUT; + } + if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { + spin_lock_irqsave(&np->lock, flags); + if (!np->in_shutdown) { + np->nic_poll_irq = np->irqmask; + np->recover_error = 1; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } + spin_unlock_irqrestore(&np->lock, flags); + __napi_complete(napi); + return pkts; + } + if (pkts < budget) { - /* re-enable receive interrupts */ + /* re-enable interrupts + (msix not enabled in napi) */ spin_lock_irqsave(&np->lock, flags); __napi_complete(napi); - np->irqmask |= NVREG_IRQ_RX_ALL; - if (np->msi_flags & NV_MSI_X_ENABLED) - writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); - else - writel(np->irqmask, base + NvRegIrqMask); + writel(np->irqmask, base + NvRegIrqMask); spin_unlock_irqrestore(&np->lock, flags); } -- cgit v1.2.1 From 9e184767c956e71d9535c9fc8433e140f819d07d Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:18 +0000 Subject: forcedeth: add new optimization mode A new optimization mode called Dynamic has been added. This will be mode where interrupt moderation logic will dynamically switch between pure throughput mode and poll based (called 'cpu') mode. Also, for newer chipsets, the timer irq is not needed for throughput mode. Secondly, since we are modifying the irqmask to change between modes, msix is not supported. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 105 ++++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 48 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 6b6765431eaf..07e245dab680 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -842,9 +842,10 @@ static int max_interrupt_work = 15; */ enum { NV_OPTIMIZATION_MODE_THROUGHPUT, - NV_OPTIMIZATION_MODE_CPU + NV_OPTIMIZATION_MODE_CPU, + NV_OPTIMIZATION_MODE_DYNAMIC }; -static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT; +static int optimization_mode = NV_OPTIMIZATION_MODE_DYNAMIC; /* * Poll interval for timer irq @@ -5645,19 +5646,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; } - np->msi_flags = 0; - if ((id->driver_data & DEV_HAS_MSI) && msi) { - np->msi_flags |= NV_MSI_CAPABLE; - } - if ((id->driver_data & DEV_HAS_MSI_X) && msix) { - /* msix has had reported issues when modifying irqmask - as in the case of napi, therefore, disable for now - */ -#ifndef CONFIG_FORCEDETH_NAPI - np->msi_flags |= NV_MSI_X_CAPABLE; -#endif - } - np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG; if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) || (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) || @@ -5802,14 +5790,35 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i } else { np->tx_flags = NV_TX2_VALID; } - if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) { - np->irqmask = NVREG_IRQMASK_THROUGHPUT; - if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */ - np->msi_flags |= 0x0003; - } else { + + np->msi_flags = 0; + if ((id->driver_data & DEV_HAS_MSI) && msi) { + np->msi_flags |= NV_MSI_CAPABLE; + } + if ((id->driver_data & DEV_HAS_MSI_X) && msix) { + /* msix has had reported issues when modifying irqmask + as in the case of napi, therefore, disable for now + */ +#ifndef CONFIG_FORCEDETH_NAPI + np->msi_flags |= NV_MSI_X_CAPABLE; +#endif + } + + if (optimization_mode == NV_OPTIMIZATION_MODE_CPU) { np->irqmask = NVREG_IRQMASK_CPU; if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */ np->msi_flags |= 0x0001; + } else if (optimization_mode == NV_OPTIMIZATION_MODE_DYNAMIC && + !(id->driver_data & DEV_NEED_TIMERIRQ)) { + /* start off in throughput mode */ + np->irqmask = NVREG_IRQMASK_THROUGHPUT; + /* remove support for msix mode */ + np->msi_flags &= ~NV_MSI_X_CAPABLE; + } else { + optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT; + np->irqmask = NVREG_IRQMASK_THROUGHPUT; + if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */ + np->msi_flags |= 0x0003; } if (id->driver_data & DEV_NEED_TIMERIRQ) @@ -6166,19 +6175,19 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), @@ -6190,83 +6199,83 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, }, { /* MCP73 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, }, { /* MCP73 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, }, { /* MCP73 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, }, { /* MCP73 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), @@ -6274,15 +6283,15 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, {0,}, }; @@ -6310,7 +6319,7 @@ static void __exit exit_nic(void) module_param(max_interrupt_work, int, 0); MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt"); module_param(optimization_mode, int, 0); -MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer."); +MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer. In dynamic mode (2), the mode toggles between throughput and CPU mode based on network load."); module_param(poll_interval, int, 0); MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535."); module_param(msi, int, 0); -- cgit v1.2.1 From b67874ac1604cda8070d60d432e892c09d761b2e Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:22 +0000 Subject: forcedeth: remove isr processing loop This patch is only a subset of changes so that it is easier to see the modifications. This patch removes the isr 'for' loop and shifts all the logic to account for new tab spacing. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 252 ++++++++++++++++++++---------------------------- 1 file changed, 105 insertions(+), 147 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 07e245dab680..2c3a7f851f20 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3423,99 +3423,78 @@ static irqreturn_t nv_nic_irq(int foo, void *data) struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int i; dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name); - for (i=0; ; i++) { - if (!(np->msi_flags & NV_MSI_X_ENABLED)) { - np->events = readl(base + NvRegIrqStatus); - writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); - } else { - np->events = readl(base + NvRegMSIXIrqStatus); - writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); - } - dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); - if (!(np->events & np->irqmask)) - break; + if (!(np->msi_flags & NV_MSI_X_ENABLED)) { + np->events = readl(base + NvRegIrqStatus); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + } else { + np->events = readl(base + NvRegMSIXIrqStatus); + writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); + } + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); + if (!(np->events & np->irqmask)) + return IRQ_NONE; - nv_msi_workaround(np); + nv_msi_workaround(np); #ifdef CONFIG_FORCEDETH_NAPI - spin_lock(&np->lock); - napi_schedule(&np->napi); + spin_lock(&np->lock); + napi_schedule(&np->napi); - /* Disable furthur irq's - (msix not enabled with napi) */ - writel(0, base + NvRegIrqMask); + /* Disable furthur irq's + (msix not enabled with napi) */ + writel(0, base + NvRegIrqMask); - spin_unlock(&np->lock); + spin_unlock(&np->lock); - return IRQ_HANDLED; + return IRQ_HANDLED; #else - spin_lock(&np->lock); - nv_tx_done(dev, np->tx_ring_size); - spin_unlock(&np->lock); - - if (nv_rx_process(dev, RX_WORK_PER_LOOP)) { - if (unlikely(nv_alloc_rx(dev))) { - spin_lock(&np->lock); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); - } - } + spin_lock(&np->lock); + nv_tx_done(dev, np->tx_ring_size); + spin_unlock(&np->lock); - if (unlikely(np->events & NVREG_IRQ_LINK)) { + if (nv_rx_process(dev, RX_WORK_PER_LOOP)) { + if (unlikely(nv_alloc_rx(dev))) { spin_lock(&np->lock); - nv_link_irq(dev); - spin_unlock(&np->lock); - } - if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { - spin_lock(&np->lock); - nv_linkchange(dev); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); spin_unlock(&np->lock); - np->link_timeout = jiffies + LINK_TIMEOUT; } - if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { - spin_lock(&np->lock); - /* disable interrupts on the nic */ - if (!(np->msi_flags & NV_MSI_X_ENABLED)) - writel(0, base + NvRegIrqMask); - else - writel(np->irqmask, base + NvRegIrqMask); - pci_push(base); + } - if (!np->in_shutdown) { - np->nic_poll_irq = np->irqmask; - np->recover_error = 1; - mod_timer(&np->nic_poll, jiffies + POLL_WAIT); - } - spin_unlock(&np->lock); - break; - } - if (unlikely(i > max_interrupt_work)) { - spin_lock(&np->lock); - /* disable interrupts on the nic */ - if (!(np->msi_flags & NV_MSI_X_ENABLED)) - writel(0, base + NvRegIrqMask); - else - writel(np->irqmask, base + NvRegIrqMask); - pci_push(base); + if (unlikely(np->events & NVREG_IRQ_LINK)) { + spin_lock(&np->lock); + nv_link_irq(dev); + spin_unlock(&np->lock); + } + if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { + spin_lock(&np->lock); + nv_linkchange(dev); + spin_unlock(&np->lock); + np->link_timeout = jiffies + LINK_TIMEOUT; + } + if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + if (!(np->msi_flags & NV_MSI_X_ENABLED)) + writel(0, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); - if (!np->in_shutdown) { - np->nic_poll_irq = np->irqmask; - mod_timer(&np->nic_poll, jiffies + POLL_WAIT); - } - spin_unlock(&np->lock); - printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); - break; + if (!np->in_shutdown) { + np->nic_poll_irq = np->irqmask; + np->recover_error = 1; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } -#endif + spin_unlock(&np->lock); } +#endif dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name); - return IRQ_RETVAL(i); + return IRQ_HANDLED; } /** @@ -3528,100 +3507,79 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int i; dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name); - for (i=0; ; i++) { - if (!(np->msi_flags & NV_MSI_X_ENABLED)) { - np->events = readl(base + NvRegIrqStatus); - writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); - } else { - np->events = readl(base + NvRegMSIXIrqStatus); - writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); - } - dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); - if (!(np->events & np->irqmask)) - break; + if (!(np->msi_flags & NV_MSI_X_ENABLED)) { + np->events = readl(base + NvRegIrqStatus); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + } else { + np->events = readl(base + NvRegMSIXIrqStatus); + writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); + } + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); + if (!(np->events & np->irqmask)) + return IRQ_NONE; - nv_msi_workaround(np); + nv_msi_workaround(np); #ifdef CONFIG_FORCEDETH_NAPI - spin_lock(&np->lock); - napi_schedule(&np->napi); + spin_lock(&np->lock); + napi_schedule(&np->napi); - /* Disable furthur irq's - (msix not enabled with napi) */ - writel(0, base + NvRegIrqMask); + /* Disable furthur irq's + (msix not enabled with napi) */ + writel(0, base + NvRegIrqMask); - spin_unlock(&np->lock); + spin_unlock(&np->lock); - return IRQ_HANDLED; + return IRQ_HANDLED; #else - spin_lock(&np->lock); - nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); - spin_unlock(&np->lock); - - if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) { - if (unlikely(nv_alloc_rx_optimized(dev))) { - spin_lock(&np->lock); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); - } - } + spin_lock(&np->lock); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); + spin_unlock(&np->lock); - if (unlikely(np->events & NVREG_IRQ_LINK)) { + if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) { + if (unlikely(nv_alloc_rx_optimized(dev))) { spin_lock(&np->lock); - nv_link_irq(dev); - spin_unlock(&np->lock); - } - if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { - spin_lock(&np->lock); - nv_linkchange(dev); - spin_unlock(&np->lock); - np->link_timeout = jiffies + LINK_TIMEOUT; - } - if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { - spin_lock(&np->lock); - /* disable interrupts on the nic */ - if (!(np->msi_flags & NV_MSI_X_ENABLED)) - writel(0, base + NvRegIrqMask); - else - writel(np->irqmask, base + NvRegIrqMask); - pci_push(base); - - if (!np->in_shutdown) { - np->nic_poll_irq = np->irqmask; - np->recover_error = 1; - mod_timer(&np->nic_poll, jiffies + POLL_WAIT); - } + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); spin_unlock(&np->lock); - break; } + } - if (unlikely(i > max_interrupt_work)) { - spin_lock(&np->lock); - /* disable interrupts on the nic */ - if (!(np->msi_flags & NV_MSI_X_ENABLED)) - writel(0, base + NvRegIrqMask); - else - writel(np->irqmask, base + NvRegIrqMask); - pci_push(base); + if (unlikely(np->events & NVREG_IRQ_LINK)) { + spin_lock(&np->lock); + nv_link_irq(dev); + spin_unlock(&np->lock); + } + if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { + spin_lock(&np->lock); + nv_linkchange(dev); + spin_unlock(&np->lock); + np->link_timeout = jiffies + LINK_TIMEOUT; + } + if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + if (!(np->msi_flags & NV_MSI_X_ENABLED)) + writel(0, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); - if (!np->in_shutdown) { - np->nic_poll_irq = np->irqmask; - mod_timer(&np->nic_poll, jiffies + POLL_WAIT); - } - spin_unlock(&np->lock); - printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); - break; + if (!np->in_shutdown) { + np->nic_poll_irq = np->irqmask; + np->recover_error = 1; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } -#endif + spin_unlock(&np->lock); } + +#endif dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name); - return IRQ_RETVAL(i); + return IRQ_HANDLED; } static irqreturn_t nv_nic_irq_tx(int foo, void *data) -- cgit v1.2.1 From 4145ade2bb265b34331265bfa2221e40b069b3ca Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:26 +0000 Subject: forcedeth: add interrupt moderation logic This patch adds the logic to moderate the interrupts by changing the mode between throughput and poll. If there has been a large amount of time without any burst of network load, the code will transition to pure throughput mode (where each tx/rx/other will cause an interrupt). If bursts of network load occurs, it will transition to poll based mode to help reduce cpu utilization (it will not interrupt on each packet) while maintaining the optimum network bandwidth utilization. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 137 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 31 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 2c3a7f851f20..341a35117eae 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -593,6 +593,9 @@ union ring_type { #define NV_TX_LIMIT_COUNT 16 +#define NV_DYNAMIC_THRESHOLD 4 +#define NV_DYNAMIC_MAX_QUIET_COUNT 2048 + /* statistics */ struct nv_ethtool_str { char name[ETH_GSTRING_LEN]; @@ -750,6 +753,7 @@ struct fe_priv { u16 gigabit; int intr_test; int recover_error; + int quiet_count; /* General data: RO fields */ dma_addr_t ring_addr; @@ -832,7 +836,7 @@ struct fe_priv { * Maximum number of loops until we assume that a bit in the irq mask * is stuck. Overridable with module param. */ -static int max_interrupt_work = 15; +static int max_interrupt_work = 4; /* * Optimization can be either throuput mode or cpu mode @@ -3418,11 +3422,43 @@ static void nv_msi_workaround(struct fe_priv *np) } } +static inline int nv_change_interrupt_mode(struct net_device *dev, int total_work) +{ + struct fe_priv *np = netdev_priv(dev); + + if (optimization_mode == NV_OPTIMIZATION_MODE_DYNAMIC) { + if (total_work > NV_DYNAMIC_THRESHOLD) { + /* transition to poll based interrupts */ + np->quiet_count = 0; + if (np->irqmask != NVREG_IRQMASK_CPU) { + np->irqmask = NVREG_IRQMASK_CPU; + return 1; + } + } else { + if (np->quiet_count < NV_DYNAMIC_MAX_QUIET_COUNT) { + np->quiet_count++; + } else { + /* reached a period of low activity, switch + to per tx/rx packet interrupts */ + if (np->irqmask != NVREG_IRQMASK_THROUGHPUT) { + np->irqmask = NVREG_IRQMASK_THROUGHPUT; + return 1; + } + } + } + } + return 0; +} + static irqreturn_t nv_nic_irq(int foo, void *data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); +#ifndef CONFIG_FORCEDETH_NAPI + int total_work = 0; + int loop_count = 0; +#endif dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name); @@ -3449,19 +3485,35 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); - return IRQ_HANDLED; #else - spin_lock(&np->lock); - nv_tx_done(dev, np->tx_ring_size); - spin_unlock(&np->lock); - - if (nv_rx_process(dev, RX_WORK_PER_LOOP)) { - if (unlikely(nv_alloc_rx(dev))) { - spin_lock(&np->lock); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); + do + { + int work = 0; + if ((work = nv_rx_process(dev, RX_WORK_PER_LOOP))) { + if (unlikely(nv_alloc_rx(dev))) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } } + + spin_lock(&np->lock); + work += nv_tx_done(dev, TX_WORK_PER_LOOP); + spin_unlock(&np->lock); + + if (!work) + break; + + total_work += work; + + loop_count++; + } + while (loop_count < max_interrupt_work); + + if (nv_change_interrupt_mode(dev, total_work)) { + /* setup new irq mask */ + writel(np->irqmask, base + NvRegIrqMask); } if (unlikely(np->events & NVREG_IRQ_LINK)) { @@ -3507,6 +3559,10 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); +#ifndef CONFIG_FORCEDETH_NAPI + int total_work = 0; + int loop_count = 0; +#endif dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name); @@ -3533,19 +3589,35 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) spin_unlock(&np->lock); - return IRQ_HANDLED; #else - spin_lock(&np->lock); - nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); - spin_unlock(&np->lock); - - if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) { - if (unlikely(nv_alloc_rx_optimized(dev))) { - spin_lock(&np->lock); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); + do + { + int work = 0; + if ((work = nv_rx_process_optimized(dev, RX_WORK_PER_LOOP))) { + if (unlikely(nv_alloc_rx_optimized(dev))) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } } + + spin_lock(&np->lock); + work += nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); + spin_unlock(&np->lock); + + if (!work) + break; + + total_work += work; + + loop_count++; + } + while (loop_count < max_interrupt_work); + + if (nv_change_interrupt_mode(dev, total_work)) { + /* setup new irq mask */ + writel(np->irqmask, base + NvRegIrqMask); } if (unlikely(np->events & NVREG_IRQ_LINK)) { @@ -3632,21 +3704,22 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) struct net_device *dev = np->dev; u8 __iomem *base = get_hwbase(dev); unsigned long flags; - int pkts, retcode; + int retcode; + int tx_work, rx_work; if (!nv_optimized(np)) { spin_lock_irqsave(&np->lock, flags); - nv_tx_done(dev, np->tx_ring_size); + tx_work = nv_tx_done(dev, np->tx_ring_size); spin_unlock_irqrestore(&np->lock, flags); - pkts = nv_rx_process(dev, budget); + rx_work = nv_rx_process(dev, budget); retcode = nv_alloc_rx(dev); } else { spin_lock_irqsave(&np->lock, flags); - nv_tx_done_optimized(dev, np->tx_ring_size); + tx_work = nv_tx_done_optimized(dev, np->tx_ring_size); spin_unlock_irqrestore(&np->lock, flags); - pkts = nv_rx_process_optimized(dev, budget); + rx_work = nv_rx_process_optimized(dev, budget); retcode = nv_alloc_rx_optimized(dev); } @@ -3657,6 +3730,8 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) spin_unlock_irqrestore(&np->lock, flags); } + nv_change_interrupt_mode(dev, tx_work + rx_work); + if (unlikely(np->events & NVREG_IRQ_LINK)) { spin_lock_irqsave(&np->lock, flags); nv_link_irq(dev); @@ -3677,10 +3752,10 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) } spin_unlock_irqrestore(&np->lock, flags); __napi_complete(napi); - return pkts; + return rx_work; } - if (pkts < budget) { + if (rx_work < budget) { /* re-enable interrupts (msix not enabled in napi) */ spin_lock_irqsave(&np->lock, flags); @@ -3691,7 +3766,7 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) spin_unlock_irqrestore(&np->lock, flags); } - return pkts; + return rx_work; } #endif -- cgit v1.2.1 From 6cef67a02f7994c97dbd716dbeb592265fb5b7b0 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:30 +0000 Subject: forcedeth: performance changes This patch modifies the throughput mode poll settings to reduce the number of interrupts. This is only used by older hardware that need a timer irq in throughput mode. Secondly, this patch increases the default rx ring from 128 to 512. This drastically improves bandwidth utilization for small packets sizes i.e 512 bytes. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 341a35117eae..28fc3357268a 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -128,7 +128,7 @@ enum { * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms */ NvRegPollingInterval = 0x00c, -#define NVREG_POLL_DEFAULT_THROUGHPUT 970 /* backup tx cleanup if loop max reached */ +#define NVREG_POLL_DEFAULT_THROUGHPUT 65535 /* backup tx cleanup if loop max reached */ #define NVREG_POLL_DEFAULT_CPU 13 NvRegMSIMap0 = 0x020, NvRegMSIMap1 = 0x024, @@ -463,7 +463,7 @@ union ring_type { /* General driver defaults */ #define NV_WATCHDOG_TIMEO (5*HZ) -#define RX_RING_DEFAULT 128 +#define RX_RING_DEFAULT 512 #define TX_RING_DEFAULT 256 #define RX_RING_MIN 128 #define TX_RING_MIN 64 -- cgit v1.2.1 From 1b2bb76f575699eff3f58b18dcfebf5d3b1f6ddb Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:34 +0000 Subject: forcedeth: fix irq clearing and napi spin lock changes This patch clears the irqstatus register with the exact same events it has read from it. Since the read-write operation is not atomic, a new irqstatus bit could have been set in between these operations and would then be cleared accidentally. Secondly, we now don't need any spin lock protection when scheduling/completing napi poll as the isr will not execute anymore (as we turn off all interrupts now). Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 28fc3357268a..514aaf189af9 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3464,10 +3464,10 @@ static irqreturn_t nv_nic_irq(int foo, void *data) if (!(np->msi_flags & NV_MSI_X_ENABLED)) { np->events = readl(base + NvRegIrqStatus); - writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + writel(np->events, base + NvRegIrqStatus); } else { np->events = readl(base + NvRegMSIXIrqStatus); - writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); + writel(np->events, base + NvRegMSIXIrqStatus); } dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); if (!(np->events & np->irqmask)) @@ -3476,15 +3476,12 @@ static irqreturn_t nv_nic_irq(int foo, void *data) nv_msi_workaround(np); #ifdef CONFIG_FORCEDETH_NAPI - spin_lock(&np->lock); napi_schedule(&np->napi); /* Disable furthur irq's (msix not enabled with napi) */ writel(0, base + NvRegIrqMask); - spin_unlock(&np->lock); - #else do { @@ -3568,10 +3565,10 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) if (!(np->msi_flags & NV_MSI_X_ENABLED)) { np->events = readl(base + NvRegIrqStatus); - writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + writel(np->events, base + NvRegIrqStatus); } else { np->events = readl(base + NvRegMSIXIrqStatus); - writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); + writel(np->events, base + NvRegMSIXIrqStatus); } dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events); if (!(np->events & np->irqmask)) @@ -3580,15 +3577,12 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) nv_msi_workaround(np); #ifdef CONFIG_FORCEDETH_NAPI - spin_lock(&np->lock); napi_schedule(&np->napi); /* Disable furthur irq's (msix not enabled with napi) */ writel(0, base + NvRegIrqMask); - spin_unlock(&np->lock); - #else do { @@ -3758,13 +3752,9 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) if (rx_work < budget) { /* re-enable interrupts (msix not enabled in napi) */ - spin_lock_irqsave(&np->lock, flags); - __napi_complete(napi); writel(np->irqmask, base + NvRegIrqMask); - - spin_unlock_irqrestore(&np->lock, flags); } return rx_work; } -- cgit v1.2.1 From 3e1a3ce2f19a8a74fe6771f6dcd642d61ae050dc Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Mar 2009 08:02:38 +0000 Subject: forcedeth: version bump to 64 This patch bumps up the version to 0.64 Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/forcedeth.c') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 514aaf189af9..a858c6ff80dd 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -39,7 +39,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.63" +#define FORCEDETH_VERSION "0.64" #define DRV_NAME "forcedeth" #include -- cgit v1.2.1