]> Git Repo - J-linux.git/commitdiff
Merge tag 'pci-v5.16-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
authorLinus Torvalds <[email protected]>
Thu, 11 Nov 2021 23:10:18 +0000 (15:10 -0800)
committerLinus Torvalds <[email protected]>
Thu, 11 Nov 2021 23:10:18 +0000 (15:10 -0800)
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"

1  2 
drivers/pci/pci.c
include/linux/pci.h

diff --combined drivers/pci/pci.c
index f2cd11130737c63679102e957092522d5f5f4d93,40012d13c3c432c7208728f4ca054aeeaa8365de..1579a3724eb43e7816587438b71ecfb7a64c509b
@@@ -732,38 -732,6 +732,38 @@@ u16 pci_find_vsec_capability(struct pci
  }
  EXPORT_SYMBOL_GPL(pci_find_vsec_capability);
  
 +/**
 + * pci_find_dvsec_capability - Find DVSEC for vendor
 + * @dev: PCI device to query
 + * @vendor: Vendor ID to match for the DVSEC
 + * @dvsec: Designated Vendor-specific capability ID
 + *
 + * If DVSEC has Vendor ID @vendor and DVSEC ID @dvsec return the capability
 + * offset in config space; otherwise return 0.
 + */
 +u16 pci_find_dvsec_capability(struct pci_dev *dev, u16 vendor, u16 dvsec)
 +{
 +      int pos;
 +
 +      pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DVSEC);
 +      if (!pos)
 +              return 0;
 +
 +      while (pos) {
 +              u16 v, id;
 +
 +              pci_read_config_word(dev, pos + PCI_DVSEC_HEADER1, &v);
 +              pci_read_config_word(dev, pos + PCI_DVSEC_HEADER2, &id);
 +              if (vendor == v && dvsec == id)
 +                      return pos;
 +
 +              pos = pci_find_next_ext_capability(dev, pos, PCI_EXT_CAP_ID_DVSEC);
 +      }
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(pci_find_dvsec_capability);
 +
  /**
   * pci_find_parent_resource - return resource region of parent bus of given
   *                          region
@@@ -1004,67 -972,61 +1004,67 @@@ static void pci_restore_bars(struct pci
                pci_update_resource(dev, i);
  }
  
 -static const struct pci_platform_pm_ops *pci_platform_pm;
 -
 -int pci_set_platform_pm(const struct pci_platform_pm_ops *ops)
 -{
 -      if (!ops->is_manageable || !ops->set_state  || !ops->get_state ||
 -          !ops->choose_state  || !ops->set_wakeup || !ops->need_resume)
 -              return -EINVAL;
 -      pci_platform_pm = ops;
 -      return 0;
 -}
 -
  static inline bool platform_pci_power_manageable(struct pci_dev *dev)
  {
 -      return pci_platform_pm ? pci_platform_pm->is_manageable(dev) : false;
 +      if (pci_use_mid_pm())
 +              return true;
 +
 +      return acpi_pci_power_manageable(dev);
  }
  
  static inline int platform_pci_set_power_state(struct pci_dev *dev,
                                               pci_power_t t)
  {
 -      return pci_platform_pm ? pci_platform_pm->set_state(dev, t) : -ENOSYS;
 +      if (pci_use_mid_pm())
 +              return mid_pci_set_power_state(dev, t);
 +
 +      return acpi_pci_set_power_state(dev, t);
  }
  
  static inline pci_power_t platform_pci_get_power_state(struct pci_dev *dev)
  {
 -      return pci_platform_pm ? pci_platform_pm->get_state(dev) : PCI_UNKNOWN;
 +      if (pci_use_mid_pm())
 +              return mid_pci_get_power_state(dev);
 +
 +      return acpi_pci_get_power_state(dev);
  }
  
  static inline void platform_pci_refresh_power_state(struct pci_dev *dev)
  {
 -      if (pci_platform_pm && pci_platform_pm->refresh_state)
 -              pci_platform_pm->refresh_state(dev);
 +      if (!pci_use_mid_pm())
 +              acpi_pci_refresh_power_state(dev);
  }
  
  static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
  {
 -      return pci_platform_pm ?
 -                      pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
 +      if (pci_use_mid_pm())
 +              return PCI_POWER_ERROR;
 +
 +      return acpi_pci_choose_state(dev);
  }
  
  static inline int platform_pci_set_wakeup(struct pci_dev *dev, bool enable)
  {
 -      return pci_platform_pm ?
 -                      pci_platform_pm->set_wakeup(dev, enable) : -ENODEV;
 +      if (pci_use_mid_pm())
 +              return PCI_POWER_ERROR;
 +
 +      return acpi_pci_wakeup(dev, enable);
  }
  
  static inline bool platform_pci_need_resume(struct pci_dev *dev)
  {
 -      return pci_platform_pm ? pci_platform_pm->need_resume(dev) : false;
 +      if (pci_use_mid_pm())
 +              return false;
 +
 +      return acpi_pci_need_resume(dev);
  }
  
  static inline bool platform_pci_bridge_d3(struct pci_dev *dev)
  {
 -      if (pci_platform_pm && pci_platform_pm->bridge_d3)
 -              return pci_platform_pm->bridge_d3(dev);
 -      return false;
 +      if (pci_use_mid_pm())
 +              return false;
 +
 +      return acpi_pci_bridge_d3(dev);
  }
  
  /**
@@@ -1223,7 -1185,9 +1223,7 @@@ void pci_update_current_state(struct pc
   */
  void pci_refresh_power_state(struct pci_dev *dev)
  {
 -      if (platform_pci_power_manageable(dev))
 -              platform_pci_refresh_power_state(dev);
 -
 +      platform_pci_refresh_power_state(dev);
        pci_update_current_state(dev, dev->current_state);
  }
  
@@@ -1236,10 -1200,14 +1236,10 @@@ int pci_platform_power_transition(struc
  {
        int error;
  
 -      if (platform_pci_power_manageable(dev)) {
 -              error = platform_pci_set_power_state(dev, state);
 -              if (!error)
 -                      pci_update_current_state(dev, state);
 -      } else
 -              error = -ENODEV;
 -
 -      if (error && !dev->pm_cap) /* Fall back to PCI_D0 */
 +      error = platform_pci_set_power_state(dev, state);
 +      if (!error)
 +              pci_update_current_state(dev, state);
 +      else if (!dev->pm_cap) /* Fall back to PCI_D0 */
                dev->current_state = PCI_D0;
  
        return error;
@@@ -1420,6 -1388,44 +1420,6 @@@ int pci_set_power_state(struct pci_dev 
  }
  EXPORT_SYMBOL(pci_set_power_state);
  
 -/**
 - * pci_choose_state - Choose the power state of a PCI device
 - * @dev: PCI device to be suspended
 - * @state: target sleep state for the whole system. This is the value
 - *       that is passed to suspend() function.
 - *
 - * Returns PCI power state suitable for given device and given system
 - * message.
 - */
 -pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
 -{
 -      pci_power_t ret;
 -
 -      if (!dev->pm_cap)
 -              return PCI_D0;
 -
 -      ret = platform_pci_choose_state(dev);
 -      if (ret != PCI_POWER_ERROR)
 -              return ret;
 -
 -      switch (state.event) {
 -      case PM_EVENT_ON:
 -              return PCI_D0;
 -      case PM_EVENT_FREEZE:
 -      case PM_EVENT_PRETHAW:
 -              /* REVISIT both freeze and pre-thaw "should" use D0 */
 -      case PM_EVENT_SUSPEND:
 -      case PM_EVENT_HIBERNATE:
 -              return PCI_D3hot;
 -      default:
 -              pci_info(dev, "unrecognized suspend event %d\n",
 -                       state.event);
 -              BUG();
 -      }
 -      return PCI_D0;
 -}
 -EXPORT_SYMBOL(pci_choose_state);
 -
  #define PCI_EXP_SAVE_REGS     7
  
  static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev,
@@@ -2598,6 -2604,8 +2598,6 @@@ EXPORT_SYMBOL(pci_wake_from_d3)
   */
  static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
  {
 -      pci_power_t target_state = PCI_D3hot;
 -
        if (platform_pci_power_manageable(dev)) {
                /*
                 * Call the platform to find the target state for the device.
                switch (state) {
                case PCI_POWER_ERROR:
                case PCI_UNKNOWN:
 -                      break;
 +                      return PCI_D3hot;
 +
                case PCI_D1:
                case PCI_D2:
                        if (pci_no_d1d2(dev))
 -                              break;
 -                      fallthrough;
 -              default:
 -                      target_state = state;
 +                              return PCI_D3hot;
                }
  
 -              return target_state;
 +              return state;
        }
  
 -      if (!dev->pm_cap)
 -              target_state = PCI_D0;
 -
        /*
         * If the device is in D3cold even though it's not power-manageable by
         * the platform, it may have been powered down by non-standard means.
         * Best to let it slumber.
         */
        if (dev->current_state == PCI_D3cold)
 -              target_state = PCI_D3cold;
 +              return PCI_D3cold;
 +      else if (!dev->pm_cap)
 +              return PCI_D0;
  
        if (wakeup && dev->pme_support) {
 -              pci_power_t state = target_state;
 +              pci_power_t state = PCI_D3hot;
  
                /*
                 * Find the deepest state from which the device can generate
                        return PCI_D0;
        }
  
 -      return target_state;
 +      return PCI_D3hot;
  }
  
  /**
@@@ -2697,13 -2708,8 +2697,13 @@@ EXPORT_SYMBOL(pci_prepare_to_sleep)
   */
  int pci_back_from_sleep(struct pci_dev *dev)
  {
 +      int ret = pci_set_power_state(dev, PCI_D0);
 +
 +      if (ret)
 +              return ret;
 +
        pci_enable_wake(dev, PCI_D0, false);
 -      return pci_set_power_state(dev, PCI_D0);
 +      return 0;
  }
  EXPORT_SYMBOL(pci_back_from_sleep);
  
@@@ -2863,22 -2869,6 +2863,22 @@@ void pci_dev_complete_resume(struct pci
        spin_unlock_irq(&dev->power.lock);
  }
  
 +/**
 + * pci_choose_state - Choose the power state of a PCI device.
 + * @dev: Target PCI device.
 + * @state: Target state for the whole system.
 + *
 + * Returns PCI power state suitable for @dev and @state.
 + */
 +pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
 +{
 +      if (state.event == PM_EVENT_ON)
 +              return PCI_D0;
 +
 +      return pci_target_state(dev, false);
 +}
 +EXPORT_SYMBOL(pci_choose_state);
 +
  void pci_config_pm_runtime_get(struct pci_dev *pdev)
  {
        struct device *dev = &pdev->dev;
@@@ -4168,7 -4158,6 +4168,7 @@@ unsigned long __weak pci_address_to_pio
   * architectures that have memory mapped IO functions defined (and the
   * PCI_IOBASE value defined) should call this function.
   */
 +#ifndef pci_remap_iospace
  int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
  {
  #if defined(PCI_IOBASE) && defined(CONFIG_MMU)
  #endif
  }
  EXPORT_SYMBOL(pci_remap_iospace);
 +#endif
  
  /**
   * pci_unmap_iospace - Unmap the memory mapped I/O space
@@@ -5135,14 -5123,13 +5135,13 @@@ EXPORT_SYMBOL_GPL(pci_dev_unlock)
  
  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 =
-                       drv ? drv->err_handler : NULL;
+                       dev->driver ? dev->driver->err_handler : NULL;
  
        /*
-        * drv->err_handler->reset_prepare() is protected against races
-        * with ->remove() by the device lock, which must be held by the
-        * caller.
+        * dev->driver->err_handler->reset_prepare() is protected against
+        * races with ->remove() by the device lock, which must be held by
+        * the caller.
         */
        if (err_handler && err_handler->reset_prepare)
                err_handler->reset_prepare(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 =
-                       drv ? drv->err_handler : NULL;
+                       dev->driver ? dev->driver->err_handler : NULL;
  
        pci_restore_state(dev);
  
        /*
-        * drv->err_handler->reset_done() is protected against races with
-        * ->remove() by the device lock, which must be held by the caller.
+        * dev->driver->err_handler->reset_done() is protected against
+        * races with ->remove() by the device lock, which must be held by
+        * the caller.
         */
        if (err_handler && err_handler->reset_done)
                err_handler->reset_done(dev);
diff --combined include/linux/pci.h
index c8afbee5da4bfc0912336585326afb071bf02869,e58888e21ab7362427bc8d415e4bd14ec589ae8b..138d764c1c3577d9ebda599dc7be5e0c8cfc2508
@@@ -342,6 -342,7 +342,7 @@@ struct pci_dev 
        u16             pcie_flags_reg; /* Cached PCIe Capabilities Register */
        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
                                           device implements.  Normally this is
                                           0xffffffff.  You only need to change
@@@ -1132,7 -1133,6 +1133,7 @@@ u16 pci_find_ext_capability(struct pci_
  u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 pos, int cap);
  struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
  u16 pci_find_vsec_capability(struct pci_dev *dev, u16 vendor, int cap);
 +u16 pci_find_dvsec_capability(struct pci_dev *dev, u16 vendor, u16 dvsec);
  
  u64 pci_get_dsn(struct pci_dev *dev);
  
This page took 0.080414 seconds and 4 git commands to generate.