Merge branch 'pci/vpd'
authorBjorn Helgaas <bhelgaas@google.com>
Thu, 2 Sep 2021 19:56:44 +0000 (14:56 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 2 Sep 2021 19:56:44 +0000 (14:56 -0500)
- Check Resource Item Names against those defined for type (Bjorn Helgaas)

- Treat initial 0xff as missing EEPROM (Heiner Kallweit)

- Reject resource tags with invalid size (Bjorn Helgaas)

- Don't check Large Resource Item Names for validity (Bjorn Helgaas)

- Allow access to valid parts of VPD if some is invalid (Bjorn Helgaas)

- Remove pci_vpd_size() old_size argument (Heiner Kallweit)

- Make pci_vpd_wait() uninterruptible (Heiner Kallweit)

- Remove struct pci_vpd.flag (Heiner Kallweit)

- Remove struct pci_vpd_ops (Heiner Kallweit)

- Remove struct pci_vpd.valid member (Heiner Kallweit)

- Embed struct pci_vpd in struct pci_dev (Heiner Kallweit)

- Determine VPD size in pci_vpd_init() (Heiner Kallweit)

- Treat invalid VPD like missing VPD capability (Heiner Kallweit)

- Add pci_vpd_alloc() to allocate buffer and read VPD into it (Heiner
  Kallweit)

- Add pci_vpd_find_ro_info_keyword() (Heiner Kallweit)

- Add pci_vpd_check_csum() (Heiner Kallweit)

- Add pci_vpd_find_id_string() (Heiner Kallweit)

- Read VPD with pci_vpd_alloc() (bnx2x, bnxt, sfc, sfc falcon, tg3 drivers)
  (Heiner Kallweit)

- Search VPD with pci_vpd_find_ro_info_keyword() (bnx2, bnx2x, bnxt, cxgb4,
  cxlflash SCSI, sfc, sfc falcon, tg3 drivers) (Heiner Kallweit)

- Search VPD with pci_vpd_find_id_string() (cxgb4 driver) (Heiner Kallweit)

- Validate VPD checksum with pci_vpd_check_csum() (cxgb4, tg3 drivers)
  (Heiner Kallweit)

- Replace open-coded byte swapping with swab32s() in bnx2 (Heiner Kallweit)

- Remove unused vpd_param member ec (Heiner Kallweit)

- Stop exporting pci_vpd_find_tag(), pci_vpd_find_info_keyword() (Heiner
  Kallweit)

- Move several VPD defines and inlines to internal PCI core (Heiner
  Kallweit)

* pci/vpd:
  PCI/VPD: Use unaligned access helpers
  PCI/VPD: Clean up public VPD defines and inline functions
  cxgb4: Use pci_vpd_find_id_string() to find VPD ID string
  PCI/VPD: Add pci_vpd_find_id_string()
  PCI/VPD: Include post-processing in pci_vpd_find_tag()
  PCI/VPD: Stop exporting pci_vpd_find_info_keyword()
  PCI/VPD: Stop exporting pci_vpd_find_tag()
  scsi: cxlflash: Search VPD with pci_vpd_find_ro_info_keyword()
  cxgb4: Search VPD with pci_vpd_find_ro_info_keyword()
  cxgb4: Remove unused vpd_param member ec
  cxgb4: Validate VPD checksum with pci_vpd_check_csum()
  bnxt: Search VPD with pci_vpd_find_ro_info_keyword()
  bnxt: Read VPD with pci_vpd_alloc()
  bnx2x: Search VPD with pci_vpd_find_ro_info_keyword()
  bnx2x: Read VPD with pci_vpd_alloc()
  bnx2: Replace open-coded byte swapping with swab32s()
  bnx2: Search VPD with pci_vpd_find_ro_info_keyword()
  sfc: falcon: Search VPD with pci_vpd_find_ro_info_keyword()
  sfc: falcon: Read VPD with pci_vpd_alloc()
  tg3: Search VPD with pci_vpd_find_ro_info_keyword()
  tg3: Validate VPD checksum with pci_vpd_check_csum()
  tg3: Read VPD with pci_vpd_alloc()
  sfc: Search VPD with pci_vpd_find_ro_info_keyword()
  sfc: Read VPD with pci_vpd_alloc()
  PCI/VPD: Add pci_vpd_check_csum()
  PCI/VPD: Add pci_vpd_find_ro_info_keyword()
  PCI/VPD: Add pci_vpd_alloc()
  PCI/VPD: Treat invalid VPD like missing VPD capability
  PCI/VPD: Determine VPD size in pci_vpd_init()
  PCI/VPD: Embed struct pci_vpd in struct pci_dev
  PCI/VPD: Remove struct pci_vpd.valid member
  PCI/VPD: Remove struct pci_vpd_ops
  PCI/VPD: Reorder pci_read_vpd(), pci_write_vpd()
  PCI/VPD: Remove struct pci_vpd.flag
  PCI/VPD: Make pci_vpd_wait() uninterruptible
  PCI/VPD: Remove pci_vpd_size() old_size argument
  PCI/VPD: Allow access to valid parts of VPD if some is invalid
  PCI/VPD: Don't check Large Resource Item Names for validity
  PCI/VPD: Reject resource tags with invalid size
  PCI/VPD: Treat initial 0xff as missing EEPROM
  PCI/VPD: Check Resource Item Names against those valid for type
  PCI/VPD: Correct diagnostic for VPD read failure

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

diff --combined drivers/pci/probe.c
@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/hypervisor.h>
  #include <linux/irqdomain.h>
  #include <linux/pm_runtime.h>
 +#include <linux/bitfield.h>
  #include "pci.h"
  
  #define CARDBUS_LATENCY_TIMER 176     /* secondary latency timer */
@@@ -1499,8 -1498,8 +1499,8 @@@ void set_pcie_port_type(struct pci_dev 
        pdev->pcie_cap = pos;
        pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
        pdev->pcie_flags_reg = reg16;
 -      pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
 -      pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
 +      pci_read_config_dword(pdev, pos + PCI_EXP_DEVCAP, &pdev->devcap);
 +      pdev->pcie_mpss = FIELD_GET(PCI_EXP_DEVCAP_PAYLOAD, pdev->devcap);
  
        parent = pci_upstream_bridge(pdev);
        if (!parent)
@@@ -1810,9 -1809,6 +1810,9 @@@ int pci_setup_device(struct pci_dev *de
        dev->error_state = pci_channel_io_normal;
        set_pcie_port_type(dev);
  
 +      pci_set_of_node(dev);
 +      pci_set_acpi_fwnode(dev);
 +
        pci_dev_assign_slot(dev);
  
        /*
        default:                                    /* unknown header */
                pci_err(dev, "unknown header type %02x, ignoring device\n",
                        dev->hdr_type);
 +              pci_release_of_node(dev);
                return -EIO;
  
        bad:
@@@ -2230,7 -2225,6 +2230,6 @@@ static void pci_release_capabilities(st
  {
        pci_aer_exit(dev);
        pci_rcec_exit(dev);
-       pci_vpd_release(dev);
        pci_iov_release(dev);
        pci_free_cap_save_buffers(dev);
  }
@@@ -2379,7 -2373,10 +2378,7 @@@ static struct pci_dev *pci_scan_device(
        dev->vendor = l & 0xffff;
        dev->device = (l >> 16) & 0xffff;
  
 -      pci_set_of_node(dev);
 -
        if (pci_setup_device(dev)) {
 -              pci_release_of_node(dev);
                pci_bus_put(dev->bus);
                kfree(dev);
                return NULL;
@@@ -2430,7 -2427,9 +2429,7 @@@ static void pci_init_capabilities(struc
        pci_rcec_init(dev);             /* Root Complex Event Collector */
  
        pcie_report_downtraining(dev);
 -
 -      if (pci_probe_reset_function(dev) == 0)
 -              dev->reset_fn = 1;
 +      pci_init_reset_methods(dev);
  }
  
  /*
diff --combined include/linux/pci.h
                               PCI_STATUS_SIG_TARGET_ABORT | \
                               PCI_STATUS_PARITY)
  
 +/* Number of reset methods used in pci_reset_fn_methods array in pci.c */
 +#define PCI_NUM_RESET_METHODS 7
 +
 +#define PCI_RESET_PROBE               true
 +#define PCI_RESET_DO_RESET    false
 +
  /*
   * The PCI interface treats multi-function devices as independent
   * devices.  The slot/function address of each device is encoded
@@@ -306,9 -300,14 +306,14 @@@ struct pci_cap_saved_state 
        struct pci_cap_saved_data       cap;
  };
  
+ struct pci_vpd {
+       struct mutex    lock;
+       unsigned int    len;
+       u8              cap;
+ };
  struct irq_affinity;
  struct pcie_link_state;
- struct pci_vpd;
  struct pci_sriov;
  struct pci_p2pdma;
  struct rcec_ea;
@@@ -339,7 -338,6 +344,7 @@@ struct pci_dev 
        struct rcec_ea  *rcec_ea;       /* RCEC cached endpoint association */
        struct pci_dev  *rcec;          /* Associated RCEC device */
  #endif
 +      u32             devcap;         /* PCIe Device Capabilities */
        u8              pcie_cap;       /* PCIe capability offset */
        u8              msi_cap;        /* MSI capability offset */
        u8              msix_cap;       /* MSI-X capability offset */
                                           supported from root to here */
        u16             l1ss;           /* L1SS Capability pointer */
  #endif
 +      unsigned int    pasid_no_tlp:1;         /* PASID works without TLP Prefix */
        unsigned int    eetlp_prefix_path:1;    /* End-to-End TLP Prefix */
  
        pci_channel_state_t error_state;        /* Current connectivity state */
        unsigned int    state_saved:1;
        unsigned int    is_physfn:1;
        unsigned int    is_virtfn:1;
 -      unsigned int    reset_fn:1;
        unsigned int    is_hotplug_bridge:1;
        unsigned int    shpc_managed:1;         /* SHPC owned by shpchp */
        unsigned int    is_thunderbolt:1;       /* Thunderbolt controller */
  #ifdef CONFIG_PCI_MSI
        const struct attribute_group **msi_irq_groups;
  #endif
-       struct pci_vpd *vpd;
+       struct pci_vpd  vpd;
  #ifdef CONFIG_PCIE_DPC
        u16             dpc_cap;
        unsigned int    dpc_rp_extensions:1;
        char            *driver_override; /* Driver name to force a match */
  
        unsigned long   priv_flags;     /* Private flags for the PCI driver */
 +
 +      /* These methods index pci_reset_fn_methods[] */
 +      u8 reset_methods[PCI_NUM_RESET_METHODS]; /* In priority order */
  };
  
  static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
@@@ -1238,7 -1233,7 +1243,7 @@@ u32 pcie_bandwidth_available(struct pci
                             enum pci_bus_speed *speed,
                             enum pcie_link_width *width);
  void pcie_print_link_status(struct pci_dev *dev);
 -bool pcie_has_flr(struct pci_dev *dev);
 +int pcie_reset_flr(struct pci_dev *dev, bool probe);
  int pcie_flr(struct pci_dev *dev);
  int __pci_reset_function_locked(struct pci_dev *dev);
  int pci_reset_function(struct pci_dev *dev);
@@@ -1891,7 -1886,9 +1896,7 @@@ int pci_iobar_pfn(struct pci_dev *pdev
  #define pci_resource_end(dev, bar)    ((dev)->resource[(bar)].end)
  #define pci_resource_flags(dev, bar)  ((dev)->resource[(bar)].flags)
  #define pci_resource_len(dev,bar) \
 -      ((pci_resource_start((dev), (bar)) == 0 &&      \
 -        pci_resource_end((dev), (bar)) ==             \
 -        pci_resource_start((dev), (bar))) ? 0 :       \
 +      ((pci_resource_end((dev), (bar)) == 0) ? 0 :    \
                                                        \
         (pci_resource_end((dev), (bar)) -              \
          pci_resource_start((dev), (bar)) + 1))
@@@ -2258,20 -2255,6 +2263,6 @@@ int pci_enable_atomic_ops_to_root(struc
  #define PCI_VPD_LRDT_RO_DATA          PCI_VPD_LRDT_ID(PCI_VPD_LTIN_RO_DATA)
  #define PCI_VPD_LRDT_RW_DATA          PCI_VPD_LRDT_ID(PCI_VPD_LTIN_RW_DATA)
  
- /* Small Resource Data Type Tag Item Names */
- #define PCI_VPD_STIN_END              0x0f    /* End */
- #define PCI_VPD_SRDT_END              (PCI_VPD_STIN_END << 3)
- #define PCI_VPD_SRDT_TIN_MASK         0x78
- #define PCI_VPD_SRDT_LEN_MASK         0x07
- #define PCI_VPD_LRDT_TIN_MASK         0x7f
- #define PCI_VPD_LRDT_TAG_SIZE         3
- #define PCI_VPD_SRDT_TAG_SIZE         1
- #define PCI_VPD_INFO_FLD_HDR_SIZE     3
  #define PCI_VPD_RO_KEYWORD_PARTNO     "PN"
  #define PCI_VPD_RO_KEYWORD_SERIALNO   "SN"
  #define PCI_VPD_RO_KEYWORD_MFR_ID     "MN"
  #define PCI_VPD_RO_KEYWORD_CHKSUM     "RV"
  
  /**
-  * pci_vpd_lrdt_size - Extracts the Large Resource Data Type length
-  * @lrdt: Pointer to the beginning of the Large Resource Data Type tag
-  *
-  * Returns the extracted Large Resource Data Type length.
-  */
- static inline u16 pci_vpd_lrdt_size(const u8 *lrdt)
- {
-       return (u16)lrdt[1] + ((u16)lrdt[2] << 8);
- }
- /**
-  * pci_vpd_lrdt_tag - Extracts the Large Resource Data Type Tag Item
-  * @lrdt: Pointer to the beginning of the Large Resource Data Type tag
-  *
-  * Returns the extracted Large Resource Data Type Tag item.
-  */
- static inline u16 pci_vpd_lrdt_tag(const u8 *lrdt)
- {
-       return (u16)(lrdt[0] & PCI_VPD_LRDT_TIN_MASK);
- }
- /**
-  * pci_vpd_srdt_size - Extracts the Small Resource Data Type length
-  * @srdt: Pointer to the beginning of the Small Resource Data Type tag
-  *
-  * Returns the extracted Small Resource Data Type length.
-  */
- static inline u8 pci_vpd_srdt_size(const u8 *srdt)
- {
-       return (*srdt) & PCI_VPD_SRDT_LEN_MASK;
- }
- /**
-  * pci_vpd_srdt_tag - Extracts the Small Resource Data Type Tag Item
-  * @srdt: Pointer to the beginning of the Small Resource Data Type tag
+  * pci_vpd_alloc - Allocate buffer and read VPD into it
+  * @dev: PCI device
+  * @size: pointer to field where VPD length is returned
   *
-  * Returns the extracted Small Resource Data Type Tag Item.
+  * Returns pointer to allocated buffer or an ERR_PTR in case of failure
   */
- static inline u8 pci_vpd_srdt_tag(const u8 *srdt)
- {
-       return ((*srdt) & PCI_VPD_SRDT_TIN_MASK) >> 3;
- }
+ void *pci_vpd_alloc(struct pci_dev *dev, unsigned int *size);
  
  /**
-  * pci_vpd_info_field_size - Extracts the information field length
-  * @info_field: Pointer to the beginning of an information field header
+  * pci_vpd_find_id_string - Locate id string in VPD
+  * @buf: Pointer to buffered VPD data
+  * @len: The length of the buffer area in which to search
+  * @size: Pointer to field where length of id string is returned
   *
-  * Returns the extracted information field length.
+  * Returns the index of the id string or -ENOENT if not found.
   */
- static inline u8 pci_vpd_info_field_size(const u8 *info_field)
- {
-       return info_field[2];
- }
+ int pci_vpd_find_id_string(const u8 *buf, unsigned int len, unsigned int *size);
  
  /**
-  * pci_vpd_find_tag - Locates the Resource Data Type tag provided
-  * @buf: Pointer to buffered vpd data
-  * @len: The length of the vpd buffer
-  * @rdt: The Resource Data Type to search for
+  * pci_vpd_find_ro_info_keyword - Locate info field keyword in VPD RO section
+  * @buf: Pointer to buffered VPD data
+  * @len: The length of the buffer area in which to search
+  * @kw: The keyword to search for
+  * @size: Pointer to field where length of found keyword data is returned
   *
-  * Returns the index where the Resource Data Type was found or
-  * -ENOENT otherwise.
+  * Returns the index of the information field keyword data or -ENOENT if
+  * not found.
   */
- int pci_vpd_find_tag(const u8 *buf, unsigned int len, u8 rdt);
+ int pci_vpd_find_ro_info_keyword(const void *buf, unsigned int len,
+                                const char *kw, unsigned int *size);
  
  /**
-  * pci_vpd_find_info_keyword - Locates an information field keyword in the VPD
-  * @buf: Pointer to buffered vpd data
-  * @off: The offset into the buffer at which to begin the search
-  * @len: The length of the buffer area, relative to off, in which to search
-  * @kw: The keyword to search for
+  * pci_vpd_check_csum - Check VPD checksum
+  * @buf: Pointer to buffered VPD data
+  * @len: VPD size
   *
-  * Returns the index where the information field keyword was found or
-  * -ENOENT otherwise.
+  * Returns 1 if VPD has no checksum, otherwise 0 or an errno
   */
- int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
-                             unsigned int len, const char *kw);
+ int pci_vpd_check_csum(const void *buf, unsigned int len);
  
  /* PCI <-> OF binding helpers */
  #ifdef CONFIG_OF