diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-bus-pci | 10 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 37 | ||||
-rw-r--r-- | drivers/pci/pci.c | 16 | ||||
-rw-r--r-- | drivers/pci/pci.h | 1 | ||||
-rw-r--r-- | include/linux/pci.h | 1 |
5 files changed, 65 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 6bf68053e4b8..25be3250f7d6 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci | |||
@@ -84,6 +84,16 @@ Description: | |||
84 | from this part of the device tree. | 84 | from this part of the device tree. |
85 | Depends on CONFIG_HOTPLUG. | 85 | Depends on CONFIG_HOTPLUG. |
86 | 86 | ||
87 | What: /sys/bus/pci/devices/.../reset | ||
88 | Date: July 2009 | ||
89 | Contact: Michael S. Tsirkin <mst@redhat.com> | ||
90 | Description: | ||
91 | Some devices allow an individual function to be reset | ||
92 | without affecting other functions in the same device. | ||
93 | For devices that have this support, a file named reset | ||
94 | will be present in sysfs. Writing 1 to this file | ||
95 | will perform reset. | ||
96 | |||
87 | What: /sys/bus/pci/devices/.../vpd | 97 | What: /sys/bus/pci/devices/.../vpd |
88 | Date: February 2008 | 98 | Date: February 2008 |
89 | Contact: Ben Hutchings <bhutchings@solarflare.com> | 99 | Contact: Ben Hutchings <bhutchings@solarflare.com> |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 85ebd02a64a7..0f6382f090ee 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -916,6 +916,24 @@ int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev) | |||
916 | return 0; | 916 | return 0; |
917 | } | 917 | } |
918 | 918 | ||
919 | static ssize_t reset_store(struct device *dev, | ||
920 | struct device_attribute *attr, const char *buf, | ||
921 | size_t count) | ||
922 | { | ||
923 | struct pci_dev *pdev = to_pci_dev(dev); | ||
924 | unsigned long val; | ||
925 | ssize_t result = strict_strtoul(buf, 0, &val); | ||
926 | |||
927 | if (result < 0) | ||
928 | return result; | ||
929 | |||
930 | if (val != 1) | ||
931 | return -EINVAL; | ||
932 | return pci_reset_function(pdev); | ||
933 | } | ||
934 | |||
935 | static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_store); | ||
936 | |||
919 | static int pci_create_capabilities_sysfs(struct pci_dev *dev) | 937 | static int pci_create_capabilities_sysfs(struct pci_dev *dev) |
920 | { | 938 | { |
921 | int retval; | 939 | int retval; |
@@ -943,7 +961,22 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev) | |||
943 | /* Active State Power Management */ | 961 | /* Active State Power Management */ |
944 | pcie_aspm_create_sysfs_dev_files(dev); | 962 | pcie_aspm_create_sysfs_dev_files(dev); |
945 | 963 | ||
964 | if (!pci_probe_reset_function(dev)) { | ||
965 | retval = device_create_file(&dev->dev, &reset_attr); | ||
966 | if (retval) | ||
967 | goto error; | ||
968 | dev->reset_fn = 1; | ||
969 | } | ||
946 | return 0; | 970 | return 0; |
971 | |||
972 | error: | ||
973 | pcie_aspm_remove_sysfs_dev_files(dev); | ||
974 | if (dev->vpd && dev->vpd->attr) { | ||
975 | sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr); | ||
976 | kfree(dev->vpd->attr); | ||
977 | } | ||
978 | |||
979 | return retval; | ||
947 | } | 980 | } |
948 | 981 | ||
949 | int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | 982 | int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) |
@@ -1037,6 +1070,10 @@ static void pci_remove_capabilities_sysfs(struct pci_dev *dev) | |||
1037 | } | 1070 | } |
1038 | 1071 | ||
1039 | pcie_aspm_remove_sysfs_dev_files(dev); | 1072 | pcie_aspm_remove_sysfs_dev_files(dev); |
1073 | if (dev->reset_fn) { | ||
1074 | device_remove_file(&dev->dev, &reset_attr); | ||
1075 | dev->reset_fn = 0; | ||
1076 | } | ||
1040 | } | 1077 | } |
1041 | 1078 | ||
1042 | /** | 1079 | /** |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7b70312181d7..7d55039ffa05 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -2262,6 +2262,22 @@ int __pci_reset_function(struct pci_dev *dev) | |||
2262 | EXPORT_SYMBOL_GPL(__pci_reset_function); | 2262 | EXPORT_SYMBOL_GPL(__pci_reset_function); |
2263 | 2263 | ||
2264 | /** | 2264 | /** |
2265 | * pci_probe_reset_function - check whether the device can be safely reset | ||
2266 | * @dev: PCI device to reset | ||
2267 | * | ||
2268 | * Some devices allow an individual function to be reset without affecting | ||
2269 | * other functions in the same device. The PCI device must be responsive | ||
2270 | * to PCI config space in order to use this function. | ||
2271 | * | ||
2272 | * Returns 0 if the device function can be reset or negative if the | ||
2273 | * device doesn't support resetting a single function. | ||
2274 | */ | ||
2275 | int pci_probe_reset_function(struct pci_dev *dev) | ||
2276 | { | ||
2277 | return pci_dev_reset(dev, 1); | ||
2278 | } | ||
2279 | |||
2280 | /** | ||
2265 | * pci_reset_function - quiesce and reset a PCI device function | 2281 | * pci_reset_function - quiesce and reset a PCI device function |
2266 | * @dev: PCI device to reset | 2282 | * @dev: PCI device to reset |
2267 | * | 2283 | * |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 5ff4d25bf0e9..73d9d92715a0 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -16,6 +16,7 @@ extern void pci_cleanup_rom(struct pci_dev *dev); | |||
16 | extern int pci_mmap_fits(struct pci_dev *pdev, int resno, | 16 | extern int pci_mmap_fits(struct pci_dev *pdev, int resno, |
17 | struct vm_area_struct *vma); | 17 | struct vm_area_struct *vma); |
18 | #endif | 18 | #endif |
19 | int pci_probe_reset_function(struct pci_dev *dev); | ||
19 | 20 | ||
20 | /** | 21 | /** |
21 | * struct pci_platform_pm_ops - Firmware PM callbacks | 22 | * struct pci_platform_pm_ops - Firmware PM callbacks |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 115fb7ba5089..a90f94020798 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -276,6 +276,7 @@ struct pci_dev { | |||
276 | unsigned int state_saved:1; | 276 | unsigned int state_saved:1; |
277 | unsigned int is_physfn:1; | 277 | unsigned int is_physfn:1; |
278 | unsigned int is_virtfn:1; | 278 | unsigned int is_virtfn:1; |
279 | unsigned int reset_fn:1; | ||
279 | pci_dev_flags_t dev_flags; | 280 | pci_dev_flags_t dev_flags; |
280 | atomic_t enable_cnt; /* pci_enable_device has been called */ | 281 | atomic_t enable_cnt; /* pci_enable_device has been called */ |
281 | 282 | ||