diff options
Diffstat (limited to 'drivers/pci/hotplug/sgi_hotplug.c')
-rw-r--r-- | drivers/pci/hotplug/sgi_hotplug.c | 155 |
1 files changed, 148 insertions, 7 deletions
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 5d188c558386..78cf0711d1fa 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <asm/sn/sn_feature_sets.h> | 28 | #include <asm/sn/sn_feature_sets.h> |
29 | #include <asm/sn/sn_sal.h> | 29 | #include <asm/sn/sn_sal.h> |
30 | #include <asm/sn/types.h> | 30 | #include <asm/sn/types.h> |
31 | #include <linux/acpi.h> | ||
32 | #include <asm/sn/acpi.h> | ||
31 | 33 | ||
32 | #include "../pci.h" | 34 | #include "../pci.h" |
33 | 35 | ||
@@ -35,14 +37,17 @@ MODULE_LICENSE("GPL"); | |||
35 | MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); | 37 | MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); |
36 | MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); | 38 | MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); |
37 | 39 | ||
38 | #define PCIIO_ASIC_TYPE_TIOCA 4 | 40 | |
41 | /* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */ | ||
39 | #define PCI_SLOT_ALREADY_UP 2 /* slot already up */ | 42 | #define PCI_SLOT_ALREADY_UP 2 /* slot already up */ |
40 | #define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ | 43 | #define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ |
41 | #define PCI_L1_ERR 7 /* L1 console command error */ | 44 | #define PCI_L1_ERR 7 /* L1 console command error */ |
42 | #define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ | 45 | #define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ |
46 | |||
47 | |||
48 | #define PCIIO_ASIC_TYPE_TIOCA 4 | ||
43 | #define PCI_L1_QSIZE 128 /* our L1 message buffer size */ | 49 | #define PCI_L1_QSIZE 128 /* our L1 message buffer size */ |
44 | #define SN_MAX_HP_SLOTS 32 /* max hotplug slots */ | 50 | #define SN_MAX_HP_SLOTS 32 /* max hotplug slots */ |
45 | #define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */ | ||
46 | #define SN_SLOT_NAME_SIZE 33 /* size of name string */ | 51 | #define SN_SLOT_NAME_SIZE 33 /* size of name string */ |
47 | 52 | ||
48 | /* internal list head */ | 53 | /* internal list head */ |
@@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_dev *dev) | |||
227 | } | 232 | } |
228 | 233 | ||
229 | static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, | 234 | static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, |
230 | int device_num) | 235 | int device_num, char **ssdt) |
231 | { | 236 | { |
232 | struct slot *slot = bss_hotplug_slot->private; | 237 | struct slot *slot = bss_hotplug_slot->private; |
233 | struct pcibus_info *pcibus_info; | 238 | struct pcibus_info *pcibus_info; |
@@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, | |||
240 | * Power-on and initialize the slot in the SN | 245 | * Power-on and initialize the slot in the SN |
241 | * PCI infrastructure. | 246 | * PCI infrastructure. |
242 | */ | 247 | */ |
243 | rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp); | 248 | rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt); |
249 | |||
244 | 250 | ||
245 | if (rc == PCI_SLOT_ALREADY_UP) { | 251 | if (rc == PCI_SLOT_ALREADY_UP) { |
246 | dev_dbg(slot->pci_bus->self, "is already active\n"); | 252 | dev_dbg(slot->pci_bus->self, "is already active\n"); |
@@ -335,6 +341,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
335 | int func, num_funcs; | 341 | int func, num_funcs; |
336 | int new_ppb = 0; | 342 | int new_ppb = 0; |
337 | int rc; | 343 | int rc; |
344 | char *ssdt = NULL; | ||
338 | void pcibios_fixup_device_resources(struct pci_dev *); | 345 | void pcibios_fixup_device_resources(struct pci_dev *); |
339 | 346 | ||
340 | /* Serialize the Linux PCI infrastructure */ | 347 | /* Serialize the Linux PCI infrastructure */ |
@@ -342,14 +349,29 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
342 | 349 | ||
343 | /* | 350 | /* |
344 | * Power-on and initialize the slot in the SN | 351 | * Power-on and initialize the slot in the SN |
345 | * PCI infrastructure. | 352 | * PCI infrastructure. Also, retrieve the ACPI SSDT |
353 | * table for the slot (if ACPI capable PROM). | ||
346 | */ | 354 | */ |
347 | rc = sn_slot_enable(bss_hotplug_slot, slot->device_num); | 355 | rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt); |
348 | if (rc) { | 356 | if (rc) { |
349 | mutex_unlock(&sn_hotplug_mutex); | 357 | mutex_unlock(&sn_hotplug_mutex); |
350 | return rc; | 358 | return rc; |
351 | } | 359 | } |
352 | 360 | ||
361 | if (ssdt) | ||
362 | ssdt = __va(ssdt); | ||
363 | /* Add the new SSDT for the slot to the ACPI namespace */ | ||
364 | if (SN_ACPI_BASE_SUPPORT() && ssdt) { | ||
365 | acpi_status ret; | ||
366 | |||
367 | ret = acpi_load_table((struct acpi_table_header *)ssdt); | ||
368 | if (ACPI_FAILURE(ret)) { | ||
369 | printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n", | ||
370 | __FUNCTION__, ret); | ||
371 | /* try to continue on */ | ||
372 | } | ||
373 | } | ||
374 | |||
353 | num_funcs = pci_scan_slot(slot->pci_bus, | 375 | num_funcs = pci_scan_slot(slot->pci_bus, |
354 | PCI_DEVFN(slot->device_num + 1, 0)); | 376 | PCI_DEVFN(slot->device_num + 1, 0)); |
355 | if (!num_funcs) { | 377 | if (!num_funcs) { |
@@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
374 | * pdi_host_pcidev_info). | 396 | * pdi_host_pcidev_info). |
375 | */ | 397 | */ |
376 | pcibios_fixup_device_resources(dev); | 398 | pcibios_fixup_device_resources(dev); |
377 | sn_pci_fixup_slot(dev); | 399 | if (SN_ACPI_BASE_SUPPORT()) |
400 | sn_acpi_slot_fixup(dev); | ||
401 | else | ||
402 | sn_io_slot_fixup(dev); | ||
378 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | 403 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { |
379 | unsigned char sec_bus; | 404 | unsigned char sec_bus; |
380 | pci_read_config_byte(dev, PCI_SECONDARY_BUS, | 405 | pci_read_config_byte(dev, PCI_SECONDARY_BUS, |
@@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
388 | } | 413 | } |
389 | } | 414 | } |
390 | 415 | ||
416 | /* | ||
417 | * Add the slot's devices to the ACPI infrastructure */ | ||
418 | if (SN_ACPI_BASE_SUPPORT() && ssdt) { | ||
419 | unsigned long adr; | ||
420 | struct acpi_device *pdevice; | ||
421 | struct acpi_device *device; | ||
422 | acpi_handle phandle; | ||
423 | acpi_handle chandle = NULL; | ||
424 | acpi_handle rethandle; | ||
425 | acpi_status ret; | ||
426 | |||
427 | phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle; | ||
428 | |||
429 | if (acpi_bus_get_device(phandle, &pdevice)) { | ||
430 | dev_dbg(slot->pci_bus->self, | ||
431 | "no parent device, assuming NULL\n"); | ||
432 | pdevice = NULL; | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * Walk the rootbus node's immediate children looking for | ||
437 | * the slot's device node(s). There can be more than | ||
438 | * one for multifunction devices. | ||
439 | */ | ||
440 | for (;;) { | ||
441 | rethandle = NULL; | ||
442 | ret = acpi_get_next_object(ACPI_TYPE_DEVICE, | ||
443 | phandle, chandle, | ||
444 | &rethandle); | ||
445 | |||
446 | if (ret == AE_NOT_FOUND || rethandle == NULL) | ||
447 | break; | ||
448 | |||
449 | chandle = rethandle; | ||
450 | |||
451 | ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR, | ||
452 | NULL, &adr); | ||
453 | |||
454 | if (ACPI_SUCCESS(ret) && | ||
455 | (adr>>16) == (slot->device_num + 1)) { | ||
456 | |||
457 | ret = acpi_bus_add(&device, pdevice, chandle, | ||
458 | ACPI_BUS_TYPE_DEVICE); | ||
459 | if (ACPI_FAILURE(ret)) { | ||
460 | printk(KERN_ERR "%s: acpi_bus_add " | ||
461 | "failed (0x%x) for slot %d " | ||
462 | "func %d\n", __FUNCTION__, | ||
463 | ret, (int)(adr>>16), | ||
464 | (int)(adr&0xffff)); | ||
465 | /* try to continue on */ | ||
466 | } else { | ||
467 | acpi_bus_start(device); | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | |||
391 | /* Call the driver for the new device */ | 473 | /* Call the driver for the new device */ |
392 | pci_bus_add_devices(slot->pci_bus); | 474 | pci_bus_add_devices(slot->pci_bus); |
393 | /* Call the drivers for the new devices subordinate to PPB */ | 475 | /* Call the drivers for the new devices subordinate to PPB */ |
@@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
412 | struct pci_dev *dev; | 494 | struct pci_dev *dev; |
413 | int func; | 495 | int func; |
414 | int rc; | 496 | int rc; |
497 | acpi_owner_id ssdt_id = 0; | ||
415 | 498 | ||
416 | /* Acquire update access to the bus */ | 499 | /* Acquire update access to the bus */ |
417 | mutex_lock(&sn_hotplug_mutex); | 500 | mutex_lock(&sn_hotplug_mutex); |
@@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
422 | if (rc) | 505 | if (rc) |
423 | goto leaving; | 506 | goto leaving; |
424 | 507 | ||
508 | /* free the ACPI resources for the slot */ | ||
509 | if (SN_ACPI_BASE_SUPPORT() && | ||
510 | PCI_CONTROLLER(slot->pci_bus)->acpi_handle) { | ||
511 | unsigned long adr; | ||
512 | struct acpi_device *device; | ||
513 | acpi_handle phandle; | ||
514 | acpi_handle chandle = NULL; | ||
515 | acpi_handle rethandle; | ||
516 | acpi_status ret; | ||
517 | |||
518 | /* Get the rootbus node pointer */ | ||
519 | phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle; | ||
520 | |||
521 | /* | ||
522 | * Walk the rootbus node's immediate children looking for | ||
523 | * the slot's device node(s). There can be more than | ||
524 | * one for multifunction devices. | ||
525 | */ | ||
526 | for (;;) { | ||
527 | rethandle = NULL; | ||
528 | ret = acpi_get_next_object(ACPI_TYPE_DEVICE, | ||
529 | phandle, chandle, | ||
530 | &rethandle); | ||
531 | |||
532 | if (ret == AE_NOT_FOUND || rethandle == NULL) | ||
533 | break; | ||
534 | |||
535 | chandle = rethandle; | ||
536 | |||
537 | ret = acpi_evaluate_integer(chandle, | ||
538 | METHOD_NAME__ADR, | ||
539 | NULL, &adr); | ||
540 | if (ACPI_SUCCESS(ret) && | ||
541 | (adr>>16) == (slot->device_num + 1)) { | ||
542 | /* retain the owner id */ | ||
543 | acpi_get_id(chandle, &ssdt_id); | ||
544 | |||
545 | ret = acpi_bus_get_device(chandle, | ||
546 | &device); | ||
547 | if (ACPI_SUCCESS(ret)) | ||
548 | acpi_bus_trim(device, 1); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | } | ||
553 | |||
425 | /* Free the SN resources assigned to the Linux device.*/ | 554 | /* Free the SN resources assigned to the Linux device.*/ |
426 | for (func = 0; func < 8; func++) { | 555 | for (func = 0; func < 8; func++) { |
427 | dev = pci_get_slot(slot->pci_bus, | 556 | dev = pci_get_slot(slot->pci_bus, |
@@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
434 | } | 563 | } |
435 | } | 564 | } |
436 | 565 | ||
566 | /* Remove the SSDT for the slot from the ACPI namespace */ | ||
567 | if (SN_ACPI_BASE_SUPPORT() && ssdt_id) { | ||
568 | acpi_status ret; | ||
569 | ret = acpi_unload_table_id(ssdt_id); | ||
570 | if (ACPI_FAILURE(ret)) { | ||
571 | printk(KERN_ERR "%s: acpi_unload_table_id " | ||
572 | "failed (0x%x) for id %d\n", | ||
573 | __FUNCTION__, ret, ssdt_id); | ||
574 | /* try to continue on */ | ||
575 | } | ||
576 | } | ||
577 | |||
437 | /* free the collected sysdata pointers */ | 578 | /* free the collected sysdata pointers */ |
438 | sn_bus_free_sysdata(); | 579 | sn_bus_free_sysdata(); |
439 | 580 | ||