Skip to content

Commit aaca43f

Browse files
lsgunthbjorn-helgaas
authored andcommitted
PCI: Add "pci=disable_acs_redir=" parameter for peer-to-peer support
To support peer-to-peer traffic on a segment of the PCI hierarchy, we must 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, add a kernel command line parameter 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 its ACS redirect bits disabled. This is similar to the existing 'resource_alignment' parameter. 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 or platform firmware sets the bits. If the user tries to disable the ACS redirect for a device without the ACS capability, print a warning to dmesg. Signed-off-by: Logan Gunthorpe <logang@deltatee.com> [bhelgaas: reorder to add the generic code first and move the device-specific quirk to subsequent patches] 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>
1 parent 45db337 commit aaca43f

File tree

2 files changed

+80
-2
lines changed

2 files changed

+80
-2
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3192,6 +3192,15 @@
31923192
Adding the window is slightly risky (it may
31933193
conflict with unreported devices), so this
31943194
taints the kernel.
3195+
disable_acs_redir=<pci_dev>[; ...]
3196+
Specify one or more PCI devices (in the format
3197+
specified above) separated by semicolons.
3198+
Each device specified will have the PCI ACS
3199+
redirect capabilities forced off which will
3200+
allow P2P traffic between devices through
3201+
bridges without forcing it upstream. Note:
3202+
this removes isolation between devices and
3203+
may put more devices in an IOMMU group.
31953204

31963205
pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
31973206
Management.

drivers/pci/pci.c

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2982,6 +2982,63 @@ void pci_request_acs(void)
29822982
pci_acs_enable = 1;
29832983
}
29842984

2985+
static const char *disable_acs_redir_param;
2986+
2987+
/**
2988+
* pci_disable_acs_redir - disable ACS redirect capabilities
2989+
* @dev: the PCI device
2990+
*
2991+
* For only devices specified in the disable_acs_redir parameter.
2992+
*/
2993+
static void pci_disable_acs_redir(struct pci_dev *dev)
2994+
{
2995+
int ret = 0;
2996+
const char *p;
2997+
int pos;
2998+
u16 ctrl;
2999+
3000+
if (!disable_acs_redir_param)
3001+
return;
3002+
3003+
p = disable_acs_redir_param;
3004+
while (*p) {
3005+
ret = pci_dev_str_match(dev, p, &p);
3006+
if (ret < 0) {
3007+
pr_info_once("PCI: Can't parse disable_acs_redir parameter: %s\n",
3008+
disable_acs_redir_param);
3009+
3010+
break;
3011+
} else if (ret == 1) {
3012+
/* Found a match */
3013+
break;
3014+
}
3015+
3016+
if (*p != ';' && *p != ',') {
3017+
/* End of param or invalid format */
3018+
break;
3019+
}
3020+
p++;
3021+
}
3022+
3023+
if (ret != 1)
3024+
return;
3025+
3026+
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
3027+
if (!pos) {
3028+
pci_warn(dev, "cannot disable ACS redirect for this hardware as it does not have ACS capabilities\n");
3029+
return;
3030+
}
3031+
3032+
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
3033+
3034+
/* P2P Request & Completion Redirect */
3035+
ctrl &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC);
3036+
3037+
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
3038+
3039+
pci_info(dev, "disabled ACS redirect\n");
3040+
}
3041+
29853042
/**
29863043
* pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
29873044
* @dev: the PCI device
@@ -3021,12 +3078,22 @@ static void pci_std_enable_acs(struct pci_dev *dev)
30213078
void pci_enable_acs(struct pci_dev *dev)
30223079
{
30233080
if (!pci_acs_enable)
3024-
return;
3081+
goto disable_acs_redir;
30253082

30263083
if (!pci_dev_specific_enable_acs(dev))
3027-
return;
3084+
goto disable_acs_redir;
30283085

30293086
pci_std_enable_acs(dev);
3087+
3088+
disable_acs_redir:
3089+
/*
3090+
* Note: pci_disable_acs_redir() must be called even if ACS was not
3091+
* enabled by the kernel because it may have been enabled by
3092+
* platform firmware. So if we are told to disable it, we should
3093+
* always disable it after setting the kernel's default
3094+
* preferences.
3095+
*/
3096+
pci_disable_acs_redir(dev);
30303097
}
30313098

30323099
static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
@@ -5966,6 +6033,8 @@ static int __init pci_setup(char *str)
59666033
pcie_bus_config = PCIE_BUS_PEER2PEER;
59676034
} else if (!strncmp(str, "pcie_scan_all", 13)) {
59686035
pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS);
6036+
} else if (!strncmp(str, "disable_acs_redir=", 18)) {
6037+
disable_acs_redir_param = str + 18;
59696038
} else {
59706039
printk(KERN_ERR "PCI: Unknown option `%s'\n",
59716040
str);

0 commit comments

Comments
 (0)