From: Andy Gospodarek <gospo@redhat.com> Date: Tue, 26 Aug 2008 16:53:15 -0400 Subject: [net] ixgb: hardware support and other upstream fixes Message-id: 20080826205314.GB4507@gospo.rdu.redhat.com O-Subject: [RHEL5.3 PATCH] ixgb: sun hardware support and several other upstream fixes (repost) Bugzilla: 441609 RH-Acked-by: Jeff Garzik <jgarzik@redhat.com> RH-Acked-by: David Miller <davem@redhat.com> commit 3fd7131feacc01c1e23e46c416228f36ebdcc0d4 Author: Matheos Worku <matheos.worku@sun.com> Date: Fri Dec 14 11:48:29 2007 -0800 ixgb: make sure jumbos stay enabled after reset and commit 8b32e63d48d43f3843222ca66fecd45ff2a74147 Author: Matheos Worku <matheos.worku@sun.com> Date: Fri Dec 14 11:48:36 2007 -0800 ixgb: enable sun hardware support for broadcom phy I also added a few other napi fixes, a new ethtool stat called 'rx_no_buffer_count' that should help when debugging ixgb performance issues, and removed the buggy irq_sem. The driver has been tested by the requester of RHBZ 441609 and appears to be working well. diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 3173c36..6084f85 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -158,7 +158,6 @@ struct ixgb_adapter { uint16_t link_speed; uint16_t link_duplex; spinlock_t tx_lock; - atomic_t irq_sem; struct work_struct tx_timeout_task; struct timer_list blink_timer; @@ -194,6 +193,15 @@ struct ixgb_adapter { struct ixgb_hw_stats stats; uint32_t alloc_rx_buff_failed; boolean_t have_msi; + unsigned long flags; +}; + +enum ixgb_state_t { + /* TBD + __IXGB_TESTING, + __IXGB_RESETTING, + */ + __IXGB_DOWN }; /* Exported from other modules */ @@ -202,4 +210,14 @@ extern void ixgb_set_ethtool_ops(struct net_device *netdev); extern char ixgb_driver_name[]; extern const char ixgb_driver_version[]; +extern int ixgb_up(struct ixgb_adapter *adapter); +extern void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog); +extern void ixgb_reset(struct ixgb_adapter *adapter); +extern int ixgb_setup_rx_resources(struct ixgb_adapter *adapter); +extern int ixgb_setup_tx_resources(struct ixgb_adapter *adapter); +extern void ixgb_free_rx_resources(struct ixgb_adapter *adapter); +extern void ixgb_free_tx_resources(struct ixgb_adapter *adapter); +extern void ixgb_update_stats(struct ixgb_adapter *adapter); + + #endif /* _IXGB_H_ */ diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index d8dbbef..01f45f8 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -32,15 +32,6 @@ #include <asm/uaccess.h> -extern int ixgb_up(struct ixgb_adapter *adapter); -extern void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog); -extern void ixgb_reset(struct ixgb_adapter *adapter); -extern int ixgb_setup_rx_resources(struct ixgb_adapter *adapter); -extern int ixgb_setup_tx_resources(struct ixgb_adapter *adapter); -extern void ixgb_free_rx_resources(struct ixgb_adapter *adapter); -extern void ixgb_free_tx_resources(struct ixgb_adapter *adapter); -extern void ixgb_update_stats(struct ixgb_adapter *adapter); - #define IXGB_ALL_RAR_ENTRIES 16 struct ixgb_stats { @@ -49,7 +40,7 @@ struct ixgb_stats { int stat_offset; }; -#define IXGB_STAT(m) sizeof(((struct ixgb_adapter *)0)->m), \ +#define IXGB_STAT(m) FIELD_SIZEOF(struct ixgb_adapter, m), \ offsetof(struct ixgb_adapter, m) static struct ixgb_stats ixgb_gstrings_stats[] = { {"rx_packets", IXGB_STAT(net_stats.rx_packets)}, @@ -67,6 +58,7 @@ static struct ixgb_stats ixgb_gstrings_stats[] = { {"rx_over_errors", IXGB_STAT(net_stats.rx_over_errors)}, {"rx_crc_errors", IXGB_STAT(net_stats.rx_crc_errors)}, {"rx_frame_errors", IXGB_STAT(net_stats.rx_frame_errors)}, + {"rx_no_buffer_count", IXGB_STAT(stats.rnbc)}, {"rx_fifo_errors", IXGB_STAT(net_stats.rx_fifo_errors)}, {"rx_missed_errors", IXGB_STAT(net_stats.rx_missed_errors)}, {"tx_aborted_errors", IXGB_STAT(net_stats.tx_aborted_errors)}, diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index 2c6367a..80a8b98 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -45,6 +45,8 @@ static boolean_t ixgb_link_reset(struct ixgb_hw *hw); static void ixgb_optics_reset(struct ixgb_hw *hw); +static void ixgb_optics_reset_bcm(struct ixgb_hw *hw); + static ixgb_phy_type ixgb_identify_phy(struct ixgb_hw *hw); static void ixgb_clear_hw_cntrs(struct ixgb_hw *hw); @@ -90,10 +92,20 @@ static uint32_t ixgb_mac_reset(struct ixgb_hw *hw) ASSERT(!(ctrl_reg & IXGB_CTRL0_RST)); #endif - if (hw->phy_type == ixgb_phy_type_txn17401) { - ixgb_optics_reset(hw); + if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID) { + ctrl_reg = /* Enable interrupt from XFP and SerDes */ + IXGB_CTRL1_GPI0_EN | + IXGB_CTRL1_SDP6_DIR | + IXGB_CTRL1_SDP7_DIR | + IXGB_CTRL1_SDP6 | + IXGB_CTRL1_SDP7; + IXGB_WRITE_REG(hw, CTRL1, ctrl_reg); + ixgb_optics_reset_bcm(hw); } + if (hw->phy_type == ixgb_phy_type_txn17401) + ixgb_optics_reset(hw); + return ctrl_reg; } @@ -253,6 +265,10 @@ ixgb_identify_phy(struct ixgb_hw *hw) break; } + /* update phy type for sun specific board */ + if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID) + phy_type = ixgb_phy_type_bcm; + return (phy_type); } @@ -1225,3 +1241,65 @@ ixgb_optics_reset(struct ixgb_hw *hw) return; } + +/****************************************************************************** + * Resets the 10GbE optics module for Sun variant NIC. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ + +#define IXGB_BCM8704_USER_PMD_TX_CTRL_REG 0xC803 +#define IXGB_BCM8704_USER_PMD_TX_CTRL_REG_VAL 0x0164 +#define IXGB_BCM8704_USER_CTRL_REG 0xC800 +#define IXGB_BCM8704_USER_CTRL_REG_VAL 0x7FBF +#define IXGB_BCM8704_USER_DEV3_ADDR 0x0003 +#define IXGB_SUN_PHY_ADDRESS 0x0000 +#define IXGB_SUN_PHY_RESET_DELAY 305 + +static void +ixgb_optics_reset_bcm(struct ixgb_hw *hw) +{ + u32 ctrl = IXGB_READ_REG(hw, CTRL0); + ctrl &= ~IXGB_CTRL0_SDP2; + ctrl |= IXGB_CTRL0_SDP3; + IXGB_WRITE_REG(hw, CTRL0, ctrl); + + /* SerDes needs extra delay */ + msleep(IXGB_SUN_PHY_RESET_DELAY); + + /* Broadcom 7408L configuration */ + /* Reference clock config */ + ixgb_write_phy_reg(hw, + IXGB_BCM8704_USER_PMD_TX_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR, + IXGB_BCM8704_USER_PMD_TX_CTRL_REG_VAL); + /* we must read the registers twice */ + ixgb_read_phy_reg(hw, + IXGB_BCM8704_USER_PMD_TX_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR); + ixgb_read_phy_reg(hw, + IXGB_BCM8704_USER_PMD_TX_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR); + + ixgb_write_phy_reg(hw, + IXGB_BCM8704_USER_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR, + IXGB_BCM8704_USER_CTRL_REG_VAL); + ixgb_read_phy_reg(hw, + IXGB_BCM8704_USER_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR); + ixgb_read_phy_reg(hw, + IXGB_BCM8704_USER_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR); + + /* SerDes needs extra delay */ + msleep(IXGB_SUN_PHY_RESET_DELAY); + + return; +} diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index af56433..4f176ff 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -44,7 +44,8 @@ typedef enum { ixgb_phy_type_g6005, /* 850nm, MM fiber, XPAK transceiver */ ixgb_phy_type_g6104, /* 1310nm, SM fiber, XPAK transceiver */ ixgb_phy_type_txn17201, /* 850nm, MM fiber, XPAK transceiver */ - ixgb_phy_type_txn17401 /* 1310nm, SM fiber, XENPAK transceiver */ + ixgb_phy_type_txn17401, /* 1310nm, SM fiber, XENPAK transceiver */ + ixgb_phy_type_bcm /* SUN specific board */ } ixgb_phy_type; /* XPAK transceiver vendors, for the SR adapters */ @@ -534,12 +535,12 @@ typedef enum { * in which case the structure must be packed in some compiler-specific * manner. */ struct ixgb_rx_desc { - uint64_t buff_addr; - uint16_t length; - uint16_t reserved; + __le64 buff_addr; + __le16 length; + __le16 reserved; uint8_t status; uint8_t errors; - uint16_t special; + __le16 special; }; #define IXGB_RX_DESC_STATUS_DD 0x01 @@ -567,11 +568,11 @@ struct ixgb_rx_desc { * in which case the structure must be packed in some compiler-specific * manner. */ struct ixgb_tx_desc { - uint64_t buff_addr; - uint32_t cmd_type_len; + __le64 buff_addr; + __le32 cmd_type_len; uint8_t status; uint8_t popts; - uint16_t vlan; + __le16 vlan; }; #define IXGB_TX_DESC_LENGTH_MASK 0x000FFFFF @@ -596,14 +597,14 @@ struct ixgb_tx_desc { struct ixgb_context_desc { uint8_t ipcss; uint8_t ipcso; - uint16_t ipcse; + __le16 ipcse; uint8_t tucss; uint8_t tucso; - uint16_t tucse; - uint32_t cmd_type_len; + __le16 tucse; + __le32 cmd_type_len; uint8_t status; uint8_t hdr_len; - uint16_t mss; + __le16 mss; }; #define IXGB_CONTEXT_DESC_CMD_TCP 0x01000000 diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h index 4376e7e..180d20e 100644 --- a/drivers/net/ixgb/ixgb_ids.h +++ b/drivers/net/ixgb/ixgb_ids.h @@ -35,7 +35,8 @@ #define INTEL_VENDOR_ID 0x8086 #define INTEL_SUBVENDOR_ID 0x8086 - +#define SUN_VENDOR_ID 0x108E +#define SUN_SUBVENDOR_ID 0x108E #define IXGB_DEVICE_ID_82597EX 0x1048 #define IXGB_DEVICE_ID_82597EX_SR 0x1A48 @@ -46,6 +47,7 @@ #define IXGB_DEVICE_ID_82597EX_CX4 0x109E #define IXGB_SUBDEVICE_ID_A00C 0xA00C #define IXGB_SUBDEVICE_ID_A01C 0xA01C +#define IXGB_SUBDEVICE_ID_7036 0x7036 #endif /* #ifndef _IXGB_IDS_H_ */ /* End of File */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index b0b0805..1b22d78 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "1.0.126-k2"DRIVERNAPI +#define DRV_VERSION "1.0.126-k4"DRIVERNAPI const char ixgb_driver_version[] = DRV_VERSION; static const char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -146,14 +146,6 @@ static int debug = DEFAULT_DEBUG_LEVEL_SHIFT; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); -/* some defines for controlling descriptor fetches in h/w */ -#define RXDCTL_WTHRESH_DEFAULT 15 /* chip writes back at this many or RXT0 */ -#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below - * this */ -#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail - * is pushed this many descriptors - * from head */ - /** * ixgb_init_module - Driver Registration Routine * @@ -197,7 +189,6 @@ module_exit(ixgb_exit_module); static void ixgb_irq_disable(struct ixgb_adapter *adapter) { - atomic_inc(&adapter->irq_sem); IXGB_WRITE_REG(&adapter->hw, IMC, ~0); IXGB_WRITE_FLUSH(&adapter->hw); synchronize_irq(adapter->pdev->irq); @@ -211,12 +202,12 @@ ixgb_irq_disable(struct ixgb_adapter *adapter) static void ixgb_irq_enable(struct ixgb_adapter *adapter) { - if(atomic_dec_and_test(&adapter->irq_sem)) { - IXGB_WRITE_REG(&adapter->hw, IMS, - IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW | - IXGB_INT_LSC); - IXGB_WRITE_FLUSH(&adapter->hw); - } + u32 val = IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | + IXGB_INT_TXDW | IXGB_INT_LSC; + if (adapter->hw.subsystem_vendor_id == SUN_SUBVENDOR_ID) + val |= IXGB_INT_GPI0; + IXGB_WRITE_REG(&adapter->hw, IMS, val); + IXGB_WRITE_FLUSH(&adapter->hw); } int @@ -281,13 +272,15 @@ ixgb_up(struct ixgb_adapter *adapter) } } - mod_timer(&adapter->watchdog_timer, jiffies); + clear_bit(__IXGB_DOWN, &adapter->flags); #ifdef CONFIG_IXGB_NAPI netif_poll_enable(netdev); #endif ixgb_irq_enable(adapter); + mod_timer(&adapter->watchdog_timer, jiffies); + return 0; } @@ -296,6 +289,13 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) { struct net_device *netdev = adapter->netdev; + /* prevent the interrupt handler from restarting watchdog */ + set_bit(__IXGB_DOWN, &adapter->flags); + +#ifdef CONFIG_IXGB_NAPI + netif_poll_disable(netdev); +#endif + /* waiting for NAPI to complete can re-enable interrupts */ ixgb_irq_disable(adapter); free_irq(adapter->pdev->irq, netdev); @@ -304,9 +304,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) if(kill_watchdog) del_timer_sync(&adapter->watchdog_timer); -#ifdef CONFIG_IXGB_NAPI - netif_poll_disable(netdev); -#endif + adapter->link_speed = 0; adapter->link_duplex = 0; netif_carrier_off(netdev); @@ -320,10 +318,22 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) void ixgb_reset(struct ixgb_adapter *adapter) { + struct ixgb_hw *hw = &adapter->hw; - ixgb_adapter_stop(&adapter->hw); - if(!ixgb_init_hw(&adapter->hw)) + ixgb_adapter_stop(hw); + if (!ixgb_init_hw(hw)) DPRINTK(PROBE, ERR, "ixgb_init_hw failed.\n"); + + /* restore frame size information */ + IXGB_WRITE_REG(hw, MFS, hw->max_frame_size << IXGB_MFS_SHIFT); + if (hw->max_frame_size > + IXGB_MAX_ENET_FRAME_SIZE_WITHOUT_FCS + ENET_FCS_LENGTH) { + u32 ctrl0 = IXGB_READ_REG(hw, CTRL0); + if (!(ctrl0 & IXGB_CTRL0_JFE)) { + ctrl0 |= IXGB_CTRL0_JFE; + IXGB_WRITE_REG(hw, CTRL0, ctrl0); + } + } } /** @@ -528,6 +538,8 @@ ixgb_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct ixgb_adapter *adapter = netdev_priv(netdev); + flush_scheduled_work(); + unregister_netdev(netdev); iounmap(adapter->hw.hw_addr); @@ -560,7 +572,7 @@ ixgb_sw_init(struct ixgb_adapter *adapter) hw->subsystem_id = pdev->subsystem_device; hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; - adapter->rx_buffer_len = hw->max_frame_size; + adapter->rx_buffer_len = hw->max_frame_size + 8; /* + 8 for errata */ if((hw->device_id == IXGB_DEVICE_ID_82597EX) || (hw->device_id == IXGB_DEVICE_ID_82597EX_CX4) @@ -575,9 +587,9 @@ ixgb_sw_init(struct ixgb_adapter *adapter) /* enable flow control to be programmed */ hw->fc.send_xon = 1; - atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->tx_lock); + set_bit(__IXGB_DOWN, &adapter->flags); return 0; } @@ -831,7 +843,6 @@ ixgb_configure_rx(struct ixgb_adapter *adapter) struct ixgb_hw *hw = &adapter->hw; uint32_t rctl; uint32_t rxcsum; - uint32_t rxdctl; /* make sure receives are disabled while setting up the descriptors */ @@ -853,18 +864,12 @@ ixgb_configure_rx(struct ixgb_adapter *adapter) IXGB_WRITE_REG(hw, RDH, 0); IXGB_WRITE_REG(hw, RDT, 0); - /* set up pre-fetching of receive buffers so we get some before we - * run out (default hardware behavior is to run out before fetching - * more). This sets up to fetch if HTHRESH rx descriptors are avail - * and the descriptors in hw cache are below PTHRESH. This avoids - * the hardware behavior of fetching <=512 descriptors in a single - * burst that pre-empts all other activity, usually causing fifo - * overflows. */ - /* use WTHRESH to burst write 16 descriptors or burst when RXT0 */ - rxdctl = RXDCTL_WTHRESH_DEFAULT << IXGB_RXDCTL_WTHRESH_SHIFT | - RXDCTL_HTHRESH_DEFAULT << IXGB_RXDCTL_HTHRESH_SHIFT | - RXDCTL_PTHRESH_DEFAULT << IXGB_RXDCTL_PTHRESH_SHIFT; - IXGB_WRITE_REG(hw, RXDCTL, rxdctl); + /* due to the hardware errata with RXDCTL, we are unable to use any of + * the performance enhancing features of it without causing other + * subtle bugs, some of the bugs could include receive length + * corruption at high data rates (WTHRESH > 0) and/or receive + * descriptor ring irregularites (particularly in hardware cache) */ + IXGB_WRITE_REG(hw, RXDCTL, 0); /* Enable Receive Checksum Offload for TCP and UDP */ if(adapter->rx_csum == TRUE) { @@ -1297,12 +1302,12 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; WARN_ON(buffer_info->dma != 0); + buffer_info->time_stamp = jiffies; buffer_info->dma = pci_map_single(adapter->pdev, skb->data + offset, size, PCI_DMA_TODEVICE); - buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = 0; len -= size; @@ -1329,13 +1334,13 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, size -= 4; buffer_info->length = size; + buffer_info->time_stamp = jiffies; buffer_info->dma = pci_map_page(adapter->pdev, frag->page, frag->page_offset + offset, size, PCI_DMA_TODEVICE); - buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = 0; len -= size; @@ -1450,14 +1455,18 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) int vlan_id = 0; int tso; + if (test_bit(__IXGB_DOWN, &adapter->flags)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + if(skb->len <= 0) { dev_kfree_skb_any(skb); return 0; } #ifdef NETIF_F_LLTX - local_irq_save(flags); - if (!spin_trylock(&adapter->tx_lock)) { + if (!spin_trylock_irqsave(&adapter->tx_lock, flags)) { /* Collision - tell upper layer to requeue */ local_irq_restore(flags); return NETDEV_TX_LOCKED; @@ -1575,14 +1584,18 @@ ixgb_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } - adapter->rx_buffer_len = max_frame; + if (old_max_frame == max_frame) + return 0; + + if (netif_running(netdev)) + ixgb_down(adapter, true); + + adapter->rx_buffer_len = max_frame + 8; /* + 8 for errata */ netdev->mtu = new_mtu; - if ((old_max_frame != max_frame) && netif_running(netdev)) { - ixgb_down(adapter, TRUE); + if (netif_running(netdev)) ixgb_up(adapter); - } return 0; } @@ -1739,9 +1752,9 @@ ixgb_intr(int irq, void *data, struct pt_regs *regs) if(unlikely(!icr)) return IRQ_NONE; /* Not our interrupt */ - if(unlikely(icr & (IXGB_INT_RXSEQ | IXGB_INT_LSC))) { - mod_timer(&adapter->watchdog_timer, jiffies); - } + if (unlikely(icr & (IXGB_INT_RXSEQ | IXGB_INT_LSC))) + if (!test_bit(__IXGB_DOWN, &adapter->flags)) + mod_timer(&adapter->watchdog_timer, jiffies); #ifdef CONFIG_IXGB_NAPI if(netif_rx_schedule_prep(netdev)) { @@ -1750,7 +1763,6 @@ ixgb_intr(int irq, void *data, struct pt_regs *regs) of the posted write is intentionally left out. */ - atomic_inc(&adapter->irq_sem); IXGB_WRITE_REG(&adapter->hw, IMC, ~0); __netif_rx_schedule(netdev); } @@ -1778,19 +1790,18 @@ ixgb_clean(struct net_device *netdev, int *budget) { struct ixgb_adapter *adapter = netdev_priv(netdev); int work_to_do = min(*budget, netdev->quota); - int tx_cleaned; int work_done = 0; - tx_cleaned = ixgb_clean_tx_irq(adapter); + ixgb_clean_tx_irq(adapter); ixgb_clean_rx_irq(adapter, &work_done, work_to_do); *budget -= work_done; netdev->quota -= work_done; - /* if no Tx and not enough Rx work done, exit the polling mode */ - if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { + if ((work_done < *budget) || !netif_running(netdev)) { netif_rx_complete(netdev); - ixgb_irq_enable(adapter); + if (!test_bit(__IXGB_DOWN, &adapter->flags)) + ixgb_irq_enable(adapter); return 0; } @@ -2080,14 +2091,12 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter) struct ixgb_buffer *buffer_info; struct sk_buff *skb; unsigned int i; - int num_group_tail_writes; long cleancount; i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; cleancount = IXGB_DESC_UNUSED(rx_ring); - num_group_tail_writes = IXGB_RX_BUFFER_WRITE; /* leave three descriptors unused */ while(--cleancount > 2) { @@ -2187,7 +2196,9 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) IXGB_WRITE_REG(&adapter->hw, RCTL, rctl); } - ixgb_irq_enable(adapter); + /* don't enable interrupts unless we are UP */ + if (adapter->netdev->flags & IFF_UP) + ixgb_irq_enable(adapter); } static void @@ -2215,9 +2226,11 @@ ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) if(adapter->vlgrp) adapter->vlgrp->vlan_devices[vid] = NULL; - ixgb_irq_enable(adapter); + /* don't enable interrupts unless we are UP */ + if (adapter->netdev->flags & IFF_UP) + ixgb_irq_enable(adapter); - /* remove VID from filter table*/ + /* remove VID from filter table */ index = (vid >> 5) & 0x7F; vfta = IXGB_READ_REG_ARRAY(&adapter->hw, VFTA, index);