]> Git Repo - J-linux.git/commitdiff
Merge tag 'cxl-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
authorLinus Torvalds <[email protected]>
Mon, 8 Nov 2021 19:49:48 +0000 (11:49 -0800)
committerLinus Torvalds <[email protected]>
Mon, 8 Nov 2021 19:49:48 +0000 (11:49 -0800)
Pull cxl updates from Dan Williams:
 "More preparation and plumbing work in the CXL subsystem.

  From an end user perspective the highlight here is lighting up the CXL
  Persistent Memory related commands (label read / write) with the
  generic ioctl() front-end in LIBNVDIMM.

  Otherwise, the ability to instantiate new persistent and volatile
  memory regions is still on track for v5.17.

  Summary:

   - Fix support for platforms that do not enumerate every ACPI0016 (CXL
     Host Bridge) in the CHBS (ACPI Host Bridge Structure).

   - Introduce a common pci_find_dvsec_capability() helper, clean up
     open coded implementations in various drivers.

   - Add 'cxl_test' for regression testing CXL subsystem ABIs.
     'cxl_test' is a module built from tools/testing/cxl/ that mocks up
     a CXL topology to augment the nascent support for emulation of CXL
     devices in QEMU.

   - Convert libnvdimm to use the uuid API.

   - Complete the definition of CXL namespace labels in libnvdimm.

   - Tunnel libnvdimm label operations from nd_ioctl() back to the CXL
     mailbox driver. Enable 'ndctl {read,write}-labels' for CXL.

   - Continue to sort and refactor functionality into distinct driver
     and core-infrastructure buckets. For example, mailbox handling is
     now a generic core capability consumed by the PCI and cxl_test
     drivers"

* tag 'cxl-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: (34 commits)
  ocxl: Use pci core's DVSEC functionality
  cxl/pci: Use pci core's DVSEC functionality
  PCI: Add pci_find_dvsec_capability to find designated VSEC
  cxl/pci: Split cxl_pci_setup_regs()
  cxl/pci: Add @base to cxl_register_map
  cxl/pci: Make more use of cxl_register_map
  cxl/pci: Remove pci request/release regions
  cxl/pci: Fix NULL vs ERR_PTR confusion
  cxl/pci: Remove dev_dbg for unknown register blocks
  cxl/pci: Convert register block identifiers to an enum
  cxl/acpi: Do not fail cxl_acpi_probe() based on a missing CHBS
  cxl/pci: Disambiguate cxl_pci further from cxl_mem
  Documentation/cxl: Add bus internal docs
  cxl/core: Split decoder setup into alloc + add
  tools/testing/cxl: Introduce a mock memory device + driver
  cxl/mbox: Move command definitions to common location
  cxl/bus: Populate the target list at decoder create
  tools/testing/cxl: Introduce a mocked-up CXL port hierarchy
  cxl/pmem: Add support for multiple nvdimm-bridge objects
  cxl/pmem: Translate NVDIMM label commands to CXL label commands
  ...

1  2 
drivers/cxl/cxl.h
drivers/nvdimm/btt.c
drivers/nvdimm/core.c
drivers/pci/pci.c
include/linux/pci.h

diff --combined drivers/cxl/cxl.h
index 9db0c402c9ce8bc7236c4d6d10dc71b3cdf7dd1e,5e2e934519286f97dd6129007bf7ccc3104d50ab..3af704e9b448e91b70564fc6623965c56b7c8d42
@@@ -75,27 -75,52 +75,27 @@@ static inline int cxl_hdm_decoder_count
  #define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18
  #define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20
  
 -#define CXL_COMPONENT_REGS() \
 -      void __iomem *hdm_decoder
 -
 -#define CXL_DEVICE_REGS() \
 -      void __iomem *status; \
 -      void __iomem *mbox; \
 -      void __iomem *memdev
 -
 -/* See note for 'struct cxl_regs' for the rationale of this organization */
 -/*
 - * CXL_COMPONENT_REGS - Common set of CXL Component register block base pointers
 - * @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
 - */
 -struct cxl_component_regs {
 -      CXL_COMPONENT_REGS();
 -};
 -
 -/* See note for 'struct cxl_regs' for the rationale of this organization */
 -/*
 - * CXL_DEVICE_REGS - Common set of CXL Device register block base pointers
 - * @status: CXL 2.0 8.2.8.3 Device Status Registers
 - * @mbox: CXL 2.0 8.2.8.4 Mailbox Registers
 - * @memdev: CXL 2.0 8.2.8.5 Memory Device Registers
 - */
 -struct cxl_device_regs {
 -      CXL_DEVICE_REGS();
 -};
 -
  /*
 - * Note, the anonymous union organization allows for per
 - * register-block-type helper routines, without requiring block-type
 - * agnostic code to include the prefix.
 + * Using struct_group() allows for per register-block-type helper routines,
 + * without requiring block-type agnostic code to include the prefix.
   */
  struct cxl_regs {
 -      union {
 -              struct {
 -                      CXL_COMPONENT_REGS();
 -              };
 -              struct cxl_component_regs component;
 -      };
 -      union {
 -              struct {
 -                      CXL_DEVICE_REGS();
 -              };
 -              struct cxl_device_regs device_regs;
 -      };
 +      /*
 +       * Common set of CXL Component register block base pointers
 +       * @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
 +       */
 +      struct_group_tagged(cxl_component_regs, component,
 +              void __iomem *hdm_decoder;
 +      );
 +      /*
 +       * Common set of CXL Device register block base pointers
 +       * @status: CXL 2.0 8.2.8.3 Device Status Registers
 +       * @mbox: CXL 2.0 8.2.8.4 Mailbox Registers
 +       * @memdev: CXL 2.0 8.2.8.5 Memory Device Registers
 +       */
 +      struct_group_tagged(cxl_device_regs, device_regs,
 +              void __iomem *status, *mbox, *memdev;
 +      );
  };
  
  struct cxl_reg_map {
@@@ -114,7 -139,17 +114,17 @@@ struct cxl_device_reg_map 
        struct cxl_reg_map memdev;
  };
  
+ /**
+  * struct cxl_register_map - DVSEC harvested register block mapping parameters
+  * @base: virtual base of the register-block-BAR + @block_offset
+  * @block_offset: offset to start of register block in @barno
+  * @reg_type: see enum cxl_regloc_type
+  * @barno: PCI BAR number containing the register block
+  * @component_map: cxl_reg_map for component registers
+  * @device_map: cxl_reg_maps for device registers
+  */
  struct cxl_register_map {
+       void __iomem *base;
        u64 block_offset;
        u8 reg_type;
        u8 barno;
@@@ -155,6 -190,12 +165,12 @@@ enum cxl_decoder_type 
         CXL_DECODER_EXPANDER = 3,
  };
  
+ /*
+  * Current specification goes up to 8, double that seems a reasonable
+  * software max for the foreseeable future
+  */
+ #define CXL_DECODER_MAX_INTERLEAVE 16
  /**
   * struct cxl_decoder - CXL address range decode configuration
   * @dev: this decoder's device
   * @interleave_granularity: data stride per dport
   * @target_type: accelerator vs expander (type2 vs type3) selector
   * @flags: memory type capabilities and locking
+  * @nr_targets: number of elements in @target
   * @target: active ordered target list in current decoder configuration
   */
  struct cxl_decoder {
        int interleave_granularity;
        enum cxl_decoder_type target_type;
        unsigned long flags;
+       const int nr_targets;
        struct cxl_dport *target[];
  };
  
@@@ -186,6 -229,7 +204,7 @@@ enum cxl_nvdimm_brige_state 
  };
  
  struct cxl_nvdimm_bridge {
+       int id;
        struct device dev;
        struct cxl_port *port;
        struct nvdimm_bus *nvdimm_bus;
@@@ -200,6 -244,14 +219,14 @@@ struct cxl_nvdimm 
        struct nvdimm *nvdimm;
  };
  
+ struct cxl_walk_context {
+       struct device *dev;
+       struct pci_bus *root;
+       struct cxl_port *port;
+       int error;
+       int count;
+ };
  /**
   * struct cxl_port - logical collection of upstream port devices and
   *                 downstream port devices to construct a CXL memory
@@@ -246,25 -298,9 +273,9 @@@ int cxl_add_dport(struct cxl_port *port
  
  struct cxl_decoder *to_cxl_decoder(struct device *dev);
  bool is_root_decoder(struct device *dev);
- struct cxl_decoder *
- devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets,
-                    resource_size_t base, resource_size_t len,
-                    int interleave_ways, int interleave_granularity,
-                    enum cxl_decoder_type type, unsigned long flags);
- /*
-  * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure)
-  * single ported host-bridges need not publish a decoder capability when a
-  * passthrough decode can be assumed, i.e. all transactions that the uport sees
-  * are claimed and passed to the single dport. Default the range a 0-base
-  * 0-length until the first CXL region is activated.
-  */
- static inline struct cxl_decoder *
- devm_cxl_add_passthrough_decoder(struct device *host, struct cxl_port *port)
- {
-       return devm_cxl_add_decoder(host, port, 1, 0, 0, 1, PAGE_SIZE,
-                                   CXL_DECODER_EXPANDER, 0);
- }
+ struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets);
+ int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map);
+ int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);
  
  extern struct bus_type cxl_bus_type;
  
@@@ -298,4 -334,13 +309,13 @@@ struct cxl_nvdimm_bridge *devm_cxl_add_
  struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
  bool is_cxl_nvdimm(struct device *dev);
  int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
+ struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd);
+ /*
+  * Unit test builds overrides this to __weak, find the 'strong' version
+  * of these symbols in tools/testing/cxl/.
+  */
+ #ifndef __mock
+ #define __mock static
+ #endif
  #endif /* __CXL_H__ */
diff --combined drivers/nvdimm/btt.c
index 4295fa8094209b56bd06308a8db30f1d05cee8fe,52de60b7adeea240bbadbf2185add2e59f8a9ab0..f10a50ffa047e1bd06cc38175ef63c475d6be719
@@@ -973,7 -973,7 +973,7 @@@ static int btt_arena_write_layout(struc
        u64 sum;
        struct btt_sb *super;
        struct nd_btt *nd_btt = arena->nd_btt;
-       const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev);
+       const uuid_t *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev);
  
        ret = btt_map_init(arena);
        if (ret)
                return -ENOMEM;
  
        strncpy(super->signature, BTT_SIG, BTT_SIG_LEN);
-       memcpy(super->uuid, nd_btt->uuid, 16);
-       memcpy(super->parent_uuid, parent_uuid, 16);
+       export_uuid(super->uuid, nd_btt->uuid);
+       export_uuid(super->parent_uuid, parent_uuid);
        super->flags = cpu_to_le32(arena->flags);
        super->version_major = cpu_to_le16(arena->version_major);
        super->version_minor = cpu_to_le16(arena->version_minor);
@@@ -1440,7 -1440,7 +1440,7 @@@ static int btt_do_bvec(struct btt *btt
        return ret;
  }
  
 -static blk_qc_t btt_submit_bio(struct bio *bio)
 +static void btt_submit_bio(struct bio *bio)
  {
        struct bio_integrity_payload *bip = bio_integrity(bio);
        struct btt *btt = bio->bi_bdev->bd_disk->private_data;
        bool do_acct;
  
        if (!bio_integrity_prep(bio))
 -              return BLK_QC_T_NONE;
 +              return;
  
        do_acct = blk_queue_io_stat(bio->bi_bdev->bd_disk->queue);
        if (do_acct)
                bio_end_io_acct(bio, start);
  
        bio_endio(bio);
 -      return BLK_QC_T_NONE;
  }
  
  static int btt_rw_page(struct block_device *bdev, sector_t sector,
@@@ -1574,7 -1575,8 +1574,8 @@@ static void btt_blk_cleanup(struct btt 
   * Pointer to a new struct btt on success, NULL on failure.
   */
  static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize,
-               u32 lbasize, u8 *uuid, struct nd_region *nd_region)
+                           u32 lbasize, uuid_t *uuid,
+                           struct nd_region *nd_region)
  {
        int ret;
        struct btt *btt;
@@@ -1693,7 -1695,7 +1694,7 @@@ int nvdimm_namespace_attach_btt(struct 
        }
        nd_region = to_nd_region(nd_btt->dev.parent);
        btt = btt_init(nd_btt, rawsize, nd_btt->lbasize, nd_btt->uuid,
-                       nd_region);
+                      nd_region);
        if (!btt)
                return -ENOMEM;
        nd_btt->btt = btt;
diff --combined drivers/nvdimm/core.c
index 6a45fa91e8a3ee22aa1a71244663c821f3cfe2c3,690152d62bf0155b9bbe7574e1ab965ad44b3fec..69a03358817f1c9a78d7b695d34183b7776d0fb4
@@@ -7,7 -7,6 +7,7 @@@
  #include <linux/export.h>
  #include <linux/module.h>
  #include <linux/blkdev.h>
 +#include <linux/blk-integrity.h>
  #include <linux/device.h>
  #include <linux/ctype.h>
  #include <linux/ndctl.h>
@@@ -207,38 -206,6 +207,6 @@@ struct device *to_nvdimm_bus_dev(struc
  }
  EXPORT_SYMBOL_GPL(to_nvdimm_bus_dev);
  
- static bool is_uuid_sep(char sep)
- {
-       if (sep == '\n' || sep == '-' || sep == ':' || sep == '\0')
-               return true;
-       return false;
- }
- static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf,
-               size_t len)
- {
-       const char *str = buf;
-       u8 uuid[16];
-       int i;
-       for (i = 0; i < 16; i++) {
-               if (!isxdigit(str[0]) || !isxdigit(str[1])) {
-                       dev_dbg(dev, "pos: %d buf[%zd]: %c buf[%zd]: %c\n",
-                                       i, str - buf, str[0],
-                                       str + 1 - buf, str[1]);
-                       return -EINVAL;
-               }
-               uuid[i] = (hex_to_bin(str[0]) << 4) | hex_to_bin(str[1]);
-               str += 2;
-               if (is_uuid_sep(*str))
-                       str++;
-       }
-       memcpy(uuid_out, uuid, sizeof(uuid));
-       return 0;
- }
  /**
   * nd_uuid_store: common implementation for writing 'uuid' sysfs attributes
   * @dev: container device for the uuid property
   * (driver detached)
   * LOCKING: expects nd_device_lock() is held on entry
   */
- int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf,
+ int nd_uuid_store(struct device *dev, uuid_t **uuid_out, const char *buf,
                size_t len)
  {
-       u8 uuid[16];
+       uuid_t uuid;
        int rc;
  
        if (dev->driver)
                return -EBUSY;
  
-       rc = nd_uuid_parse(dev, uuid, buf, len);
+       rc = uuid_parse(buf, &uuid);
        if (rc)
                return rc;
  
        kfree(*uuid_out);
-       *uuid_out = kmemdup(uuid, sizeof(uuid), GFP_KERNEL);
+       *uuid_out = kmemdup(&uuid, sizeof(uuid), GFP_KERNEL);
        if (!(*uuid_out))
                return -ENOMEM;
  
diff --combined drivers/pci/pci.c
index da75c422ba857419d14b0b731c4434096c62f1de,94ac86ff28b0097af387330f6a94ef978b1467ec..f2cd11130737c63679102e957092522d5f5f4d93
@@@ -269,7 -269,7 +269,7 @@@ static int pci_dev_str_match_path(struc
                                  const char **endptr)
  {
        int ret;
 -      int seg, bus, slot, func;
 +      unsigned int seg, bus, slot, func;
        char *wpath, *p;
        char end;
  
@@@ -732,6 -732,38 +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
@@@ -972,67 -1004,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);
  }
  
  /**
@@@ -1191,7 -1217,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);
  }
  
@@@ -1204,10 -1232,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;
@@@ -1388,6 -1420,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,
@@@ -1439,24 -1509,6 +1471,24 @@@ static int pci_save_pcie_state(struct p
        return 0;
  }
  
 +void pci_bridge_reconfigure_ltr(struct pci_dev *dev)
 +{
 +#ifdef CONFIG_PCIEASPM
 +      struct pci_dev *bridge;
 +      u32 ctl;
 +
 +      bridge = pci_upstream_bridge(dev);
 +      if (bridge && bridge->ltr_path) {
 +              pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl);
 +              if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) {
 +                      pci_dbg(bridge, "re-enabling LTR\n");
 +                      pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
 +                                               PCI_EXP_DEVCTL2_LTR_EN);
 +              }
 +      }
 +#endif
 +}
 +
  static void pci_restore_pcie_state(struct pci_dev *dev)
  {
        int i = 0;
        if (!save_state)
                return;
  
 +      /*
 +       * Downstream ports reset the LTR enable bit when link goes down.
 +       * Check and re-configure the bit here before restoring device.
 +       * PCIe r5.0, sec 7.5.3.16.
 +       */
 +      pci_bridge_reconfigure_ltr(dev);
 +
        cap = (u16 *)&save_state->cap.data[0];
        pcie_capability_write_word(dev, PCI_EXP_DEVCTL, cap[i++]);
        pcie_capability_write_word(dev, PCI_EXP_LNKCTL, cap[i++]);
@@@ -2078,14 -2123,14 +2110,14 @@@ void pcim_pin_device(struct pci_dev *pd
  EXPORT_SYMBOL(pcim_pin_device);
  
  /*
 - * pcibios_add_device - provide arch specific hooks when adding device dev
 + * pcibios_device_add - provide arch specific hooks when adding device dev
   * @dev: the PCI device being added
   *
   * Permits the platform to provide architecture specific functionality when
   * devices are added. This is the default implementation. Architecture
   * implementations can override this.
   */
 -int __weak pcibios_add_device(struct pci_dev *dev)
 +int __weak pcibios_device_add(struct pci_dev *dev)
  {
        return 0;
  }
@@@ -2205,7 -2250,6 +2237,7 @@@ int pci_set_pcie_reset_state(struct pci
  }
  EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
  
 +#ifdef CONFIG_PCIEAER
  void pcie_clear_device_status(struct pci_dev *dev)
  {
        u16 sta;
        pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
        pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
  }
 +#endif
  
  /**
   * pcie_clear_root_pme_status - Clear root port PME interrupt status.
@@@ -2566,6 -2609,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;
  }
  
  /**
@@@ -2665,13 -2713,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);
  
@@@ -2831,22 -2874,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;
@@@ -3724,14 -3751,6 +3756,14 @@@ int pci_enable_atomic_ops_to_root(struc
        struct pci_dev *bridge;
        u32 cap, ctl2;
  
 +      /*
 +       * Per PCIe r5.0, sec 9.3.5.10, the AtomicOp Requester Enable bit
 +       * in Device Control 2 is reserved in VFs and the PF value applies
 +       * to all associated VFs.
 +       */
 +      if (dev->is_virtfn)
 +              return -EINVAL;
 +
        if (!pci_is_pcie(dev))
                return -EINVAL;
  
@@@ -4136,7 -4155,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
@@@ -5103,14 -5120,13 +5135,14 @@@ 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 =
 -                      dev->driver ? dev->driver->err_handler : NULL;
 +                      drv ? drv->err_handler : NULL;
  
        /*
 -       * dev->driver->err_handler->reset_prepare() is protected against
 -       * races with ->remove() by the device lock, which must be held by
 -       * the caller.
 +       * drv->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 =
 -                      dev->driver ? dev->driver->err_handler : NULL;
 +                      drv ? drv->err_handler : NULL;
  
        pci_restore_state(dev);
  
        /*
 -       * dev->driver->err_handler->reset_done() is protected against
 -       * races with ->remove() by the device lock, which must be held by
 -       * the caller.
 +       * drv->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);
@@@ -5304,7 -5320,7 +5336,7 @@@ const struct attribute_group pci_dev_re
   */
  int __pci_reset_function_locked(struct pci_dev *dev)
  {
 -      int i, m, rc = -ENOTTY;
 +      int i, m, rc;
  
        might_sleep();
  
@@@ -6340,12 -6356,11 +6372,12 @@@ EXPORT_SYMBOL_GPL(pci_pr3_present)
   * cannot be left as a userspace activity).  DMA aliases should therefore
   * be configured via quirks, such as the PCI fixup header quirk.
   */
 -void pci_add_dma_alias(struct pci_dev *dev, u8 devfn_from, unsigned nr_devfns)
 +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn_from,
 +                     unsigned int nr_devfns)
  {
        int devfn_to;
  
 -      nr_devfns = min(nr_devfns, (unsignedMAX_NR_DEVFNS - devfn_from);
 +      nr_devfns = min(nr_devfns, (unsigned int)MAX_NR_DEVFNS - devfn_from);
        devfn_to = devfn_from + nr_devfns - 1;
  
        if (!dev->dma_alias_mask)
diff --combined include/linux/pci.h
index b4dbcc86b3f1334c8567a485366d5c30d5611f35,c93ccfa4571b406e3c61e433a7e301f6812cd46c..c8afbee5da4bfc0912336585326afb071bf02869
@@@ -342,6 -342,7 +342,6 @@@ 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
@@@ -899,10 -900,7 +899,10 @@@ struct pci_driver 
        struct pci_dynids       dynids;
  };
  
 -#define       to_pci_driver(drv) container_of(drv, struct pci_driver, driver)
 +static inline struct pci_driver *to_pci_driver(struct device_driver *drv)
 +{
 +    return drv ? container_of(drv, struct pci_driver, driver) : NULL;
 +}
  
  /**
   * PCI_DEVICE - macro used to describe a specific PCI device
@@@ -1132,6 -1130,7 +1132,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);
  
@@@ -1352,8 -1351,6 +1353,8 @@@ void pci_unlock_rescan_remove(void)
  /* Vital Product Data routines */
  ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
  ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
 +ssize_t pci_read_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
 +ssize_t pci_write_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
  
  /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
  resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
@@@ -1502,8 -1499,19 +1503,8 @@@ int pci_set_vga_state(struct pci_dev *p
  #define PCI_IRQ_ALL_TYPES \
        (PCI_IRQ_LEGACY | PCI_IRQ_MSI | PCI_IRQ_MSIX)
  
 -/* kmem_cache style wrapper around pci_alloc_consistent() */
 -
  #include <linux/dmapool.h>
  
 -#define       pci_pool dma_pool
 -#define pci_pool_create(name, pdev, size, align, allocation) \
 -              dma_pool_create(name, &pdev->dev, size, align, allocation)
 -#define       pci_pool_destroy(pool) dma_pool_destroy(pool)
 -#define       pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle)
 -#define       pci_pool_zalloc(pool, flags, handle) \
 -              dma_pool_zalloc(pool, flags, handle)
 -#define       pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr)
 -
  struct msix_entry {
        u32     vector; /* Kernel uses to write allocated vector */
        u16     entry;  /* Driver uses to specify entry, OS writes */
@@@ -2119,7 -2127,7 +2120,7 @@@ void pcibios_disable_device(struct pci_
  void pcibios_set_master(struct pci_dev *dev);
  int pcibios_set_pcie_reset_state(struct pci_dev *dev,
                                 enum pcie_reset_state state);
 -int pcibios_add_device(struct pci_dev *dev);
 +int pcibios_device_add(struct pci_dev *dev);
  void pcibios_release_device(struct pci_dev *dev);
  #ifdef CONFIG_PCI
  void pcibios_penalize_isa_irq(int irq, int active);
This page took 0.10679 seconds and 4 git commands to generate.