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>
This commit is contained in:
parent
30e56918dd
commit
8496e85c20
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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);
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue