aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci/pci-sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r--drivers/pci/pci-sysfs.c68
1 files changed, 49 insertions, 19 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 5d0f4db1cab7..7679d75d71e5 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -521,6 +521,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,
@@ -625,6 +650,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,
};
@@ -818,21 +844,20 @@ static struct bin_attribute *pci_dev_config_attrs[] = {
NULL,
};
-static umode_t pci_dev_config_attr_is_visible(struct kobject *kobj,
- struct bin_attribute *a, int n)
+static size_t pci_dev_config_attr_bin_size(struct kobject *kobj,
+ const struct bin_attribute *a,
+ int n)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
- a->size = PCI_CFG_SPACE_SIZE;
if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
- a->size = PCI_CFG_SPACE_EXP_SIZE;
-
- return a->attr.mode;
+ return PCI_CFG_SPACE_EXP_SIZE;
+ return PCI_CFG_SPACE_SIZE;
}
static const struct attribute_group pci_dev_config_attr_group = {
.bin_attrs = pci_dev_config_attrs,
- .is_bin_visible = pci_dev_config_attr_is_visible,
+ .bin_size = pci_dev_config_attr_bin_size,
};
/*
@@ -842,7 +867,7 @@ static const struct attribute_group pci_dev_config_attr_group = {
static __maybe_unused loff_t
pci_llseek_resource(struct file *filep,
struct kobject *kobj __always_unused,
- struct bin_attribute *attr,
+ const struct bin_attribute *attr,
loff_t offset, int whence)
{
return fixed_size_llseek(filep, offset, whence, attr->size);
@@ -911,7 +936,7 @@ static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj,
* memory space.
*/
static int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
+ const struct bin_attribute *attr,
struct vm_area_struct *vma)
{
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
@@ -931,7 +956,7 @@ static int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj,
* memory space. Returns -ENOSYS if the operation isn't supported
*/
static int pci_mmap_legacy_io(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
+ const struct bin_attribute *attr,
struct vm_area_struct *vma)
{
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
@@ -1035,7 +1060,7 @@ void pci_remove_legacy_files(struct pci_bus *b)
*
* Use the regular PCI mapping routines to map a PCI resource into userspace.
*/
-static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
+static int pci_mmap_resource(struct kobject *kobj, const struct bin_attribute *attr,
struct vm_area_struct *vma, int write_combine)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
@@ -1060,14 +1085,14 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
}
static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
+ const struct bin_attribute *attr,
struct vm_area_struct *vma)
{
return pci_mmap_resource(kobj, attr, vma, 0);
}
static int pci_mmap_resource_wc(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
+ const struct bin_attribute *attr,
struct vm_area_struct *vma)
{
return pci_mmap_resource(kobj, attr, vma, 1);
@@ -1327,24 +1352,29 @@ static struct bin_attribute *pci_dev_rom_attrs[] = {
};
static umode_t pci_dev_rom_attr_is_visible(struct kobject *kobj,
- struct bin_attribute *a, int n)
+ const struct bin_attribute *a, int n)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
- size_t rom_size;
/* If the device has a ROM, try to expose it in sysfs. */
- rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
- if (!rom_size)
+ if (!pci_resource_end(pdev, PCI_ROM_RESOURCE))
return 0;
- a->size = rom_size;
-
return a->attr.mode;
}
+static size_t pci_dev_rom_attr_bin_size(struct kobject *kobj,
+ const struct bin_attribute *a, int n)
+{
+ struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
+
+ return pci_resource_len(pdev, PCI_ROM_RESOURCE);
+}
+
static const struct attribute_group pci_dev_rom_attr_group = {
.bin_attrs = pci_dev_rom_attrs,
.is_bin_visible = pci_dev_rom_attr_is_visible,
+ .bin_size = pci_dev_rom_attr_bin_size,
};
static ssize_t reset_store(struct device *dev, struct device_attribute *attr,