diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-11 15:10:18 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-11 15:10:18 -0800 |
commit | 5833291ab6de9c3e2374336b51c814e515e8f3a5 (patch) | |
tree | 65eaac2536356b0741266926ae70b2924d2565d3 /drivers/pci/pci-driver.c | |
parent | ca2ef2d9f2aad7a28d346522bb4c473a0aa05249 (diff) | |
parent | e0217c5ba10d7bf640f038b2feae58e630f2f958 (diff) |
Merge tag 'pci-v5.16-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI fixes from Bjorn Helgaas:
"Revert conversion to struct device.driver instead of struct
pci_dev.driver.
The device.driver is set earlier, and using it caused the PCI core to
call driver PM entry points before .probe() and after .remove(), when
the driver isn't prepared.
This caused NULL pointer dereferences in i2c_designware_pci and
probably other driver issues"
* tag 'pci-v5.16-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
Revert "PCI: Use to_pci_driver() instead of pci_dev->driver"
Revert "PCI: Remove struct pci_dev->driver"
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r-- | drivers/pci/pci-driver.c | 37 |
1 files changed, 20 insertions, 17 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 1d98c974381c..588588cfda48 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -319,10 +319,12 @@ static long local_pci_probe(void *_ddi) * its remove routine. */ pm_runtime_get_sync(dev); + pci_dev->driver = pci_drv; rc = pci_drv->probe(pci_dev, ddi->id); if (!rc) return rc; if (rc < 0) { + pci_dev->driver = NULL; pm_runtime_put_sync(dev); return rc; } @@ -388,6 +390,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, * @pci_dev: PCI device being probed * * returns 0 on success, else error. + * side-effect: pci_dev->driver is set to drv when drv claims pci_dev. */ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) { @@ -454,7 +457,7 @@ static int pci_device_probe(struct device *dev) static void pci_device_remove(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = to_pci_driver(dev->driver); + struct pci_driver *drv = pci_dev->driver; if (drv->remove) { pm_runtime_get_sync(dev); @@ -462,6 +465,7 @@ static void pci_device_remove(struct device *dev) pm_runtime_put_noidle(dev); } pcibios_free_irq(pci_dev); + pci_dev->driver = NULL; pci_iov_remove(pci_dev); /* Undo the runtime PM settings in local_pci_probe() */ @@ -489,7 +493,7 @@ static void pci_device_remove(struct device *dev) static void pci_device_shutdown(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = to_pci_driver(dev->driver); + struct pci_driver *drv = pci_dev->driver; pm_runtime_resume(dev); @@ -585,7 +589,7 @@ static int pci_pm_reenable_device(struct pci_dev *pci_dev) static int pci_legacy_suspend(struct device *dev, pm_message_t state) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = to_pci_driver(dev->driver); + struct pci_driver *drv = pci_dev->driver; if (drv && drv->suspend) { pci_power_t prev = pci_dev->current_state; @@ -626,7 +630,7 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) static int pci_legacy_resume(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = to_pci_driver(dev->driver); + struct pci_driver *drv = pci_dev->driver; pci_fixup_device(pci_fixup_resume, pci_dev); @@ -645,7 +649,7 @@ static void pci_pm_default_suspend(struct pci_dev *pci_dev) static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) { - struct pci_driver *drv = to_pci_driver(pci_dev->dev.driver); + struct pci_driver *drv = pci_dev->driver; bool ret = drv && (drv->suspend || drv->resume); /* @@ -1238,11 +1242,11 @@ static int pci_pm_runtime_suspend(struct device *dev) int error; /* - * If the device has no driver, we leave it in D0, but it may go to - * D3cold when the bridge above it runtime suspends. Save its - * config space in case that happens. + * If pci_dev->driver is not set (unbound), we leave the device in D0, + * but it may go to D3cold when the bridge above it runtime suspends. + * Save its config space in case that happens. */ - if (!to_pci_driver(dev->driver)) { + if (!pci_dev->driver) { pci_save_state(pci_dev); return 0; } @@ -1299,7 +1303,7 @@ static int pci_pm_runtime_resume(struct device *dev) */ pci_restore_standard_config(pci_dev); - if (!to_pci_driver(dev->driver)) + if (!pci_dev->driver) return 0; pci_fixup_device(pci_fixup_resume_early, pci_dev); @@ -1318,13 +1322,14 @@ static int pci_pm_runtime_resume(struct device *dev) static int pci_pm_runtime_idle(struct device *dev) { + struct pci_dev *pci_dev = to_pci_dev(dev); const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; /* - * If the device has no driver, it should always remain in D0 - * regardless of the runtime PM status + * If pci_dev->driver is not set (unbound), the device should + * always remain in D0 regardless of the runtime PM status */ - if (!to_pci_driver(dev->driver)) + if (!pci_dev->driver) return 0; if (!pm) @@ -1431,10 +1436,8 @@ static struct pci_driver pci_compat_driver = { */ struct pci_driver *pci_dev_driver(const struct pci_dev *dev) { - struct pci_driver *drv = to_pci_driver(dev->dev.driver); - - if (drv) - return drv; + if (dev->driver) + return dev->driver; else { int i; for (i = 0; i <= PCI_ROM_RESOURCE; i++) |