|
@@ -117,6 +117,7 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
|
|
|
const char *buf, size_t count)
|
|
|
{
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
+ int retval = 0;
|
|
|
|
|
|
/* this can crash the machine when done on the "wrong" device */
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
@@ -126,8 +127,10 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
|
|
|
pci_disable_device(pdev);
|
|
|
|
|
|
if (*buf == '1')
|
|
|
- pci_enable_device(pdev);
|
|
|
+ retval = pci_enable_device(pdev);
|
|
|
|
|
|
+ if (retval)
|
|
|
+ return retval;
|
|
|
return count;
|
|
|
}
|
|
|
|
|
@@ -425,16 +428,39 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
|
|
|
return pci_mmap_page_range(pdev, vma, mmap_type, 0);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * pci_remove_resource_files - cleanup resource files
|
|
|
+ * @dev: dev to cleanup
|
|
|
+ *
|
|
|
+ * If we created resource files for @dev, remove them from sysfs and
|
|
|
+ * free their resources.
|
|
|
+ */
|
|
|
+static void
|
|
|
+pci_remove_resource_files(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
|
|
|
+ struct bin_attribute *res_attr;
|
|
|
+
|
|
|
+ res_attr = pdev->res_attr[i];
|
|
|
+ if (res_attr) {
|
|
|
+ sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
|
|
|
+ kfree(res_attr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* pci_create_resource_files - create resource files in sysfs for @dev
|
|
|
* @dev: dev in question
|
|
|
*
|
|
|
* Walk the resources in @dev creating files for each resource available.
|
|
|
*/
|
|
|
-static void
|
|
|
-pci_create_resource_files(struct pci_dev *pdev)
|
|
|
+static int pci_create_resource_files(struct pci_dev *pdev)
|
|
|
{
|
|
|
int i;
|
|
|
+ int retval;
|
|
|
|
|
|
/* Expose the PCI resources from this device as files */
|
|
|
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
|
|
@@ -457,35 +483,19 @@ pci_create_resource_files(struct pci_dev *pdev)
|
|
|
res_attr->size = pci_resource_len(pdev, i);
|
|
|
res_attr->mmap = pci_mmap_resource;
|
|
|
res_attr->private = &pdev->resource[i];
|
|
|
- sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * pci_remove_resource_files - cleanup resource files
|
|
|
- * @dev: dev to cleanup
|
|
|
- *
|
|
|
- * If we created resource files for @dev, remove them from sysfs and
|
|
|
- * free their resources.
|
|
|
- */
|
|
|
-static void
|
|
|
-pci_remove_resource_files(struct pci_dev *pdev)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < PCI_ROM_RESOURCE; i++) {
|
|
|
- struct bin_attribute *res_attr;
|
|
|
-
|
|
|
- res_attr = pdev->res_attr[i];
|
|
|
- if (res_attr) {
|
|
|
- sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
|
|
|
- kfree(res_attr);
|
|
|
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
|
|
|
+ if (retval) {
|
|
|
+ pci_remove_resource_files(pdev);
|
|
|
+ return retval;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
}
|
|
|
+ return 0;
|
|
|
}
|
|
|
#else /* !HAVE_PCI_MMAP */
|
|
|
-static inline void pci_create_resource_files(struct pci_dev *dev) { return; }
|
|
|
+static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
|
|
|
static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
|
|
|
#endif /* HAVE_PCI_MMAP */
|
|
|
|
|
@@ -570,22 +580,27 @@ static struct bin_attribute pcie_config_attr = {
|
|
|
.write = pci_write_config,
|
|
|
};
|
|
|
|
|
|
-int pci_create_sysfs_dev_files (struct pci_dev *pdev)
|
|
|
+int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
|
|
|
{
|
|
|
+ struct bin_attribute *rom_attr = NULL;
|
|
|
+ int retval;
|
|
|
+
|
|
|
if (!sysfs_initialized)
|
|
|
return -EACCES;
|
|
|
|
|
|
if (pdev->cfg_size < 4096)
|
|
|
- sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
|
|
|
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
|
|
|
else
|
|
|
- sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
|
|
|
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
|
|
|
+ if (retval)
|
|
|
+ goto err;
|
|
|
|
|
|
- pci_create_resource_files(pdev);
|
|
|
+ retval = pci_create_resource_files(pdev);
|
|
|
+ if (retval)
|
|
|
+ goto err_bin_file;
|
|
|
|
|
|
/* If the device has a ROM, try to expose it in sysfs. */
|
|
|
if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
|
|
|
- struct bin_attribute *rom_attr;
|
|
|
-
|
|
|
rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
|
|
|
if (rom_attr) {
|
|
|
pdev->rom_attr = rom_attr;
|
|
@@ -595,13 +610,28 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev)
|
|
|
rom_attr->attr.owner = THIS_MODULE;
|
|
|
rom_attr->read = pci_read_rom;
|
|
|
rom_attr->write = pci_write_rom;
|
|
|
- sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
|
|
|
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
|
|
|
+ if (retval)
|
|
|
+ goto err_rom;
|
|
|
+ } else {
|
|
|
+ retval = -ENOMEM;
|
|
|
+ goto err_bin_file;
|
|
|
}
|
|
|
}
|
|
|
/* add platform-specific attributes */
|
|
|
pcibios_add_platform_entries(pdev);
|
|
|
-
|
|
|
+
|
|
|
return 0;
|
|
|
+
|
|
|
+err_rom:
|
|
|
+ kfree(rom_attr);
|
|
|
+err_bin_file:
|
|
|
+ if (pdev->cfg_size < 4096)
|
|
|
+ sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
|
|
|
+ else
|
|
|
+ sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
|
|
|
+err:
|
|
|
+ return retval;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -630,10 +660,14 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
|
|
|
static int __init pci_sysfs_init(void)
|
|
|
{
|
|
|
struct pci_dev *pdev = NULL;
|
|
|
-
|
|
|
+ int retval;
|
|
|
+
|
|
|
sysfs_initialized = 1;
|
|
|
- for_each_pci_dev(pdev)
|
|
|
- pci_create_sysfs_dev_files(pdev);
|
|
|
+ for_each_pci_dev(pdev) {
|
|
|
+ retval = pci_create_sysfs_dev_files(pdev);
|
|
|
+ if (retval)
|
|
|
+ return retval;
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|