1 From b3c32c4f9565f93407921c0d8a4458042eb8998e Mon Sep 17 00:00:00 2001
2 From: Huang Ying <ying.huang@intel.com>
3 Date: Thu, 25 Oct 2012 09:36:03 +0800
4 Subject: PCI/PM: Fix proc config reg access for D3cold and bridge suspending
6 From: Huang Ying <ying.huang@intel.com>
8 commit b3c32c4f9565f93407921c0d8a4458042eb8998e upstream.
10 In https://bugzilla.kernel.org/show_bug.cgi?id=48981
11 Peter reported that /proc/bus/pci/??/??.? does not work for 3.6.
12 This is because the device configuration space registers are
13 not accessible if the corresponding parent bridge is suspended or
14 the device is put into D3cold state.
16 This is the same as /sys/bus/pci/devices/0000:??:??.?/config access
17 issue. So the function used to solve sysfs issue is used to solve
20 This patch moves pci_config_pm_runtime_get()/_put() from pci/pci-sysfs.c
21 to pci/pci.c and makes them extern so they can be used by both the
24 [bhelgaas: changelog, references, reporters]
25 Reference: https://bugzilla.kernel.org/show_bug.cgi?id=48981
26 Reference: https://bugzilla.kernel.org/show_bug.cgi?id=49031
27 Reported-by: Forrest Loomis <cybercyst@gmail.com>
28 Reported-by: Peter <lekensteyn@gmail.com>
29 Reported-by: Micael Dias <kam1kaz3@gmail.com>
30 Signed-off-by: Huang Ying <ying.huang@intel.com>
31 Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
32 Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
33 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
36 drivers/pci/pci-sysfs.c | 34 ----------------------------------
37 drivers/pci/pci.c | 32 ++++++++++++++++++++++++++++++++
38 drivers/pci/pci.h | 2 ++
39 drivers/pci/proc.c | 8 ++++++++
40 4 files changed, 42 insertions(+), 34 deletions(-)
42 --- a/drivers/pci/pci-sysfs.c
43 +++ b/drivers/pci/pci-sysfs.c
44 @@ -458,40 +458,6 @@ boot_vga_show(struct device *dev, struct
46 struct device_attribute vga_attr = __ATTR_RO(boot_vga);
49 -pci_config_pm_runtime_get(struct pci_dev *pdev)
51 - struct device *dev = &pdev->dev;
52 - struct device *parent = dev->parent;
55 - pm_runtime_get_sync(parent);
56 - pm_runtime_get_noresume(dev);
58 - * pdev->current_state is set to PCI_D3cold during suspending,
59 - * so wait until suspending completes
61 - pm_runtime_barrier(dev);
63 - * Only need to resume devices in D3cold, because config
64 - * registers are still accessible for devices suspended but
67 - if (pdev->current_state == PCI_D3cold)
68 - pm_runtime_resume(dev);
72 -pci_config_pm_runtime_put(struct pci_dev *pdev)
74 - struct device *dev = &pdev->dev;
75 - struct device *parent = dev->parent;
77 - pm_runtime_put(dev);
79 - pm_runtime_put_sync(parent);
83 pci_read_config(struct file *filp, struct kobject *kobj,
84 struct bin_attribute *bin_attr,
85 --- a/drivers/pci/pci.c
86 +++ b/drivers/pci/pci.c
87 @@ -1910,6 +1910,38 @@ bool pci_dev_run_wake(struct pci_dev *de
89 EXPORT_SYMBOL_GPL(pci_dev_run_wake);
91 +void pci_config_pm_runtime_get(struct pci_dev *pdev)
93 + struct device *dev = &pdev->dev;
94 + struct device *parent = dev->parent;
97 + pm_runtime_get_sync(parent);
98 + pm_runtime_get_noresume(dev);
100 + * pdev->current_state is set to PCI_D3cold during suspending,
101 + * so wait until suspending completes
103 + pm_runtime_barrier(dev);
105 + * Only need to resume devices in D3cold, because config
106 + * registers are still accessible for devices suspended but
109 + if (pdev->current_state == PCI_D3cold)
110 + pm_runtime_resume(dev);
113 +void pci_config_pm_runtime_put(struct pci_dev *pdev)
115 + struct device *dev = &pdev->dev;
116 + struct device *parent = dev->parent;
118 + pm_runtime_put(dev);
120 + pm_runtime_put_sync(parent);
124 * pci_pm_init - Initialize PM functions of given PCI device
125 * @dev: PCI device to handle.
126 --- a/drivers/pci/pci.h
127 +++ b/drivers/pci/pci.h
128 @@ -72,6 +72,8 @@ extern void pci_disable_enabled_device(s
129 extern int pci_finish_runtime_suspend(struct pci_dev *dev);
130 extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
131 extern void pci_wakeup_bus(struct pci_bus *bus);
132 +extern void pci_config_pm_runtime_get(struct pci_dev *dev);
133 +extern void pci_config_pm_runtime_put(struct pci_dev *dev);
134 extern void pci_pm_init(struct pci_dev *dev);
135 extern void platform_pci_wakeup_init(struct pci_dev *dev);
136 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
137 --- a/drivers/pci/proc.c
138 +++ b/drivers/pci/proc.c
139 @@ -76,6 +76,8 @@ proc_bus_pci_read(struct file *file, cha
140 if (!access_ok(VERIFY_WRITE, buf, cnt))
143 + pci_config_pm_runtime_get(dev);
145 if ((pos & 1) && cnt) {
147 pci_user_read_config_byte(dev, pos, &val);
148 @@ -121,6 +123,8 @@ proc_bus_pci_read(struct file *file, cha
152 + pci_config_pm_runtime_put(dev);
157 @@ -146,6 +150,8 @@ proc_bus_pci_write(struct file *file, co
158 if (!access_ok(VERIFY_READ, buf, cnt))
161 + pci_config_pm_runtime_get(dev);
163 if ((pos & 1) && cnt) {
165 __get_user(val, buf);
166 @@ -191,6 +197,8 @@ proc_bus_pci_write(struct file *file, co
170 + pci_config_pm_runtime_put(dev);
173 i_size_write(ino, dp->size);