aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2012-10-24 21:36:03 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-11-05 12:46:23 -0500
commitb3c32c4f9565f93407921c0d8a4458042eb8998e (patch)
tree9c035788cf5a2f5fcf897f3fe63c32064bdef255 /drivers/pci
parent3ff2de9ba1a2e22e548979dbcd46e999b22c93d8 (diff)
PCI/PM: Fix proc config reg access for D3cold and bridge suspending
In https://bugzilla.kernel.org/show_bug.cgi?id=48981 Peter reported that /proc/bus/pci/??/??.? does not work for 3.6. This is because the device configuration space registers are not accessible if the corresponding parent bridge is suspended or the device is put into D3cold state. This is the same as /sys/bus/pci/devices/0000:??:??.?/config access issue. So the function used to solve sysfs issue is used to solve this issue. This patch moves pci_config_pm_runtime_get()/_put() from pci/pci-sysfs.c to pci/pci.c and makes them extern so they can be used by both the sysfs and proc paths. [bhelgaas: changelog, references, reporters] Reference: https://bugzilla.kernel.org/show_bug.cgi?id=48981 Reference: https://bugzilla.kernel.org/show_bug.cgi?id=49031 Reported-by: Forrest Loomis <cybercyst@gmail.com> Reported-by: Peter <lekensteyn@gmail.com> Reported-by: Micael Dias <kam1kaz3@gmail.com> Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> CC: stable@vger.kernel.org # v3.6+
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci-sysfs.c34
-rw-r--r--drivers/pci/pci.c32
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/proc.c8
4 files changed, 42 insertions, 34 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 02d107b15281..f39378d9da15 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -458,40 +458,6 @@ boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
458} 458}
459struct device_attribute vga_attr = __ATTR_RO(boot_vga); 459struct device_attribute vga_attr = __ATTR_RO(boot_vga);
460 460
461static void
462pci_config_pm_runtime_get(struct pci_dev *pdev)
463{
464 struct device *dev = &pdev->dev;
465 struct device *parent = dev->parent;
466
467 if (parent)
468 pm_runtime_get_sync(parent);
469 pm_runtime_get_noresume(dev);
470 /*
471 * pdev->current_state is set to PCI_D3cold during suspending,
472 * so wait until suspending completes
473 */
474 pm_runtime_barrier(dev);
475 /*
476 * Only need to resume devices in D3cold, because config
477 * registers are still accessible for devices suspended but
478 * not in D3cold.
479 */
480 if (pdev->current_state == PCI_D3cold)
481 pm_runtime_resume(dev);
482}
483
484static void
485pci_config_pm_runtime_put(struct pci_dev *pdev)
486{
487 struct device *dev = &pdev->dev;
488 struct device *parent = dev->parent;
489
490 pm_runtime_put(dev);
491 if (parent)
492 pm_runtime_put_sync(parent);
493}
494
495static ssize_t 461static ssize_t
496pci_read_config(struct file *filp, struct kobject *kobj, 462pci_read_config(struct file *filp, struct kobject *kobj,
497 struct bin_attribute *bin_attr, 463 struct bin_attribute *bin_attr,
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 54858838f098..aabf64798bda 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1858,6 +1858,38 @@ bool pci_dev_run_wake(struct pci_dev *dev)
1858} 1858}
1859EXPORT_SYMBOL_GPL(pci_dev_run_wake); 1859EXPORT_SYMBOL_GPL(pci_dev_run_wake);
1860 1860
1861void pci_config_pm_runtime_get(struct pci_dev *pdev)
1862{
1863 struct device *dev = &pdev->dev;
1864 struct device *parent = dev->parent;
1865
1866 if (parent)
1867 pm_runtime_get_sync(parent);
1868 pm_runtime_get_noresume(dev);
1869 /*
1870 * pdev->current_state is set to PCI_D3cold during suspending,
1871 * so wait until suspending completes
1872 */
1873 pm_runtime_barrier(dev);
1874 /*
1875 * Only need to resume devices in D3cold, because config
1876 * registers are still accessible for devices suspended but
1877 * not in D3cold.
1878 */
1879 if (pdev->current_state == PCI_D3cold)
1880 pm_runtime_resume(dev);
1881}
1882
1883void pci_config_pm_runtime_put(struct pci_dev *pdev)
1884{
1885 struct device *dev = &pdev->dev;
1886 struct device *parent = dev->parent;
1887
1888 pm_runtime_put(dev);
1889 if (parent)
1890 pm_runtime_put_sync(parent);
1891}
1892
1861/** 1893/**
1862 * pci_pm_init - Initialize PM functions of given PCI device 1894 * pci_pm_init - Initialize PM functions of given PCI device
1863 * @dev: PCI device to handle. 1895 * @dev: PCI device to handle.
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index bacbcba69cf3..fd92aab9904b 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -72,6 +72,8 @@ extern void pci_disable_enabled_device(struct pci_dev *dev);
72extern int pci_finish_runtime_suspend(struct pci_dev *dev); 72extern int pci_finish_runtime_suspend(struct pci_dev *dev);
73extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); 73extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
74extern void pci_wakeup_bus(struct pci_bus *bus); 74extern void pci_wakeup_bus(struct pci_bus *bus);
75extern void pci_config_pm_runtime_get(struct pci_dev *dev);
76extern void pci_config_pm_runtime_put(struct pci_dev *dev);
75extern void pci_pm_init(struct pci_dev *dev); 77extern void pci_pm_init(struct pci_dev *dev);
76extern void platform_pci_wakeup_init(struct pci_dev *dev); 78extern void platform_pci_wakeup_init(struct pci_dev *dev);
77extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); 79extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index eb907a8faf2a..9b8505ccc56d 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -76,6 +76,8 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
76 if (!access_ok(VERIFY_WRITE, buf, cnt)) 76 if (!access_ok(VERIFY_WRITE, buf, cnt))
77 return -EINVAL; 77 return -EINVAL;
78 78
79 pci_config_pm_runtime_get(dev);
80
79 if ((pos & 1) && cnt) { 81 if ((pos & 1) && cnt) {
80 unsigned char val; 82 unsigned char val;
81 pci_user_read_config_byte(dev, pos, &val); 83 pci_user_read_config_byte(dev, pos, &val);
@@ -121,6 +123,8 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
121 cnt--; 123 cnt--;
122 } 124 }
123 125
126 pci_config_pm_runtime_put(dev);
127
124 *ppos = pos; 128 *ppos = pos;
125 return nbytes; 129 return nbytes;
126} 130}
@@ -146,6 +150,8 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
146 if (!access_ok(VERIFY_READ, buf, cnt)) 150 if (!access_ok(VERIFY_READ, buf, cnt))
147 return -EINVAL; 151 return -EINVAL;
148 152
153 pci_config_pm_runtime_get(dev);
154
149 if ((pos & 1) && cnt) { 155 if ((pos & 1) && cnt) {
150 unsigned char val; 156 unsigned char val;
151 __get_user(val, buf); 157 __get_user(val, buf);
@@ -191,6 +197,8 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
191 cnt--; 197 cnt--;
192 } 198 }
193 199
200 pci_config_pm_runtime_put(dev);
201
194 *ppos = pos; 202 *ppos = pos;
195 i_size_write(ino, dp->size); 203 i_size_write(ino, dp->size);
196 return nbytes; 204 return nbytes;