aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2018-07-30 12:18:37 -0400
committerBjorn Helgaas <bhelgaas@google.com>2018-08-09 17:23:06 -0400
commit07d8d7e57c28ca9a07dab4efd75dad3a654aeb85 (patch)
tree53592de54320ccabbfd94f043769cc3881ad0b41
parentbd2e9567db72e37f7f4b90faa5133bc7365b5f65 (diff)
PCI: Make specifying PCI devices in kernel parameters reusable
Separate out the code to match a PCI device with a string (typically originating from a kernel parameter) from the pci_specified_resource_alignment() function into its own helper function. While we are at it, this change fixes the kernel style of the function (fixing a number of long lines and extra parentheses). Additionally, make the analogous change to the kernel parameter documentation: Separate the description of how to specify a PCI device into its own section at the head of the "pci=" parameter. This patch should have no functional alterations. Signed-off-by: Logan Gunthorpe <logang@deltatee.com> [bhelgaas: use "device" instead of "slot" in documentation since that's the usual language in the PCI specs] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Stephen Bates <sbates@raithlin.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com> Acked-by: Christian König <christian.koenig@amd.com>
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt28
-rw-r--r--drivers/pci/pci.c157
2 files changed, 126 insertions, 59 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index efc7aa7a0670..ab36fb34ed01 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2994,7 +2994,26 @@
2994 See header of drivers/block/paride/pcd.c. 2994 See header of drivers/block/paride/pcd.c.
2995 See also Documentation/blockdev/paride.txt. 2995 See also Documentation/blockdev/paride.txt.
2996 2996
2997 pci=option[,option...] [PCI] various PCI subsystem options: 2997 pci=option[,option...] [PCI] various PCI subsystem options.
2998
2999 Some options herein operate on a specific device
3000 or a set of devices (<pci_dev>). These are
3001 specified in one of the following formats:
3002
3003 [<domain>:]<bus>:<device>.<func>
3004 pci:<vendor>:<device>[:<subvendor>:<subdevice>]
3005
3006 Note: the first format specifies a PCI
3007 bus/device/function address which may change
3008 if new hardware is inserted, if motherboard
3009 firmware changes, or due to changes caused
3010 by other kernel parameters. If the
3011 domain is left unspecified, it is
3012 taken to be zero. The second format
3013 selects devices using IDs from the
3014 configuration space which may match multiple
3015 devices in the system.
3016
2998 earlydump [X86] dump PCI config space before the kernel 3017 earlydump [X86] dump PCI config space before the kernel
2999 changes anything 3018 changes anything
3000 off [X86] don't probe for the PCI bus 3019 off [X86] don't probe for the PCI bus
@@ -3123,11 +3142,10 @@
3123 window. The default value is 64 megabytes. 3142 window. The default value is 64 megabytes.
3124 resource_alignment= 3143 resource_alignment=
3125 Format: 3144 Format:
3126 [<order of align>@][<domain>:]<bus>:<slot>.<func>[; ...] 3145 [<order of align>@]<pci_dev>[; ...]
3127 [<order of align>@]pci:<vendor>:<device>\
3128 [:<subvendor>:<subdevice>][; ...]
3129 Specifies alignment and device to reassign 3146 Specifies alignment and device to reassign
3130 aligned memory resources. 3147 aligned memory resources. How to
3148 specify the device is described above.
3131 If <order of align> is not specified, 3149 If <order of align> is not specified,
3132 PAGE_SIZE is used as alignment. 3150 PAGE_SIZE is used as alignment.
3133 PCI-PCI bridge can be specified, if resource 3151 PCI-PCI bridge can be specified, if resource
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 97acba712e4e..1574b2da25e7 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -191,6 +191,92 @@ void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
191EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar); 191EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
192#endif 192#endif
193 193
194/**
195 * pci_dev_str_match - test if a string matches a device
196 * @dev: the PCI device to test
197 * @p: string to match the device against
198 * @endptr: pointer to the string after the match
199 *
200 * Test if a string (typically from a kernel parameter) matches a specified
201 * PCI device. The string may be of one of the following formats:
202 *
203 * [<domain>:]<bus>:<device>.<func>
204 * pci:<vendor>:<device>[:<subvendor>:<subdevice>]
205 *
206 * The first format specifies a PCI bus/device/function address which
207 * may change if new hardware is inserted, if motherboard firmware changes,
208 * or due to changes caused in kernel parameters. If the domain is
209 * left unspecified, it is taken to be 0.
210 *
211 * The second format matches devices using IDs in the configuration
212 * space which may match multiple devices in the system. A value of 0
213 * for any field will match all devices. (Note: this differs from
214 * in-kernel code that uses PCI_ANY_ID which is ~0; this is for
215 * legacy reasons and convenience so users don't have to specify
216 * FFFFFFFFs on the command line.)
217 *
218 * Returns 1 if the string matches the device, 0 if it does not and
219 * a negative error code if the string cannot be parsed.
220 */
221static int pci_dev_str_match(struct pci_dev *dev, const char *p,
222 const char **endptr)
223{
224 int ret;
225 int seg, bus, slot, func, count;
226 unsigned short vendor, device, subsystem_vendor, subsystem_device;
227
228 if (strncmp(p, "pci:", 4) == 0) {
229 /* PCI vendor/device (subvendor/subdevice) IDs are specified */
230 p += 4;
231 ret = sscanf(p, "%hx:%hx:%hx:%hx%n", &vendor, &device,
232 &subsystem_vendor, &subsystem_device, &count);
233 if (ret != 4) {
234 ret = sscanf(p, "%hx:%hx%n", &vendor, &device, &count);
235 if (ret != 2)
236 return -EINVAL;
237
238 subsystem_vendor = 0;
239 subsystem_device = 0;
240 }
241
242 p += count;
243
244 if ((!vendor || vendor == dev->vendor) &&
245 (!device || device == dev->device) &&
246 (!subsystem_vendor ||
247 subsystem_vendor == dev->subsystem_vendor) &&
248 (!subsystem_device ||
249 subsystem_device == dev->subsystem_device))
250 goto found;
251
252 } else {
253 /* PCI Bus, Device, Function IDs are specified */
254 ret = sscanf(p, "%x:%x:%x.%x%n", &seg, &bus, &slot,
255 &func, &count);
256 if (ret != 4) {
257 seg = 0;
258 ret = sscanf(p, "%x:%x.%x%n", &bus, &slot,
259 &func, &count);
260 if (ret != 3)
261 return -EINVAL;
262 }
263
264 p += count;
265
266 if (seg == pci_domain_nr(dev->bus) &&
267 bus == dev->bus->number &&
268 slot == PCI_SLOT(dev->devfn) &&
269 func == PCI_FUNC(dev->devfn))
270 goto found;
271 }
272
273 *endptr = p;
274 return 0;
275
276found:
277 *endptr = p;
278 return 1;
279}
194 280
195static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, 281static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
196 u8 pos, int cap, int *ttl) 282 u8 pos, int cap, int *ttl)
@@ -5454,10 +5540,10 @@ static DEFINE_SPINLOCK(resource_alignment_lock);
5454static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev, 5540static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
5455 bool *resize) 5541 bool *resize)
5456{ 5542{
5457 int seg, bus, slot, func, align_order, count; 5543 int align_order, count;
5458 unsigned short vendor, device, subsystem_vendor, subsystem_device;
5459 resource_size_t align = pcibios_default_alignment(); 5544 resource_size_t align = pcibios_default_alignment();
5460 char *p; 5545 const char *p;
5546 int ret;
5461 5547
5462 spin_lock(&resource_alignment_lock); 5548 spin_lock(&resource_alignment_lock);
5463 p = resource_alignment_param; 5549 p = resource_alignment_param;
@@ -5477,58 +5563,21 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
5477 } else { 5563 } else {
5478 align_order = -1; 5564 align_order = -1;
5479 } 5565 }
5480 if (strncmp(p, "pci:", 4) == 0) { 5566
5481 /* PCI vendor/device (subvendor/subdevice) ids are specified */ 5567 ret = pci_dev_str_match(dev, p, &p);
5482 p += 4; 5568 if (ret == 1) {
5483 if (sscanf(p, "%hx:%hx:%hx:%hx%n", 5569 *resize = true;
5484 &vendor, &device, &subsystem_vendor, &subsystem_device, &count) != 4) { 5570 if (align_order == -1)
5485 if (sscanf(p, "%hx:%hx%n", &vendor, &device, &count) != 2) { 5571 align = PAGE_SIZE;
5486 printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: pci:%s\n", 5572 else
5487 p); 5573 align = 1 << align_order;
5488 break; 5574 break;
5489 } 5575 } else if (ret < 0) {
5490 subsystem_vendor = subsystem_device = 0; 5576 pr_err("PCI: Can't parse resource_alignment parameter: %s\n",
5491 } 5577 p);
5492 p += count; 5578 break;
5493 if ((!vendor || (vendor == dev->vendor)) &&
5494 (!device || (device == dev->device)) &&
5495 (!subsystem_vendor || (subsystem_vendor == dev->subsystem_vendor)) &&
5496 (!subsystem_device || (subsystem_device == dev->subsystem_device))) {
5497 *resize = true;
5498 if (align_order == -1)
5499 align = PAGE_SIZE;
5500 else
5501 align = 1 << align_order;
5502 /* Found */
5503 break;
5504 }
5505 }
5506 else {
5507 if (sscanf(p, "%x:%x:%x.%x%n",
5508 &seg, &bus, &slot, &func, &count) != 4) {
5509 seg = 0;
5510 if (sscanf(p, "%x:%x.%x%n",
5511 &bus, &slot, &func, &count) != 3) {
5512 /* Invalid format */
5513 printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
5514 p);
5515 break;
5516 }
5517 }
5518 p += count;
5519 if (seg == pci_domain_nr(dev->bus) &&
5520 bus == dev->bus->number &&
5521 slot == PCI_SLOT(dev->devfn) &&
5522 func == PCI_FUNC(dev->devfn)) {
5523 *resize = true;
5524 if (align_order == -1)
5525 align = PAGE_SIZE;
5526 else
5527 align = 1 << align_order;
5528 /* Found */
5529 break;
5530 }
5531 } 5579 }
5580
5532 if (*p != ';' && *p != ',') { 5581 if (*p != ';' && *p != ',') {
5533 /* End of param or invalid format */ 5582 /* End of param or invalid format */
5534 break; 5583 break;