It was found that on some platforms the bogus pci device might bring troubles to the system. For example, on a MacBookPro the system could not be power off or suspended due to internal pci resource confliction between bogus pci device and [io 0x1804]. Another case is that, once resumed from hibernation on a VM, the pci config space of a pci device is corrupt. To narrow down and benefit future debugging for such kind of issues, introduce the command line blacklist_dev=<vendor:device_id>> to blacklist such pci devices thus they will not be scanned thus not visible after bootup. For example, pci.blacklist_dev=8086:293e forbid the audio device to be exposed to the OS. Signed-off-by: Chen Yu <yu.c.chen@xxxxxxxxx> --- Documentation/admin-guide/kernel-parameters.txt | 6 ++++++ drivers/pci/pci.c | 17 +++++++++++++++++ drivers/pci/pci.h | 1 + drivers/pci/probe.c | 3 +++ 4 files changed, 27 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index ade4e6ec23e0..cd4a47e236aa 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3583,6 +3583,12 @@ may put more devices in an IOMMU group. force_floating [S390] Force usage of floating interrupts. nomio [S390] Do not use MIO instructions. + blacklist_dev=<vendor:device_id>[; ...] + Specify one or more PCI devices (in the format + specified above) separated by semicolons. + Each device specified will not be scanned thus + will be invisible after boot up. This can be + used for debugging purpose. pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power Management. diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e87196cc1a7f..0e3626a401f4 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6393,6 +6393,19 @@ void __weak pci_fixup_cardbus(struct pci_bus *bus) } EXPORT_SYMBOL(pci_fixup_cardbus); +static const char *pci_blacklist_devs_param; + +bool pci_is_blacklist_dev(unsigned short vendor, unsigned short device) +{ + char search[10]; + + if (!pci_blacklist_devs_param) + return false; + sprintf(search, "%x:%x", vendor, device); + + return strstr(pci_blacklist_devs_param, search) ? true : false; +} + static int __init pci_setup(char *str) { while (str) { @@ -6451,6 +6464,8 @@ static int __init pci_setup(char *str) pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS); } else if (!strncmp(str, "disable_acs_redir=", 18)) { disable_acs_redir_param = str + 18; + } else if (!strncmp(str, "blacklist_dev=", 14)) { + pci_blacklist_devs_param = str + 14; } else { pr_err("PCI: Unknown option `%s'\n", str); } @@ -6476,6 +6491,8 @@ static int __init pci_realloc_setup_params(void) GFP_KERNEL); disable_acs_redir_param = kstrdup(disable_acs_redir_param, GFP_KERNEL); + pci_blacklist_devs_param = kstrdup(pci_blacklist_devs_param, GFP_KERNEL); + return 0; } pure_initcall(pci_realloc_setup_params); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a0a53bd05a0b..01b8ab2da065 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -669,4 +669,5 @@ static inline int pci_acpi_program_hp_params(struct pci_dev *dev) extern const struct attribute_group aspm_ctrl_attr_group; #endif +bool pci_is_blacklist_dev(unsigned short vendor, unsigned short device); #endif /* DRIVERS_PCI_H */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 512cb4312ddd..812ef901ecea 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2271,6 +2271,9 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000)) return NULL; + if (pci_is_blacklist_dev(l & 0xffff, (l >> 16) & 0xffff)) + return NULL; + dev = pci_alloc_dev(bus); if (!dev) return NULL; -- 2.17.1