Skip to content

Commit bd27ddb

Browse files
computersforpeacegregkh
authored andcommitted
PCI/sysfs: Ensure devices are powered for config reads
commit 48991e4 upstream. The "max_link_width", "current_link_speed", "current_link_width", "secondary_bus_number", and "subordinate_bus_number" sysfs files all access config registers, but they don't check the runtime PM state. If the device is in D3cold or a parent bridge is suspended, we may see -EINVAL, bogus values, or worse, depending on implementation details. Wrap these access in pci_config_pm_runtime_{get,put}() like most of the rest of the similar sysfs attributes. Notably, "max_link_speed" does not access config registers; it returns a cached value since d2bd39c ("PCI: Store all PCIe Supported Link Speeds"). Fixes: 56c1af4 ("PCI: Add sysfs max_link_speed/width, current_link_speed/width, etc") Signed-off-by: Brian Norris <[email protected]> Signed-off-by: Brian Norris <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Cc: [email protected] Link: https://patch.msgid.link/20250924095711.v2.1.Ibb5b6ca1e2c059e04ec53140cd98a44f2684c668@changeid Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 7a9dee3 commit bd27ddb

File tree

1 file changed

+19
-1
lines changed

1 file changed

+19
-1
lines changed

drivers/pci/pci-sysfs.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,14 @@ static ssize_t max_link_width_show(struct device *dev,
196196
struct device_attribute *attr, char *buf)
197197
{
198198
struct pci_dev *pdev = to_pci_dev(dev);
199+
ssize_t ret;
199200

200-
return sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
201+
/* We read PCI_EXP_LNKCAP, so we need the device to be accessible. */
202+
pci_config_pm_runtime_get(pdev);
203+
ret = sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
204+
pci_config_pm_runtime_put(pdev);
205+
206+
return ret;
201207
}
202208
static DEVICE_ATTR_RO(max_link_width);
203209

@@ -209,7 +215,10 @@ static ssize_t current_link_speed_show(struct device *dev,
209215
int err;
210216
enum pci_bus_speed speed;
211217

218+
pci_config_pm_runtime_get(pci_dev);
212219
err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
220+
pci_config_pm_runtime_put(pci_dev);
221+
213222
if (err)
214223
return -EINVAL;
215224

@@ -226,7 +235,10 @@ static ssize_t current_link_width_show(struct device *dev,
226235
u16 linkstat;
227236
int err;
228237

238+
pci_config_pm_runtime_get(pci_dev);
229239
err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
240+
pci_config_pm_runtime_put(pci_dev);
241+
230242
if (err)
231243
return -EINVAL;
232244

@@ -242,7 +254,10 @@ static ssize_t secondary_bus_number_show(struct device *dev,
242254
u8 sec_bus;
243255
int err;
244256

257+
pci_config_pm_runtime_get(pci_dev);
245258
err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus);
259+
pci_config_pm_runtime_put(pci_dev);
260+
246261
if (err)
247262
return -EINVAL;
248263

@@ -258,7 +273,10 @@ static ssize_t subordinate_bus_number_show(struct device *dev,
258273
u8 sub_bus;
259274
int err;
260275

276+
pci_config_pm_runtime_get(pci_dev);
261277
err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus);
278+
pci_config_pm_runtime_put(pci_dev);
279+
262280
if (err)
263281
return -EINVAL;
264282

0 commit comments

Comments
 (0)