Commit 5833291a authored by Linus Torvalds's avatar Linus Torvalds

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"
parents ca2ef2d9 e0217c5b
...@@ -164,15 +164,13 @@ static ssize_t sriov_vf_total_msix_show(struct device *dev, ...@@ -164,15 +164,13 @@ static ssize_t sriov_vf_total_msix_show(struct device *dev,
char *buf) char *buf)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct pci_driver *pdrv;
u32 vf_total_msix = 0; u32 vf_total_msix = 0;
device_lock(dev); device_lock(dev);
pdrv = to_pci_driver(dev->driver); if (!pdev->driver || !pdev->driver->sriov_get_vf_total_msix)
if (!pdrv || !pdrv->sriov_get_vf_total_msix)
goto unlock; goto unlock;
vf_total_msix = pdrv->sriov_get_vf_total_msix(pdev); vf_total_msix = pdev->driver->sriov_get_vf_total_msix(pdev);
unlock: unlock:
device_unlock(dev); device_unlock(dev);
return sysfs_emit(buf, "%u\n", vf_total_msix); return sysfs_emit(buf, "%u\n", vf_total_msix);
...@@ -185,7 +183,6 @@ static ssize_t sriov_vf_msix_count_store(struct device *dev, ...@@ -185,7 +183,6 @@ static ssize_t sriov_vf_msix_count_store(struct device *dev,
{ {
struct pci_dev *vf_dev = to_pci_dev(dev); struct pci_dev *vf_dev = to_pci_dev(dev);
struct pci_dev *pdev = pci_physfn(vf_dev); struct pci_dev *pdev = pci_physfn(vf_dev);
struct pci_driver *pdrv;
int val, ret = 0; int val, ret = 0;
if (kstrtoint(buf, 0, &val) < 0) if (kstrtoint(buf, 0, &val) < 0)
...@@ -195,14 +192,13 @@ static ssize_t sriov_vf_msix_count_store(struct device *dev, ...@@ -195,14 +192,13 @@ static ssize_t sriov_vf_msix_count_store(struct device *dev,
return -EINVAL; return -EINVAL;
device_lock(&pdev->dev); device_lock(&pdev->dev);
pdrv = to_pci_driver(dev->driver); if (!pdev->driver || !pdev->driver->sriov_set_msix_vec_count) {
if (!pdrv || !pdrv->sriov_set_msix_vec_count) {
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto err_pdev; goto err_pdev;
} }
device_lock(&vf_dev->dev); device_lock(&vf_dev->dev);
if (to_pci_driver(vf_dev->dev.driver)) { if (vf_dev->driver) {
/* /*
* A driver is already attached to this VF and has configured * A driver is already attached to this VF and has configured
* itself based on the current MSI-X vector count. Changing * itself based on the current MSI-X vector count. Changing
...@@ -212,7 +208,7 @@ static ssize_t sriov_vf_msix_count_store(struct device *dev, ...@@ -212,7 +208,7 @@ static ssize_t sriov_vf_msix_count_store(struct device *dev,
goto err_dev; goto err_dev;
} }
ret = pdrv->sriov_set_msix_vec_count(vf_dev, val); ret = pdev->driver->sriov_set_msix_vec_count(vf_dev, val);
err_dev: err_dev:
device_unlock(&vf_dev->dev); device_unlock(&vf_dev->dev);
...@@ -379,7 +375,6 @@ static ssize_t sriov_numvfs_store(struct device *dev, ...@@ -379,7 +375,6 @@ static ssize_t sriov_numvfs_store(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct pci_driver *pdrv;
int ret = 0; int ret = 0;
u16 num_vfs; u16 num_vfs;
...@@ -395,15 +390,14 @@ static ssize_t sriov_numvfs_store(struct device *dev, ...@@ -395,15 +390,14 @@ static ssize_t sriov_numvfs_store(struct device *dev,
goto exit; goto exit;
/* is PF driver loaded */ /* is PF driver loaded */
pdrv = to_pci_driver(dev->driver); if (!pdev->driver) {
if (!pdrv) {
pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n"); pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n");
ret = -ENOENT; ret = -ENOENT;
goto exit; goto exit;
} }
/* is PF driver loaded w/callback */ /* is PF driver loaded w/callback */
if (!pdrv->sriov_configure) { if (!pdev->driver->sriov_configure) {
pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n"); pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n");
ret = -ENOENT; ret = -ENOENT;
goto exit; goto exit;
...@@ -411,7 +405,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, ...@@ -411,7 +405,7 @@ static ssize_t sriov_numvfs_store(struct device *dev,
if (num_vfs == 0) { if (num_vfs == 0) {
/* disable VFs */ /* disable VFs */
ret = pdrv->sriov_configure(pdev, 0); ret = pdev->driver->sriov_configure(pdev, 0);
goto exit; goto exit;
} }
...@@ -423,7 +417,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, ...@@ -423,7 +417,7 @@ static ssize_t sriov_numvfs_store(struct device *dev,
goto exit; goto exit;
} }
ret = pdrv->sriov_configure(pdev, num_vfs); ret = pdev->driver->sriov_configure(pdev, num_vfs);
if (ret < 0) if (ret < 0)
goto exit; goto exit;
......
...@@ -319,10 +319,12 @@ static long local_pci_probe(void *_ddi) ...@@ -319,10 +319,12 @@ static long local_pci_probe(void *_ddi)
* its remove routine. * its remove routine.
*/ */
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
pci_dev->driver = pci_drv;
rc = pci_drv->probe(pci_dev, ddi->id); rc = pci_drv->probe(pci_dev, ddi->id);
if (!rc) if (!rc)
return rc; return rc;
if (rc < 0) { if (rc < 0) {
pci_dev->driver = NULL;
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
return rc; return rc;
} }
...@@ -388,6 +390,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, ...@@ -388,6 +390,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
* @pci_dev: PCI device being probed * @pci_dev: PCI device being probed
* *
* returns 0 on success, else error. * 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) 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) ...@@ -454,7 +457,7 @@ static int pci_device_probe(struct device *dev)
static void pci_device_remove(struct device *dev) static void pci_device_remove(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(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) { if (drv->remove) {
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
...@@ -462,6 +465,7 @@ static void pci_device_remove(struct device *dev) ...@@ -462,6 +465,7 @@ static void pci_device_remove(struct device *dev)
pm_runtime_put_noidle(dev); pm_runtime_put_noidle(dev);
} }
pcibios_free_irq(pci_dev); pcibios_free_irq(pci_dev);
pci_dev->driver = NULL;
pci_iov_remove(pci_dev); pci_iov_remove(pci_dev);
/* Undo the runtime PM settings in local_pci_probe() */ /* Undo the runtime PM settings in local_pci_probe() */
...@@ -489,7 +493,7 @@ static void pci_device_remove(struct device *dev) ...@@ -489,7 +493,7 @@ static void pci_device_remove(struct device *dev)
static void pci_device_shutdown(struct device *dev) static void pci_device_shutdown(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(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); pm_runtime_resume(dev);
...@@ -585,7 +589,7 @@ static int pci_pm_reenable_device(struct pci_dev *pci_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) static int pci_legacy_suspend(struct device *dev, pm_message_t state)
{ {
struct pci_dev *pci_dev = to_pci_dev(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 && drv->suspend) { if (drv && drv->suspend) {
pci_power_t prev = pci_dev->current_state; 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) ...@@ -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) static int pci_legacy_resume(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(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); pci_fixup_device(pci_fixup_resume, pci_dev);
...@@ -645,7 +649,7 @@ static void pci_pm_default_suspend(struct pci_dev *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) 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); bool ret = drv && (drv->suspend || drv->resume);
/* /*
...@@ -1238,11 +1242,11 @@ static int pci_pm_runtime_suspend(struct device *dev) ...@@ -1238,11 +1242,11 @@ static int pci_pm_runtime_suspend(struct device *dev)
int error; int error;
/* /*
* If the device has no driver, we leave it in D0, but it may go to * If pci_dev->driver is not set (unbound), we leave the device in D0,
* D3cold when the bridge above it runtime suspends. Save its * but it may go to D3cold when the bridge above it runtime suspends.
* config space in case that happens. * Save its config space in case that happens.
*/ */
if (!to_pci_driver(dev->driver)) { if (!pci_dev->driver) {
pci_save_state(pci_dev); pci_save_state(pci_dev);
return 0; return 0;
} }
...@@ -1299,7 +1303,7 @@ static int pci_pm_runtime_resume(struct device *dev) ...@@ -1299,7 +1303,7 @@ static int pci_pm_runtime_resume(struct device *dev)
*/ */
pci_restore_standard_config(pci_dev); pci_restore_standard_config(pci_dev);
if (!to_pci_driver(dev->driver)) if (!pci_dev->driver)
return 0; return 0;
pci_fixup_device(pci_fixup_resume_early, pci_dev); pci_fixup_device(pci_fixup_resume_early, pci_dev);
...@@ -1318,13 +1322,14 @@ static int pci_pm_runtime_resume(struct device *dev) ...@@ -1318,13 +1322,14 @@ static int pci_pm_runtime_resume(struct device *dev)
static int pci_pm_runtime_idle(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; const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
/* /*
* If the device has no driver, it should always remain in D0 * If pci_dev->driver is not set (unbound), the device should
* regardless of the runtime PM status * always remain in D0 regardless of the runtime PM status
*/ */
if (!to_pci_driver(dev->driver)) if (!pci_dev->driver)
return 0; return 0;
if (!pm) if (!pm)
...@@ -1431,10 +1436,8 @@ static struct pci_driver pci_compat_driver = { ...@@ -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 *pci_dev_driver(const struct pci_dev *dev)
{ {
struct pci_driver *drv = to_pci_driver(dev->dev.driver); if (dev->driver)
return dev->driver;
if (drv)
return drv;
else { else {
int i; int i;
for (i = 0; i <= PCI_ROM_RESOURCE; i++) for (i = 0; i <= PCI_ROM_RESOURCE; i++)
......
...@@ -5135,14 +5135,13 @@ EXPORT_SYMBOL_GPL(pci_dev_unlock); ...@@ -5135,14 +5135,13 @@ EXPORT_SYMBOL_GPL(pci_dev_unlock);
static void pci_dev_save_and_disable(struct pci_dev *dev) static void pci_dev_save_and_disable(struct pci_dev *dev)
{ {
struct pci_driver *drv = to_pci_driver(dev->dev.driver);
const struct pci_error_handlers *err_handler = const struct pci_error_handlers *err_handler =
drv ? drv->err_handler : NULL; dev->driver ? dev->driver->err_handler : NULL;
/* /*
* drv->err_handler->reset_prepare() is protected against races * dev->driver->err_handler->reset_prepare() is protected against
* with ->remove() by the device lock, which must be held by the * races with ->remove() by the device lock, which must be held by
* caller. * the caller.
*/ */
if (err_handler && err_handler->reset_prepare) if (err_handler && err_handler->reset_prepare)
err_handler->reset_prepare(dev); err_handler->reset_prepare(dev);
...@@ -5167,15 +5166,15 @@ static void pci_dev_save_and_disable(struct pci_dev *dev) ...@@ -5167,15 +5166,15 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)
static void pci_dev_restore(struct pci_dev *dev) static void pci_dev_restore(struct pci_dev *dev)
{ {
struct pci_driver *drv = to_pci_driver(dev->dev.driver);
const struct pci_error_handlers *err_handler = const struct pci_error_handlers *err_handler =
drv ? drv->err_handler : NULL; dev->driver ? dev->driver->err_handler : NULL;
pci_restore_state(dev); pci_restore_state(dev);
/* /*
* drv->err_handler->reset_done() is protected against races with * dev->driver->err_handler->reset_done() is protected against
* ->remove() by the device lock, which must be held by the caller. * races with ->remove() by the device lock, which must be held by
* the caller.
*/ */
if (err_handler && err_handler->reset_done) if (err_handler && err_handler->reset_done)
err_handler->reset_done(dev); err_handler->reset_done(dev);
......
...@@ -54,7 +54,7 @@ static int report_error_detected(struct pci_dev *dev, ...@@ -54,7 +54,7 @@ static int report_error_detected(struct pci_dev *dev,
const struct pci_error_handlers *err_handler; const struct pci_error_handlers *err_handler;
device_lock(&dev->dev); device_lock(&dev->dev);
pdrv = to_pci_driver(dev->dev.driver); pdrv = dev->driver;
if (!pci_dev_set_io_state(dev, state) || if (!pci_dev_set_io_state(dev, state) ||
!pdrv || !pdrv ||
!pdrv->err_handler || !pdrv->err_handler ||
...@@ -98,7 +98,7 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data) ...@@ -98,7 +98,7 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data)
const struct pci_error_handlers *err_handler; const struct pci_error_handlers *err_handler;
device_lock(&dev->dev); device_lock(&dev->dev);
pdrv = to_pci_driver(dev->dev.driver); pdrv = dev->driver;
if (!pdrv || if (!pdrv ||
!pdrv->err_handler || !pdrv->err_handler ||
!pdrv->err_handler->mmio_enabled) !pdrv->err_handler->mmio_enabled)
...@@ -119,7 +119,7 @@ static int report_slot_reset(struct pci_dev *dev, void *data) ...@@ -119,7 +119,7 @@ static int report_slot_reset(struct pci_dev *dev, void *data)
const struct pci_error_handlers *err_handler; const struct pci_error_handlers *err_handler;
device_lock(&dev->dev); device_lock(&dev->dev);
pdrv = to_pci_driver(dev->dev.driver); pdrv = dev->driver;
if (!pdrv || if (!pdrv ||
!pdrv->err_handler || !pdrv->err_handler ||
!pdrv->err_handler->slot_reset) !pdrv->err_handler->slot_reset)
...@@ -139,7 +139,7 @@ static int report_resume(struct pci_dev *dev, void *data) ...@@ -139,7 +139,7 @@ static int report_resume(struct pci_dev *dev, void *data)
const struct pci_error_handlers *err_handler; const struct pci_error_handlers *err_handler;
device_lock(&dev->dev); device_lock(&dev->dev);
pdrv = to_pci_driver(dev->dev.driver); pdrv = dev->driver;
if (!pci_dev_set_io_state(dev, pci_channel_io_normal) || if (!pci_dev_set_io_state(dev, pci_channel_io_normal) ||
!pdrv || !pdrv ||
!pdrv->err_handler || !pdrv->err_handler ||
......
...@@ -342,6 +342,7 @@ struct pci_dev { ...@@ -342,6 +342,7 @@ struct pci_dev {
u16 pcie_flags_reg; /* Cached PCIe Capabilities Register */ u16 pcie_flags_reg; /* Cached PCIe Capabilities Register */
unsigned long *dma_alias_mask;/* Mask of enabled devfn aliases */ unsigned long *dma_alias_mask;/* Mask of enabled devfn aliases */
struct pci_driver *driver; /* Driver bound to this device */
u64 dma_mask; /* Mask of the bits of bus address this u64 dma_mask; /* Mask of the bits of bus address this
device implements. Normally this is device implements. Normally this is
0xffffffff. You only need to change 0xffffffff. You only need to change
......
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