Skip to content

Commit 3c02084

Browse files
Hans Zhangbjorn-helgaas
authored andcommitted
PCI: Refactor capability search into PCI_FIND_NEXT_CAP()
The PCI Capability search functionality is duplicated across the PCI core and several controller drivers. The core's current implementation requires fully initialized PCI device and bus structures, which prevents controller drivers from using it during early initialization phases before these structures are available. Move the Capability search logic into a PCI_FIND_NEXT_CAP() macro that accepts a config space accessor function as an argument. This enables controller drivers to perform Capability discovery using their early access mechanisms prior to full device initialization while sharing the Capability search code. Convert the existing PCI core Capability search implementation to use PCI_FIND_NEXT_CAP(). Controller drivers can later use this with their early access mechanisms while maintaining the existing protection against infinite loops through preserved TTL checks. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Niklas Schnelle <schnelle@linux.ibm.com> Link: https://patch.msgid.link/20250813144529.303548-3-18255117159@163.com
1 parent 37d1ade commit 3c02084

2 files changed

Lines changed: 53 additions & 34 deletions

File tree

drivers/pci/pci.c

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
*/
1010

1111
#include <linux/acpi.h>
12-
#include <linux/align.h>
1312
#include <linux/kernel.h>
1413
#include <linux/delay.h>
1514
#include <linux/dmi.h>
@@ -424,36 +423,10 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
424423
return 1;
425424
}
426425

427-
static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
428-
u8 pos, int cap, int *ttl)
429-
{
430-
u8 id;
431-
u16 ent;
432-
433-
pci_bus_read_config_byte(bus, devfn, pos, &pos);
434-
435-
while ((*ttl)--) {
436-
if (pos < PCI_STD_HEADER_SIZEOF)
437-
break;
438-
pos = ALIGN_DOWN(pos, 4);
439-
pci_bus_read_config_word(bus, devfn, pos, &ent);
440-
441-
id = FIELD_GET(PCI_CAP_ID_MASK, ent);
442-
if (id == 0xff)
443-
break;
444-
if (id == cap)
445-
return pos;
446-
pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, ent);
447-
}
448-
return 0;
449-
}
450-
451426
static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
452427
u8 pos, int cap)
453428
{
454-
int ttl = PCI_FIND_CAP_TTL;
455-
456-
return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
429+
return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, bus, devfn);
457430
}
458431

459432
u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
@@ -649,16 +622,16 @@ EXPORT_SYMBOL_GPL(pci_get_dsn);
649622

650623
static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
651624
{
652-
int rc, ttl = PCI_FIND_CAP_TTL;
625+
int rc;
653626
u8 cap, mask;
654627

655628
if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST)
656629
mask = HT_3BIT_CAP_MASK;
657630
else
658631
mask = HT_5BIT_CAP_MASK;
659632

660-
pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos,
661-
PCI_CAP_ID_HT, &ttl);
633+
pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, pos,
634+
PCI_CAP_ID_HT, dev->bus, dev->devfn);
662635
while (pos) {
663636
rc = pci_read_config_byte(dev, pos + 3, &cap);
664637
if (rc != PCIBIOS_SUCCESSFUL)
@@ -667,9 +640,10 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
667640
if ((cap & mask) == ht_cap)
668641
return pos;
669642

670-
pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn,
671-
pos + PCI_CAP_LIST_NEXT,
672-
PCI_CAP_ID_HT, &ttl);
643+
pos = PCI_FIND_NEXT_CAP(pci_bus_read_config,
644+
pos + PCI_CAP_LIST_NEXT,
645+
PCI_CAP_ID_HT, dev->bus,
646+
dev->devfn);
673647
}
674648

675649
return 0;

drivers/pci/pci.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#ifndef DRIVERS_PCI_H
33
#define DRIVERS_PCI_H
44

5+
#include <linux/align.h>
6+
#include <linux/bitfield.h>
57
#include <linux/pci.h>
68

79
struct pcie_tlp_log;
@@ -88,6 +90,49 @@ bool pcie_cap_has_lnkctl(const struct pci_dev *dev);
8890
bool pcie_cap_has_lnkctl2(const struct pci_dev *dev);
8991
bool pcie_cap_has_rtctl(const struct pci_dev *dev);
9092

93+
/* Standard Capability finder */
94+
/**
95+
* PCI_FIND_NEXT_CAP - Find a PCI standard capability
96+
* @read_cfg: Function pointer for reading PCI config space
97+
* @start: Starting position to begin search
98+
* @cap: Capability ID to find
99+
* @args: Arguments to pass to read_cfg function
100+
*
101+
* Search the capability list in PCI config space to find @cap.
102+
* Implements TTL (time-to-live) protection against infinite loops.
103+
*
104+
* Return: Position of the capability if found, 0 otherwise.
105+
*/
106+
#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, args...) \
107+
({ \
108+
int __ttl = PCI_FIND_CAP_TTL; \
109+
u8 __id, __found_pos = 0; \
110+
u8 __pos = (start); \
111+
u16 __ent; \
112+
\
113+
read_cfg##_byte(args, __pos, &__pos); \
114+
\
115+
while (__ttl--) { \
116+
if (__pos < PCI_STD_HEADER_SIZEOF) \
117+
break; \
118+
\
119+
__pos = ALIGN_DOWN(__pos, 4); \
120+
read_cfg##_word(args, __pos, &__ent); \
121+
\
122+
__id = FIELD_GET(PCI_CAP_ID_MASK, __ent); \
123+
if (__id == 0xff) \
124+
break; \
125+
\
126+
if (__id == (cap)) { \
127+
__found_pos = __pos; \
128+
break; \
129+
} \
130+
\
131+
__pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, __ent); \
132+
} \
133+
__found_pos; \
134+
})
135+
91136
/* Functions internal to the PCI core code */
92137

93138
#ifdef CONFIG_DMI

0 commit comments

Comments
 (0)