mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
PCI/sysfs: Ensure devices are powered for config reads
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 d2bd39c045 ("PCI: Store all PCIe Supported Link
Speeds").
Fixes: 56c1af4606 ("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
This commit is contained in:
parent
299fad4133
commit
48991e4935
|
|
@ -201,8 +201,14 @@ static ssize_t max_link_width_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
ssize_t ret;
|
||||
|
||||
return sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
|
||||
/* We read PCI_EXP_LNKCAP, so we need the device to be accessible. */
|
||||
pci_config_pm_runtime_get(pdev);
|
||||
ret = sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
|
||||
pci_config_pm_runtime_put(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR_RO(max_link_width);
|
||||
|
||||
|
|
@ -214,7 +220,10 @@ static ssize_t current_link_speed_show(struct device *dev,
|
|||
int err;
|
||||
enum pci_bus_speed speed;
|
||||
|
||||
pci_config_pm_runtime_get(pci_dev);
|
||||
err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
|
||||
pci_config_pm_runtime_put(pci_dev);
|
||||
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -231,7 +240,10 @@ static ssize_t current_link_width_show(struct device *dev,
|
|||
u16 linkstat;
|
||||
int err;
|
||||
|
||||
pci_config_pm_runtime_get(pci_dev);
|
||||
err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
|
||||
pci_config_pm_runtime_put(pci_dev);
|
||||
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -247,7 +259,10 @@ static ssize_t secondary_bus_number_show(struct device *dev,
|
|||
u8 sec_bus;
|
||||
int err;
|
||||
|
||||
pci_config_pm_runtime_get(pci_dev);
|
||||
err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus);
|
||||
pci_config_pm_runtime_put(pci_dev);
|
||||
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -263,7 +278,10 @@ static ssize_t subordinate_bus_number_show(struct device *dev,
|
|||
u8 sub_bus;
|
||||
int err;
|
||||
|
||||
pci_config_pm_runtime_get(pci_dev);
|
||||
err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus);
|
||||
pci_config_pm_runtime_put(pci_dev);
|
||||
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user