Skip to content

Commit 4af571f

Browse files
computersforpeaceopsiff
authored andcommitted
PCI/sysfs: Ensure devices are powered for config reads
commit 48991e4935078b05f80616c75d1ee2ea3ae18e58 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 <briannorris@google.com> Signed-off-by: Brian Norris <briannorris@chromium.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250924095711.v2.1.Ibb5b6ca1e2c059e04ec53140cd98a44f2684c668@changeid Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit 3ea9bd42858117c7c696e07942c9a3c3e7ee2a8c)
1 parent e79b2fe commit 4af571f

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
@@ -200,8 +200,14 @@ static ssize_t max_link_width_show(struct device *dev,
200200
struct device_attribute *attr, char *buf)
201201
{
202202
struct pci_dev *pdev = to_pci_dev(dev);
203+
ssize_t ret;
203204

204-
return sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
205+
/* We read PCI_EXP_LNKCAP, so we need the device to be accessible. */
206+
pci_config_pm_runtime_get(pdev);
207+
ret = sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
208+
pci_config_pm_runtime_put(pdev);
209+
210+
return ret;
205211
}
206212
static DEVICE_ATTR_RO(max_link_width);
207213

@@ -213,7 +219,10 @@ static ssize_t current_link_speed_show(struct device *dev,
213219
int err;
214220
enum pci_bus_speed speed;
215221

222+
pci_config_pm_runtime_get(pci_dev);
216223
err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
224+
pci_config_pm_runtime_put(pci_dev);
225+
217226
if (err)
218227
return -EINVAL;
219228

@@ -230,7 +239,10 @@ static ssize_t current_link_width_show(struct device *dev,
230239
u16 linkstat;
231240
int err;
232241

242+
pci_config_pm_runtime_get(pci_dev);
233243
err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
244+
pci_config_pm_runtime_put(pci_dev);
245+
234246
if (err)
235247
return -EINVAL;
236248

@@ -246,7 +258,10 @@ static ssize_t secondary_bus_number_show(struct device *dev,
246258
u8 sec_bus;
247259
int err;
248260

261+
pci_config_pm_runtime_get(pci_dev);
249262
err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus);
263+
pci_config_pm_runtime_put(pci_dev);
264+
250265
if (err)
251266
return -EINVAL;
252267

@@ -262,7 +277,10 @@ static ssize_t subordinate_bus_number_show(struct device *dev,
262277
u8 sub_bus;
263278
int err;
264279

280+
pci_config_pm_runtime_get(pci_dev);
265281
err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus);
282+
pci_config_pm_runtime_put(pci_dev);
283+
266284
if (err)
267285
return -EINVAL;
268286

0 commit comments

Comments
 (0)