The commit 5913320eb0b3 ("platform/x86: p2sb: Allow p2sb_bar() calls during PCI device probe") triggered repeated ACPI errors on ASUS VivoBook D540NV-GQ065T [1]. The P2SB device on the system has multiple functions, and the system requires P2SB device function 2. The commit introduced the P2SB device scan for all functions including function 0 and 2. It was confirmed that the P2SB device scan for function 0 on the system triggered the errors. To avoid the errors, defer the P2SB device scan on the concerned device. If the P2SB device has function 0, defer the device scan and do it later when p2sb_bar() is called for the first time. At the deferred scan, do not scan multiple functions and scan only the requested function to avoid the unnecessary scan of function 0. If sysfs pci bus rescans trigger the first p2sb_bar() call, deadlock happens in the deferred P2SB device scan. In most cases, the p2sb_bar() calls happen during the system boot process, then there is no chance of deadlock. After this change, the code to scan multiple functions for P2SB devices with function 0 in p2sb_scan_and_cache() is no longer required. The resource validity check in p2sb_scan_and_cache() is not required either since it is done in p2sb_bar() also. Remove p2sb_scan_and_cache() and call p2sb_scan_and_cache_devfn() instead. Link: https://bugzilla.kernel.org/show_bug.cgi?id=218531 [1] Fixes: 5913320eb0b3 ("platform/x86: p2sb: Allow p2sb_bar() calls during PCI device probe") Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@xxxxxxx> --- Changes from v2: * Target only the requested devfn at the deferred scan and cache * Removed p2sb_scan_and_cache() and use p2sb_scan_and_cache_devfn() instead Changes from v1: * Removed unnecessary p2sb_resource_cached() * Reflected other review comments drivers/platform/x86/p2sb.c | 47 ++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/drivers/platform/x86/p2sb.c b/drivers/platform/x86/p2sb.c index 6bd14d0132db..c829dbd8f058 100644 --- a/drivers/platform/x86/p2sb.c +++ b/drivers/platform/x86/p2sb.c @@ -96,30 +96,6 @@ static void p2sb_scan_and_cache_devfn(struct pci_bus *bus, unsigned int devfn) pci_stop_and_remove_bus_device(pdev); } -static int p2sb_scan_and_cache(struct pci_bus *bus, unsigned int devfn) -{ - unsigned int slot, fn; - - if (PCI_FUNC(devfn) == 0) { - /* - * When function number of the P2SB device is zero, scan it and - * other function numbers, and if devices are available, cache - * their BAR0s. - */ - slot = PCI_SLOT(devfn); - for (fn = 0; fn < NR_P2SB_RES_CACHE; fn++) - p2sb_scan_and_cache_devfn(bus, PCI_DEVFN(slot, fn)); - } else { - /* Scan the P2SB device and cache its BAR0 */ - p2sb_scan_and_cache_devfn(bus, devfn); - } - - if (!p2sb_valid_resource(&p2sb_resources[PCI_FUNC(devfn)].res)) - return -ENOENT; - - return 0; -} - static struct pci_bus *p2sb_get_bus(struct pci_bus *bus) { static struct pci_bus *p2sb_bus; @@ -133,7 +109,7 @@ static struct pci_bus *p2sb_get_bus(struct pci_bus *bus) return p2sb_bus; } -static int p2sb_cache_resources(void) +static int p2sb_cache_resources(unsigned int devfn_to_cache, bool from_fs_init) { unsigned int devfn_p2sb; u32 value = P2SBC_HIDE; @@ -150,6 +126,18 @@ static int p2sb_cache_resources(void) if (!bus) return -ENODEV; + /* + * On ASUS VivoBook D540NV-GQ065T which has Goldmont CPU family Pentium + * N4200, P2SB device scan including function 0 at fs_initcall() step + * causes ACPI errors. To avoid the errors, defer P2SB device scan and + * cache when P2SB devices has function 0. + */ + if (PCI_FUNC(devfn_p2sb) == 0 && from_fs_init) + return -EBUSY; + + if (devfn_to_cache == 0) + devfn_to_cache = devfn_p2sb; + /* * When a device with same devfn exists and its device class is not * PCI_CLASS_MEMORY_OTHER for P2SB, do not touch it. @@ -173,7 +161,7 @@ static int p2sb_cache_resources(void) if (value & P2SBC_HIDE) pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0); - ret = p2sb_scan_and_cache(bus, devfn_p2sb); + p2sb_scan_and_cache_devfn(bus, devfn_to_cache); /* Hide the P2SB device, if it was hidden */ if (value & P2SBC_HIDE) @@ -214,6 +202,11 @@ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) } cache = &p2sb_resources[PCI_FUNC(devfn)]; + + /* Scan and cache P2SB device if it was deferred at fs_initcall() */ + if (!p2sb_valid_resource(&cache->res)) + p2sb_cache_resources(devfn, false); + if (cache->bus_dev_id != bus->dev.id) return -ENODEV; @@ -227,7 +220,7 @@ EXPORT_SYMBOL_GPL(p2sb_bar); static int __init p2sb_fs_init(void) { - p2sb_cache_resources(); + p2sb_cache_resources(0, true); return 0; } -- 2.43.0