Commit 8496e85c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by David S. Miller

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: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 30e56918
...@@ -8932,6 +8932,9 @@ static int tg3_chip_reset(struct tg3 *tp) ...@@ -8932,6 +8932,9 @@ static int tg3_chip_reset(struct tg3 *tp)
void (*write_op)(struct tg3 *, u32, u32); void (*write_op)(struct tg3 *, u32, u32);
int i, err; int i, err;
if (!pci_device_is_present(tp->pdev))
return -ENODEV;
tg3_nvram_lock(tp); tg3_nvram_lock(tp);
tg3_ape_lock(tp, TG3_APE_LOCK_GRC); tg3_ape_lock(tp, TG3_APE_LOCK_GRC);
...@@ -11581,10 +11584,11 @@ static int tg3_close(struct net_device *dev) ...@@ -11581,10 +11584,11 @@ static int tg3_close(struct net_device *dev)
memset(&tp->net_stats_prev, 0, sizeof(tp->net_stats_prev)); memset(&tp->net_stats_prev, 0, sizeof(tp->net_stats_prev));
memset(&tp->estats_prev, 0, sizeof(tp->estats_prev)); memset(&tp->estats_prev, 0, sizeof(tp->estats_prev));
tg3_power_down_prepare(tp); if (pci_device_is_present(tp->pdev)) {
tg3_power_down_prepare(tp);
tg3_carrier_off(tp);
tg3_carrier_off(tp);
}
return 0; return 0;
} }
...@@ -17726,10 +17730,12 @@ static int tg3_suspend(struct device *device) ...@@ -17726,10 +17730,12 @@ static int tg3_suspend(struct device *device)
struct pci_dev *pdev = to_pci_dev(device); struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
int err; int err = 0;
rtnl_lock();
if (!netif_running(dev)) if (!netif_running(dev))
return 0; goto unlock;
tg3_reset_task_cancel(tp); tg3_reset_task_cancel(tp);
tg3_phy_stop(tp); tg3_phy_stop(tp);
...@@ -17771,6 +17777,8 @@ static int tg3_suspend(struct device *device) ...@@ -17771,6 +17777,8 @@ static int tg3_suspend(struct device *device)
tg3_phy_start(tp); tg3_phy_start(tp);
} }
unlock:
rtnl_unlock();
return err; return err;
} }
...@@ -17779,10 +17787,12 @@ static int tg3_resume(struct device *device) ...@@ -17779,10 +17787,12 @@ static int tg3_resume(struct device *device)
struct pci_dev *pdev = to_pci_dev(device); struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
int err; int err = 0;
rtnl_lock();
if (!netif_running(dev)) if (!netif_running(dev))
return 0; goto unlock;
netif_device_attach(dev); netif_device_attach(dev);
...@@ -17806,6 +17816,8 @@ static int tg3_resume(struct device *device) ...@@ -17806,6 +17816,8 @@ static int tg3_resume(struct device *device)
if (!err) if (!err)
tg3_phy_start(tp); tg3_phy_start(tp);
unlock:
rtnl_unlock();
return err; return err;
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
......
...@@ -4165,6 +4165,14 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, ...@@ -4165,6 +4165,14 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
return 0; return 0;
} }
bool pci_device_is_present(struct pci_dev *pdev)
{
u32 v;
return pci_bus_read_dev_vendor_id(pdev->bus, pdev->devfn, &v, 0);
}
EXPORT_SYMBOL_GPL(pci_device_is_present);
#define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE #define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE
static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0}; static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0};
static DEFINE_SPINLOCK(resource_alignment_lock); static DEFINE_SPINLOCK(resource_alignment_lock);
......
...@@ -960,6 +960,7 @@ void pci_update_resource(struct pci_dev *dev, int resno); ...@@ -960,6 +960,7 @@ void pci_update_resource(struct pci_dev *dev, int resno);
int __must_check pci_assign_resource(struct pci_dev *dev, int i); int __must_check pci_assign_resource(struct pci_dev *dev, int i);
int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align); int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
int pci_select_bars(struct pci_dev *dev, unsigned long flags); int pci_select_bars(struct pci_dev *dev, unsigned long flags);
bool pci_device_is_present(struct pci_dev *pdev);
/* ROM control related routines */ /* ROM control related routines */
int pci_enable_rom(struct pci_dev *pdev); int pci_enable_rom(struct pci_dev *pdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment