From: AMEET M. PARANJAPE <aparanja@redhat.com> Date: Wed, 5 Nov 2008 17:10:42 -0500 Subject: [net] bnx2: prevent ethtool -r EEH event Message-id: 20081105221007.9395.9816.sendpatchset@squad5-lp1.lab.bos.redhat.com O-Subject: [PATCH RHEL5.3 BZ469962] bnx2: prevent ethtool -r EEH event Bugzilla: 469962 RH-Acked-by: Andy Gospodarek <gospo@redhat.com> RH-Acked-by: David Howells <dhowells@redhat.com> RH-Acked-by: John W. Linville <linville@redhat.com> RHBZ#: ====== https://bugzilla.redhat.com/show_bug.cgi?id=469962 Description: =========== We need to check netif_running() state in most ethtool operations and properly handle the !netif_running() state where the chip is in an uninitailzed state or low power state that may not accept any I/O. RHEL Version Found: ================ RHEL 5.3 Beta kABI Status: ============ No symbols were harmed. Brew: ===== Built on all platforms. http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1559090 Upstream Status: ================ The fixes for this are upstream in mainline at: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=9f52b564b7162ede5a73a4f4b421ccf93c55b025 and http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=74bf4ba3d367aacbc04fef167289767f162cd730 Test Status: ============ Before the patch these steps: 1. ifconfig or ifup the adapter, test ping 2. ifdown or ifconfig ethX down on the adapter 3. run 'ethtool -r ethX' would cause and EEH event. With the patch this does not happen. =============================================================== Ameet Paranjape 978-392-3903 ext 23903 IBM on-site partner Proposed Patch: =============== diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index c77f2ba..9106ea7 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3223,6 +3223,9 @@ bnx2_set_rx_mode(struct net_device *dev) u32 rx_mode, sort_mode; int i; + if (!netif_running(dev)) + return; + spin_lock_bh(&bp->phy_lock); rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS | @@ -5106,6 +5109,21 @@ bnx2_init_nic(struct bnx2 *bp, int reset_phy) } static int +bnx2_shutdown_chip(struct bnx2 *bp) +{ + u32 reset_code; + + if (bp->flags & BNX2_FLAG_NO_WOL) + reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; + else if (bp->wol) + reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; + else + reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; + + return bnx2_reset_chip(bp, reset_code); +} + +static int bnx2_test_registers(struct bnx2 *bp) { int ret; @@ -5539,6 +5557,9 @@ bnx2_test_link(struct bnx2 *bp) { u32 bmsr; + if (!netif_running(bp->dev)) + return -ENODEV; + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { if (bp->link_up) return 0; @@ -6133,7 +6154,6 @@ static int bnx2_close(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); - u32 reset_code; /* Calling flush_scheduled_work() may deadlock because * linkwatch_event() may be on the workqueue and it will try to get @@ -6145,13 +6165,7 @@ bnx2_close(struct net_device *dev) bnx2_netif_stop(bp); bnx2_napi_disable(bp); del_timer_sync(&bp->timer); - if (bp->flags & BNX2_FLAG_NO_WOL) - reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; - else if (bp->wol) - reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; - else - reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; - bnx2_reset_chip(bp, reset_code); + bnx2_shutdown_chip(bp); bnx2_free_irq(bp); bnx2_free_skbs(bp); bnx2_free_mem(bp); @@ -6520,6 +6534,9 @@ bnx2_nway_reset(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); u32 bmcr; + if (!netif_running(dev)) + return -EAGAIN; + if (!(bp->autoneg & AUTONEG_SPEED)) { return -EINVAL; } @@ -6575,6 +6592,9 @@ bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct bnx2 *bp = netdev_priv(dev); int rc; + if (!netif_running(dev)) + return -EAGAIN; + /* parameters already validated in ethtool_get_eeprom */ rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); @@ -6589,6 +6609,9 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct bnx2 *bp = netdev_priv(dev); int rc; + if (!netif_running(dev)) + return -EAGAIN; + /* parameters already validated in ethtool_set_eeprom */ rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); @@ -6753,11 +6776,11 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) bp->autoneg &= ~AUTONEG_FLOW_CTRL; } - spin_lock_bh(&bp->phy_lock); - - bnx2_setup_phy(bp, bp->phy_port); - - spin_unlock_bh(&bp->phy_lock); + if (netif_running(dev)) { + spin_lock_bh(&bp->phy_lock); + bnx2_setup_phy(bp, bp->phy_port); + spin_unlock_bh(&bp->phy_lock); + } return 0; } @@ -6941,6 +6964,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) { struct bnx2 *bp = netdev_priv(dev); + bnx2_set_power_state(bp, PCI_D0); + memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS); if (etest->flags & ETH_TEST_FL_OFFLINE) { int i; @@ -6960,9 +6985,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) if ((buf[2] = bnx2_test_loopback(bp)) != 0) etest->flags |= ETH_TEST_FL_FAILED; - if (!netif_running(bp->dev)) { - bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); - } + if (!netif_running(bp->dev)) + bnx2_shutdown_chip(bp); else { bnx2_init_nic(bp, 1); bnx2_netif_start(bp); @@ -6990,6 +7014,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) etest->flags |= ETH_TEST_FL_FAILED; } + if (!netif_running(bp->dev)) + bnx2_set_power_state(bp, PCI_D3hot); } static void @@ -7061,6 +7087,8 @@ bnx2_phys_id(struct net_device *dev, u32 data) int i; u32 save; + bnx2_set_power_state(bp, PCI_D0); + if (data == 0) data = 2; @@ -7085,6 +7113,10 @@ bnx2_phys_id(struct net_device *dev, u32 data) } REG_WR(bp, BNX2_EMAC_LED, 0); REG_WR(bp, BNX2_MISC_CFG, save); + + if (!netif_running(dev)) + bnx2_set_power_state(bp, PCI_D3hot); + return 0; } @@ -7850,7 +7882,6 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct bnx2 *bp = netdev_priv(dev); - u32 reset_code; /* PCI register 4 needs to be saved whether netif_running() or not. * MSI address and data need to be saved if using MSI and @@ -7864,13 +7895,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) bnx2_netif_stop(bp); netif_device_detach(dev); del_timer_sync(&bp->timer); - if (bp->flags & BNX2_FLAG_NO_WOL) - reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; - else if (bp->wol) - reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; - else - reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; - bnx2_reset_chip(bp, reset_code); + bnx2_shutdown_chip(bp); bnx2_free_skbs(bp); bnx2_set_power_state(bp, pci_choose_state(pdev, state)); return 0;