aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/sgi_hotplug.c
diff options
context:
space:
mode:
authorJohn Keller <jpk@sgi.com>2007-01-30 01:18:38 -0500
committerLen Brown <len.brown@intel.com>2007-02-02 22:14:57 -0500
commit3e643e77a929202455a0cc868c2030a5ba8d1371 (patch)
treeb89d4c70ff8a9b06b00d86a6d92c7c9f5149767a /drivers/pci/hotplug/sgi_hotplug.c
parent6f09a9250a5d76c0765cd51a33e0a042e9761cfc (diff)
Altix: Add ACPI SSDT PCI device support (hotplug)
Support for dynamic loading and unloading of ACPI SSDT tables upon slot hotplugs and unplugs. On SN platforms, we now represent every populated root bus slot with a single ACPI SSDT table containing info for every device and PPB attached to the slot. These SSDTs are generated by the prom at initial boot and hotplug time. The info in these SSDT tables is used by the SN kernel IO "fixup" code (which is called at boot and hotplug time). On hotplugs (i.e. enable_slot()), if running with an ACPI capable prom, attempt to obtain a new ACPI SSDT table for the slot being hotplugged. If successful, add the table to the ACPI namespace (acpi_load_table()) and then walk the new devices and add them to the ACPI infrastructure (acpi_bus_add()). On hot unplugs (i.e. disable_slot()), if running with an ACPI capable prom, attempt to remove the SSDT table associated with the slot from the ACPI namespace (acpi_unload_table_id()) and infastructure (acpi_bus_trim()). From: John Keller <jpk@sgi.com> A bug was fixed where the sgi hotplug driver was removing the slot's SSDT table from the ACPI namespace a bit too early in disable_slot(). Also, we now call acpi_bus_start() subsequent to acpi_bus_add(). Signed-off-by: Aaron Young <ayoung@sgi.com> Cc: Greg KH <greg@kroah.com> Cc: "Luck, Tony" <tony.luck@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Len Brown<len.brown@intel.com>
Diffstat (limited to 'drivers/pci/hotplug/sgi_hotplug.c')
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c155
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");
35MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); 37MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
36MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); 38MODULE_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
229static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, 234static 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