Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform/x86: p2sb: Allow p2sb_bar() calls during PCI device probe

p2sb_bar() unhides P2SB device to get resources from the device. It
guards the operation by locking pci_rescan_remove_lock so that parallel
rescans do not find the P2SB device. However, this lock causes deadlock
when PCI bus rescan is triggered by /sys/bus/pci/rescan. The rescan
locks pci_rescan_remove_lock and probes PCI devices. When PCI devices
call p2sb_bar() during probe, it locks pci_rescan_remove_lock again.
Hence the deadlock.

To avoid the deadlock, do not lock pci_rescan_remove_lock in p2sb_bar().
Instead, do the lock at fs_initcall. Introduce p2sb_cache_resources()
for fs_initcall which gets and caches the P2SB resources. At p2sb_bar(),
refer the cache and return to the caller.

Before operating the device at P2SB DEVFN for resource cache, check
that its device class is PCI_CLASS_MEMORY_OTHER 0x0580 that PCH
specifications define. This avoids unexpected operation to other devices
at the same DEVFN.

Link: https://lore.kernel.org/linux-pci/6xb24fjmptxxn5js2fjrrddjae6twex5bjaftwqsuawuqqqydx@7cl3uik5ef6j/
Fixes: 9745fb07474f ("platform/x86/intel: Add Primary to Sideband (P2SB) bridge support")
Cc: stable@vger.kernel.org
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Link: https://lore.kernel.org/r/20240108062059.3583028-2-shinichiro.kawasaki@wdc.com
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Tested-by Klara Modin <klarasmodin@gmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Shin'ichiro Kawasaki and committed by
Hans de Goede
5913320e 416de024

+150 -52
+150 -52
drivers/platform/x86/p2sb.c
··· 26 26 {} 27 27 }; 28 28 29 + /* 30 + * Cache BAR0 of P2SB device functions 0 to 7. 31 + * TODO: The constant 8 is the number of functions that PCI specification 32 + * defines. Same definitions exist tree-wide. Unify this definition and 33 + * the other definitions then move to include/uapi/linux/pci.h. 34 + */ 35 + #define NR_P2SB_RES_CACHE 8 36 + 37 + struct p2sb_res_cache { 38 + u32 bus_dev_id; 39 + struct resource res; 40 + }; 41 + 42 + static struct p2sb_res_cache p2sb_resources[NR_P2SB_RES_CACHE]; 43 + 29 44 static int p2sb_get_devfn(unsigned int *devfn) 30 45 { 31 46 unsigned int fn = P2SB_DEVFN_DEFAULT; ··· 54 39 return 0; 55 40 } 56 41 42 + static bool p2sb_valid_resource(struct resource *res) 43 + { 44 + if (res->flags) 45 + return true; 46 + 47 + return false; 48 + } 49 + 57 50 /* Copy resource from the first BAR of the device in question */ 58 - static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) 51 + static void p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) 59 52 { 60 53 struct resource *bar0 = &pdev->resource[0]; 61 54 ··· 79 56 mem->end = bar0->end; 80 57 mem->flags = bar0->flags; 81 58 mem->desc = bar0->desc; 59 + } 60 + 61 + static void p2sb_scan_and_cache_devfn(struct pci_bus *bus, unsigned int devfn) 62 + { 63 + struct p2sb_res_cache *cache = &p2sb_resources[PCI_FUNC(devfn)]; 64 + struct pci_dev *pdev; 65 + 66 + pdev = pci_scan_single_device(bus, devfn); 67 + if (!pdev) 68 + return; 69 + 70 + p2sb_read_bar0(pdev, &cache->res); 71 + cache->bus_dev_id = bus->dev.id; 72 + 73 + pci_stop_and_remove_bus_device(pdev); 74 + } 75 + 76 + static int p2sb_scan_and_cache(struct pci_bus *bus, unsigned int devfn) 77 + { 78 + unsigned int slot, fn; 79 + 80 + if (PCI_FUNC(devfn) == 0) { 81 + /* 82 + * When function number of the P2SB device is zero, scan it and 83 + * other function numbers, and if devices are available, cache 84 + * their BAR0s. 85 + */ 86 + slot = PCI_SLOT(devfn); 87 + for (fn = 0; fn < NR_P2SB_RES_CACHE; fn++) 88 + p2sb_scan_and_cache_devfn(bus, PCI_DEVFN(slot, fn)); 89 + } else { 90 + /* Scan the P2SB device and cache its BAR0 */ 91 + p2sb_scan_and_cache_devfn(bus, devfn); 92 + } 93 + 94 + if (!p2sb_valid_resource(&p2sb_resources[PCI_FUNC(devfn)].res)) 95 + return -ENOENT; 82 96 83 97 return 0; 84 98 } 85 99 86 - static int p2sb_scan_and_read(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 100 + static struct pci_bus *p2sb_get_bus(struct pci_bus *bus) 87 101 { 88 - struct pci_dev *pdev; 102 + static struct pci_bus *p2sb_bus; 103 + 104 + bus = bus ?: p2sb_bus; 105 + if (bus) 106 + return bus; 107 + 108 + /* Assume P2SB is on the bus 0 in domain 0 */ 109 + p2sb_bus = pci_find_bus(0, 0); 110 + return p2sb_bus; 111 + } 112 + 113 + static int p2sb_cache_resources(void) 114 + { 115 + unsigned int devfn_p2sb; 116 + u32 value = P2SBC_HIDE; 117 + struct pci_bus *bus; 118 + u16 class; 89 119 int ret; 90 120 91 - pdev = pci_scan_single_device(bus, devfn); 92 - if (!pdev) 121 + /* Get devfn for P2SB device itself */ 122 + ret = p2sb_get_devfn(&devfn_p2sb); 123 + if (ret) 124 + return ret; 125 + 126 + bus = p2sb_get_bus(NULL); 127 + if (!bus) 93 128 return -ENODEV; 94 129 95 - ret = p2sb_read_bar0(pdev, mem); 130 + /* 131 + * When a device with same devfn exists and its device class is not 132 + * PCI_CLASS_MEMORY_OTHER for P2SB, do not touch it. 133 + */ 134 + pci_bus_read_config_word(bus, devfn_p2sb, PCI_CLASS_DEVICE, &class); 135 + if (!PCI_POSSIBLE_ERROR(class) && class != PCI_CLASS_MEMORY_OTHER) 136 + return -ENODEV; 96 137 97 - pci_stop_and_remove_bus_device(pdev); 138 + /* 139 + * Prevent concurrent PCI bus scan from seeing the P2SB device and 140 + * removing via sysfs while it is temporarily exposed. 141 + */ 142 + pci_lock_rescan_remove(); 143 + 144 + /* 145 + * The BIOS prevents the P2SB device from being enumerated by the PCI 146 + * subsystem, so we need to unhide and hide it back to lookup the BAR. 147 + * Unhide the P2SB device here, if needed. 148 + */ 149 + pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value); 150 + if (value & P2SBC_HIDE) 151 + pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0); 152 + 153 + ret = p2sb_scan_and_cache(bus, devfn_p2sb); 154 + 155 + /* Hide the P2SB device, if it was hidden */ 156 + if (value & P2SBC_HIDE) 157 + pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, P2SBC_HIDE); 158 + 159 + pci_unlock_rescan_remove(); 160 + 98 161 return ret; 99 162 } 100 163 ··· 190 81 * @devfn: PCI slot and function to communicate with 191 82 * @mem: memory resource to be filled in 192 83 * 193 - * The BIOS prevents the P2SB device from being enumerated by the PCI 194 - * subsystem, so we need to unhide and hide it back to lookup the BAR. 195 - * 196 - * if @bus is NULL, the bus 0 in domain 0 will be used. 84 + * If @bus is NULL, the bus 0 in domain 0 will be used. 197 85 * If @devfn is 0, it will be replaced by devfn of the P2SB device. 198 86 * 199 87 * Caller must provide a valid pointer to @mem. 200 - * 201 - * Locking is handled by pci_rescan_remove_lock mutex. 202 88 * 203 89 * Return: 204 90 * 0 on success or appropriate errno value on error. 205 91 */ 206 92 int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 207 93 { 208 - struct pci_dev *pdev_p2sb; 209 - unsigned int devfn_p2sb; 210 - u32 value = P2SBC_HIDE; 94 + struct p2sb_res_cache *cache; 211 95 int ret; 212 96 213 - /* Get devfn for P2SB device itself */ 214 - ret = p2sb_get_devfn(&devfn_p2sb); 215 - if (ret) 216 - return ret; 217 - 218 - /* if @bus is NULL, use bus 0 in domain 0 */ 219 - bus = bus ?: pci_find_bus(0, 0); 220 - 221 - /* 222 - * Prevent concurrent PCI bus scan from seeing the P2SB device and 223 - * removing via sysfs while it is temporarily exposed. 224 - */ 225 - pci_lock_rescan_remove(); 226 - 227 - /* Unhide the P2SB device, if needed */ 228 - pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value); 229 - if (value & P2SBC_HIDE) 230 - pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0); 231 - 232 - pdev_p2sb = pci_scan_single_device(bus, devfn_p2sb); 233 - if (devfn) 234 - ret = p2sb_scan_and_read(bus, devfn, mem); 235 - else 236 - ret = p2sb_read_bar0(pdev_p2sb, mem); 237 - pci_stop_and_remove_bus_device(pdev_p2sb); 238 - 239 - /* Hide the P2SB device, if it was hidden */ 240 - if (value & P2SBC_HIDE) 241 - pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, P2SBC_HIDE); 242 - 243 - pci_unlock_rescan_remove(); 244 - 245 - if (ret) 246 - return ret; 247 - 248 - if (mem->flags == 0) 97 + bus = p2sb_get_bus(bus); 98 + if (!bus) 249 99 return -ENODEV; 250 100 101 + if (!devfn) { 102 + ret = p2sb_get_devfn(&devfn); 103 + if (ret) 104 + return ret; 105 + } 106 + 107 + cache = &p2sb_resources[PCI_FUNC(devfn)]; 108 + if (cache->bus_dev_id != bus->dev.id) 109 + return -ENODEV; 110 + 111 + if (!p2sb_valid_resource(&cache->res)) 112 + return -ENOENT; 113 + 114 + memcpy(mem, &cache->res, sizeof(*mem)); 251 115 return 0; 252 116 } 253 117 EXPORT_SYMBOL_GPL(p2sb_bar); 118 + 119 + static int __init p2sb_fs_init(void) 120 + { 121 + p2sb_cache_resources(); 122 + return 0; 123 + } 124 + 125 + /* 126 + * pci_rescan_remove_lock to avoid access to unhidden P2SB devices can 127 + * not be locked in sysfs pci bus rescan path because of deadlock. To 128 + * avoid the deadlock, access to P2SB devices with the lock at an early 129 + * step in kernel initialization and cache required resources. This 130 + * should happen after subsys_initcall which initializes PCI subsystem 131 + * and before device_initcall which requires P2SB resources. 132 + */ 133 + fs_initcall(p2sb_fs_init);