]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.6.8/pci-pm-fix-proc-config-reg-access-for-d3cold-and-bridge-suspending.patch
Fixes for 4.19
[thirdparty/kernel/stable-queue.git] / releases / 3.6.8 / pci-pm-fix-proc-config-reg-access-for-d3cold-and-bridge-suspending.patch
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
5
6 From: Huang Ying <ying.huang@intel.com>
7
8 commit b3c32c4f9565f93407921c0d8a4458042eb8998e upstream.
9
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.
15
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
18 this issue.
19
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
22 sysfs and proc paths.
23
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>
34
35 ---
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(-)
41
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
45 }
46 struct device_attribute vga_attr = __ATTR_RO(boot_vga);
47
48 -static void
49 -pci_config_pm_runtime_get(struct pci_dev *pdev)
50 -{
51 - struct device *dev = &pdev->dev;
52 - struct device *parent = dev->parent;
53 -
54 - if (parent)
55 - pm_runtime_get_sync(parent);
56 - pm_runtime_get_noresume(dev);
57 - /*
58 - * pdev->current_state is set to PCI_D3cold during suspending,
59 - * so wait until suspending completes
60 - */
61 - pm_runtime_barrier(dev);
62 - /*
63 - * Only need to resume devices in D3cold, because config
64 - * registers are still accessible for devices suspended but
65 - * not in D3cold.
66 - */
67 - if (pdev->current_state == PCI_D3cold)
68 - pm_runtime_resume(dev);
69 -}
70 -
71 -static void
72 -pci_config_pm_runtime_put(struct pci_dev *pdev)
73 -{
74 - struct device *dev = &pdev->dev;
75 - struct device *parent = dev->parent;
76 -
77 - pm_runtime_put(dev);
78 - if (parent)
79 - pm_runtime_put_sync(parent);
80 -}
81 -
82 static ssize_t
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
88 }
89 EXPORT_SYMBOL_GPL(pci_dev_run_wake);
90
91 +void pci_config_pm_runtime_get(struct pci_dev *pdev)
92 +{
93 + struct device *dev = &pdev->dev;
94 + struct device *parent = dev->parent;
95 +
96 + if (parent)
97 + pm_runtime_get_sync(parent);
98 + pm_runtime_get_noresume(dev);
99 + /*
100 + * pdev->current_state is set to PCI_D3cold during suspending,
101 + * so wait until suspending completes
102 + */
103 + pm_runtime_barrier(dev);
104 + /*
105 + * Only need to resume devices in D3cold, because config
106 + * registers are still accessible for devices suspended but
107 + * not in D3cold.
108 + */
109 + if (pdev->current_state == PCI_D3cold)
110 + pm_runtime_resume(dev);
111 +}
112 +
113 +void pci_config_pm_runtime_put(struct pci_dev *pdev)
114 +{
115 + struct device *dev = &pdev->dev;
116 + struct device *parent = dev->parent;
117 +
118 + pm_runtime_put(dev);
119 + if (parent)
120 + pm_runtime_put_sync(parent);
121 +}
122 +
123 /**
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))
141 return -EINVAL;
142
143 + pci_config_pm_runtime_get(dev);
144 +
145 if ((pos & 1) && cnt) {
146 unsigned char val;
147 pci_user_read_config_byte(dev, pos, &val);
148 @@ -121,6 +123,8 @@ proc_bus_pci_read(struct file *file, cha
149 cnt--;
150 }
151
152 + pci_config_pm_runtime_put(dev);
153 +
154 *ppos = pos;
155 return nbytes;
156 }
157 @@ -146,6 +150,8 @@ proc_bus_pci_write(struct file *file, co
158 if (!access_ok(VERIFY_READ, buf, cnt))
159 return -EINVAL;
160
161 + pci_config_pm_runtime_get(dev);
162 +
163 if ((pos & 1) && cnt) {
164 unsigned char val;
165 __get_user(val, buf);
166 @@ -191,6 +197,8 @@ proc_bus_pci_write(struct file *file, co
167 cnt--;
168 }
169
170 + pci_config_pm_runtime_put(dev);
171 +
172 *ppos = pos;
173 i_size_write(ino, dp->size);
174 return nbytes;