diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-11-30 20:34:37 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-12-02 16:01:49 -0500 |
| commit | 8496e85c20e7836b3dec97780e40f420a3ae2801 (patch) | |
| tree | 9859b6aad0ebc29acd964d46b8236b6af05b8ec4 /drivers | |
| parent | 30e56918dd1e6d64350661f186657f6a6f2646e6 (diff) | |
PCI / tg3: Give up chip reset and carrier loss handling if PCI device is not present
Modify tg3_chip_reset() and tg3_close() to check if the PCI network
adapter device is accessible at all in order to skip poking it or
trying to handle a carrier loss in vain when that's not the case.
Introduce a special PCI helper function pci_device_is_present()
for this purpose.
Of course, this uncovers the lack of the appropriate RTNL locking
in tg3_suspend() and tg3_resume(), so add that locking in there
too.
These changes prevent tg3 from burning a CPU at 100% load level for
solid several seconds after the Thunderbolt link is disconnected from
a Matrox DS1 docking station.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 26 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 8 |
2 files changed, 27 insertions, 7 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 369b736dde05..472305cdff4f 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c | |||
| @@ -8932,6 +8932,9 @@ static int tg3_chip_reset(struct tg3 *tp) | |||
| 8932 | void (*write_op)(struct tg3 *, u32, u32); | 8932 | void (*write_op)(struct tg3 *, u32, u32); |
| 8933 | int i, err; | 8933 | int i, err; |
| 8934 | 8934 | ||
| 8935 | if (!pci_device_is_present(tp->pdev)) | ||
| 8936 | return -ENODEV; | ||
| 8937 | |||
| 8935 | tg3_nvram_lock(tp); | 8938 | tg3_nvram_lock(tp); |
| 8936 | 8939 | ||
| 8937 | tg3_ape_lock(tp, TG3_APE_LOCK_GRC); | 8940 | tg3_ape_lock(tp, TG3_APE_LOCK_GRC); |
| @@ -11581,10 +11584,11 @@ static int tg3_close(struct net_device *dev) | |||
| 11581 | memset(&tp->net_stats_prev, 0, sizeof(tp->net_stats_prev)); | 11584 | memset(&tp->net_stats_prev, 0, sizeof(tp->net_stats_prev)); |
| 11582 | memset(&tp->estats_prev, 0, sizeof(tp->estats_prev)); | 11585 | memset(&tp->estats_prev, 0, sizeof(tp->estats_prev)); |
| 11583 | 11586 | ||
| 11584 | tg3_power_down_prepare(tp); | 11587 | if (pci_device_is_present(tp->pdev)) { |
| 11585 | 11588 | tg3_power_down_prepare(tp); | |
| 11586 | tg3_carrier_off(tp); | ||
| 11587 | 11589 | ||
| 11590 | tg3_carrier_off(tp); | ||
| 11591 | } | ||
| 11588 | return 0; | 11592 | return 0; |
| 11589 | } | 11593 | } |
| 11590 | 11594 | ||
| @@ -17726,10 +17730,12 @@ static int tg3_suspend(struct device *device) | |||
| 17726 | struct pci_dev *pdev = to_pci_dev(device); | 17730 | struct pci_dev *pdev = to_pci_dev(device); |
| 17727 | struct net_device *dev = pci_get_drvdata(pdev); | 17731 | struct net_device *dev = pci_get_drvdata(pdev); |
| 17728 | struct tg3 *tp = netdev_priv(dev); | 17732 | struct tg3 *tp = netdev_priv(dev); |
| 17729 | int err; | 17733 | int err = 0; |
| 17734 | |||
| 17735 | rtnl_lock(); | ||
| 17730 | 17736 | ||
| 17731 | if (!netif_running(dev)) | 17737 | if (!netif_running(dev)) |
| 17732 | return 0; | 17738 | goto unlock; |
| 17733 | 17739 | ||
| 17734 | tg3_reset_task_cancel(tp); | 17740 | tg3_reset_task_cancel(tp); |
| 17735 | tg3_phy_stop(tp); | 17741 | tg3_phy_stop(tp); |
| @@ -17771,6 +17777,8 @@ out: | |||
| 17771 | tg3_phy_start(tp); | 17777 | tg3_phy_start(tp); |
| 17772 | } | 17778 | } |
| 17773 | 17779 | ||
| 17780 | unlock: | ||
| 17781 | rtnl_unlock(); | ||
| 17774 | return err; | 17782 | return err; |
| 17775 | } | 17783 | } |
| 17776 | 17784 | ||
| @@ -17779,10 +17787,12 @@ static int tg3_resume(struct device *device) | |||
| 17779 | struct pci_dev *pdev = to_pci_dev(device); | 17787 | struct pci_dev *pdev = to_pci_dev(device); |
| 17780 | struct net_device *dev = pci_get_drvdata(pdev); | 17788 | struct net_device *dev = pci_get_drvdata(pdev); |
| 17781 | struct tg3 *tp = netdev_priv(dev); | 17789 | struct tg3 *tp = netdev_priv(dev); |
| 17782 | int err; | 17790 | int err = 0; |
| 17791 | |||
| 17792 | rtnl_lock(); | ||
| 17783 | 17793 | ||
| 17784 | if (!netif_running(dev)) | 17794 | if (!netif_running(dev)) |
| 17785 | return 0; | 17795 | goto unlock; |
| 17786 | 17796 | ||
| 17787 | netif_device_attach(dev); | 17797 | netif_device_attach(dev); |
| 17788 | 17798 | ||
| @@ -17806,6 +17816,8 @@ out: | |||
| 17806 | if (!err) | 17816 | if (!err) |
| 17807 | tg3_phy_start(tp); | 17817 | tg3_phy_start(tp); |
| 17808 | 17818 | ||
| 17819 | unlock: | ||
| 17820 | rtnl_unlock(); | ||
| 17809 | return err; | 17821 | return err; |
| 17810 | } | 17822 | } |
| 17811 | #endif /* CONFIG_PM_SLEEP */ | 17823 | #endif /* CONFIG_PM_SLEEP */ |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 33120d156668..07369f32e8bb 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -4165,6 +4165,14 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, | |||
| 4165 | return 0; | 4165 | return 0; |
| 4166 | } | 4166 | } |
| 4167 | 4167 | ||
| 4168 | bool pci_device_is_present(struct pci_dev *pdev) | ||
| 4169 | { | ||
| 4170 | u32 v; | ||
| 4171 | |||
| 4172 | return pci_bus_read_dev_vendor_id(pdev->bus, pdev->devfn, &v, 0); | ||
| 4173 | } | ||
| 4174 | EXPORT_SYMBOL_GPL(pci_device_is_present); | ||
| 4175 | |||
| 4168 | #define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE | 4176 | #define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE |
| 4169 | static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0}; | 4177 | static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0}; |
| 4170 | static DEFINE_SPINLOCK(resource_alignment_lock); | 4178 | static DEFINE_SPINLOCK(resource_alignment_lock); |
