From 1a9ff3c9bbb1e9bd458264a6adbf903aeab499f6 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 18 Jun 2009 14:46:47 -0600 Subject: [PATCH] --- yaml --- r: 154154 b: refs/heads/master c: fbe2b31b4b6dfa790cbc88e00631f3112c4fc54e h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/acpi/glue.c | 40 +++ trunk/drivers/acpi/pci_bind.c | 313 ++++++++++++++++++++--- trunk/drivers/acpi/pci_irq.c | 17 +- trunk/drivers/acpi/pci_root.c | 166 ++---------- trunk/drivers/acpi/video.c | 6 +- trunk/drivers/acpi/video_detect.c | 9 +- trunk/drivers/pci/hotplug/acpi_pcihp.c | 40 ++- trunk/drivers/pci/hotplug/acpiphp_glue.c | 27 +- trunk/include/acpi/acpi_bus.h | 2 +- trunk/include/acpi/acpi_drivers.h | 10 +- trunk/include/linux/pci_hotplug.h | 1 + 12 files changed, 418 insertions(+), 215 deletions(-) diff --git a/[refs] b/[refs] index eb63e3f26951..83d0afdbc779 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 7fe2a6c275a5bcec52fb3ef643daaf8265b7af0d +refs/heads/master: fbe2b31b4b6dfa790cbc88e00631f3112c4fc54e diff --git a/trunk/drivers/acpi/glue.c b/trunk/drivers/acpi/glue.c index a8a5c29958c8..8bd2c2a6884d 100644 --- a/trunk/drivers/acpi/glue.c +++ b/trunk/drivers/acpi/glue.c @@ -140,6 +140,46 @@ struct device *acpi_get_physical_device(acpi_handle handle) EXPORT_SYMBOL(acpi_get_physical_device); +/* ToDo: When a PCI bridge is found, return the PCI device behind the bridge + * This should work in general, but did not on a Lenovo T61 for the + * graphics card. But this must be fixed when the PCI device is + * bound and the kernel device struct is attached to the acpi device + * Note: A success call will increase reference count by one + * Do call put_device(dev) on the returned device then + */ +struct device *acpi_get_physical_pci_device(acpi_handle handle) +{ + struct device *dev; + long long device_id; + acpi_status status; + + status = + acpi_evaluate_integer(handle, "_ADR", NULL, &device_id); + + if (ACPI_FAILURE(status)) + return NULL; + + /* We need to attempt to determine whether the _ADR refers to a + PCI device or not. There's no terribly good way to do this, + so the best we can hope for is to assume that there'll never + be a device in the host bridge */ + if (device_id >= 0x10000) { + /* It looks like a PCI device. Does it exist? */ + dev = acpi_get_physical_device(handle); + } else { + /* It doesn't look like a PCI device. Does its parent + exist? */ + acpi_handle phandle; + if (acpi_get_parent(handle, &phandle)) + return NULL; + dev = acpi_get_physical_device(phandle); + } + if (!dev) + return NULL; + return dev; +} +EXPORT_SYMBOL(acpi_get_physical_pci_device); + static int acpi_bind_one(struct device *dev, acpi_handle handle) { struct acpi_device *acpi_dev; diff --git a/trunk/drivers/acpi/pci_bind.c b/trunk/drivers/acpi/pci_bind.c index a5a77b78a723..bc46de3d967f 100644 --- a/trunk/drivers/acpi/pci_bind.c +++ b/trunk/drivers/acpi/pci_bind.c @@ -24,7 +24,12 @@ */ #include +#include +#include #include +#include +#include +#include #include #include #include @@ -33,76 +38,310 @@ #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_bind"); -static int acpi_pci_unbind(struct acpi_device *device) -{ +struct acpi_pci_data { + struct acpi_pci_id id; + struct pci_bus *bus; struct pci_dev *dev; +}; + +static int acpi_pci_unbind(struct acpi_device *device); + +static void acpi_pci_data_handler(acpi_handle handle, u32 function, + void *context) +{ + + /* TBD: Anything we need to do here? */ + + return; +} + +/** + * acpi_get_pci_id + * ------------------ + * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem) + * to resolve PCI information for ACPI-PCI devices defined in the namespace. + * This typically occurs when resolving PCI operation region information. + */ +acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_device *device = NULL; + struct acpi_pci_data *data = NULL; + + + if (!id) + return AE_BAD_PARAMETER; + + result = acpi_bus_get_device(handle, &device); + if (result) { + printk(KERN_ERR PREFIX + "Invalid ACPI Bus context for device %s\n", + acpi_device_bid(device)); + return AE_NOT_EXIST; + } + + status = acpi_get_data(handle, acpi_pci_data_handler, (void **)&data); + if (ACPI_FAILURE(status) || !data) { + ACPI_EXCEPTION((AE_INFO, status, + "Invalid ACPI-PCI context for device %s", + acpi_device_bid(device))); + return status; + } - dev = acpi_get_pci_dev(device->handle); - if (!dev || !dev->subordinate) - goto out; + *id = data->id; - acpi_pci_irq_del_prt(dev->subordinate); + /* + id->segment = data->id.segment; + id->bus = data->id.bus; + id->device = data->id.device; + id->function = data->id.function; + */ - device->ops.bind = NULL; - device->ops.unbind = NULL; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Device %s has PCI address %04x:%02x:%02x.%d\n", + acpi_device_bid(device), id->segment, id->bus, + id->device, id->function)); -out: - pci_dev_put(dev); - return 0; + return AE_OK; } -static int acpi_pci_bind(struct acpi_device *device) +EXPORT_SYMBOL(acpi_get_pci_id); + +int acpi_pci_bind(struct acpi_device *device) { + int result = 0; acpi_status status; + struct acpi_pci_data *data; + struct acpi_pci_data *pdata; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_handle handle; - struct pci_bus *bus; - struct pci_dev *dev; - dev = acpi_get_pci_dev(device->handle); - if (!dev) - return 0; + if (!device || !device->parent) + return -EINVAL; + + data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) { + kfree(data); + return -ENODEV; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", + (char *)buffer.pointer)); + + /* + * Segment & Bus + * ------------- + * These are obtained via the parent device's ACPI-PCI context. + */ + status = acpi_get_data(device->parent->handle, acpi_pci_data_handler, + (void **)&pdata); + if (ACPI_FAILURE(status) || !pdata || !pdata->bus) { + ACPI_EXCEPTION((AE_INFO, status, + "Invalid ACPI-PCI context for parent device %s", + acpi_device_bid(device->parent))); + result = -ENODEV; + goto end; + } + data->id.segment = pdata->id.segment; + data->id.bus = pdata->bus->number; + + /* + * Device & Function + * ----------------- + * These are simply obtained from the device's _ADR method. Note + * that a value of zero is valid. + */ + data->id.device = device->pnp.bus_address >> 16; + data->id.function = device->pnp.bus_address & 0xFFFF; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n", + data->id.segment, data->id.bus, data->id.device, + data->id.function)); + + /* + * TBD: Support slot devices (e.g. function=0xFFFF). + */ + + /* + * Locate PCI Device + * ----------------- + * Locate matching device in PCI namespace. If it doesn't exist + * this typically means that the device isn't currently inserted + * (e.g. docking station, port replicator, etc.). + */ + data->dev = pci_get_slot(pdata->bus, + PCI_DEVFN(data->id.device, data->id.function)); + if (!data->dev) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Device %04x:%02x:%02x.%d not present in PCI namespace\n", + data->id.segment, data->id.bus, + data->id.device, data->id.function)); + result = -ENODEV; + goto end; + } + if (!data->dev->bus) { + printk(KERN_ERR PREFIX + "Device %04x:%02x:%02x.%d has invalid 'bus' field\n", + data->id.segment, data->id.bus, + data->id.device, data->id.function); + result = -ENODEV; + goto end; + } /* - * Install the 'bind' function to facilitate callbacks for - * children of the P2P bridge. + * PCI Bridge? + * ----------- + * If so, set the 'bus' field and install the 'bind' function to + * facilitate callbacks for all of its children. */ - if (dev->subordinate) { + if (data->dev->subordinate) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %04x:%02x:%02x.%d is a PCI bridge\n", - pci_domain_nr(dev->bus), dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn))); + data->id.segment, data->id.bus, + data->id.device, data->id.function)); + data->bus = data->dev->subordinate; device->ops.bind = acpi_pci_bind; device->ops.unbind = acpi_pci_unbind; } /* - * Evaluate and parse _PRT, if exists. This code allows parsing of - * _PRT objects within the scope of non-bridge devices. Note that - * _PRTs within the scope of a PCI bridge assume the bridge's - * subordinate bus number. + * Attach ACPI-PCI Context + * ----------------------- + * Thus binding the ACPI and PCI devices. + */ + status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Unable to attach ACPI-PCI context to device %s", + acpi_device_bid(device))); + result = -ENODEV; + goto end; + } + + /* + * PCI Routing Table + * ----------------- + * Evaluate and parse _PRT, if exists. This code is independent of + * PCI bridges (above) to allow parsing of _PRT objects within the + * scope of non-bridge devices. Note that _PRTs within the scope of + * a PCI bridge assume the bridge's subordinate bus number. * * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? */ status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); + if (ACPI_SUCCESS(status)) { + if (data->bus) /* PCI-PCI bridge */ + acpi_pci_irq_add_prt(device->handle, data->id.segment, + data->bus->number); + else /* non-bridge PCI device */ + acpi_pci_irq_add_prt(device->handle, data->id.segment, + data->id.bus); + } + + end: + kfree(buffer.pointer); + if (result) { + pci_dev_put(data->dev); + kfree(data); + } + return result; +} + +static int acpi_pci_unbind(struct acpi_device *device) +{ + int result = 0; + acpi_status status; + struct acpi_pci_data *data; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + + if (!device || !device->parent) + return -EINVAL; + + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); if (ACPI_FAILURE(status)) - goto out; + return -ENODEV; - if (dev->subordinate) - bus = dev->subordinate; - else - bus = dev->bus; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n", + (char *) buffer.pointer)); + kfree(buffer.pointer); - acpi_pci_irq_add_prt(device->handle, bus); + status = + acpi_get_data(device->handle, acpi_pci_data_handler, + (void **)&data); + if (ACPI_FAILURE(status)) { + result = -ENODEV; + goto end; + } -out: - pci_dev_put(dev); - return 0; + status = acpi_detach_data(device->handle, acpi_pci_data_handler); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Unable to detach data from device %s", + acpi_device_bid(device))); + result = -ENODEV; + goto end; + } + if (data->dev->subordinate) { + acpi_pci_irq_del_prt(data->id.segment, data->bus->number); + } + pci_dev_put(data->dev); + kfree(data); + + end: + return result; } -int acpi_pci_bind_root(struct acpi_device *device) +int +acpi_pci_bind_root(struct acpi_device *device, + struct acpi_pci_id *id, struct pci_bus *bus) { + int result = 0; + acpi_status status; + struct acpi_pci_data *data = NULL; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + if (!device || !id || !bus) { + return -EINVAL; + } + + data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->id = *id; + data->bus = bus; device->ops.bind = acpi_pci_bind; device->ops.unbind = acpi_pci_unbind; - return 0; + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) { + kfree (data); + return -ENODEV; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to " + "%04x:%02x\n", (char *)buffer.pointer, + id->segment, id->bus)); + + status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Unable to attach ACPI-PCI context to device %s", + (char *)buffer.pointer)); + result = -ENODEV; + goto end; + } + + end: + kfree(buffer.pointer); + if (result != 0) + kfree(data); + + return result; } diff --git a/trunk/drivers/acpi/pci_irq.c b/trunk/drivers/acpi/pci_irq.c index ef9509e33191..51b9f8280f88 100644 --- a/trunk/drivers/acpi/pci_irq.c +++ b/trunk/drivers/acpi/pci_irq.c @@ -182,7 +182,7 @@ static void do_prt_fixups(struct acpi_prt_entry *entry, } } -static int acpi_pci_irq_add_entry(acpi_handle handle, struct pci_bus *bus, +static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, struct acpi_pci_routing_table *prt) { struct acpi_prt_entry *entry; @@ -196,8 +196,8 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, struct pci_bus *bus, * 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert * it here. */ - entry->id.segment = pci_domain_nr(bus); - entry->id.bus = bus->number; + entry->id.segment = segment; + entry->id.bus = bus; entry->id.device = (prt->address >> 16) & 0xFFFF; entry->pin = prt->pin + 1; @@ -242,7 +242,7 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, struct pci_bus *bus, return 0; } -int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus) +int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) { acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -271,7 +271,7 @@ int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus) entry = buffer.pointer; while (entry && (entry->length > 0)) { - acpi_pci_irq_add_entry(handle, bus, entry); + acpi_pci_irq_add_entry(handle, segment, bus, entry); entry = (struct acpi_pci_routing_table *) ((unsigned long)entry + entry->length); } @@ -280,17 +280,16 @@ int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus) return 0; } -void acpi_pci_irq_del_prt(struct pci_bus *bus) +void acpi_pci_irq_del_prt(int segment, int bus) { struct acpi_prt_entry *entry, *tmp; printk(KERN_DEBUG "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n", - pci_domain_nr(bus), bus->number); + segment, bus); spin_lock(&acpi_prt_lock); list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) { - if (pci_domain_nr(bus) == entry->id.segment - && bus->number == entry->id.bus) { + if (segment == entry->id.segment && bus == entry->id.bus) { list_del(&entry->list); kfree(entry); } diff --git a/trunk/drivers/acpi/pci_root.c b/trunk/drivers/acpi/pci_root.c index f341b0756c9e..a8b250783937 100644 --- a/trunk/drivers/acpi/pci_root.c +++ b/trunk/drivers/acpi/pci_root.c @@ -142,30 +142,6 @@ acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); -/** - * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge - * @handle - the ACPI CA node in question. - * - * Note: we could make this API take a struct acpi_device * instead, but - * for now, it's more convenient to operate on an acpi_handle. - */ -int acpi_is_root_bridge(acpi_handle handle) -{ - int ret; - struct acpi_device *device; - - ret = acpi_bus_get_device(handle, &device); - if (ret) - return 0; - - ret = acpi_match_device_ids(device, root_device_ids); - if (ret) - return 0; - else - return 1; -} -EXPORT_SYMBOL_GPL(acpi_is_root_bridge); - static acpi_status get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) { @@ -329,87 +305,6 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) return NULL; } -struct acpi_handle_node { - struct list_head node; - acpi_handle handle; -}; - -/** - * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev - * @handle: the handle in question - * - * Given an ACPI CA handle, the desired PCI device is located in the - * list of PCI devices. - * - * If the device is found, its reference count is increased and this - * function returns a pointer to its data structure. The caller must - * decrement the reference count by calling pci_dev_put(). - * If no device is found, %NULL is returned. - */ -struct pci_dev *acpi_get_pci_dev(acpi_handle handle) -{ - int dev, fn; - unsigned long long adr; - acpi_status status; - acpi_handle phandle; - struct pci_bus *pbus; - struct pci_dev *pdev = NULL; - struct acpi_handle_node *node, *tmp; - struct acpi_pci_root *root; - LIST_HEAD(device_list); - - /* - * Walk up the ACPI CA namespace until we reach a PCI root bridge. - */ - phandle = handle; - while (!acpi_is_root_bridge(phandle)) { - node = kzalloc(sizeof(struct acpi_handle_node), GFP_KERNEL); - if (!node) - goto out; - - INIT_LIST_HEAD(&node->node); - node->handle = phandle; - list_add(&node->node, &device_list); - - status = acpi_get_parent(phandle, &phandle); - if (ACPI_FAILURE(status)) - goto out; - } - - root = acpi_pci_find_root(phandle); - if (!root) - goto out; - - pbus = root->bus; - - /* - * Now, walk back down the PCI device tree until we return to our - * original handle. Assumes that everything between the PCI root - * bridge and the device we're looking for must be a P2P bridge. - */ - list_for_each_entry(node, &device_list, node) { - acpi_handle hnd = node->handle; - status = acpi_evaluate_integer(hnd, "_ADR", NULL, &adr); - if (ACPI_FAILURE(status)) - goto out; - dev = (adr >> 16) & 0xffff; - fn = adr & 0xffff; - - pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn)); - if (hnd == handle) - break; - - pbus = pdev->subordinate; - pci_dev_put(pdev); - } -out: - list_for_each_entry_safe(node, tmp, &device_list, node) - kfree(node); - - return pdev; -} -EXPORT_SYMBOL_GPL(acpi_get_pci_dev); - /** * acpi_pci_osc_control_set - commit requested control to Firmware * @handle: acpi_handle for the target ACPI object @@ -470,12 +365,12 @@ static int __devinit 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 long value = 0; acpi_handle handle = NULL; struct acpi_device *child; u32 flags, base_flags; + int bus; if (!device) @@ -491,6 +386,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); device->driver_data = root; + device->ops.bind = acpi_pci_bind; + /* * All supported architectures that use ACPI have support for * PCI domains, so we indicate this in _OSC support capabilities. @@ -523,46 +420,24 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) /* * Bus * --- - * Obtained via _BBN, if exists, otherwise assumed to be zero (0). + * Check _CRS first, then _BBN. If no _BBN, default to zero. */ - status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, - &value); - switch (status) { - case AE_OK: - root->id.bus = (u16) value; - break; - case AE_NOT_FOUND: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n")); - root->id.bus = 0; - break; - default: - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN")); - result = -ENODEV; - goto end; - } - - /* 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)) { - 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; + status = try_get_root_bridge_busnr(device->handle, &bus); + if (ACPI_SUCCESS(status)) + root->id.bus = bus; + else { + status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &value); + if (ACPI_SUCCESS(status)) + root->id.bus = (u16) value; + else if (status == AE_NOT_FOUND) + root->id.bus = 0; + else { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN")); + result = -ENODEV; + goto end; } } + /* * Device & Function * ----------------- @@ -603,7 +478,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) * ----------------------- * Thus binding the ACPI and PCI devices. */ - result = acpi_pci_bind_root(device); + result = acpi_pci_bind_root(device, &root->id, root->bus); if (result) goto end; @@ -614,7 +489,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) */ status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); if (ACPI_SUCCESS(status)) - result = acpi_pci_irq_add_prt(device->handle, root->bus); + result = acpi_pci_irq_add_prt(device->handle, root->id.segment, + root->id.bus); /* * Scan and bind all _ADR-Based Devices diff --git a/trunk/drivers/acpi/video.c b/trunk/drivers/acpi/video.c index 5adbf9361e60..1bdfb37377e3 100644 --- a/trunk/drivers/acpi/video.c +++ b/trunk/drivers/acpi/video.c @@ -1054,15 +1054,15 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video) static int acpi_video_bus_check(struct acpi_video_bus *video) { acpi_status status = -ENOENT; - struct pci_dev *dev; + struct device *dev; if (!video) return -EINVAL; - dev = acpi_get_pci_dev(video->device->handle); + dev = acpi_get_physical_pci_device(video->device->handle); if (!dev) return -ENODEV; - pci_dev_put(dev); + put_device(dev); /* Since there is no HID, CID and so on for VGA driver, we have * to check well known required nodes. diff --git a/trunk/drivers/acpi/video_detect.c b/trunk/drivers/acpi/video_detect.c index 7cd2b63435ea..09737275e25f 100644 --- a/trunk/drivers/acpi/video_detect.c +++ b/trunk/drivers/acpi/video_detect.c @@ -10,7 +10,7 @@ * assinged * * After PCI devices are glued with ACPI devices - * acpi_get_pci_dev() can be called to identify ACPI graphics + * acpi_get_physical_pci_device() can be called to identify ACPI graphics * devices for which a real graphics card is plugged in * * Now acpi_video_get_capabilities() can be called to check which @@ -36,7 +36,6 @@ #include #include -#include ACPI_MODULE_NAME("video"); #define _COMPONENT ACPI_VIDEO_COMPONENT @@ -110,7 +109,7 @@ static acpi_status find_video(acpi_handle handle, u32 lvl, void *context, void **rv) { long *cap = context; - struct pci_dev *dev; + struct device *dev; struct acpi_device *acpi_dev; const struct acpi_device_id video_ids[] = { @@ -121,10 +120,10 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; if (!acpi_match_device_ids(acpi_dev, video_ids)) { - dev = acpi_get_pci_dev(handle); + dev = acpi_get_physical_pci_device(handle); if (!dev) return AE_OK; - pci_dev_put(dev); + put_device(dev); *cap |= acpi_is_video_device(acpi_dev); } return AE_OK; diff --git a/trunk/drivers/pci/hotplug/acpi_pcihp.c b/trunk/drivers/pci/hotplug/acpi_pcihp.c index eb159587d0bf..fbc63d5e459f 100644 --- a/trunk/drivers/pci/hotplug/acpi_pcihp.c +++ b/trunk/drivers/pci/hotplug/acpi_pcihp.c @@ -354,7 +354,7 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, status = acpi_run_hpp(handle, hpp); if (ACPI_SUCCESS(status)) break; - if (acpi_is_root_bridge(handle)) + if (acpi_root_bridge(handle)) break; status = acpi_get_parent(handle, &phandle); if (ACPI_FAILURE(status)) @@ -428,7 +428,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) status = acpi_run_oshp(handle); if (ACPI_SUCCESS(status)) goto got_one; - if (acpi_is_root_bridge(handle)) + if (acpi_root_bridge(handle)) break; chandle = handle; status = acpi_get_parent(chandle, &handle); @@ -449,6 +449,42 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) } EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware); +/* acpi_root_bridge - check to see if this acpi object is a root bridge + * + * @handle - the acpi object in question. + */ +int acpi_root_bridge(acpi_handle handle) +{ + acpi_status status; + struct acpi_device_info *info; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + int i; + + status = acpi_get_object_info(handle, &buffer); + if (ACPI_SUCCESS(status)) { + info = buffer.pointer; + if ((info->valid & ACPI_VALID_HID) && + !strcmp(PCI_ROOT_HID_STRING, + info->hardware_id.value)) { + kfree(buffer.pointer); + return 1; + } + if (info->valid & ACPI_VALID_CID) { + for (i=0; i < info->compatibility_id.count; i++) { + if (!strcmp(PCI_ROOT_HID_STRING, + info->compatibility_id.id[i].value)) { + kfree(buffer.pointer); + return 1; + } + } + } + kfree(buffer.pointer); + } + return 0; +} +EXPORT_SYMBOL_GPL(acpi_root_bridge); + + static int is_ejectable(acpi_handle handle) { acpi_status status; diff --git a/trunk/drivers/pci/hotplug/acpiphp_glue.c b/trunk/drivers/pci/hotplug/acpiphp_glue.c index 0cb0f830a993..3a6064bce561 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_glue.c +++ b/trunk/drivers/pci/hotplug/acpiphp_glue.c @@ -678,9 +678,18 @@ static void remove_bridge(acpi_handle handle) static struct pci_dev * get_apic_pci_info(acpi_handle handle) { + struct acpi_pci_id id; + struct pci_bus *bus; struct pci_dev *dev; - dev = acpi_get_pci_dev(handle); + if (ACPI_FAILURE(acpi_get_pci_id(handle, &id))) + return NULL; + + bus = pci_find_bus(id.segment, id.bus); + if (!bus) + return NULL; + + dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function)); if (!dev) return NULL; @@ -1387,16 +1396,19 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) /* Program resources in newly inserted bridge */ static int acpiphp_configure_bridge (acpi_handle handle) { - struct pci_dev *dev; + struct acpi_pci_id pci_id; struct pci_bus *bus; - dev = acpi_get_pci_dev(handle); - if (!dev) { + if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { err("cannot get PCI domain and bus number for bridge\n"); return -EINVAL; } - - bus = dev->bus; + bus = pci_find_bus(pci_id.segment, pci_id.bus); + if (!bus) { + err("cannot find bus %d:%d\n", + pci_id.segment, pci_id.bus); + return -EINVAL; + } pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); @@ -1404,7 +1416,6 @@ static int acpiphp_configure_bridge (acpi_handle handle) acpiphp_set_hpp_values(handle, bus); pci_enable_bridges(bus); acpiphp_configure_ioapics(handle); - pci_dev_put(dev); return 0; } @@ -1620,7 +1631,7 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) { int *count = (int *)context; - if (acpi_is_root_bridge(handle)) { + if (acpi_root_bridge(handle)) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge, NULL); (*count)++; diff --git a/trunk/include/acpi/acpi_bus.h b/trunk/include/acpi/acpi_bus.h index 700b263c898a..c34b11022908 100644 --- a/trunk/include/acpi/acpi_bus.h +++ b/trunk/include/acpi/acpi_bus.h @@ -365,10 +365,10 @@ struct acpi_bus_type { int register_acpi_bus_type(struct acpi_bus_type *); int unregister_acpi_bus_type(struct acpi_bus_type *); struct device *acpi_get_physical_device(acpi_handle); +struct device *acpi_get_physical_pci_device(acpi_handle); /* helper */ acpi_handle acpi_get_child(acpi_handle, acpi_integer); -int acpi_is_root_bridge(acpi_handle); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) diff --git a/trunk/include/acpi/acpi_drivers.h b/trunk/include/acpi/acpi_drivers.h index b69285773177..0352c8f0b05b 100644 --- a/trunk/include/acpi/acpi_drivers.h +++ b/trunk/include/acpi/acpi_drivers.h @@ -91,15 +91,17 @@ int acpi_pci_link_free_irq(acpi_handle handle); /* ACPI PCI Interrupt Routing (pci_irq.c) */ -int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus); -void acpi_pci_irq_del_prt(struct pci_bus *bus); +int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus); +void acpi_pci_irq_del_prt(int segment, int bus); /* ACPI PCI Device Binding (pci_bind.c) */ struct pci_bus; -struct pci_dev *acpi_get_pci_dev(acpi_handle); -int acpi_pci_bind_root(struct acpi_device *device); +acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id); +int acpi_pci_bind(struct acpi_device *device); +int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id, + struct pci_bus *bus); /* Arch-defined function to add a bus to the system */ diff --git a/trunk/include/linux/pci_hotplug.h b/trunk/include/linux/pci_hotplug.h index a3576ef9fc74..20998746518e 100644 --- a/trunk/include/linux/pci_hotplug.h +++ b/trunk/include/linux/pci_hotplug.h @@ -226,6 +226,7 @@ struct hotplug_params { extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, struct hotplug_params *hpp); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); +int acpi_root_bridge(acpi_handle handle); int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); int acpi_pci_detect_ejectable(struct pci_bus *pbus); #endif