Commit a2582e05 authored by Qiang Yu's avatar Qiang Yu Committed by Manivannan Sadhasivam
Browse files

PCI: Add preceding capability position support in PCI_FIND_NEXT_*_CAP macros



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: default avatarQiang Yu <qiang.yu@oss.qualcomm.com>
Signed-off-by: default avatarManivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20251109-remove_cap-v1-1-2208f46f4dc2@oss.qualcomm.com
parent 8f0b4cce
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -13,13 +13,13 @@
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);

+1 −1
Original line number Diff line number Diff line
@@ -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);
}

/**
+3 −3
Original line number Diff line number Diff line
@@ -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;
+4 −4
Original line number Diff line number Diff line
@@ -426,7 +426,7 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
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);
	}

+19 −4
Original line number Diff line number Diff line
@@ -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 __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;							\