X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Facpi%2Fpci_root.c;h=a860efa2c562670768e447ada93eea69b03277d1;hb=refs%2Fheads%2Fvserver;hp=3d19331bc088bd0ff68c275651ef9d0bf39e2c91;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 3d19331bc..a860efa2c 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -35,33 +35,32 @@ #include #include - #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME ("pci_root") - +ACPI_MODULE_NAME("pci_root") #define ACPI_PCI_ROOT_CLASS "pci_bridge" #define ACPI_PCI_ROOT_HID "PNP0A03" #define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" - -static int acpi_pci_root_add (struct acpi_device *device); -static int acpi_pci_root_remove (struct acpi_device *device, int type); +static int acpi_pci_root_add(struct acpi_device *device); +static int acpi_pci_root_remove(struct acpi_device *device, int type); +static int acpi_pci_root_start(struct acpi_device *device); static struct acpi_driver acpi_pci_root_driver = { - .name = ACPI_PCI_ROOT_DRIVER_NAME, - .class = ACPI_PCI_ROOT_CLASS, - .ids = ACPI_PCI_ROOT_HID, - .ops = { - .add = acpi_pci_root_add, - .remove = acpi_pci_root_remove, - }, + .name = ACPI_PCI_ROOT_DRIVER_NAME, + .class = ACPI_PCI_ROOT_CLASS, + .ids = ACPI_PCI_ROOT_HID, + .ops = { + .add = acpi_pci_root_add, + .remove = acpi_pci_root_remove, + .start = acpi_pci_root_start, + }, }; struct acpi_pci_root { - struct list_head node; - acpi_handle handle; - struct acpi_pci_id id; - struct pci_bus *bus; + struct list_head node; + struct acpi_device * device; + struct acpi_pci_id id; + struct pci_bus *bus; }; static LIST_HEAD(acpi_pci_roots); @@ -84,24 +83,27 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver) list_for_each(entry, &acpi_pci_roots) { struct acpi_pci_root *root; root = list_entry(entry, struct acpi_pci_root, node); - driver->add(root->handle); + driver->add(root->device->handle); n++; } return n; } +EXPORT_SYMBOL(acpi_pci_register_driver); + void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) { struct list_head *entry; struct acpi_pci_driver **pptr = &sub_driver; while (*pptr) { - if (*pptr != driver) - continue; - *pptr = (*pptr)->next; - break; + if (*pptr == driver) + break; + pptr = &(*pptr)->next; } + BUG_ON(!*pptr); + *pptr = (*pptr)->next; if (!driver->remove) return; @@ -109,32 +111,66 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) list_for_each(entry, &acpi_pci_roots) { struct acpi_pci_root *root; root = list_entry(entry, struct acpi_pci_root, node); - driver->remove(root->handle); + driver->remove(root->device->handle); } } -static int -acpi_pci_root_add ( - struct acpi_device *device) +EXPORT_SYMBOL(acpi_pci_unregister_driver); + +static acpi_status +get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) +{ + int *busnr = data; + struct acpi_resource_address64 address; + + if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 && + resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 && + resource->type != ACPI_RESOURCE_TYPE_ADDRESS64) + return AE_OK; + + acpi_resource_to_address64(resource, &address); + if ((address.address_length > 0) && + (address.resource_type == ACPI_BUS_NUMBER_RANGE)) + *busnr = address.minimum; + + return AE_OK; +} + +static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum) { - int result = 0; - struct acpi_pci_root *root = NULL; - struct acpi_pci_root *tmp; - acpi_status status = AE_OK; - unsigned long value = 0; - acpi_handle handle = NULL; + acpi_status status; + + *busnum = -1; + status = + acpi_walk_resources(handle, METHOD_NAME__CRS, + get_root_bridge_busnr_callback, busnum); + if (ACPI_FAILURE(status)) + return status; + /* Check if we really get a bus number from _CRS */ + if (*busnum == -1) + return AE_ERROR; + return AE_OK; +} + +static int acpi_pci_root_add(struct acpi_device *device) +{ + int result = 0; + struct acpi_pci_root *root = NULL; + struct acpi_pci_root *tmp; + acpi_status status = AE_OK; + unsigned long value = 0; + acpi_handle handle = NULL; - ACPI_FUNCTION_TRACE("acpi_pci_root_add"); if (!device) - return_VALUE(-EINVAL); + return -EINVAL; - root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); + root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) - return_VALUE(-ENOMEM); - memset(root, 0, sizeof(struct acpi_pci_root)); + return -ENOMEM; + INIT_LIST_HEAD(&root->node); - root->handle = device->handle; + root->device = device; strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); acpi_driver_data(device) = root; @@ -149,19 +185,19 @@ acpi_pci_root_add ( * ------- * Obtained via _SEG, if exists, otherwise assumed to be zero (0). */ - status = acpi_evaluate_integer(root->handle, METHOD_NAME__SEG, NULL, - &value); + status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL, + &value); switch (status) { case AE_OK: root->id.segment = (u16) value; break; case AE_NOT_FOUND: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Assuming segment 0 (no _SEG)\n")); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Assuming segment 0 (no _SEG)\n")); root->id.segment = 0; break; default: - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SEG\n")); + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SEG")); result = -ENODEV; goto end; } @@ -171,8 +207,8 @@ acpi_pci_root_add ( * --- * Obtained via _BBN, if exists, otherwise assumed to be zero (0). */ - status = acpi_evaluate_integer(root->handle, METHOD_NAME__BBN, NULL, - &value); + status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, + &value); switch (status) { case AE_OK: root->id.bus = (u16) value; @@ -182,7 +218,7 @@ acpi_pci_root_add ( root->id.bus = 0; break; default: - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BBN\n")); + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN")); result = -ENODEV; goto end; } @@ -190,9 +226,24 @@ acpi_pci_root_add ( /* Some systems have wrong _BBN */ list_for_each_entry(tmp, &acpi_pci_roots, node) { if ((tmp->id.segment == root->id.segment) - && (tmp->id.bus == root->id.bus)) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Wrong _BBN value, please reboot and using option 'pci=noacpi'\n")); + && (tmp->id.bus == root->id.bus)) { + int bus = 0; + acpi_status status; + + printk(KERN_ERR PREFIX + "Wrong _BBN value, reboot" + " and use option 'pci=noacpi'\n"); + + status = try_get_root_bridge_busnr(device->handle, &bus); + if (ACPI_FAILURE(status)) + break; + if (bus != root->id.bus) { + printk(KERN_INFO PREFIX + "PCI _CRS %d overrides _BBN 0\n", bus); + root->id.bus = bus; + } + break; + } } /* * Device & Function @@ -206,12 +257,12 @@ acpi_pci_root_add ( * TBD: Need PCI interface for enumeration/configuration of roots. */ - /* TBD: Locking */ - list_add_tail(&root->node, &acpi_pci_roots); + /* TBD: Locking */ + list_add_tail(&root->node, &acpi_pci_roots); - printk(KERN_INFO PREFIX "%s [%s] (%02x:%02x)\n", - acpi_device_name(device), acpi_device_bid(device), - root->id.segment, root->id.bus); + printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n", + acpi_device_name(device), acpi_device_bid(device), + root->id.segment, root->id.bus); /* * Scan the Root Bridge @@ -222,9 +273,9 @@ acpi_pci_root_add ( */ root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus); if (!root->bus) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Bus %02x:%02x not present in PCI namespace\n", - root->id.segment, root->id.bus)); + printk(KERN_ERR PREFIX + "Bus %04x:%02x not present in PCI namespace\n", + root->id.segment, root->id.bus); result = -ENODEV; goto end; } @@ -243,56 +294,65 @@ acpi_pci_root_add ( * ----------------- * Evaluate and parse _PRT, if exists. */ - status = acpi_get_handle(root->handle, METHOD_NAME__PRT, &handle); + status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); if (ACPI_SUCCESS(status)) - result = acpi_pci_irq_add_prt(root->handle, root->id.segment, - root->id.bus); + result = acpi_pci_irq_add_prt(device->handle, root->id.segment, + root->id.bus); -end: - if (result) + end: + if (result) { + if (!list_empty(&root->node)) + list_del(&root->node); kfree(root); + } - return_VALUE(result); + return result; } +static int acpi_pci_root_start(struct acpi_device *device) +{ + struct acpi_pci_root *root; + -static int -acpi_pci_root_remove ( - struct acpi_device *device, - int type) + list_for_each_entry(root, &acpi_pci_roots, node) { + if (root->device == device) { + pci_bus_add_devices(root->bus); + return 0; + } + } + return -ENODEV; +} + +static int acpi_pci_root_remove(struct acpi_device *device, int type) { - struct acpi_pci_root *root = NULL; + struct acpi_pci_root *root = NULL; - ACPI_FUNCTION_TRACE("acpi_pci_root_remove"); if (!device || !acpi_driver_data(device)) - return_VALUE(-EINVAL); + return -EINVAL; - root = (struct acpi_pci_root *) acpi_driver_data(device); + root = acpi_driver_data(device); kfree(root); - return_VALUE(0); + return 0; } - -static int __init acpi_pci_root_init (void) +static int __init acpi_pci_root_init(void) { - ACPI_FUNCTION_TRACE("acpi_pci_root_init"); if (acpi_pci_disabled) - return_VALUE(0); + return 0; /* DEBUG: - acpi_dbg_layer = ACPI_PCI_COMPONENT; - acpi_dbg_level = 0xFFFFFFFF; + acpi_dbg_layer = ACPI_PCI_COMPONENT; + acpi_dbg_level = 0xFFFFFFFF; */ if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) - return_VALUE(-ENODEV); + return -ENODEV; - return_VALUE(0); + return 0; } subsys_initcall(acpi_pci_root_init); -