]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: Add preceding capability position support in PCI_FIND_NEXT_*_CAP macros
authorQiang Yu <qiang.yu@oss.qualcomm.com>
Mon, 10 Nov 2025 06:59:40 +0000 (22:59 -0800)
committerManivannan Sadhasivam <mani@kernel.org>
Thu, 18 Dec 2025 07:16:16 +0000 (12:46 +0530)
Add support for finding the preceding capability position in PCI
capability list by extending the capability finding macros with an
additional parameter. This functionality is essential for modifying PCI
capability list, as it provides the necessary information to update the
"next" pointer of the predecessor capability when removing entries.

Modify two macros to accept a new 'prev_ptr' parameter:
- PCI_FIND_NEXT_CAP - Now accepts 'prev_ptr' parameter for standard
  capabilities
- PCI_FIND_NEXT_EXT_CAP - Now accepts 'prev_ptr' parameter for extended
  capabilities

When a capability is found, these macros:
- Store the position of the preceding capability in *prev_ptr
  (if prev_ptr != NULL)
- Maintain all existing functionality when prev_ptr is NULL

Update current callers to accommodate this API change by passing NULL to
'prev_ptr' argument if they do not care about the preceding capability
position.

No functional changes to driver behavior result from this commit as it
maintains the existing capability finding functionality while adding the
infrastructure for future capability removal operations.

Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20251109-remove_cap-v1-1-2208f46f4dc2@oss.qualcomm.com
drivers/pci/controller/cadence/pcie-cadence.c
drivers/pci/controller/dwc/pcie-designware-ep.c
drivers/pci/controller/dwc/pcie-designware.c
drivers/pci/pci.c
drivers/pci/pci.h

index e6f1a4ac0fb7ab664cd4641bdfac4c944684e6b5..a1eada56edba76095f1c4bad16fa7cea834d8a97 100644 (file)
 u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap)
 {
        return PCI_FIND_NEXT_CAP(cdns_pcie_read_cfg, PCI_CAPABILITY_LIST,
-                                cap, pcie);
+                                cap, NULL, pcie);
 }
 EXPORT_SYMBOL_GPL(cdns_pcie_find_capability);
 
 u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap)
 {
-       return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, pcie);
+       return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, NULL, pcie);
 }
 EXPORT_SYMBOL_GPL(cdns_pcie_find_ext_capability);
 
index 19571ac2b9617103666f6ee6b2d9a0a2d6f57020..f6c54625486e2aa8fcdacce21eaee91ce049bd3e 100644 (file)
@@ -72,7 +72,7 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar);
 static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
 {
        return PCI_FIND_NEXT_CAP(dw_pcie_ep_read_cfg, PCI_CAPABILITY_LIST,
-                                cap, ep, func_no);
+                                cap, NULL, ep, func_no);
 }
 
 /**
index 75fc8b767fccfe2a68816ed236c1ee17393ddd50..5d7a7e6f5724e1c719adeea2d629918fdc066d23 100644 (file)
@@ -226,13 +226,13 @@ void dw_pcie_version_detect(struct dw_pcie *pci)
 u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
 {
        return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap,
-                                pci);
+                                NULL, pci);
 }
 EXPORT_SYMBOL_GPL(dw_pcie_find_capability);
 
 u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
 {
-       return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, pci);
+       return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, NULL, pci);
 }
 EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
 
@@ -246,7 +246,7 @@ static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id,
                return 0;
 
        while ((vsec = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, vsec,
-                                            PCI_EXT_CAP_ID_VNDR, pci))) {
+                                            PCI_EXT_CAP_ID_VNDR, NULL, pci))) {
                header = dw_pcie_readl_dbi(pci, vsec + PCI_VNDR_HEADER);
                if (PCI_VNDR_HEADER_ID(header) == vsec_id)
                        return vsec;
index 13dbb405dc31f8054afa090a2d14acf16845f587..b1142fbbd6e5e03717a05f0aed4afe1f7be33e2d 100644 (file)
@@ -426,7 +426,7 @@ found:
 static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
                              u8 pos, int cap)
 {
-       return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, bus, devfn);
+       return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, NULL, bus, devfn);
 }
 
 u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
@@ -531,7 +531,7 @@ u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap)
                return 0;
 
        return PCI_FIND_NEXT_EXT_CAP(pci_bus_read_config, start, cap,
-                                    dev->bus, dev->devfn);
+                                    NULL, dev->bus, dev->devfn);
 }
 EXPORT_SYMBOL_GPL(pci_find_next_ext_capability);
 
@@ -600,7 +600,7 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
                mask = HT_5BIT_CAP_MASK;
 
        pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, pos,
-                               PCI_CAP_ID_HT, dev->bus, dev->devfn);
+                               PCI_CAP_ID_HT, NULL, dev->bus, dev->devfn);
        while (pos) {
                rc = pci_read_config_byte(dev, pos + 3, &cap);
                if (rc != PCIBIOS_SUCCESSFUL)
@@ -611,7 +611,7 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
 
                pos = PCI_FIND_NEXT_CAP(pci_bus_read_config,
                                        pos + PCI_CAP_LIST_NEXT,
-                                       PCI_CAP_ID_HT, dev->bus,
+                                       PCI_CAP_ID_HT, NULL, dev->bus,
                                        dev->devfn);
        }
 
index 0e67014aa0013a7086c3a45d576d4b1ca2bb159f..1d1742bd6a1bf8d1a4cabde9518a1579116cbb43 100644 (file)
@@ -103,17 +103,21 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
  * @read_cfg: Function pointer for reading PCI config space
  * @start: Starting position to begin search
  * @cap: Capability ID to find
+ * @prev_ptr: Pointer to store position of preceding capability (optional)
  * @args: Arguments to pass to read_cfg function
  *
- * Search the capability list in PCI config space to find @cap.
+ * Search the capability list in PCI config space to find @cap. If
+ * found, update *prev_ptr with the position of the preceding capability
+ * (if prev_ptr != NULL)
  * Implements TTL (time-to-live) protection against infinite loops.
  *
  * Return: Position of the capability if found, 0 otherwise.
  */
-#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, args...)               \
+#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, prev_ptr, args...)     \
 ({                                                                     \
        int __ttl = PCI_FIND_CAP_TTL;                                   \
-       u8 __id, __found_pos = 0;                                       \
+       u8 __id,  __found_pos = 0;                                      \
+       u8 __prev_pos = (start);                                        \
        u8 __pos = (start);                                             \
        u16 __ent;                                                      \
                                                                        \
@@ -132,9 +136,12 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
                                                                        \
                if (__id == (cap)) {                                    \
                        __found_pos = __pos;                            \
+                       if (prev_ptr != NULL)                           \
+                               *(u8 *)prev_ptr = __prev_pos;           \
                        break;                                          \
                }                                                       \
                                                                        \
+               __prev_pos = __pos;                                     \
                __pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, __ent);       \
        }                                                               \
        __found_pos;                                                    \
@@ -146,21 +153,26 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
  * @read_cfg: Function pointer for reading PCI config space
  * @start: Starting position to begin search (0 for initial search)
  * @cap: Extended capability ID to find
+ * @prev_ptr: Pointer to store position of preceding capability (optional)
  * @args: Arguments to pass to read_cfg function
  *
  * Search the extended capability list in PCI config space to find @cap.
+ * If found, update *prev_ptr with the position of the preceding capability
+ * (if prev_ptr != NULL)
  * Implements TTL protection against infinite loops using a calculated
  * maximum search count.
  *
  * Return: Position of the capability if found, 0 otherwise.
  */
-#define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, args...)           \
+#define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, prev_ptr, args...) \
 ({                                                                     \
        u16 __pos = (start) ?: PCI_CFG_SPACE_SIZE;                      \
        u16 __found_pos = 0;                                            \
+       u16 __prev_pos;                                                 \
        int __ttl, __ret;                                               \
        u32 __header;                                                   \
                                                                        \
+       __prev_pos = __pos;                                             \
        __ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;      \
        while (__ttl-- > 0 && __pos >= PCI_CFG_SPACE_SIZE) {            \
                __ret = read_cfg##_dword(args, __pos, &__header);       \
@@ -172,9 +184,12 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
                                                                        \
                if (PCI_EXT_CAP_ID(__header) == (cap) && __pos != start) {\
                        __found_pos = __pos;                            \
+                       if (prev_ptr != NULL)                           \
+                               *(u16 *)prev_ptr = __prev_pos;          \
                        break;                                          \
                }                                                       \
                                                                        \
+               __prev_pos = __pos;                                     \
                __pos = PCI_EXT_CAP_NEXT(__header);                     \
        }                                                               \
        __found_pos;                                                    \