diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2014-09-12 17:23:14 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-09-12 22:01:27 -0400 |
commit | 9ce90ea5c0d512ff66693b238167b56dbaef786b (patch) | |
tree | 7cc4ddf40415114108f1a8b1a0e78ef150bfb645 /drivers/pci/pci-acpi.c | |
parent | 1197ba22c57df96bf3cac0bb2a936fb695370f35 (diff) |
PCI: Move pci_get_hp_params() to drivers/pci/pci-acpi.c
Move pci_get_hp_params() and related functions from
drivers/pci/hotplug/acpi_pcihp.c to drivers/pci/pci-acpi.c.
Previously, pci_get_hp_params() was used only by hotplug drivers. But
future changes will move this into the normal device enumeration process,
so it will be used even when CONFIG_HOTPLUG_PCI is not set.
No functional change.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/pci-acpi.c')
-rw-r--r-- | drivers/pci/pci-acpi.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 37263b0ebfe3..06e0b41c397e 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
13 | #include <linux/pci_hotplug.h> | ||
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
14 | #include <linux/pci-aspm.h> | 15 | #include <linux/pci-aspm.h> |
15 | #include <linux/pci-acpi.h> | 16 | #include <linux/pci-acpi.h> |
@@ -98,6 +99,255 @@ phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) | |||
98 | return (phys_addr_t)mcfg_addr; | 99 | return (phys_addr_t)mcfg_addr; |
99 | } | 100 | } |
100 | 101 | ||
102 | static acpi_status | ||
103 | decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx) | ||
104 | { | ||
105 | int i; | ||
106 | union acpi_object *fields = record->package.elements; | ||
107 | u32 revision = fields[1].integer.value; | ||
108 | |||
109 | switch (revision) { | ||
110 | case 1: | ||
111 | if (record->package.count != 6) | ||
112 | return AE_ERROR; | ||
113 | for (i = 2; i < 6; i++) | ||
114 | if (fields[i].type != ACPI_TYPE_INTEGER) | ||
115 | return AE_ERROR; | ||
116 | hpx->t0 = &hpx->type0_data; | ||
117 | hpx->t0->revision = revision; | ||
118 | hpx->t0->cache_line_size = fields[2].integer.value; | ||
119 | hpx->t0->latency_timer = fields[3].integer.value; | ||
120 | hpx->t0->enable_serr = fields[4].integer.value; | ||
121 | hpx->t0->enable_perr = fields[5].integer.value; | ||
122 | break; | ||
123 | default: | ||
124 | printk(KERN_WARNING | ||
125 | "%s: Type 0 Revision %d record not supported\n", | ||
126 | __func__, revision); | ||
127 | return AE_ERROR; | ||
128 | } | ||
129 | return AE_OK; | ||
130 | } | ||
131 | |||
132 | static acpi_status | ||
133 | decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx) | ||
134 | { | ||
135 | int i; | ||
136 | union acpi_object *fields = record->package.elements; | ||
137 | u32 revision = fields[1].integer.value; | ||
138 | |||
139 | switch (revision) { | ||
140 | case 1: | ||
141 | if (record->package.count != 5) | ||
142 | return AE_ERROR; | ||
143 | for (i = 2; i < 5; i++) | ||
144 | if (fields[i].type != ACPI_TYPE_INTEGER) | ||
145 | return AE_ERROR; | ||
146 | hpx->t1 = &hpx->type1_data; | ||
147 | hpx->t1->revision = revision; | ||
148 | hpx->t1->max_mem_read = fields[2].integer.value; | ||
149 | hpx->t1->avg_max_split = fields[3].integer.value; | ||
150 | hpx->t1->tot_max_split = fields[4].integer.value; | ||
151 | break; | ||
152 | default: | ||
153 | printk(KERN_WARNING | ||
154 | "%s: Type 1 Revision %d record not supported\n", | ||
155 | __func__, revision); | ||
156 | return AE_ERROR; | ||
157 | } | ||
158 | return AE_OK; | ||
159 | } | ||
160 | |||
161 | static acpi_status | ||
162 | decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx) | ||
163 | { | ||
164 | int i; | ||
165 | union acpi_object *fields = record->package.elements; | ||
166 | u32 revision = fields[1].integer.value; | ||
167 | |||
168 | switch (revision) { | ||
169 | case 1: | ||
170 | if (record->package.count != 18) | ||
171 | return AE_ERROR; | ||
172 | for (i = 2; i < 18; i++) | ||
173 | if (fields[i].type != ACPI_TYPE_INTEGER) | ||
174 | return AE_ERROR; | ||
175 | hpx->t2 = &hpx->type2_data; | ||
176 | hpx->t2->revision = revision; | ||
177 | hpx->t2->unc_err_mask_and = fields[2].integer.value; | ||
178 | hpx->t2->unc_err_mask_or = fields[3].integer.value; | ||
179 | hpx->t2->unc_err_sever_and = fields[4].integer.value; | ||
180 | hpx->t2->unc_err_sever_or = fields[5].integer.value; | ||
181 | hpx->t2->cor_err_mask_and = fields[6].integer.value; | ||
182 | hpx->t2->cor_err_mask_or = fields[7].integer.value; | ||
183 | hpx->t2->adv_err_cap_and = fields[8].integer.value; | ||
184 | hpx->t2->adv_err_cap_or = fields[9].integer.value; | ||
185 | hpx->t2->pci_exp_devctl_and = fields[10].integer.value; | ||
186 | hpx->t2->pci_exp_devctl_or = fields[11].integer.value; | ||
187 | hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value; | ||
188 | hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value; | ||
189 | hpx->t2->sec_unc_err_sever_and = fields[14].integer.value; | ||
190 | hpx->t2->sec_unc_err_sever_or = fields[15].integer.value; | ||
191 | hpx->t2->sec_unc_err_mask_and = fields[16].integer.value; | ||
192 | hpx->t2->sec_unc_err_mask_or = fields[17].integer.value; | ||
193 | break; | ||
194 | default: | ||
195 | printk(KERN_WARNING | ||
196 | "%s: Type 2 Revision %d record not supported\n", | ||
197 | __func__, revision); | ||
198 | return AE_ERROR; | ||
199 | } | ||
200 | return AE_OK; | ||
201 | } | ||
202 | |||
203 | static acpi_status | ||
204 | acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) | ||
205 | { | ||
206 | acpi_status status; | ||
207 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
208 | union acpi_object *package, *record, *fields; | ||
209 | u32 type; | ||
210 | int i; | ||
211 | |||
212 | /* Clear the return buffer with zeros */ | ||
213 | memset(hpx, 0, sizeof(struct hotplug_params)); | ||
214 | |||
215 | status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer); | ||
216 | if (ACPI_FAILURE(status)) | ||
217 | return status; | ||
218 | |||
219 | package = (union acpi_object *)buffer.pointer; | ||
220 | if (package->type != ACPI_TYPE_PACKAGE) { | ||
221 | status = AE_ERROR; | ||
222 | goto exit; | ||
223 | } | ||
224 | |||
225 | for (i = 0; i < package->package.count; i++) { | ||
226 | record = &package->package.elements[i]; | ||
227 | if (record->type != ACPI_TYPE_PACKAGE) { | ||
228 | status = AE_ERROR; | ||
229 | goto exit; | ||
230 | } | ||
231 | |||
232 | fields = record->package.elements; | ||
233 | if (fields[0].type != ACPI_TYPE_INTEGER || | ||
234 | fields[1].type != ACPI_TYPE_INTEGER) { | ||
235 | status = AE_ERROR; | ||
236 | goto exit; | ||
237 | } | ||
238 | |||
239 | type = fields[0].integer.value; | ||
240 | switch (type) { | ||
241 | case 0: | ||
242 | status = decode_type0_hpx_record(record, hpx); | ||
243 | if (ACPI_FAILURE(status)) | ||
244 | goto exit; | ||
245 | break; | ||
246 | case 1: | ||
247 | status = decode_type1_hpx_record(record, hpx); | ||
248 | if (ACPI_FAILURE(status)) | ||
249 | goto exit; | ||
250 | break; | ||
251 | case 2: | ||
252 | status = decode_type2_hpx_record(record, hpx); | ||
253 | if (ACPI_FAILURE(status)) | ||
254 | goto exit; | ||
255 | break; | ||
256 | default: | ||
257 | printk(KERN_ERR "%s: Type %d record not supported\n", | ||
258 | __func__, type); | ||
259 | status = AE_ERROR; | ||
260 | goto exit; | ||
261 | } | ||
262 | } | ||
263 | exit: | ||
264 | kfree(buffer.pointer); | ||
265 | return status; | ||
266 | } | ||
267 | |||
268 | static acpi_status | ||
269 | acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) | ||
270 | { | ||
271 | acpi_status status; | ||
272 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
273 | union acpi_object *package, *fields; | ||
274 | int i; | ||
275 | |||
276 | memset(hpp, 0, sizeof(struct hotplug_params)); | ||
277 | |||
278 | status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer); | ||
279 | if (ACPI_FAILURE(status)) | ||
280 | return status; | ||
281 | |||
282 | package = (union acpi_object *) buffer.pointer; | ||
283 | if (package->type != ACPI_TYPE_PACKAGE || | ||
284 | package->package.count != 4) { | ||
285 | status = AE_ERROR; | ||
286 | goto exit; | ||
287 | } | ||
288 | |||
289 | fields = package->package.elements; | ||
290 | for (i = 0; i < 4; i++) { | ||
291 | if (fields[i].type != ACPI_TYPE_INTEGER) { | ||
292 | status = AE_ERROR; | ||
293 | goto exit; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | hpp->t0 = &hpp->type0_data; | ||
298 | hpp->t0->revision = 1; | ||
299 | hpp->t0->cache_line_size = fields[0].integer.value; | ||
300 | hpp->t0->latency_timer = fields[1].integer.value; | ||
301 | hpp->t0->enable_serr = fields[2].integer.value; | ||
302 | hpp->t0->enable_perr = fields[3].integer.value; | ||
303 | |||
304 | exit: | ||
305 | kfree(buffer.pointer); | ||
306 | return status; | ||
307 | } | ||
308 | |||
309 | /* pci_get_hp_params | ||
310 | * | ||
311 | * @dev - the pci_dev for which we want parameters | ||
312 | * @hpp - allocated by the caller | ||
313 | */ | ||
314 | int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) | ||
315 | { | ||
316 | acpi_status status; | ||
317 | acpi_handle handle, phandle; | ||
318 | struct pci_bus *pbus; | ||
319 | |||
320 | handle = NULL; | ||
321 | for (pbus = dev->bus; pbus; pbus = pbus->parent) { | ||
322 | handle = acpi_pci_get_bridge_handle(pbus); | ||
323 | if (handle) | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * _HPP settings apply to all child buses, until another _HPP is | ||
329 | * encountered. If we don't find an _HPP for the input pci dev, | ||
330 | * look for it in the parent device scope since that would apply to | ||
331 | * this pci dev. | ||
332 | */ | ||
333 | while (handle) { | ||
334 | status = acpi_run_hpx(handle, hpp); | ||
335 | if (ACPI_SUCCESS(status)) | ||
336 | return 0; | ||
337 | status = acpi_run_hpp(handle, hpp); | ||
338 | if (ACPI_SUCCESS(status)) | ||
339 | return 0; | ||
340 | if (acpi_is_root_bridge(handle)) | ||
341 | break; | ||
342 | status = acpi_get_parent(handle, &phandle); | ||
343 | if (ACPI_FAILURE(status)) | ||
344 | break; | ||
345 | handle = phandle; | ||
346 | } | ||
347 | return -ENODEV; | ||
348 | } | ||
349 | EXPORT_SYMBOL_GPL(pci_get_hp_params); | ||
350 | |||
101 | /* | 351 | /* |
102 | * _SxD returns the D-state with the highest power | 352 | * _SxD returns the D-state with the highest power |
103 | * (lowest D-state number) supported in the S-state "x". | 353 | * (lowest D-state number) supported in the S-state "x". |