diff options
Diffstat (limited to 'drivers/pci/hotplug/shpchprm_acpi.c')
-rw-r--r-- | drivers/pci/hotplug/shpchprm_acpi.c | 794 |
1 files changed, 62 insertions, 732 deletions
diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index 3d2f9c5269c7..3be518c7d47a 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c | |||
@@ -38,62 +38,11 @@ | |||
38 | #include <acpi/acpi_bus.h> | 38 | #include <acpi/acpi_bus.h> |
39 | #include <acpi/actypes.h> | 39 | #include <acpi/actypes.h> |
40 | #include "shpchp.h" | 40 | #include "shpchp.h" |
41 | #include "shpchprm.h" | ||
42 | |||
43 | #define PCI_MAX_BUS 0x100 | ||
44 | #define ACPI_STA_DEVICE_PRESENT 0x01 | ||
45 | 41 | ||
46 | #define METHOD_NAME__SUN "_SUN" | 42 | #define METHOD_NAME__SUN "_SUN" |
47 | #define METHOD_NAME__HPP "_HPP" | 43 | #define METHOD_NAME__HPP "_HPP" |
48 | #define METHOD_NAME_OSHP "OSHP" | 44 | #define METHOD_NAME_OSHP "OSHP" |
49 | 45 | ||
50 | #define PHP_RES_BUS 0xA0 | ||
51 | #define PHP_RES_IO 0xA1 | ||
52 | #define PHP_RES_MEM 0xA2 | ||
53 | #define PHP_RES_PMEM 0xA3 | ||
54 | |||
55 | #define BRIDGE_TYPE_P2P 0x00 | ||
56 | #define BRIDGE_TYPE_HOST 0x01 | ||
57 | |||
58 | /* this should go to drivers/acpi/include/ */ | ||
59 | struct acpi__hpp { | ||
60 | u8 cache_line_size; | ||
61 | u8 latency_timer; | ||
62 | u8 enable_serr; | ||
63 | u8 enable_perr; | ||
64 | }; | ||
65 | |||
66 | struct acpi_php_slot { | ||
67 | struct acpi_php_slot *next; | ||
68 | struct acpi_bridge *bridge; | ||
69 | acpi_handle handle; | ||
70 | int seg; | ||
71 | int bus; | ||
72 | int dev; | ||
73 | int fun; | ||
74 | u32 sun; | ||
75 | void *slot_ops; /* _STA, _EJx, etc */ | ||
76 | struct slot *slot; | ||
77 | }; /* per func */ | ||
78 | |||
79 | struct acpi_bridge { | ||
80 | struct acpi_bridge *parent; | ||
81 | struct acpi_bridge *next; | ||
82 | struct acpi_bridge *child; | ||
83 | acpi_handle handle; | ||
84 | int seg; | ||
85 | int pbus; /* pdev->bus->number */ | ||
86 | int pdevice; /* PCI_SLOT(pdev->devfn) */ | ||
87 | int pfunction; /* PCI_DEVFN(pdev->devfn) */ | ||
88 | int bus; /* pdev->subordinate->number */ | ||
89 | struct acpi__hpp *_hpp; | ||
90 | struct acpi_php_slot *slots; | ||
91 | int scanned; | ||
92 | int type; | ||
93 | }; | ||
94 | |||
95 | static struct acpi_bridge *acpi_bridges_head; | ||
96 | |||
97 | static u8 * acpi_path_name( acpi_handle handle) | 46 | static u8 * acpi_path_name( acpi_handle handle) |
98 | { | 47 | { |
99 | acpi_status status; | 48 | acpi_status status; |
@@ -109,82 +58,43 @@ static u8 * acpi_path_name( acpi_handle handle) | |||
109 | return path_name; | 58 | return path_name; |
110 | } | 59 | } |
111 | 60 | ||
112 | static void acpi_get__hpp ( struct acpi_bridge *ab); | 61 | static acpi_status |
113 | static void acpi_run_oshp ( struct acpi_bridge *ab); | 62 | acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) |
114 | |||
115 | static int acpi_add_slot_to_php_slots( | ||
116 | struct acpi_bridge *ab, | ||
117 | int bus_num, | ||
118 | acpi_handle handle, | ||
119 | u32 adr, | ||
120 | u32 sun | ||
121 | ) | ||
122 | { | ||
123 | struct acpi_php_slot *aps; | ||
124 | static long samesun = -1; | ||
125 | |||
126 | aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL); | ||
127 | if (!aps) { | ||
128 | err ("acpi_shpchprm: alloc for aps fail\n"); | ||
129 | return -1; | ||
130 | } | ||
131 | memset(aps, 0, sizeof(struct acpi_php_slot)); | ||
132 | |||
133 | aps->handle = handle; | ||
134 | aps->bus = bus_num; | ||
135 | aps->dev = (adr >> 16) & 0xffff; | ||
136 | aps->fun = adr & 0xffff; | ||
137 | aps->sun = sun; | ||
138 | |||
139 | aps->next = ab->slots; /* cling to the bridge */ | ||
140 | aps->bridge = ab; | ||
141 | ab->slots = aps; | ||
142 | |||
143 | ab->scanned += 1; | ||
144 | if (!ab->_hpp) | ||
145 | acpi_get__hpp(ab); | ||
146 | |||
147 | acpi_run_oshp(ab); | ||
148 | |||
149 | if (sun != samesun) { | ||
150 | info("acpi_shpchprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps->sun, ab->seg, | ||
151 | aps->bus, aps->dev, aps->fun); | ||
152 | samesun = sun; | ||
153 | } | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static void acpi_get__hpp ( struct acpi_bridge *ab) | ||
158 | { | 63 | { |
159 | acpi_status status; | 64 | acpi_status status; |
160 | u8 nui[4]; | 65 | u8 nui[4]; |
161 | struct acpi_buffer ret_buf = { 0, NULL}; | 66 | struct acpi_buffer ret_buf = { 0, NULL}; |
162 | union acpi_object *ext_obj, *package; | 67 | union acpi_object *ext_obj, *package; |
163 | u8 *path_name = acpi_path_name(ab->handle); | 68 | u8 *path_name = acpi_path_name(handle); |
164 | int i, len = 0; | 69 | int i, len = 0; |
165 | 70 | ||
166 | /* get _hpp */ | 71 | /* get _hpp */ |
167 | status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); | 72 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); |
168 | switch (status) { | 73 | switch (status) { |
169 | case AE_BUFFER_OVERFLOW: | 74 | case AE_BUFFER_OVERFLOW: |
170 | ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); | 75 | ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); |
171 | if (!ret_buf.pointer) { | 76 | if (!ret_buf.pointer) { |
172 | err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name); | 77 | err ("%s:%s alloc for _HPP fail\n", __FUNCTION__, |
173 | return; | 78 | path_name); |
79 | return AE_NO_MEMORY; | ||
174 | } | 80 | } |
175 | status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); | 81 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, |
82 | NULL, &ret_buf); | ||
176 | if (ACPI_SUCCESS(status)) | 83 | if (ACPI_SUCCESS(status)) |
177 | break; | 84 | break; |
178 | default: | 85 | default: |
179 | if (ACPI_FAILURE(status)) { | 86 | if (ACPI_FAILURE(status)) { |
180 | err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status); | 87 | dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__, |
181 | return; | 88 | path_name, status); |
89 | return status; | ||
182 | } | 90 | } |
183 | } | 91 | } |
184 | 92 | ||
185 | ext_obj = (union acpi_object *) ret_buf.pointer; | 93 | ext_obj = (union acpi_object *) ret_buf.pointer; |
186 | if (ext_obj->type != ACPI_TYPE_PACKAGE) { | 94 | if (ext_obj->type != ACPI_TYPE_PACKAGE) { |
187 | err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name); | 95 | err ("%s:%s _HPP obj not a package\n", __FUNCTION__, |
96 | path_name); | ||
97 | status = AE_ERROR; | ||
188 | goto free_and_return; | 98 | goto free_and_return; |
189 | } | 99 | } |
190 | 100 | ||
@@ -197,553 +107,41 @@ static void acpi_get__hpp ( struct acpi_bridge *ab) | |||
197 | nui[i] = (u8)ext_obj->integer.value; | 107 | nui[i] = (u8)ext_obj->integer.value; |
198 | break; | 108 | break; |
199 | default: | 109 | default: |
200 | err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name); | 110 | err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__, |
111 | path_name); | ||
112 | status = AE_ERROR; | ||
201 | goto free_and_return; | 113 | goto free_and_return; |
202 | } | 114 | } |
203 | } | 115 | } |
204 | 116 | ||
205 | ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); | 117 | hpp->cache_line_size = nui[0]; |
206 | if (!ab->_hpp) { | 118 | hpp->latency_timer = nui[1]; |
207 | err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name); | 119 | hpp->enable_serr = nui[2]; |
208 | goto free_and_return; | 120 | hpp->enable_perr = nui[3]; |
209 | } | ||
210 | memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); | ||
211 | |||
212 | ab->_hpp->cache_line_size = nui[0]; | ||
213 | ab->_hpp->latency_timer = nui[1]; | ||
214 | ab->_hpp->enable_serr = nui[2]; | ||
215 | ab->_hpp->enable_perr = nui[3]; | ||
216 | 121 | ||
217 | dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); | 122 | dbg(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); |
218 | dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); | 123 | dbg(" _HPP: latency timer =0x%x\n", hpp->latency_timer); |
219 | dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); | 124 | dbg(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); |
220 | dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); | 125 | dbg(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); |
221 | 126 | ||
222 | free_and_return: | 127 | free_and_return: |
223 | kfree(ret_buf.pointer); | 128 | kfree(ret_buf.pointer); |
129 | return status; | ||
224 | } | 130 | } |
225 | 131 | ||
226 | static void acpi_run_oshp ( struct acpi_bridge *ab) | 132 | static void acpi_run_oshp(acpi_handle handle) |
227 | { | ||
228 | acpi_status status; | ||
229 | u8 *path_name = acpi_path_name(ab->handle); | ||
230 | |||
231 | /* run OSHP */ | ||
232 | status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL); | ||
233 | if (ACPI_FAILURE(status)) { | ||
234 | err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); | ||
235 | } else | ||
236 | dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); | ||
237 | return; | ||
238 | } | ||
239 | |||
240 | /* find acpi_bridge downword from ab. */ | ||
241 | static struct acpi_bridge * | ||
242 | find_acpi_bridge_by_bus( | ||
243 | struct acpi_bridge *ab, | ||
244 | int seg, | ||
245 | int bus /* pdev->subordinate->number */ | ||
246 | ) | ||
247 | { | ||
248 | struct acpi_bridge *lab = NULL; | ||
249 | |||
250 | if (!ab) | ||
251 | return NULL; | ||
252 | |||
253 | if ((ab->bus == bus) && (ab->seg == seg)) | ||
254 | return ab; | ||
255 | |||
256 | if (ab->child) | ||
257 | lab = find_acpi_bridge_by_bus(ab->child, seg, bus); | ||
258 | |||
259 | if (!lab) | ||
260 | if (ab->next) | ||
261 | lab = find_acpi_bridge_by_bus(ab->next, seg, bus); | ||
262 | |||
263 | return lab; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * Build a device tree of ACPI PCI Bridges | ||
268 | */ | ||
269 | static void shpchprm_acpi_register_a_bridge ( | ||
270 | struct acpi_bridge **head, | ||
271 | struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ | ||
272 | struct acpi_bridge *cab /* child bridge to add */ | ||
273 | ) | ||
274 | { | ||
275 | struct acpi_bridge *lpab; | ||
276 | struct acpi_bridge *lcab; | ||
277 | |||
278 | lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); | ||
279 | if (!lpab) { | ||
280 | if (!(pab->type & BRIDGE_TYPE_HOST)) | ||
281 | warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); | ||
282 | pab->next = *head; | ||
283 | *head = pab; | ||
284 | lpab = pab; | ||
285 | } | ||
286 | |||
287 | if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) | ||
288 | return; | ||
289 | |||
290 | lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); | ||
291 | if (lcab) { | ||
292 | if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) | ||
293 | err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); | ||
294 | return; | ||
295 | } else | ||
296 | lcab = cab; | ||
297 | |||
298 | lcab->parent = lpab; | ||
299 | lcab->next = lpab->child; | ||
300 | lpab->child = lcab; | ||
301 | } | ||
302 | |||
303 | static acpi_status shpchprm_acpi_build_php_slots_callback( | ||
304 | acpi_handle handle, | ||
305 | u32 Level, | ||
306 | void *context, | ||
307 | void **retval | ||
308 | ) | ||
309 | { | 133 | { |
310 | ulong bus_num; | ||
311 | ulong seg_num; | ||
312 | ulong sun, adr; | ||
313 | ulong padr = 0; | ||
314 | acpi_handle phandle = NULL; | ||
315 | struct acpi_bridge *pab = (struct acpi_bridge *)context; | ||
316 | struct acpi_bridge *lab; | ||
317 | acpi_status status; | 134 | acpi_status status; |
318 | u8 *path_name = acpi_path_name(handle); | 135 | u8 *path_name = acpi_path_name(handle); |
319 | 136 | ||
320 | /* get _SUN */ | 137 | /* run OSHP */ |
321 | status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); | 138 | status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); |
322 | switch(status) { | ||
323 | case AE_NOT_FOUND: | ||
324 | return AE_OK; | ||
325 | default: | ||
326 | if (ACPI_FAILURE(status)) { | ||
327 | err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status); | ||
328 | return status; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | /* get _ADR. _ADR must exist if _SUN exists */ | ||
333 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
334 | if (ACPI_FAILURE(status)) { | ||
335 | err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); | ||
336 | return status; | ||
337 | } | ||
338 | |||
339 | dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); | ||
340 | |||
341 | status = acpi_get_parent(handle, &phandle); | ||
342 | if (ACPI_FAILURE(status)) { | 139 | if (ACPI_FAILURE(status)) { |
343 | err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status); | 140 | err("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name, |
344 | return (status); | 141 | status); |
345 | } | ||
346 | |||
347 | bus_num = pab->bus; | ||
348 | seg_num = pab->seg; | ||
349 | |||
350 | if (pab->bus == bus_num) { | ||
351 | lab = pab; | ||
352 | } else { | 142 | } else { |
353 | dbg("WARN: pab is not parent\n"); | 143 | dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name); |
354 | lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); | ||
355 | if (!lab) { | ||
356 | dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); | ||
357 | lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); | ||
358 | if (!lab) { | ||
359 | err("acpi_shpchprm: alloc for ab fail\n"); | ||
360 | return AE_NO_MEMORY; | ||
361 | } | ||
362 | memset(lab, 0, sizeof(struct acpi_bridge)); | ||
363 | |||
364 | lab->handle = phandle; | ||
365 | lab->pbus = pab->bus; | ||
366 | lab->pdevice = (int)(padr >> 16) & 0xffff; | ||
367 | lab->pfunction = (int)(padr & 0xffff); | ||
368 | lab->bus = (int)bus_num; | ||
369 | lab->scanned = 0; | ||
370 | lab->type = BRIDGE_TYPE_P2P; | ||
371 | |||
372 | shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); | ||
373 | } else | ||
374 | dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); | ||
375 | } | ||
376 | |||
377 | acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); | ||
378 | return (status); | ||
379 | } | ||
380 | |||
381 | static int shpchprm_acpi_build_php_slots( | ||
382 | struct acpi_bridge *ab, | ||
383 | u32 depth | ||
384 | ) | ||
385 | { | ||
386 | acpi_status status; | ||
387 | u8 *path_name = acpi_path_name(ab->handle); | ||
388 | |||
389 | /* Walk down this pci bridge to get _SUNs if any behind P2P */ | ||
390 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
391 | ab->handle, | ||
392 | depth, | ||
393 | shpchprm_acpi_build_php_slots_callback, | ||
394 | ab, | ||
395 | NULL ); | ||
396 | if (ACPI_FAILURE(status)) { | ||
397 | dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status); | ||
398 | return -1; | ||
399 | } | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static void build_a_bridge( | ||
405 | struct acpi_bridge *pab, | ||
406 | struct acpi_bridge *ab | ||
407 | ) | ||
408 | { | ||
409 | u8 *path_name = acpi_path_name(ab->handle); | ||
410 | |||
411 | shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); | ||
412 | |||
413 | switch (ab->type) { | ||
414 | case BRIDGE_TYPE_HOST: | ||
415 | dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", | ||
416 | ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); | ||
417 | break; | ||
418 | case BRIDGE_TYPE_P2P: | ||
419 | dbg("acpi_shpchprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", | ||
420 | ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); | ||
421 | break; | ||
422 | }; | ||
423 | |||
424 | /* build any immediate PHP slots under this pci bridge */ | ||
425 | shpchprm_acpi_build_php_slots(ab, 1); | ||
426 | } | ||
427 | |||
428 | static struct acpi_bridge * add_p2p_bridge( | ||
429 | acpi_handle handle, | ||
430 | struct acpi_bridge *pab, /* parent */ | ||
431 | ulong adr | ||
432 | ) | ||
433 | { | ||
434 | struct acpi_bridge *ab; | ||
435 | struct pci_dev *pdev; | ||
436 | ulong devnum, funcnum; | ||
437 | u8 *path_name = acpi_path_name(handle); | ||
438 | |||
439 | ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); | ||
440 | if (!ab) { | ||
441 | err("acpi_shpchprm: alloc for ab fail\n"); | ||
442 | return NULL; | ||
443 | } | ||
444 | memset(ab, 0, sizeof(struct acpi_bridge)); | ||
445 | |||
446 | devnum = (adr >> 16) & 0xffff; | ||
447 | funcnum = adr & 0xffff; | ||
448 | |||
449 | pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); | ||
450 | if (!pdev || !pdev->subordinate) { | ||
451 | err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name); | ||
452 | kfree(ab); | ||
453 | return NULL; | ||
454 | } | ||
455 | |||
456 | ab->handle = handle; | ||
457 | ab->seg = pab->seg; | ||
458 | ab->pbus = pab->bus; /* or pdev->bus->number */ | ||
459 | ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ | ||
460 | ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ | ||
461 | ab->bus = pdev->subordinate->number; | ||
462 | ab->scanned = 0; | ||
463 | ab->type = BRIDGE_TYPE_P2P; | ||
464 | |||
465 | dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", | ||
466 | pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | ||
467 | pab->bus, (u32)devnum, (u32)funcnum, path_name); | ||
468 | |||
469 | build_a_bridge(pab, ab); | ||
470 | |||
471 | return ab; | ||
472 | } | ||
473 | |||
474 | static acpi_status scan_p2p_bridge( | ||
475 | acpi_handle handle, | ||
476 | u32 Level, | ||
477 | void *context, | ||
478 | void **retval | ||
479 | ) | ||
480 | { | ||
481 | struct acpi_bridge *pab = (struct acpi_bridge *)context; | ||
482 | struct acpi_bridge *ab; | ||
483 | acpi_status status; | ||
484 | ulong adr = 0; | ||
485 | u8 *path_name = acpi_path_name(handle); | ||
486 | ulong devnum, funcnum; | ||
487 | struct pci_dev *pdev; | ||
488 | |||
489 | /* get device, function */ | ||
490 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
491 | if (ACPI_FAILURE(status)) { | ||
492 | if (status != AE_NOT_FOUND) | ||
493 | err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); | ||
494 | return AE_OK; | ||
495 | } | 144 | } |
496 | |||
497 | devnum = (adr >> 16) & 0xffff; | ||
498 | funcnum = adr & 0xffff; | ||
499 | |||
500 | pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); | ||
501 | if (!pdev) | ||
502 | return AE_OK; | ||
503 | if (!pdev->subordinate) | ||
504 | return AE_OK; | ||
505 | |||
506 | ab = add_p2p_bridge(handle, pab, adr); | ||
507 | if (ab) { | ||
508 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
509 | handle, | ||
510 | (u32)1, | ||
511 | scan_p2p_bridge, | ||
512 | ab, | ||
513 | NULL); | ||
514 | if (ACPI_FAILURE(status)) | ||
515 | dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); | ||
516 | } | ||
517 | |||
518 | return AE_OK; | ||
519 | } | ||
520 | |||
521 | static struct acpi_bridge * add_host_bridge( | ||
522 | acpi_handle handle, | ||
523 | ulong segnum, | ||
524 | ulong busnum | ||
525 | ) | ||
526 | { | ||
527 | ulong adr = 0; | ||
528 | acpi_status status; | ||
529 | struct acpi_bridge *ab; | ||
530 | u8 *path_name = acpi_path_name(handle); | ||
531 | |||
532 | /* get device, function: host br adr is always 0000 though. */ | ||
533 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
534 | if (ACPI_FAILURE(status)) { | ||
535 | err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); | ||
536 | return NULL; | ||
537 | } | ||
538 | dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, | ||
539 | (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); | ||
540 | |||
541 | ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); | ||
542 | if (!ab) { | ||
543 | err("acpi_shpchprm: alloc for ab fail\n"); | ||
544 | return NULL; | ||
545 | } | ||
546 | memset(ab, 0, sizeof(struct acpi_bridge)); | ||
547 | |||
548 | ab->handle = handle; | ||
549 | ab->seg = (int)segnum; | ||
550 | ab->bus = ab->pbus = (int)busnum; | ||
551 | ab->pdevice = (int)(adr >> 16) & 0xffff; | ||
552 | ab->pfunction = (int)(adr & 0xffff); | ||
553 | ab->scanned = 0; | ||
554 | ab->type = BRIDGE_TYPE_HOST; | ||
555 | |||
556 | build_a_bridge(ab, ab); | ||
557 | |||
558 | return ab; | ||
559 | } | ||
560 | |||
561 | static acpi_status acpi_scan_from_root_pci_callback ( | ||
562 | acpi_handle handle, | ||
563 | u32 Level, | ||
564 | void *context, | ||
565 | void **retval | ||
566 | ) | ||
567 | { | ||
568 | ulong segnum = 0; | ||
569 | ulong busnum = 0; | ||
570 | acpi_status status; | ||
571 | struct acpi_bridge *ab; | ||
572 | u8 *path_name = acpi_path_name(handle); | ||
573 | |||
574 | /* get bus number of this pci root bridge */ | ||
575 | status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); | ||
576 | if (ACPI_FAILURE(status)) { | ||
577 | if (status != AE_NOT_FOUND) { | ||
578 | err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status); | ||
579 | return status; | ||
580 | } | ||
581 | segnum = 0; | ||
582 | } | ||
583 | |||
584 | /* get bus number of this pci root bridge */ | ||
585 | status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); | ||
586 | if (ACPI_FAILURE(status)) { | ||
587 | err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status); | ||
588 | return (status); | ||
589 | } | ||
590 | |||
591 | ab = add_host_bridge(handle, segnum, busnum); | ||
592 | if (ab) { | ||
593 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
594 | handle, | ||
595 | 1, | ||
596 | scan_p2p_bridge, | ||
597 | ab, | ||
598 | NULL); | ||
599 | if (ACPI_FAILURE(status)) | ||
600 | dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); | ||
601 | } | ||
602 | |||
603 | return AE_OK; | ||
604 | } | ||
605 | |||
606 | static int shpchprm_acpi_scan_pci (void) | ||
607 | { | ||
608 | acpi_status status; | ||
609 | |||
610 | /* | ||
611 | * TBD: traverse LDM device tree with the help of | ||
612 | * unified ACPI augmented for php device population. | ||
613 | */ | ||
614 | status = acpi_get_devices ( PCI_ROOT_HID_STRING, | ||
615 | acpi_scan_from_root_pci_callback, | ||
616 | NULL, | ||
617 | NULL ); | ||
618 | if (ACPI_FAILURE(status)) { | ||
619 | err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status); | ||
620 | return -1; | ||
621 | } | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | int shpchprm_init(enum php_ctlr_type ctlr_type) | ||
627 | { | ||
628 | int rc; | ||
629 | |||
630 | if (ctlr_type != PCI) | ||
631 | return -ENODEV; | ||
632 | |||
633 | dbg("shpchprm ACPI init <enter>\n"); | ||
634 | acpi_bridges_head = NULL; | ||
635 | |||
636 | /* construct PCI bus:device tree of acpi_handles */ | ||
637 | rc = shpchprm_acpi_scan_pci(); | ||
638 | if (rc) | ||
639 | return rc; | ||
640 | |||
641 | dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success"); | ||
642 | return rc; | ||
643 | } | ||
644 | |||
645 | static void free_a_slot(struct acpi_php_slot *aps) | ||
646 | { | ||
647 | dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); | ||
648 | |||
649 | kfree(aps); | ||
650 | } | ||
651 | |||
652 | static void free_a_bridge( struct acpi_bridge *ab) | ||
653 | { | ||
654 | struct acpi_php_slot *aps, *next; | ||
655 | |||
656 | switch (ab->type) { | ||
657 | case BRIDGE_TYPE_HOST: | ||
658 | dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", | ||
659 | ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); | ||
660 | break; | ||
661 | case BRIDGE_TYPE_P2P: | ||
662 | dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", | ||
663 | ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); | ||
664 | break; | ||
665 | }; | ||
666 | |||
667 | /* free slots first */ | ||
668 | for (aps = ab->slots; aps; aps = next) { | ||
669 | next = aps->next; | ||
670 | free_a_slot(aps); | ||
671 | } | ||
672 | |||
673 | kfree(ab); | ||
674 | } | ||
675 | |||
676 | static void shpchprm_free_bridges ( struct acpi_bridge *ab) | ||
677 | { | ||
678 | if (!ab) | ||
679 | return; | ||
680 | |||
681 | if (ab->child) | ||
682 | shpchprm_free_bridges (ab->child); | ||
683 | |||
684 | if (ab->next) | ||
685 | shpchprm_free_bridges (ab->next); | ||
686 | |||
687 | free_a_bridge(ab); | ||
688 | } | ||
689 | |||
690 | void shpchprm_cleanup(void) | ||
691 | { | ||
692 | shpchprm_free_bridges (acpi_bridges_head); | ||
693 | } | ||
694 | |||
695 | static int get_number_of_slots ( | ||
696 | struct acpi_bridge *ab, | ||
697 | int selfonly | ||
698 | ) | ||
699 | { | ||
700 | struct acpi_php_slot *aps; | ||
701 | int prev_slot = -1; | ||
702 | int slot_num = 0; | ||
703 | |||
704 | for ( aps = ab->slots; aps; aps = aps->next) | ||
705 | if (aps->dev != prev_slot) { | ||
706 | prev_slot = aps->dev; | ||
707 | slot_num++; | ||
708 | } | ||
709 | |||
710 | if (ab->child) | ||
711 | slot_num += get_number_of_slots (ab->child, 0); | ||
712 | |||
713 | if (selfonly) | ||
714 | return slot_num; | ||
715 | |||
716 | if (ab->next) | ||
717 | slot_num += get_number_of_slots (ab->next, 0); | ||
718 | |||
719 | return slot_num; | ||
720 | } | ||
721 | |||
722 | static struct acpi_php_slot * get_acpi_slot ( | ||
723 | struct acpi_bridge *ab, | ||
724 | u32 sun | ||
725 | ) | ||
726 | { | ||
727 | struct acpi_php_slot *aps = NULL; | ||
728 | |||
729 | for ( aps = ab->slots; aps; aps = aps->next) | ||
730 | if (aps->sun == sun) | ||
731 | return aps; | ||
732 | |||
733 | if (!aps && ab->child) { | ||
734 | aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun); | ||
735 | if (aps) | ||
736 | return aps; | ||
737 | } | ||
738 | |||
739 | if (!aps && ab->next) { | ||
740 | aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun); | ||
741 | if (aps) | ||
742 | return aps; | ||
743 | } | ||
744 | |||
745 | return aps; | ||
746 | |||
747 | } | 145 | } |
748 | 146 | ||
749 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) | 147 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) |
@@ -755,108 +153,40 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn | |||
755 | return 0; | 153 | return 0; |
756 | } | 154 | } |
757 | 155 | ||
758 | int shpchprm_set_hpp( | 156 | void get_hp_hw_control_from_firmware(struct pci_dev *dev) |
759 | struct controller *ctrl, | ||
760 | struct pci_func *func, | ||
761 | u8 card_type | ||
762 | ) | ||
763 | { | 157 | { |
764 | struct acpi_bridge *ab; | 158 | /* |
765 | struct pci_bus lpci_bus, *pci_bus; | 159 | * OSHP is an optional ACPI firmware control method. If present, |
766 | int rc = 0; | 160 | * we need to run it to inform BIOS that we will control SHPC |
767 | unsigned int devfn; | 161 | * hardware from now on. |
768 | u8 cls= 0x08; /* default cache line size */ | 162 | */ |
769 | u8 lt = 0x40; /* default latency timer */ | 163 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev)); |
770 | u8 ep = 0; | 164 | if (!handle) |
771 | u8 es = 0; | 165 | return; |
772 | 166 | acpi_run_oshp(handle); | |
773 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
774 | pci_bus = &lpci_bus; | ||
775 | pci_bus->number = func->bus; | ||
776 | devfn = PCI_DEVFN(func->device, func->function); | ||
777 | |||
778 | ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); | ||
779 | |||
780 | if (ab) { | ||
781 | if (ab->_hpp) { | ||
782 | lt = (u8)ab->_hpp->latency_timer; | ||
783 | cls = (u8)ab->_hpp->cache_line_size; | ||
784 | ep = (u8)ab->_hpp->enable_perr; | ||
785 | es = (u8)ab->_hpp->enable_serr; | ||
786 | } else | ||
787 | dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); | ||
788 | } else | ||
789 | dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); | ||
790 | |||
791 | |||
792 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
793 | /* set subordinate Latency Timer */ | ||
794 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt); | ||
795 | } | ||
796 | |||
797 | /* set base Latency Timer */ | ||
798 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt); | ||
799 | dbg(" set latency timer =0x%02x: %x\n", lt, rc); | ||
800 | |||
801 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls); | ||
802 | dbg(" set cache_line_size=0x%02x: %x\n", cls, rc); | ||
803 | |||
804 | return rc; | ||
805 | } | 167 | } |
806 | 168 | ||
807 | void shpchprm_enable_card( | 169 | void get_hp_params_from_firmware(struct pci_dev *dev, |
808 | struct controller *ctrl, | 170 | struct hotplug_params *hpp) |
809 | struct pci_func *func, | ||
810 | u8 card_type) | ||
811 | { | 171 | { |
812 | u16 command, cmd, bcommand, bcmd; | 172 | acpi_status status = AE_NOT_FOUND; |
813 | struct pci_bus lpci_bus, *pci_bus; | 173 | struct pci_dev *pdev = dev; |
814 | struct acpi_bridge *ab; | ||
815 | unsigned int devfn; | ||
816 | int rc; | ||
817 | |||
818 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
819 | pci_bus = &lpci_bus; | ||
820 | pci_bus->number = func->bus; | ||
821 | devfn = PCI_DEVFN(func->device, func->function); | ||
822 | |||
823 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); | ||
824 | |||
825 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
826 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); | ||
827 | } | ||
828 | |||
829 | cmd = command = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | ||
830 | | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | ||
831 | bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; | ||
832 | 174 | ||
833 | ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); | 175 | /* |
834 | if (ab) { | 176 | * _HPP settings apply to all child buses, until another _HPP is |
835 | if (ab->_hpp) { | 177 | * encountered. If we don't find an _HPP for the input pci dev, |
836 | if (ab->_hpp->enable_perr) { | 178 | * look for it in the parent device scope since that would apply to |
837 | command |= PCI_COMMAND_PARITY; | 179 | * this pci dev. If we don't find any _HPP, use hardcoded defaults |
838 | bcommand |= PCI_BRIDGE_CTL_PARITY; | 180 | */ |
839 | } else { | 181 | while (pdev && (ACPI_FAILURE(status))) { |
840 | command &= ~PCI_COMMAND_PARITY; | 182 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); |
841 | bcommand &= ~PCI_BRIDGE_CTL_PARITY; | 183 | if (!handle) |
842 | } | 184 | break; |
843 | if (ab->_hpp->enable_serr) { | 185 | status = acpi_run_hpp(handle, hpp); |
844 | command |= PCI_COMMAND_SERR; | 186 | if (!(pdev->bus->parent)) |
845 | bcommand |= PCI_BRIDGE_CTL_SERR; | 187 | break; |
846 | } else { | 188 | /* Check if a parent object supports _HPP */ |
847 | command &= ~PCI_COMMAND_SERR; | 189 | pdev = pdev->bus->parent->self; |
848 | bcommand &= ~PCI_BRIDGE_CTL_SERR; | ||
849 | } | ||
850 | } else | ||
851 | dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); | ||
852 | } else | ||
853 | dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); | ||
854 | |||
855 | if (command != cmd) { | ||
856 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); | ||
857 | } | ||
858 | if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) { | ||
859 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); | ||
860 | } | 190 | } |
861 | } | 191 | } |
862 | 192 | ||