aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Vecera <ivecera@redhat.com>2014-09-01 08:21:57 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-02 16:02:19 -0400
commit0486a063b1ffce4f37ef80970689c64bf7b99e98 (patch)
treef0a5e2997aa20d3d23ea7b23009e1e852e10a787
parent88e4194712496ace4a24d7541a83f910f0326ef0 (diff)
tg3: prevent ifup/ifdown during PCI error recovery
The patch fixes race conditions between PCI error recovery callbacks and potential ifup/ifdown. First, if ifup (tg3_open) is called between tg3_io_error_detected() and tg3_io_resume() then tp->timer is armed twice before expiry. Once during tg3_open() and again during tg3_io_resume(). This results in BUG at kernel/time/timer.c:945. Second, if ifdown (tg3_close) is called between tg3_io_error_detected() and tg3_io_resume() then tg3_napi_disable() is called twice without a tg3_napi_enable between. Once during tg3_io_error_detected() and again during tg3_close(). The tg3_io_resume() then hangs on rtnl_lock(). v2: Added logging messages per Prashant's request Cc: Prashant Sreedharan <prashant@broadcom.com> Cc: Michael Chan <mchan@broadcom.com> Signed-off-by: Ivan Vecera <ivecera@redhat.com> Acked-by: Prashant Sreedharan <prashant@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c16
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h1
2 files changed, 17 insertions, 0 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 3ac5d23454a8..cb77ae93d89a 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -11617,6 +11617,12 @@ static int tg3_open(struct net_device *dev)
11617 struct tg3 *tp = netdev_priv(dev); 11617 struct tg3 *tp = netdev_priv(dev);
11618 int err; 11618 int err;
11619 11619
11620 if (tp->pcierr_recovery) {
11621 netdev_err(dev, "Failed to open device. PCI error recovery "
11622 "in progress\n");
11623 return -EAGAIN;
11624 }
11625
11620 if (tp->fw_needed) { 11626 if (tp->fw_needed) {
11621 err = tg3_request_firmware(tp); 11627 err = tg3_request_firmware(tp);
11622 if (tg3_asic_rev(tp) == ASIC_REV_57766) { 11628 if (tg3_asic_rev(tp) == ASIC_REV_57766) {
@@ -11674,6 +11680,12 @@ static int tg3_close(struct net_device *dev)
11674{ 11680{
11675 struct tg3 *tp = netdev_priv(dev); 11681 struct tg3 *tp = netdev_priv(dev);
11676 11682
11683 if (tp->pcierr_recovery) {
11684 netdev_err(dev, "Failed to close device. PCI error recovery "
11685 "in progress\n");
11686 return -EAGAIN;
11687 }
11688
11677 tg3_ptp_fini(tp); 11689 tg3_ptp_fini(tp);
11678 11690
11679 tg3_stop(tp); 11691 tg3_stop(tp);
@@ -17561,6 +17573,7 @@ static int tg3_init_one(struct pci_dev *pdev,
17561 tp->rx_mode = TG3_DEF_RX_MODE; 17573 tp->rx_mode = TG3_DEF_RX_MODE;
17562 tp->tx_mode = TG3_DEF_TX_MODE; 17574 tp->tx_mode = TG3_DEF_TX_MODE;
17563 tp->irq_sync = 1; 17575 tp->irq_sync = 1;
17576 tp->pcierr_recovery = false;
17564 17577
17565 if (tg3_debug > 0) 17578 if (tg3_debug > 0)
17566 tp->msg_enable = tg3_debug; 17579 tp->msg_enable = tg3_debug;
@@ -18071,6 +18084,8 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
18071 18084
18072 rtnl_lock(); 18085 rtnl_lock();
18073 18086
18087 tp->pcierr_recovery = true;
18088
18074 /* We probably don't have netdev yet */ 18089 /* We probably don't have netdev yet */
18075 if (!netdev || !netif_running(netdev)) 18090 if (!netdev || !netif_running(netdev))
18076 goto done; 18091 goto done;
@@ -18195,6 +18210,7 @@ static void tg3_io_resume(struct pci_dev *pdev)
18195 tg3_phy_start(tp); 18210 tg3_phy_start(tp);
18196 18211
18197done: 18212done:
18213 tp->pcierr_recovery = false;
18198 rtnl_unlock(); 18214 rtnl_unlock();
18199} 18215}
18200 18216
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 461accaf0aa4..31c9f8295953 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -3407,6 +3407,7 @@ struct tg3 {
3407 3407
3408 struct device *hwmon_dev; 3408 struct device *hwmon_dev;
3409 bool link_up; 3409 bool link_up;
3410 bool pcierr_recovery;
3410}; 3411};
3411 3412
3412/* Accessor macros for chip and asic attributes 3413/* Accessor macros for chip and asic attributes