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