Skip to contentSkip to conversation

Add parameter for disabling ACS redirection for P2P

PATCH New Logan Gunthorpe 3 participants 10 messages May 31, 2018 – Jun 1, 2018

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Add parameter for disabling ACS redirection for P2P

Hi,

As discussed in our PCI P2PDMA series, we'd like to add a kernel parameter for selectively disabling ACS redirection for select bridges. Seeing this turned out to be a small series in itself, we've decided to send this separately from the P2P work.

This series generalizes the code already done for the resource_alignment option that already exists. The first patch creates a helper function to match PCI devices against strings based on the code that already existed in pci_specified_resource_alignment().

The second patch expands the new helper to optionally take a path of PCI devfns. This is to address Alex's renumbering concern when using simple bus-devfns. The implementation is essentially how he described it and similar to the Intel VT-d spec (Section 8.3.1).

The final patch adds the disable_acs_redir kernel parameter which takes a list of PCI devices and will disable the ACS P2P Request Redirect, ACS P2P Completion Redirect and ACS P2P Egress Control bits for the selected devices. This allows P2P traffic between selected bridges and seeing it's done at boot, before IOMMU group creating the IOMMU groups will be created correctly based on the bits.

Thanks,

Logan

--

Changes since v1:

* Reworked pci_dev_str_match_path using strrchr as suggested by Alex
* Collected Christian's Acks

--

Logan Gunthorpe (3):
PCI: Make specifying PCI devices in kernel parameters reusable
PCI: Allow specifying devices using a base bus and path of devfns
PCI: Introduce the disable_acs_redir parameter

 Documentation/admin-guide/kernel-parameters.txt |  39 ++-
 drivers/pci/pci.c                               | 353 ++++++++++++++++++++----
 2 files changed, 331 insertions(+), 61 deletions(-)

--
2.11.0

#1 lore raw

PATCH v2 1/3 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: Separating the description of how to specify a PCI device into it's own section at the head of the pci= parameter.

---
 Documentation/admin-guide/kernel-parameters.txt |  26 +++-
 drivers/pci/pci.c                               | 153 +++++++++++++++---------
 2 files changed, 120 insertions(+), 59 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +21 -5
index f2040d46f095..e58cc671ff92 100644
@@ -2985,7 +2985,24 @@
 			See header of drivers/block/paride/pcd.c.
 			See also Documentation/blockdev/paride.txt.
 
-	pci=option[,option...]	[PCI] various PCI subsystem options:
+	pci=option[,option...]	[PCI] various PCI subsystem options.
+
+				Some options herein operate on a specific device
+				or a set of devices (<pci_dev>). These are
+				specified in one of two formats:
+
+				[<domain>:]<bus>:<slot>.<func>
+				pci:<vendor>:<device>[:<subvendor>:<subdevice>]
+
+				Note: the first format specifies a PCI
+				bus/slot/function address which may change
+				if new hardware is inserted, if motherboard
+				firmware changes, or due to changes caused
+				by other kernel parameters. The second format
+				selects devices using IDs from the
+				configuration space which may match multiple
+				devices in the system.
+
 		earlydump	[X86] dump PCI config space before the kernel
 			        changes anything
 		off		[X86] don't probe for the PCI bus
@@ -3114,11 +3131,10 @@
 				window. The default value is 64 megabytes.
 		resource_alignment=
 				Format:
-				[<order of align>@][<domain>:]<bus>:<slot>.<func>[; ...]
-				[<order of align>@]pci:<vendor>:<device>\
-						[:<subvendor>:<subdevice>][; ...]
+				[<order of align>@]<pci_dev>[; ...]
 				Specifies alignment and device to reassign
-				aligned memory resources.
+				aligned memory resources. How to
+				specify the device is described above.
 				If <order of align> is not specified,
 				PAGE_SIZE is used as alignment.
 				PCI-PCI bridge can be specified, if resource
drivers/pci/pci.c +99 -54

173 lines not on this page · raw message

Signature · 1 line
2.11.0
#2 lore raw

Re: [PATCH v2 1/3] PCI: Make specifying PCI devices in kernel parameters reusable

On Fri, Jun 1, 2018 at 2:50 AM, Logan Gunthorpe <[email protected]> wrote= :

Quoted 8 lines

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).

Quoted 7 lines

Additionally, make the analogous change to the kernel parameter
documentation: Separating the description of how to specify a PCI device into it's own section at the head of the pci=3D parameter.

Sorry for maybe being late here.

Review

Quoted 4 lines
(quoted diff) +3 -1
-       pci=3Doption[,option...]  [PCI] various PCI subsystem options:
+       pci=3Doption[,option...]  [PCI] various PCI subsystem options.
+
+                               Some options herein operate on a specific=

device

Quoted 1 line

+ or a set of devices (<pci_dev>). These ar=

e

Quoted 1 line

+ specified in one of two formats:

I would rather to add

<pci_dev>

here in the same way as done for options.
It would be easy for people to find a referenced paragraph.

Documentation/admin-guide/kernel-parameters.txt

Quoted 3 lines
Documentation/admin-guide/kernel-parameters.txt +3 -0
+
+                               [<domain>:]<bus>:<slot>.<func>
+                               pci:<vendor>:<device>[:<subvendor>:<subde=

vice>]

Documentation/admin-guide/kernel-parameters.txt

Quoted 3 lines
Documentation/admin-guide/kernel-parameters.txt +3 -0
+
+                               Note: the first format specifies a PCI
+                               bus/slot/function address which may chang=

e

Quoted 1 line

+ if new hardware is inserted, if motherboa=

rd

Quoted 1 line

+ firmware changes, or due to changes cause=

d

Quoted 1 line

+ by other kernel parameters. The second fo=

rmat

Review

Quoted 2 lines
(quoted diff) +2 -0
+                               selects devices using IDs from the
+                               configuration space which may match multi=

ple

drivers/pci/pci.c void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar) · line 210

Quoted 4 lines
drivers/pci/pci.c +3 -0
+                               devices in the system.
 
+static int pci_dev_str_match(struct pci_dev *dev, const char *p,
+                            const char **endptr)

This change I hope has no functional alteration, so, can be split to a separate patch.

--=20
With Best Regards,
Andy Shevchenko

#3 lore raw

Re: [PATCH v2 1/3] PCI: Make specifying PCI devices in kernel parameters reusable

Quoted 7 lines · Andy Shevchenko

Documentation/admin-guide/kernel-parameters.txt line 2992

Quoted 6 lines
Documentation/admin-guide/kernel-parameters.txt +5 -1
-       pci=option[,option...]  [PCI] various PCI subsystem options:
+       pci=option[,option...]  [PCI] various PCI subsystem options.
+
+                               Some options herein operate on a specific device
+                               or a set of devices (<pci_dev>). These are
+                               specified in one of two formats:
Quoted 6 lines

I would rather to add

<pci_dev>

here in the same way as done for options.
It would be easy for people to find a referenced paragraph.

Sorry, I don't understand what you are asking. Can you be more specific?

Quoted 13 lines
Quoted 12 lines
Documentation/admin-guide/kernel-parameters.txt +12 -0
+
+                               [<domain>:]<bus>:<slot>.<func>
+                               pci:<vendor>:<device>[:<subvendor>:<subdevice>]
+
+                               Note: the first format specifies a PCI
+                               bus/slot/function address which may change
+                               if new hardware is inserted, if motherboard
+                               firmware changes, or due to changes caused
+                               by other kernel parameters. The second format
+                               selects devices using IDs from the
+                               configuration space which may match multiple
+                               devices in the system.
Quoted 5 lines

drivers/pci/pci.c void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar) · line 210

Quoted 2 lines
drivers/pci/pci.c +2 -0
+static int pci_dev_str_match(struct pci_dev *dev, const char *p,
+                            const char **endptr)

This change I hope has no functional alteration, so, can be split to a separate patch.

That's all this patch does... Or do you want be to separate out documentation from implementation? That just seems a bit excessive to me.

Logan

#4 lore raw

PATCH v2 2/3 PCI: Allow specifying devices using a base bus and path of devfns

In reply to Logan Gunthorpe

When specifying PCI devices on the kernel command line using a BDF, the bus numbers can change when adding or replacing a device, changing motherboard firmware, or applying kernel parameters like pci=assign-buses. When this happens, it is usually undesirable to apply whatever command line tweak to the wrong device.

Therefore, it is useful to be able to specify devices with a base bus number and the path of devfns needed to get to it. (Similar to the "device scope" structure in the Intel VT-d spec, Section 8.3.1.)

Thus, we add an option to specify devices in the following format:

path:[<domain>:]<bus>:<slot>.<func>/<slot>.<func>[/ ...]

The path can be any segment within the PCI hierarchy of any length and determined through the use of 'lspci -t'. When specified this way, it is less likely that a renumbered bus will result in a valid device specification and the tweak won't be applied to the wrong device.

---
 Documentation/admin-guide/kernel-parameters.txt |  12 ++-
 drivers/pci/pci.c                               | 101 +++++++++++++++++++++++-
 2 files changed, 107 insertions(+), 6 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +8 -4
index e58cc671ff92..bc51b316f485 100644
@@ -2989,9 +2989,10 @@
 
 				Some options herein operate on a specific device
 				or a set of devices (<pci_dev>). These are
-				specified in one of two formats:
+				specified in one of three formats:
 
 				[<domain>:]<bus>:<slot>.<func>
+				path:[<domain>:]<bus>:<slot>.<func>/<slot>.<func>[/ ...]
 				pci:<vendor>:<device>[:<subvendor>:<subdevice>]
 
 				Note: the first format specifies a PCI
@@ -2999,9 +3000,12 @@
 				if new hardware is inserted, if motherboard
 				firmware changes, or due to changes caused
 				by other kernel parameters. The second format
-				selects devices using IDs from the
-				configuration space which may match multiple
-				devices in the system.
+				specifies a path from a device through
+				a path of multiple slot/function addresses
+				(this is more robust against renumbering
+				issues). The third format selects devices using
+				IDs from the configuration space which may match
+				multiple devices in the system.
 
 		earlydump	[X86] dump PCI config space before the kernel
 			        changes anything
drivers/pci/pci.c +99 -2

128 lines not on this page · raw message

Signature · 1 line
2.11.0
#5 lore raw

Re: [PATCH v2 2/3] PCI: Allow specifying devices using a base bus and path of devfns

On Fri, Jun 1, 2018 at 2:50 AM, Logan Gunthorpe <[email protected]> wrote= :

Quoted 10 lines

When specifying PCI devices on the kernel command line using a BDF, the bus numbers can change when adding or replacing a device, changing motherboard firmware, or applying kernel parameters like pci=3Dassign-buses. When this happens, it is usually undesirable to apply whatever command line tweak to the wrong device.

Therefore, it is useful to be able to specify devices with a base bus number and the path of devfns needed to get to it. (Similar to the "device scope" structure in the Intel VT-d spec, Section 8.3.1.)

Quoted 7 lines

Thus, we add an option to specify devices in the following format:

path:[<domain>:]<bus>:<slot>.<func>/<slot>.<func>[/ ...]

The path can be any segment within the PCI hierarchy of any length and determined through the use of 'lspci -t'. When specified this way, it is less likely that a renumbered bus will result in a valid device specifica=

tion

Documentation/admin-guide/kernel-parameters.txt line 2992

Quoted 8 lines

and the tweak won't be applied to the wrong device.

Documentation/admin-guide/kernel-parameters.txt +1 -1
-                               specified in one of two formats:
+                               specified in one of three formats:

...in one of the following formats:

in the first place and don't fix it each time you add/remove one?

--=20
With Best Regards,
Andy Shevchenko

#6 lore raw

Re: [PATCH v2 2/3] PCI: Allow specifying devices using a base bus and path of devfns

Quoted 6 lines · Andy Shevchenko

Documentation/admin-guide/kernel-parameters.txt line 2992

Quoted 2 lines
Documentation/admin-guide/kernel-parameters.txt +1 -1
-                               specified in one of two formats:
+                               specified in one of three formats:

...in one of the following formats:

in the first place and don't fix it each time you add/remove one?

Sure, I'll make the change in v3.

Thanks,

Logan

#7 lore raw

Re: [PATCH v2 2/3] PCI: Allow specifying devices using a base bus and path of devfns

In reply to Logan Gunthorpe
Quoted 138 lines · On Thu, 31 May 2018 17:50:09 -0600 Logan Gunthorpe <[email protected]> wrote:

When specifying PCI devices on the kernel command line using a BDF, the bus numbers can change when adding or replacing a device, changing motherboard firmware, or applying kernel parameters like pci=assign-buses. When this happens, it is usually undesirable to apply whatever command line tweak to the wrong device.

Therefore, it is useful to be able to specify devices with a base bus number and the path of devfns needed to get to it. (Similar to the "device scope" structure in the Intel VT-d spec, Section 8.3.1.)

Thus, we add an option to specify devices in the following format:

path:[<domain>:]<bus>:<slot>.<func>/<slot>.<func>[/ ...]

The path can be any segment within the PCI hierarchy of any length and determined through the use of 'lspci -t'. When specified this way, it is less likely that a renumbered bus will result in a valid device specification and the tweak won't be applied to the wrong device.

---
 Documentation/admin-guide/kernel-parameters.txt |  12 ++-
 drivers/pci/pci.c                               | 101 +++++++++++++++++++++++-
 2 files changed, 107 insertions(+), 6 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +8 -4
index e58cc671ff92..bc51b316f485 100644
@@ -2989,9 +2989,10 @@
 
 				Some options herein operate on a specific device
 				or a set of devices (<pci_dev>). These are
-				specified in one of two formats:
+				specified in one of three formats:
 
 				[<domain>:]<bus>:<slot>.<func>
+				path:[<domain>:]<bus>:<slot>.<func>/<slot>.<func>[/ ...]
 				pci:<vendor>:<device>[:<subvendor>:<subdevice>]
 
 				Note: the first format specifies a PCI
@@ -2999,9 +3000,12 @@
 				if new hardware is inserted, if motherboard
 				firmware changes, or due to changes caused
 				by other kernel parameters. The second format
-				selects devices using IDs from the
-				configuration space which may match multiple
-				devices in the system.
+				specifies a path from a device through
+				a path of multiple slot/function addresses
+				(this is more robust against renumbering
+				issues). The third format selects devices using
+				IDs from the configuration space which may match
+				multiple devices in the system.
 
 		earlydump	[X86] dump PCI config space before the kernel
 			        changes anything
drivers/pci/pci.c +71 -0
index 85fec5e2640b..39f11bd0ee03 100644
@@ -184,22 +184,111 @@ EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
 #endif
 
 /**
+ * pci_dev_str_match_path - test if a path 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
+ *
+ * Test if a string (typically from a kernel parameter) formated as a
+ * path of slot/function addresses matches a PCI device. The string must
+ * be of the form:
+ *
+ *   [<domain>:]<bus>:<slot>.<func>/<slot>.<func>[/ ...]
+ *
+ * A path for a device can be obtained using 'lspci -t'. Using a path
+ * is more robust against renumbering of devices than using only
+ * a single bus, slot and function address.
+ *
+ * Returns 1 if the string matches the device, 0 if it does not and
+ * a negative error code if it fails to parse the string.
+ */
+static int pci_dev_str_match_path(struct pci_dev *dev, const char *path,
+				  const char **endptr)
+{
+	int ret;
+	int seg, bus, slot, func;
+	char *wpath, *p;
+	char end;
+
+	*endptr = strchrnul(path, ';');
+
+	wpath = kmemdup_nul(path, *endptr - path, GFP_KERNEL);
+	if (!wpath)
+		return -ENOMEM;
+
+	while (1) {
+		p = strrchr(wpath, '/');
+		if (!p)
+			break;
+		ret = sscanf(p, "/%x.%x%c", &slot, &func, &end);
+		if (ret != 2) {
+			ret = -EINVAL;
+			goto free_and_exit;
+		}
+
+		if (dev->devfn != PCI_DEVFN(slot, func)) {
+			ret = 0;
+			goto free_and_exit;
+		}
+
+		/*
+		 * Note: we don't need to get a reference to the upstream
+		 * bridge because we hold a reference to the top level
+		 * device which should hold a reference to the bridge,
+		 * and so on.
+		 */
+		dev = pci_upstream_bridge(dev);
+		if (!dev) {
+			ret = 0;
+			goto free_and_exit;
+		}
+
+		*p = 0;
+	}
+
+	ret = sscanf(wpath, "%x:%x:%x.%x%c", &seg, &bus, &slot,
+		     &func, &end);
+	if (ret != 4) {
+		seg = 0;
+		ret = sscanf(wpath, "%x:%x.%x%c", &bus, &slot, &func, &end);
+		if (ret != 3) {
+			ret = -EINVAL;
+			goto free_and_exit;
+		}

drivers/pci/pci.c EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar); · line 267

Quoted 10 lines
drivers/pci/pci.c +10 -0
+	}
+
+	ret = (seg == pci_domain_nr(dev->bus) &&
+	       bus == dev->bus->number &&
+	       dev->devfn == PCI_DEVFN(slot, func));
+
+free_and_exit:
+	kfree(wpath);
+	return ret;
+}

Cool, I'm glad this worked. I note though that there's really not much difference between:

[domain:]bus:slot.fn

and

[domain:]bus:slot.fn[/slot.fn[/slot.fn[/...]]]

IOW, what's defined here as the "path:" specification doesn't require that we start at a root bus device, it can really specify a path starting anywhere, including the target device directly. So can we simply extend domain:bus:slot.fn to support paths without a separate identifier? Thanks,

Alex

Quoted 45 lines
drivers/pci/pci.c +18 -2
+
+/**
  * 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
  *
  * Test if a string (typically from a kernel parameter) matches a
- * specified. The string may be of one of two forms formats:
+ * specified. The string may be of one of three formats:
  *
  *   [<domain>:]<bus>:<slot>.<func>
+ *   path:[<domain>:]<bus>:<slot>.<func>/<slot>.<func>[/ ...]
  *   pci:<vendor>:<device>[:<subvendor>:<subdevice>]
  *
  * The first format specifies a PCI bus/slot/function address which
  * may change if new hardware is inserted, if motherboard firmware changes,
  * or due to changes caused in kernel parameters.
  *
- * The second format matches devices using IDs in the configuration
+ * The second format specifies a PCI bus/slot/function root address and
+ * a path of slot/function addresses to the specific device from the root.
+ * The path for a device can be determined through the use of 'lspci -t'.
+ * This format is more robust against renumbering issues than the first format.
+
+ * The third format matches devices using IDs in the configuration
  * space which may match multiple devices in the system. A value of 0
  * for any field will match all devices.
  *
@@ -236,7 +325,15 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
 		    (!subsystem_device ||
 			    subsystem_device == dev->subsystem_device))
 			goto found;
+	} else if (strncmp(p, "path:", 5) == 0) {
+		/* PCI Root Bus and a path of Slot,Function IDs */
+		p += 5;
 
+		ret = pci_dev_str_match_path(dev, p, &p);
+		if (ret < 0)
+			return ret;
+		else if (ret)
+			goto found;
 	} else {
 		/* PCI Bus,Slot,Function ids are specified */
 		ret = sscanf(p, "%x:%x:%x.%x%n", &seg, &bus, &slot,
#8 lore raw

Re: [PATCH v2 2/3] PCI: Allow specifying devices using a base bus and path of devfns

Quoted 7 lines · Alex Williamson

Cool, I'm glad this worked. I note though that there's really not much difference between:

[domain:]bus:slot.fn

and

Quoted 7 lines

[domain:]bus:slot.fn[/slot.fn[/slot.fn[/...]]]

IOW, what's defined here as the "path:" specification doesn't require that we start at a root bus device, it can really specify a path starting anywhere, including the target device directly. So can we simply extend domain:bus:slot.fn to support paths without a separate identifier? Thanks,

Yes, I think you are right. I was just hesitant to change existing behavior. But if that's the consensus I'll change it for v3.

Thanks,

Logan

#9 lore raw

PATCH v2 3/3 PCI: Introduce the disable_acs_redir parameter

In reply to Logan Gunthorpe

In order to support P2P traffic on a segment of the PCI hierarchy, we must be able to disable the ACS redirect bits for select PCI bridges. The bridges must be selected before the devices are discovered by the kernel and the IOMMU groups created. Therefore, a kernel command line parameter is created to specify devices which must have their ACS bits disabled.

The new parameter takes a list of devices separated by a semicolon. Each device specified will have it's ACS redirect bits disabled. This is similar to the existing 'resource_alignment' parameter and just like it we also create a sysfs bus attribute which can be used to read the parameter. Writing the parameter is not supported as it would require forcibly hot plugging the affected device as well as all devices whose IOMMU groups might change.

The ACS Request P2P Request Redirect, P2P Completion Redirect and P2P Egress Control bits are disabled which is sufficient to always allow passing P2P traffic uninterrupted. The bits are set after the kernel (optionally) enables the ACS bits itself. It is also done regardless of whether the kernel sets the bits or not seeing some BIOS firmware is known to set the bits on boot.

---
 Documentation/admin-guide/kernel-parameters.txt |   9 +++
 drivers/pci/pci.c                               | 103 +++++++++++++++++++++++-
 2 files changed, 110 insertions(+), 2 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +9 -0
index bc51b316f485..e4a761a2821b 100644
@@ -3179,6 +3179,15 @@
 				Adding the window is slightly risky (it may
 				conflict with unreported devices), so this
 				taints the kernel.
+		disable_acs_redir=<pci_dev>[; ...]
+				Specify one or more PCI devices (in the format
+				specified above) separated by semicolons.
+				Each device specified will have the PCI ACS
+				redirect capabilities forced off which will
+				allow P2P traffic between devices through
+				bridges without forcing it upstream. Note:
+				this removes isolation between devices and
+				will make the IOMMU groups less granular.
 
 	pcie_aspm=	[PCIE] Forcibly enable or disable PCIe Active State Power
 			Management.
drivers/pci/pci.c +101 -2

125 lines not on this page · raw message

Signature · 1 line
2.11.0