mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
PCI: Add 'reset_subordinate' to reset hierarchy below bridge
[ Upstream commit 2fa046449a
]
The "bus" and "cxl_bus" reset methods reset a device by asserting Secondary
Bus Reset on the bridge leading to the device. These only work if the
device is the only device below the bridge.
Add a sysfs 'reset_subordinate' attribute on bridges that can assert
Secondary Bus Reset regardless of how many devices are below the bridge.
This resets all the devices below a bridge in a single command, including
the locking and config space save/restore that reset methods normally do.
This may be the only way to reset devices that don't support other reset
methods (ACPI, FLR, PM reset, etc).
Link: https://lore.kernel.org/r/20241025222755.3756162-1-kbusch@meta.com
Signed-off-by: Keith Busch <kbusch@kernel.org>
[bhelgaas: commit log, add capable(CAP_SYS_ADMIN) check]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
Reviewed-by: Amey Narkhede <ameynarkhede03@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
dff561e406
commit
1af3a54dce
@ -131,6 +131,17 @@ Description:
|
||||
will be present in sysfs. Writing 1 to this file
|
||||
will perform reset.
|
||||
|
||||
What: /sys/bus/pci/devices/.../reset_subordinate
|
||||
Date: October 2024
|
||||
Contact: linux-pci@vger.kernel.org
|
||||
Description:
|
||||
This is visible only for bridge devices. If you want to reset
|
||||
all devices attached through the subordinate bus of a specific
|
||||
bridge device, writing 1 to this will try to do it. This will
|
||||
affect all devices attached to the system through this bridge
|
||||
similiar to writing 1 to their individual "reset" file, so use
|
||||
with caution.
|
||||
|
||||
What: /sys/bus/pci/devices/.../vpd
|
||||
Date: February 2008
|
||||
Contact: Ben Hutchings <bwh@kernel.org>
|
||||
|
@ -488,6 +488,31 @@ static ssize_t bus_rescan_store(struct device *dev,
|
||||
static struct device_attribute dev_attr_bus_rescan = __ATTR(rescan, 0200, NULL,
|
||||
bus_rescan_store);
|
||||
|
||||
static ssize_t reset_subordinate_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct pci_bus *bus = pdev->subordinate;
|
||||
unsigned long val;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (kstrtoul(buf, 0, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (val) {
|
||||
int ret = __pci_reset_bus(bus);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(reset_subordinate);
|
||||
|
||||
#if defined(CONFIG_PM) && defined(CONFIG_ACPI)
|
||||
static ssize_t d3cold_allowed_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
@ -611,6 +636,7 @@ static struct attribute *pci_dev_attrs[] = {
|
||||
static struct attribute *pci_bridge_attrs[] = {
|
||||
&dev_attr_subordinate_bus_number.attr,
|
||||
&dev_attr_secondary_bus_number.attr,
|
||||
&dev_attr_reset_subordinate.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -5598,7 +5598,7 @@ EXPORT_SYMBOL_GPL(pci_probe_reset_bus);
|
||||
*
|
||||
* Same as above except return -EAGAIN if the bus cannot be locked
|
||||
*/
|
||||
static int __pci_reset_bus(struct pci_bus *bus)
|
||||
int __pci_reset_bus(struct pci_bus *bus)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -42,6 +42,7 @@ int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vmai,
|
||||
int pci_probe_reset_function(struct pci_dev *dev);
|
||||
int pci_bridge_secondary_bus_reset(struct pci_dev *dev);
|
||||
int pci_bus_error_reset(struct pci_dev *dev);
|
||||
int __pci_reset_bus(struct pci_bus *bus);
|
||||
|
||||
#define PCI_PM_D2_DELAY 200 /* usec; see PCIe r4.0, sec 5.9.1 */
|
||||
#define PCI_PM_D3HOT_WAIT 10 /* msec */
|
||||
|
Loading…
Reference in New Issue
Block a user