diff options
author | Rajesh Shah <rajesh.shah@intel.com> | 2005-04-28 03:25:53 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-28 00:52:42 -0400 |
commit | 42f49a6ae5dca90cd0594475502bf1c43ff1dc07 (patch) | |
tree | f894d1335be0aaa10955f61aa92200540ef13624 /drivers/pci/hotplug/acpiphp_glue.c | |
parent | 4ce448e5fae62689b06027b46f470b944e5c2193 (diff) |
[PATCH] acpi hotplug: convert acpiphp to use generic resource code
This patch converts acpiphp to use the generic PCI resource assignment code.
It's quite large, but most of it is deleting the acpiphp_pci and acpiphp_res
files. It's tested on an hp Integrity rx8620 (which won't work without this
patch). Testers with other hardware welcomed.
Signed-off-by: Matthew Wilcox <matthew@wil.cx>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 455 |
1 files changed, 126 insertions, 329 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e7f41294f811..41c3eb28b69d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) | 4 | * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) |
5 | * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) | 5 | * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) |
6 | * Copyright (C) 2002,2003 NEC Corporation | 6 | * Copyright (C) 2002,2003 NEC Corporation |
7 | * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) | ||
8 | * Copyright (C) 2003-2005 Hewlett Packard | ||
7 | * | 9 | * |
8 | * All rights reserved. | 10 | * All rights reserved. |
9 | * | 11 | * |
@@ -26,6 +28,16 @@ | |||
26 | * | 28 | * |
27 | */ | 29 | */ |
28 | 30 | ||
31 | /* | ||
32 | * Lifetime rules for pci_dev: | ||
33 | * - The one in acpiphp_func has its refcount elevated by pci_get_slot() | ||
34 | * when the driver is loaded or when an insertion event occurs. It loses | ||
35 | * a refcount when its ejected or the driver unloads. | ||
36 | * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() | ||
37 | * when the bridge is scanned and it loses a refcount when the bridge | ||
38 | * is removed. | ||
39 | */ | ||
40 | |||
29 | #include <linux/init.h> | 41 | #include <linux/init.h> |
30 | #include <linux/module.h> | 42 | #include <linux/module.h> |
31 | 43 | ||
@@ -178,21 +190,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
178 | 190 | ||
179 | bridge->nr_slots++; | 191 | bridge->nr_slots++; |
180 | 192 | ||
181 | dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n", | 193 | dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", |
182 | slot->bridge->bus, slot->device, slot->sun); | 194 | slot->sun, pci_domain_nr(bridge->pci_bus), |
195 | bridge->pci_bus->number, slot->device); | ||
183 | } | 196 | } |
184 | 197 | ||
185 | newfunc->slot = slot; | 198 | newfunc->slot = slot; |
186 | list_add_tail(&newfunc->sibling, &slot->funcs); | 199 | list_add_tail(&newfunc->sibling, &slot->funcs); |
187 | 200 | ||
188 | /* associate corresponding pci_dev */ | 201 | /* associate corresponding pci_dev */ |
189 | newfunc->pci_dev = pci_find_slot(bridge->bus, | 202 | newfunc->pci_dev = pci_get_slot(bridge->pci_bus, |
190 | PCI_DEVFN(device, function)); | 203 | PCI_DEVFN(device, function)); |
191 | if (newfunc->pci_dev) { | 204 | if (newfunc->pci_dev) { |
192 | if (acpiphp_init_func_resource(newfunc) < 0) { | ||
193 | kfree(newfunc); | ||
194 | return AE_ERROR; | ||
195 | } | ||
196 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | 205 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); |
197 | } | 206 | } |
198 | 207 | ||
@@ -227,62 +236,6 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle) | |||
227 | } | 236 | } |
228 | 237 | ||
229 | 238 | ||
230 | /* decode ACPI _CRS data and convert into our internal resource list | ||
231 | * TBD: _TRA, etc. | ||
232 | */ | ||
233 | static acpi_status | ||
234 | decode_acpi_resource(struct acpi_resource *resource, void *context) | ||
235 | { | ||
236 | struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context; | ||
237 | struct acpi_resource_address64 address; | ||
238 | struct pci_resource *res; | ||
239 | |||
240 | if (resource->id != ACPI_RSTYPE_ADDRESS16 && | ||
241 | resource->id != ACPI_RSTYPE_ADDRESS32 && | ||
242 | resource->id != ACPI_RSTYPE_ADDRESS64) | ||
243 | return AE_OK; | ||
244 | |||
245 | acpi_resource_to_address64(resource, &address); | ||
246 | |||
247 | if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) { | ||
248 | dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type, | ||
249 | (unsigned long long)address.min_address_range, | ||
250 | (unsigned long long)address.max_address_range); | ||
251 | res = acpiphp_make_resource(address.min_address_range, | ||
252 | address.address_length); | ||
253 | if (!res) { | ||
254 | err("out of memory\n"); | ||
255 | return AE_OK; | ||
256 | } | ||
257 | |||
258 | switch (address.resource_type) { | ||
259 | case ACPI_MEMORY_RANGE: | ||
260 | if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) { | ||
261 | res->next = bridge->p_mem_head; | ||
262 | bridge->p_mem_head = res; | ||
263 | } else { | ||
264 | res->next = bridge->mem_head; | ||
265 | bridge->mem_head = res; | ||
266 | } | ||
267 | break; | ||
268 | case ACPI_IO_RANGE: | ||
269 | res->next = bridge->io_head; | ||
270 | bridge->io_head = res; | ||
271 | break; | ||
272 | case ACPI_BUS_NUMBER_RANGE: | ||
273 | res->next = bridge->bus_head; | ||
274 | bridge->bus_head = res; | ||
275 | break; | ||
276 | default: | ||
277 | /* invalid type */ | ||
278 | kfree(res); | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | return AE_OK; | ||
284 | } | ||
285 | |||
286 | /* decode ACPI 2.0 _HPP hot plug parameters */ | 239 | /* decode ACPI 2.0 _HPP hot plug parameters */ |
287 | static void decode_hpp(struct acpiphp_bridge *bridge) | 240 | static void decode_hpp(struct acpiphp_bridge *bridge) |
288 | { | 241 | { |
@@ -346,9 +299,6 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
346 | /* decode ACPI 2.0 _HPP (hot plug parameters) */ | 299 | /* decode ACPI 2.0 _HPP (hot plug parameters) */ |
347 | decode_hpp(bridge); | 300 | decode_hpp(bridge); |
348 | 301 | ||
349 | /* subtract all resources already allocated */ | ||
350 | acpiphp_detect_pci_resource(bridge); | ||
351 | |||
352 | /* register all slot objects under this bridge */ | 302 | /* register all slot objects under this bridge */ |
353 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, | 303 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, |
354 | register_slot, bridge, NULL); | 304 | register_slot, bridge, NULL); |
@@ -364,16 +314,12 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
364 | } | 314 | } |
365 | 315 | ||
366 | list_add(&bridge->list, &bridge_list); | 316 | list_add(&bridge->list, &bridge_list); |
367 | |||
368 | dbg("Bridge resource:\n"); | ||
369 | acpiphp_dump_resource(bridge); | ||
370 | } | 317 | } |
371 | 318 | ||
372 | 319 | ||
373 | /* allocate and initialize host bridge data structure */ | 320 | /* allocate and initialize host bridge data structure */ |
374 | static void add_host_bridge(acpi_handle *handle, int seg, int bus) | 321 | static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) |
375 | { | 322 | { |
376 | acpi_status status; | ||
377 | struct acpiphp_bridge *bridge; | 323 | struct acpiphp_bridge *bridge; |
378 | 324 | ||
379 | bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | 325 | bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |
@@ -384,52 +330,19 @@ static void add_host_bridge(acpi_handle *handle, int seg, int bus) | |||
384 | 330 | ||
385 | bridge->type = BRIDGE_TYPE_HOST; | 331 | bridge->type = BRIDGE_TYPE_HOST; |
386 | bridge->handle = handle; | 332 | bridge->handle = handle; |
387 | bridge->seg = seg; | ||
388 | bridge->bus = bus; | ||
389 | 333 | ||
390 | bridge->pci_bus = pci_find_bus(seg, bus); | 334 | bridge->pci_bus = pci_bus; |
391 | 335 | ||
392 | spin_lock_init(&bridge->res_lock); | 336 | spin_lock_init(&bridge->res_lock); |
393 | 337 | ||
394 | /* to be overridden when we decode _CRS */ | ||
395 | bridge->sub = bridge->bus; | ||
396 | |||
397 | /* decode resources */ | ||
398 | |||
399 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, | ||
400 | decode_acpi_resource, bridge); | ||
401 | |||
402 | if (ACPI_FAILURE(status)) { | ||
403 | err("failed to decode bridge resources\n"); | ||
404 | kfree(bridge); | ||
405 | return; | ||
406 | } | ||
407 | |||
408 | acpiphp_resource_sort_and_combine(&bridge->io_head); | ||
409 | acpiphp_resource_sort_and_combine(&bridge->mem_head); | ||
410 | acpiphp_resource_sort_and_combine(&bridge->p_mem_head); | ||
411 | acpiphp_resource_sort_and_combine(&bridge->bus_head); | ||
412 | |||
413 | dbg("ACPI _CRS resource:\n"); | ||
414 | acpiphp_dump_resource(bridge); | ||
415 | |||
416 | if (bridge->bus_head) { | ||
417 | bridge->bus = bridge->bus_head->base; | ||
418 | bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1; | ||
419 | } | ||
420 | |||
421 | init_bridge_misc(bridge); | 338 | init_bridge_misc(bridge); |
422 | } | 339 | } |
423 | 340 | ||
424 | 341 | ||
425 | /* allocate and initialize PCI-to-PCI bridge data structure */ | 342 | /* allocate and initialize PCI-to-PCI bridge data structure */ |
426 | static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int fn) | 343 | static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) |
427 | { | 344 | { |
428 | struct acpiphp_bridge *bridge; | 345 | struct acpiphp_bridge *bridge; |
429 | u8 tmp8; | ||
430 | u16 tmp16; | ||
431 | u64 base64, limit64; | ||
432 | u32 base, limit, base32u, limit32u; | ||
433 | 346 | ||
434 | bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | 347 | bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |
435 | if (bridge == NULL) { | 348 | if (bridge == NULL) { |
@@ -441,133 +354,22 @@ static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int f | |||
441 | 354 | ||
442 | bridge->type = BRIDGE_TYPE_P2P; | 355 | bridge->type = BRIDGE_TYPE_P2P; |
443 | bridge->handle = handle; | 356 | bridge->handle = handle; |
444 | bridge->seg = seg; | ||
445 | 357 | ||
446 | bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn)); | 358 | bridge->pci_dev = pci_dev_get(pci_dev); |
447 | if (!bridge->pci_dev) { | 359 | bridge->pci_bus = pci_dev->subordinate; |
448 | err("Can't get pci_dev\n"); | ||
449 | kfree(bridge); | ||
450 | return; | ||
451 | } | ||
452 | |||
453 | bridge->pci_bus = bridge->pci_dev->subordinate; | ||
454 | if (!bridge->pci_bus) { | 360 | if (!bridge->pci_bus) { |
455 | err("This is not a PCI-to-PCI bridge!\n"); | 361 | err("This is not a PCI-to-PCI bridge!\n"); |
456 | kfree(bridge); | 362 | goto err; |
457 | return; | ||
458 | } | 363 | } |
459 | 364 | ||
460 | spin_lock_init(&bridge->res_lock); | 365 | spin_lock_init(&bridge->res_lock); |
461 | 366 | ||
462 | bridge->bus = bridge->pci_bus->number; | ||
463 | bridge->sub = bridge->pci_bus->subordinate; | ||
464 | |||
465 | /* | ||
466 | * decode resources under this P2P bridge | ||
467 | */ | ||
468 | |||
469 | /* I/O resources */ | ||
470 | pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8); | ||
471 | base = tmp8; | ||
472 | pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8); | ||
473 | limit = tmp8; | ||
474 | |||
475 | switch (base & PCI_IO_RANGE_TYPE_MASK) { | ||
476 | case PCI_IO_RANGE_TYPE_16: | ||
477 | base = (base << 8) & 0xf000; | ||
478 | limit = ((limit << 8) & 0xf000) + 0xfff; | ||
479 | bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); | ||
480 | if (!bridge->io_head) { | ||
481 | err("out of memory\n"); | ||
482 | kfree(bridge); | ||
483 | return; | ||
484 | } | ||
485 | dbg("16bit I/O range: %04x-%04x\n", | ||
486 | (u32)bridge->io_head->base, | ||
487 | (u32)(bridge->io_head->base + bridge->io_head->length - 1)); | ||
488 | break; | ||
489 | case PCI_IO_RANGE_TYPE_32: | ||
490 | pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16); | ||
491 | base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000); | ||
492 | pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16); | ||
493 | limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff; | ||
494 | bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); | ||
495 | if (!bridge->io_head) { | ||
496 | err("out of memory\n"); | ||
497 | kfree(bridge); | ||
498 | return; | ||
499 | } | ||
500 | dbg("32bit I/O range: %08x-%08x\n", | ||
501 | (u32)bridge->io_head->base, | ||
502 | (u32)(bridge->io_head->base + bridge->io_head->length - 1)); | ||
503 | break; | ||
504 | case 0x0f: | ||
505 | dbg("I/O space unsupported\n"); | ||
506 | break; | ||
507 | default: | ||
508 | warn("Unknown I/O range type\n"); | ||
509 | } | ||
510 | |||
511 | /* Memory resources (mandatory for P2P bridge) */ | ||
512 | pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16); | ||
513 | base = (tmp16 & 0xfff0) << 16; | ||
514 | pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16); | ||
515 | limit = ((tmp16 & 0xfff0) << 16) | 0xfffff; | ||
516 | bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1); | ||
517 | if (!bridge->mem_head) { | ||
518 | err("out of memory\n"); | ||
519 | kfree(bridge); | ||
520 | return; | ||
521 | } | ||
522 | dbg("32bit Memory range: %08x-%08x\n", | ||
523 | (u32)bridge->mem_head->base, | ||
524 | (u32)(bridge->mem_head->base + bridge->mem_head->length-1)); | ||
525 | |||
526 | /* Prefetchable Memory resources (optional) */ | ||
527 | pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16); | ||
528 | base = tmp16; | ||
529 | pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16); | ||
530 | limit = tmp16; | ||
531 | |||
532 | switch (base & PCI_MEMORY_RANGE_TYPE_MASK) { | ||
533 | case PCI_PREF_RANGE_TYPE_32: | ||
534 | base = (base & 0xfff0) << 16; | ||
535 | limit = ((limit & 0xfff0) << 16) | 0xfffff; | ||
536 | bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1); | ||
537 | if (!bridge->p_mem_head) { | ||
538 | err("out of memory\n"); | ||
539 | kfree(bridge); | ||
540 | return; | ||
541 | } | ||
542 | dbg("32bit Prefetchable memory range: %08x-%08x\n", | ||
543 | (u32)bridge->p_mem_head->base, | ||
544 | (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1)); | ||
545 | break; | ||
546 | case PCI_PREF_RANGE_TYPE_64: | ||
547 | pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u); | ||
548 | pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u); | ||
549 | base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16); | ||
550 | limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff; | ||
551 | |||
552 | bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1); | ||
553 | if (!bridge->p_mem_head) { | ||
554 | err("out of memory\n"); | ||
555 | kfree(bridge); | ||
556 | return; | ||
557 | } | ||
558 | dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n", | ||
559 | (u32)(bridge->p_mem_head->base >> 32), | ||
560 | (u32)(bridge->p_mem_head->base & 0xffffffff), | ||
561 | (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32), | ||
562 | (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff)); | ||
563 | break; | ||
564 | case 0x0f: | ||
565 | break; | ||
566 | default: | ||
567 | warn("Unknown prefetchale memory type\n"); | ||
568 | } | ||
569 | |||
570 | init_bridge_misc(bridge); | 367 | init_bridge_misc(bridge); |
368 | return; | ||
369 | err: | ||
370 | pci_dev_put(pci_dev); | ||
371 | kfree(bridge); | ||
372 | return; | ||
571 | } | 373 | } |
572 | 374 | ||
573 | 375 | ||
@@ -577,14 +379,10 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
577 | { | 379 | { |
578 | acpi_status status; | 380 | acpi_status status; |
579 | acpi_handle dummy_handle; | 381 | acpi_handle dummy_handle; |
580 | unsigned long *segbus = context; | ||
581 | unsigned long tmp; | 382 | unsigned long tmp; |
582 | int seg, bus, device, function; | 383 | int device, function; |
583 | struct pci_dev *dev; | 384 | struct pci_dev *dev; |
584 | 385 | struct pci_bus *pci_bus = context; | |
585 | /* get PCI address */ | ||
586 | seg = (*segbus >> 8) & 0xff; | ||
587 | bus = *segbus & 0xff; | ||
588 | 386 | ||
589 | status = acpi_get_handle(handle, "_ADR", &dummy_handle); | 387 | status = acpi_get_handle(handle, "_ADR", &dummy_handle); |
590 | if (ACPI_FAILURE(status)) | 388 | if (ACPI_FAILURE(status)) |
@@ -599,20 +397,19 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
599 | device = (tmp >> 16) & 0xffff; | 397 | device = (tmp >> 16) & 0xffff; |
600 | function = tmp & 0xffff; | 398 | function = tmp & 0xffff; |
601 | 399 | ||
602 | dev = pci_find_slot(bus, PCI_DEVFN(device, function)); | 400 | dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function)); |
603 | |||
604 | if (!dev) | ||
605 | return AE_OK; | ||
606 | 401 | ||
607 | if (!dev->subordinate) | 402 | if (!dev || !dev->subordinate) |
608 | return AE_OK; | 403 | goto out; |
609 | 404 | ||
610 | /* check if this bridge has ejectable slots */ | 405 | /* check if this bridge has ejectable slots */ |
611 | if (detect_ejectable_slots(handle) > 0) { | 406 | if (detect_ejectable_slots(handle) > 0) { |
612 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); | 407 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); |
613 | add_p2p_bridge(handle, seg, bus, device, function); | 408 | add_p2p_bridge(handle, dev); |
614 | } | 409 | } |
615 | 410 | ||
411 | out: | ||
412 | pci_dev_put(dev); | ||
616 | return AE_OK; | 413 | return AE_OK; |
617 | } | 414 | } |
618 | 415 | ||
@@ -624,6 +421,7 @@ static int add_bridge(acpi_handle handle) | |||
624 | unsigned long tmp; | 421 | unsigned long tmp; |
625 | int seg, bus; | 422 | int seg, bus; |
626 | acpi_handle dummy_handle; | 423 | acpi_handle dummy_handle; |
424 | struct pci_bus *pci_bus; | ||
627 | 425 | ||
628 | /* if the bridge doesn't have _STA, we assume it is always there */ | 426 | /* if the bridge doesn't have _STA, we assume it is always there */ |
629 | status = acpi_get_handle(handle, "_STA", &dummy_handle); | 427 | status = acpi_get_handle(handle, "_STA", &dummy_handle); |
@@ -653,18 +451,22 @@ static int add_bridge(acpi_handle handle) | |||
653 | bus = 0; | 451 | bus = 0; |
654 | } | 452 | } |
655 | 453 | ||
454 | pci_bus = pci_find_bus(seg, bus); | ||
455 | if (!pci_bus) { | ||
456 | err("Can't find bus %04x:%02x\n", seg, bus); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
656 | /* check if this bridge has ejectable slots */ | 460 | /* check if this bridge has ejectable slots */ |
657 | if (detect_ejectable_slots(handle) > 0) { | 461 | if (detect_ejectable_slots(handle) > 0) { |
658 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); | 462 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); |
659 | add_host_bridge(handle, seg, bus); | 463 | add_host_bridge(handle, pci_bus); |
660 | return 0; | 464 | return 0; |
661 | } | 465 | } |
662 | 466 | ||
663 | tmp = seg << 8 | bus; | ||
664 | |||
665 | /* search P2P bridges under this host bridge */ | 467 | /* search P2P bridges under this host bridge */ |
666 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | 468 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |
667 | find_p2p_bridge, &tmp, NULL); | 469 | find_p2p_bridge, pci_bus, NULL); |
668 | 470 | ||
669 | if (ACPI_FAILURE(status)) | 471 | if (ACPI_FAILURE(status)) |
670 | warn("find_p2p_bridge faied (error code = 0x%x)\n",status); | 472 | warn("find_p2p_bridge faied (error code = 0x%x)\n",status); |
@@ -672,10 +474,59 @@ static int add_bridge(acpi_handle handle) | |||
672 | return 0; | 474 | return 0; |
673 | } | 475 | } |
674 | 476 | ||
477 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | ||
478 | { | ||
479 | struct list_head *head; | ||
480 | list_for_each(head, &bridge_list) { | ||
481 | struct acpiphp_bridge *bridge = list_entry(head, | ||
482 | struct acpiphp_bridge, list); | ||
483 | if (bridge->handle == handle) | ||
484 | return bridge; | ||
485 | } | ||
486 | |||
487 | return NULL; | ||
488 | } | ||
675 | 489 | ||
676 | static void remove_bridge(acpi_handle handle) | 490 | static void remove_bridge(acpi_handle handle) |
677 | { | 491 | { |
678 | /* No-op for now .. */ | 492 | struct list_head *list, *tmp; |
493 | struct acpiphp_bridge *bridge; | ||
494 | struct acpiphp_slot *slot; | ||
495 | acpi_status status; | ||
496 | |||
497 | bridge = acpiphp_handle_to_bridge(handle); | ||
498 | if (!bridge) { | ||
499 | err("Could not find bridge for handle %p\n", handle); | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
504 | handle_hotplug_event_bridge); | ||
505 | if (ACPI_FAILURE(status)) | ||
506 | err("failed to remove notify handler\n"); | ||
507 | |||
508 | slot = bridge->slots; | ||
509 | while (slot) { | ||
510 | struct acpiphp_slot *next = slot->next; | ||
511 | list_for_each_safe (list, tmp, &slot->funcs) { | ||
512 | struct acpiphp_func *func; | ||
513 | func = list_entry(list, struct acpiphp_func, sibling); | ||
514 | status = acpi_remove_notify_handler(func->handle, | ||
515 | ACPI_SYSTEM_NOTIFY, | ||
516 | handle_hotplug_event_func); | ||
517 | if (ACPI_FAILURE(status)) | ||
518 | err("failed to remove notify handler\n"); | ||
519 | pci_dev_put(func->pci_dev); | ||
520 | list_del(list); | ||
521 | kfree(func); | ||
522 | } | ||
523 | kfree(slot); | ||
524 | slot = next; | ||
525 | } | ||
526 | |||
527 | pci_dev_put(bridge->pci_dev); | ||
528 | list_del(&bridge->list); | ||
529 | kfree(bridge); | ||
679 | } | 530 | } |
680 | 531 | ||
681 | 532 | ||
@@ -782,70 +633,56 @@ static int power_off_slot(struct acpiphp_slot *slot) | |||
782 | */ | 633 | */ |
783 | static int enable_device(struct acpiphp_slot *slot) | 634 | static int enable_device(struct acpiphp_slot *slot) |
784 | { | 635 | { |
785 | u8 bus; | ||
786 | struct pci_dev *dev; | 636 | struct pci_dev *dev; |
787 | struct pci_bus *child; | 637 | struct pci_bus *bus = slot->bridge->pci_bus; |
788 | struct list_head *l; | 638 | struct list_head *l; |
789 | struct acpiphp_func *func; | 639 | struct acpiphp_func *func; |
790 | int retval = 0; | 640 | int retval = 0; |
791 | int num; | 641 | int num, max, pass; |
792 | 642 | ||
793 | if (slot->flags & SLOT_ENABLED) | 643 | if (slot->flags & SLOT_ENABLED) |
794 | goto err_exit; | 644 | goto err_exit; |
795 | 645 | ||
796 | /* sanity check: dev should be NULL when hot-plugged in */ | 646 | /* sanity check: dev should be NULL when hot-plugged in */ |
797 | dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); | 647 | dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); |
798 | if (dev) { | 648 | if (dev) { |
799 | /* This case shouldn't happen */ | 649 | /* This case shouldn't happen */ |
800 | err("pci_dev structure already exists.\n"); | 650 | err("pci_dev structure already exists.\n"); |
651 | pci_dev_put(dev); | ||
801 | retval = -1; | 652 | retval = -1; |
802 | goto err_exit; | 653 | goto err_exit; |
803 | } | 654 | } |
804 | 655 | ||
805 | /* allocate resources to device */ | 656 | num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); |
806 | retval = acpiphp_configure_slot(slot); | 657 | if (num == 0) { |
807 | if (retval) | ||
808 | goto err_exit; | ||
809 | |||
810 | /* returned `dev' is the *first function* only! */ | ||
811 | num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); | ||
812 | if (num) | ||
813 | pci_bus_add_devices(slot->bridge->pci_bus); | ||
814 | dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); | ||
815 | |||
816 | if (!dev) { | ||
817 | err("No new device found\n"); | 658 | err("No new device found\n"); |
818 | retval = -1; | 659 | retval = -1; |
819 | goto err_exit; | 660 | goto err_exit; |
820 | } | 661 | } |
821 | 662 | ||
822 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | 663 | max = bus->secondary; |
823 | pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus); | 664 | for (pass = 0; pass < 2; pass++) { |
824 | child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus); | 665 | list_for_each_entry(dev, &bus->devices, bus_list) { |
825 | pci_do_scan_bus(child); | 666 | if (PCI_SLOT(dev->devfn) != slot->device) |
667 | continue; | ||
668 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | ||
669 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | ||
670 | max = pci_scan_bridge(bus, dev, max, pass); | ||
671 | } | ||
826 | } | 672 | } |
827 | 673 | ||
674 | pci_bus_assign_resources(bus); | ||
675 | pci_bus_add_devices(bus); | ||
676 | |||
828 | /* associate pci_dev to our representation */ | 677 | /* associate pci_dev to our representation */ |
829 | list_for_each (l, &slot->funcs) { | 678 | list_for_each (l, &slot->funcs) { |
830 | func = list_entry(l, struct acpiphp_func, sibling); | 679 | func = list_entry(l, struct acpiphp_func, sibling); |
831 | 680 | func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, | |
832 | func->pci_dev = pci_find_slot(slot->bridge->bus, | ||
833 | PCI_DEVFN(slot->device, | ||
834 | func->function)); | 681 | func->function)); |
835 | if (!func->pci_dev) | ||
836 | continue; | ||
837 | |||
838 | /* configure device */ | ||
839 | retval = acpiphp_configure_function(func); | ||
840 | if (retval) | ||
841 | goto err_exit; | ||
842 | } | 682 | } |
843 | 683 | ||
844 | slot->flags |= SLOT_ENABLED; | 684 | slot->flags |= SLOT_ENABLED; |
845 | 685 | ||
846 | dbg("Available resources:\n"); | ||
847 | acpiphp_dump_resource(slot->bridge); | ||
848 | |||
849 | err_exit: | 686 | err_exit: |
850 | return retval; | 687 | return retval; |
851 | } | 688 | } |
@@ -866,9 +703,12 @@ static int disable_device(struct acpiphp_slot *slot) | |||
866 | 703 | ||
867 | list_for_each (l, &slot->funcs) { | 704 | list_for_each (l, &slot->funcs) { |
868 | func = list_entry(l, struct acpiphp_func, sibling); | 705 | func = list_entry(l, struct acpiphp_func, sibling); |
706 | if (!func->pci_dev) | ||
707 | continue; | ||
869 | 708 | ||
870 | if (func->pci_dev) | 709 | pci_remove_bus_device(func->pci_dev); |
871 | acpiphp_unconfigure_function(func); | 710 | pci_dev_put(func->pci_dev); |
711 | func->pci_dev = NULL; | ||
872 | } | 712 | } |
873 | 713 | ||
874 | slot->flags &= (~SLOT_ENABLED); | 714 | slot->flags &= (~SLOT_ENABLED); |
@@ -1116,46 +956,6 @@ int __init acpiphp_glue_init(void) | |||
1116 | */ | 956 | */ |
1117 | void __exit acpiphp_glue_exit(void) | 957 | void __exit acpiphp_glue_exit(void) |
1118 | { | 958 | { |
1119 | struct list_head *l1, *l2, *n1, *n2; | ||
1120 | struct acpiphp_bridge *bridge; | ||
1121 | struct acpiphp_slot *slot, *next; | ||
1122 | struct acpiphp_func *func; | ||
1123 | acpi_status status; | ||
1124 | |||
1125 | list_for_each_safe (l1, n1, &bridge_list) { | ||
1126 | bridge = (struct acpiphp_bridge *)l1; | ||
1127 | slot = bridge->slots; | ||
1128 | while (slot) { | ||
1129 | next = slot->next; | ||
1130 | list_for_each_safe (l2, n2, &slot->funcs) { | ||
1131 | func = list_entry(l2, struct acpiphp_func, sibling); | ||
1132 | acpiphp_free_resource(&func->io_head); | ||
1133 | acpiphp_free_resource(&func->mem_head); | ||
1134 | acpiphp_free_resource(&func->p_mem_head); | ||
1135 | acpiphp_free_resource(&func->bus_head); | ||
1136 | status = acpi_remove_notify_handler(func->handle, | ||
1137 | ACPI_SYSTEM_NOTIFY, | ||
1138 | handle_hotplug_event_func); | ||
1139 | if (ACPI_FAILURE(status)) | ||
1140 | err("failed to remove notify handler\n"); | ||
1141 | kfree(func); | ||
1142 | } | ||
1143 | kfree(slot); | ||
1144 | slot = next; | ||
1145 | } | ||
1146 | status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, | ||
1147 | handle_hotplug_event_bridge); | ||
1148 | if (ACPI_FAILURE(status)) | ||
1149 | err("failed to remove notify handler\n"); | ||
1150 | |||
1151 | acpiphp_free_resource(&bridge->io_head); | ||
1152 | acpiphp_free_resource(&bridge->mem_head); | ||
1153 | acpiphp_free_resource(&bridge->p_mem_head); | ||
1154 | acpiphp_free_resource(&bridge->bus_head); | ||
1155 | |||
1156 | kfree(bridge); | ||
1157 | } | ||
1158 | |||
1159 | acpi_pci_unregister_driver(&acpi_pci_hp_driver); | 959 | acpi_pci_unregister_driver(&acpi_pci_hp_driver); |
1160 | } | 960 | } |
1161 | 961 | ||
@@ -1173,11 +973,14 @@ int __init acpiphp_get_num_slots(void) | |||
1173 | 973 | ||
1174 | list_for_each (node, &bridge_list) { | 974 | list_for_each (node, &bridge_list) { |
1175 | bridge = (struct acpiphp_bridge *)node; | 975 | bridge = (struct acpiphp_bridge *)node; |
1176 | dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); | 976 | dbg("Bus %04x:%02x has %d slot%s\n", |
977 | pci_domain_nr(bridge->pci_bus), | ||
978 | bridge->pci_bus->number, bridge->nr_slots, | ||
979 | bridge->nr_slots == 1 ? "" : "s"); | ||
1177 | num_slots += bridge->nr_slots; | 980 | num_slots += bridge->nr_slots; |
1178 | } | 981 | } |
1179 | 982 | ||
1180 | dbg("Total %dslots\n", num_slots); | 983 | dbg("Total %d slots\n", num_slots); |
1181 | return num_slots; | 984 | return num_slots; |
1182 | } | 985 | } |
1183 | 986 | ||
@@ -1274,13 +1077,6 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) | |||
1274 | if (retval) | 1077 | if (retval) |
1275 | goto err_exit; | 1078 | goto err_exit; |
1276 | 1079 | ||
1277 | acpiphp_resource_sort_and_combine(&slot->bridge->io_head); | ||
1278 | acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); | ||
1279 | acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); | ||
1280 | acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); | ||
1281 | dbg("Available resources:\n"); | ||
1282 | acpiphp_dump_resource(slot->bridge); | ||
1283 | |||
1284 | err_exit: | 1080 | err_exit: |
1285 | up(&slot->crit_sect); | 1081 | up(&slot->crit_sect); |
1286 | return retval; | 1082 | return retval; |
@@ -1335,9 +1131,10 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) | |||
1335 | u32 acpiphp_get_address(struct acpiphp_slot *slot) | 1131 | u32 acpiphp_get_address(struct acpiphp_slot *slot) |
1336 | { | 1132 | { |
1337 | u32 address; | 1133 | u32 address; |
1134 | struct pci_bus *pci_bus = slot->bridge->pci_bus; | ||
1338 | 1135 | ||
1339 | address = ((slot->bridge->seg) << 16) | | 1136 | address = (pci_domain_nr(pci_bus) << 16) | |
1340 | ((slot->bridge->bus) << 8) | | 1137 | (pci_bus->number << 8) | |
1341 | slot->device; | 1138 | slot->device; |
1342 | 1139 | ||
1343 | return address; | 1140 | return address; |