diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
| -rw-r--r-- | drivers/pci/pci-sysfs.c | 73 | 
1 files changed, 63 insertions, 10 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5eea14c1f7f5..9d6f74bd95f8 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -30,6 +30,7 @@  #include <linux/msi.h>  #include <linux/of.h>  #include <linux/aperture.h> +#include <linux/unaligned.h>  #include "pci.h"  #ifndef ARCH_PCI_DEV_GROUPS @@ -177,6 +178,13 @@ static ssize_t resource_show(struct device *dev, struct device_attribute *attr,  	for (i = 0; i < max; i++) {  		struct resource *res =  &pci_dev->resource[i]; +		struct resource zerores = {}; + +		/* For backwards compatibility */ +		if (i >= PCI_BRIDGE_RESOURCES && i <= PCI_BRIDGE_RESOURCE_END && +		    res->flags & (IORESOURCE_UNSET | IORESOURCE_DISABLED)) +			res = &zerores; +  		pci_resource_to_user(pci_dev, i, res, &start, &end);  		len += sysfs_emit_at(buf, len, "0x%016llx 0x%016llx 0x%016llx\n",  				     (unsigned long long)start, @@ -201,8 +209,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 +228,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 +248,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 +267,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 +286,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; @@ -694,6 +720,22 @@ static ssize_t boot_vga_show(struct device *dev, struct device_attribute *attr,  }  static DEVICE_ATTR_RO(boot_vga); +static ssize_t serial_number_show(struct device *dev, +				  struct device_attribute *attr, char *buf) +{ +	struct pci_dev *pci_dev = to_pci_dev(dev); +	u64 dsn; +	u8 bytes[8]; + +	dsn = pci_get_dsn(pci_dev); +	if (!dsn) +		return -EIO; + +	put_unaligned_be64(dsn, bytes); +	return sysfs_emit(buf, "%8phD\n", bytes); +} +static DEVICE_ATTR_ADMIN_RO(serial_number); +  static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,  			       const struct bin_attribute *bin_attr, char *buf,  			       loff_t off, size_t count) @@ -1475,8 +1517,9 @@ static ssize_t reset_method_store(struct device *dev,  		return count;  	} -	pm_runtime_get_sync(dev); -	struct device *pmdev __free(pm_runtime_put) = dev; +	ACQUIRE(pm_runtime_active_try, pm)(dev); +	if (ACQUIRE_ERR(pm_runtime_active_try, &pm)) +		return -ENXIO;  	if (sysfs_streq(buf, "default")) {  		pci_init_reset_methods(pdev); @@ -1555,13 +1598,19 @@ static ssize_t __resource_resize_store(struct device *dev, int n,  				       const char *buf, size_t count)  {  	struct pci_dev *pdev = to_pci_dev(dev); -	unsigned long size, flags; +	struct pci_bus *bus = pdev->bus; +	struct resource *b_win, *res; +	unsigned long size;  	int ret, i;  	u16 cmd;  	if (kstrtoul(buf, 0, &size) < 0)  		return -EINVAL; +	b_win = pbus_select_window(bus, pci_resource_n(pdev, n)); +	if (!b_win) +		return -EINVAL; +  	device_lock(dev);  	if (dev->driver || pci_num_vf(pdev)) {  		ret = -EBUSY; @@ -1581,19 +1630,19 @@ static ssize_t __resource_resize_store(struct device *dev, int n,  	pci_write_config_word(pdev, PCI_COMMAND,  			      cmd & ~PCI_COMMAND_MEMORY); -	flags = pci_resource_flags(pdev, n); -  	pci_remove_resource_files(pdev); -	for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { -		if (pci_resource_len(pdev, i) && -		    pci_resource_flags(pdev, i) == flags) +	pci_dev_for_each_resource(pdev, res, i) { +		if (i >= PCI_BRIDGE_RESOURCES) +			break; + +		if (b_win == pbus_select_window(bus, res))  			pci_release_resource(pdev, i);  	}  	ret = pci_resize_resource(pdev, n, size); -	pci_assign_unassigned_bus_resources(pdev->bus); +	pci_assign_unassigned_bus_resources(bus);  	if (pci_create_resource_files(pdev))  		pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n"); @@ -1698,6 +1747,7 @@ late_initcall(pci_sysfs_init);  static struct attribute *pci_dev_dev_attrs[] = {  	&dev_attr_boot_vga.attr, +	&dev_attr_serial_number.attr,  	NULL,  }; @@ -1710,6 +1760,9 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,  	if (a == &dev_attr_boot_vga.attr && pci_is_vga(pdev))  		return a->mode; +	if (a == &dev_attr_serial_number.attr && pci_get_dsn(pdev)) +		return a->mode; +  	return 0;  }  | 
