[PATCH v10 3/6] PCI: Consolidate delimiter handling into pci_dev_str_match()

From: Wei Wang

Date: Tue Sep 22 2026 - 11:16:36 EST


Callers of pci_dev_str_match() manually checked for the ';' or ','
delimiter and advanced the parameter pointer past it. Move this common
logic into pci_dev_str_match() so callers no longer need to duplicate it.

As a side effect, pci_dev_str_match() now checks that a
pci:<vendor>:<device>[:<subvendor>:<subdevice>] token is immediately
followed by ';', ',' or the end of the string, and returns -EINVAL
otherwise. Previously, trailing characters after such a token (e.g.,
"pci=config_acs=110x@pci:10de:1234zz") were silently ignored: a
matching token was accepted as a match, and a non-matching one quietly
ended parsing of the rest of the parameter. Callers now report a parse
error in both cases.

The [<domain>:]<bus>:<device>.<func> form is unaffected, since
pci_dev_str_match_path() already rejects trailing characters.

Signed-off-by: Wei Wang <wei.w.wang@xxxxxxxxxxx>
Reviewed-by: Jason Gunthorpe <jgg@xxxxxxxxxx>
---
drivers/pci/pci.c | 43 ++++++++++++++++---------------------------
1 file changed, 16 insertions(+), 27 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 15a074e95504..3e2e34b24019 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -340,7 +340,7 @@ static int pci_dev_str_match_path(struct pci_dev *dev, const char *path,
* pci_dev_str_match - test if a string matches a device
* @dev: the PCI device to test
* @p: string to match the device against
- * @endptr: pointer to the string after the match
+ * @endptr: pointer to the string after the match, with the delimiter skipped
*
* Test if a string (typically from a kernel parameter) matches a specified
* PCI device. The string may be of one of the following formats:
@@ -389,13 +389,13 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,

p += count;

- if ((!vendor || vendor == dev->vendor) &&
- (!device || device == dev->device) &&
- (!subsystem_vendor ||
- subsystem_vendor == dev->subsystem_vendor) &&
- (!subsystem_device ||
- subsystem_device == dev->subsystem_device))
- goto found;
+ /* ret = 0 if no matching string found */
+ ret = (!vendor || vendor == dev->vendor) &&
+ (!device || device == dev->device) &&
+ (!subsystem_vendor ||
+ subsystem_vendor == dev->subsystem_vendor) &&
+ (!subsystem_device ||
+ subsystem_device == dev->subsystem_device);
} else {
/*
* PCI Bus, Device, Function IDs are specified
@@ -404,16 +404,17 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
ret = pci_dev_str_match_path(dev, p, &p);
if (ret < 0)
return ret;
- else if (ret)
- goto found;
}

- *endptr = p;
- return 0;
+ /*
+ * Whether we matched (ret == 1) or didn't (ret == 0),
+ * ensure the token ends with a valid boundary.
+ */
+ if (*p != '\0' && *p != ';' && *p != ',')
+ return -EINVAL;

-found:
- *endptr = p;
- return 1;
+ *endptr = *p == '\0' ? p : p + 1;
+ return ret;
}

static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
@@ -968,12 +969,6 @@ static void __pci_config_acs(struct pci_dev *dev, struct pci_acs *caps,
/* Found a match */
break;
}
-
- if (*p != ';' && *p != ',') {
- /* End of param or invalid format */
- break;
- }
- p++;
}

if (ret != 1)
@@ -6492,12 +6487,6 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
p);
break;
}
-
- if (*p != ';' && *p != ',') {
- /* End of param or invalid format */
- break;
- }
- p++;
}
out:
spin_unlock(&resource_alignment_lock);
--
2.51.0