mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
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 <[email protected]> [bhelgaas: reorder to add the generic code first and move the device-specific quirk to subsequent patches] Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Stephen Bates <[email protected]> Reviewed-by: Alex Williamson <[email protected]> Acked-by: Christian König <[email protected]>
This commit is contained in:
parent
45db33709c
commit
aaca43fda7
2 changed files with 80 additions and 2 deletions
|
|
@ -2982,6 +2982,63 @@ void pci_request_acs(void)
|
|||
pci_acs_enable = 1;
|
||||
}
|
||||
|
||||
static const char *disable_acs_redir_param;
|
||||
|
||||
/**
|
||||
* pci_disable_acs_redir - disable ACS redirect capabilities
|
||||
* @dev: the PCI device
|
||||
*
|
||||
* For only devices specified in the disable_acs_redir parameter.
|
||||
*/
|
||||
static void pci_disable_acs_redir(struct pci_dev *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
const char *p;
|
||||
int pos;
|
||||
u16 ctrl;
|
||||
|
||||
if (!disable_acs_redir_param)
|
||||
return;
|
||||
|
||||
p = disable_acs_redir_param;
|
||||
while (*p) {
|
||||
ret = pci_dev_str_match(dev, p, &p);
|
||||
if (ret < 0) {
|
||||
pr_info_once("PCI: Can't parse disable_acs_redir parameter: %s\n",
|
||||
disable_acs_redir_param);
|
||||
|
||||
break;
|
||||
} else if (ret == 1) {
|
||||
/* Found a match */
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != ';' && *p != ',') {
|
||||
/* End of param or invalid format */
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
if (ret != 1)
|
||||
return;
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
|
||||
if (!pos) {
|
||||
pci_warn(dev, "cannot disable ACS redirect for this hardware as it does not have ACS capabilities\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
|
||||
|
||||
/* P2P Request & Completion Redirect */
|
||||
ctrl &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC);
|
||||
|
||||
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
|
||||
|
||||
pci_info(dev, "disabled ACS redirect\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
|
||||
* @dev: the PCI device
|
||||
|
|
@ -3021,12 +3078,22 @@ static void pci_std_enable_acs(struct pci_dev *dev)
|
|||
void pci_enable_acs(struct pci_dev *dev)
|
||||
{
|
||||
if (!pci_acs_enable)
|
||||
return;
|
||||
goto disable_acs_redir;
|
||||
|
||||
if (!pci_dev_specific_enable_acs(dev))
|
||||
return;
|
||||
goto disable_acs_redir;
|
||||
|
||||
pci_std_enable_acs(dev);
|
||||
|
||||
disable_acs_redir:
|
||||
/*
|
||||
* Note: pci_disable_acs_redir() must be called even if ACS was not
|
||||
* enabled by the kernel because it may have been enabled by
|
||||
* platform firmware. So if we are told to disable it, we should
|
||||
* always disable it after setting the kernel's default
|
||||
* preferences.
|
||||
*/
|
||||
pci_disable_acs_redir(dev);
|
||||
}
|
||||
|
||||
static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
|
||||
|
|
@ -5966,6 +6033,8 @@ static int __init pci_setup(char *str)
|
|||
pcie_bus_config = PCIE_BUS_PEER2PEER;
|
||||
} else if (!strncmp(str, "pcie_scan_all", 13)) {
|
||||
pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS);
|
||||
} else if (!strncmp(str, "disable_acs_redir=", 18)) {
|
||||
disable_acs_redir_param = str + 18;
|
||||
} else {
|
||||
printk(KERN_ERR "PCI: Unknown option `%s'\n",
|
||||
str);
|
||||
|
|
|
|||
Loading…
Reference in a new issue