aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2009-07-27 16:37:48 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-09-09 16:29:24 -0400
commit711d57796f5ce2d02d6e62c9034afbb16aedda31 (patch)
tree935861fee775b171cafc96de57fe4fbfa19892eb /drivers
parent5228a828ee044834d78abdf25306bf46b19dcc4d (diff)
PCI: expose function reset capability in sysfs
Some devices allow an individual function to be reset without affecting other functions in the same device: that's what pci_reset_function does. For devices that have this support, expose reset attribite in sysfs. This is useful e.g. for virtualization, where a qemu userspace process wants to reset the device when the guest is reset, to emulate machine reboot as closely as possible. Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/pci-sysfs.c37
-rw-r--r--drivers/pci/pci.c16
-rw-r--r--drivers/pci/pci.h1
3 files changed, 54 insertions, 0 deletions
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
919static 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
935static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_store);
936
919static int pci_create_capabilities_sysfs(struct pci_dev *dev) 937static 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
972error:
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
949int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) 982int __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)
2262EXPORT_SYMBOL_GPL(__pci_reset_function); 2262EXPORT_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 */
2275int 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);
16extern int pci_mmap_fits(struct pci_dev *pdev, int resno, 16extern 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
19int 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