aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/blacklist.c16
-rw-r--r--drivers/acpi/glue.c40
-rw-r--r--drivers/acpi/osl.c25
-rw-r--r--drivers/acpi/pci_bind.c313
-rw-r--r--drivers/acpi/pci_irq.c17
-rw-r--r--drivers/acpi/pci_root.c297
-rw-r--r--drivers/acpi/power.c28
-rw-r--r--drivers/acpi/processor_core.c45
-rw-r--r--drivers/acpi/processor_idle.c47
-rw-r--r--drivers/acpi/scan.c69
-rw-r--r--drivers/acpi/video.c61
-rw-r--r--drivers/acpi/video_detect.c9
-rw-r--r--drivers/gpu/drm/i915/i915_opregion.c2
-rw-r--r--drivers/pci/hotplug/acpi_pcihp.c40
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c27
-rw-r--r--drivers/platform/x86/Kconfig17
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acerhdf.c602
-rw-r--r--drivers/platform/x86/dell-wmi.c56
-rw-r--r--drivers/platform/x86/hp-wmi.c87
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c411
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c46
22 files changed, 1535 insertions, 721 deletions
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 09c69806c1f..f6baa77deef 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -192,6 +192,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
},
},
+ {
+ .callback = dmi_disable_osi_vista,
+ .ident = "Sony VGN-NS10J_S",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"),
+ },
+ },
+ {
+ .callback = dmi_disable_osi_vista,
+ .ident = "Sony VGN-SR290J",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"),
+ },
+ },
/*
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 8bd2c2a6884..a8a5c29958c 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -140,46 +140,6 @@ 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/drivers/acpi/osl.c b/drivers/acpi/osl.c
index d916bea729f..71670719d61 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -79,6 +79,7 @@ static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_wq;
+static struct workqueue_struct *kacpi_hotplug_wq;
struct acpi_res_list {
resource_size_t start;
@@ -192,8 +193,10 @@ acpi_status acpi_os_initialize1(void)
{
kacpid_wq = create_singlethread_workqueue("kacpid");
kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
+ kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug");
BUG_ON(!kacpid_wq);
BUG_ON(!kacpi_notify_wq);
+ BUG_ON(!kacpi_hotplug_wq);
return AE_OK;
}
@@ -206,6 +209,7 @@ acpi_status acpi_os_terminate(void)
destroy_workqueue(kacpid_wq);
destroy_workqueue(kacpi_notify_wq);
+ destroy_workqueue(kacpi_hotplug_wq);
return AE_OK;
}
@@ -716,6 +720,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
struct workqueue_struct *queue;
+ work_func_t func;
int ret;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n",
@@ -740,15 +745,17 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
dpc->function = function;
dpc->context = context;
- if (!hp) {
- INIT_WORK(&dpc->work, acpi_os_execute_deferred);
- queue = (type == OSL_NOTIFY_HANDLER) ?
- kacpi_notify_wq : kacpid_wq;
- ret = queue_work(queue, &dpc->work);
- } else {
- INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
- ret = schedule_work(&dpc->work);
- }
+ /*
+ * We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq
+ * because the hotplug code may call driver .remove() functions,
+ * which invoke flush_scheduled_work/acpi_os_wait_events_complete
+ * to flush these workqueues.
+ */
+ queue = hp ? kacpi_hotplug_wq :
+ (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq);
+ func = hp ? acpi_os_execute_hp_deferred : acpi_os_execute_deferred;
+ INIT_WORK(&dpc->work, func);
+ ret = queue_work(queue, &dpc->work);
if (!ret) {
printk(KERN_ERR PREFIX
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index bc46de3d967..a5a77b78a72 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -24,12 +24,7 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
@@ -38,310 +33,76 @@
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_bind");
-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)
+static int acpi_pci_unbind(struct acpi_device *device)
{
- 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;
- }
+ struct pci_dev *dev;
- *id = data->id;
+ dev = acpi_get_pci_dev(device->handle);
+ if (!dev || !dev->subordinate)
+ goto out;
- /*
- id->segment = data->id.segment;
- id->bus = data->id.bus;
- id->device = data->id.device;
- id->function = data->id.function;
- */
+ acpi_pci_irq_del_prt(dev->subordinate);
- 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));
+ device->ops.bind = NULL;
+ device->ops.unbind = NULL;
- return AE_OK;
+out:
+ pci_dev_put(dev);
+ return 0;
}
-EXPORT_SYMBOL(acpi_get_pci_id);
-
-int acpi_pci_bind(struct acpi_device *device)
+static 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;
- 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;
- }
+ dev = acpi_get_pci_dev(device->handle);
+ if (!dev)
+ return 0;
/*
- * PCI Bridge?
- * -----------
- * If so, set the 'bus' field and install the 'bind' function to
- * facilitate callbacks for all of its children.
+ * Install the 'bind' function to facilitate callbacks for
+ * children of the P2P bridge.
*/
- if (data->dev->subordinate) {
+ if (dev->subordinate) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %04x:%02x:%02x.%d is a PCI bridge\n",
- data->id.segment, data->id.bus,
- data->id.device, data->id.function));
- data->bus = data->dev->subordinate;
+ pci_domain_nr(dev->bus), dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)));
device->ops.bind = acpi_pci_bind;
device->ops.unbind = acpi_pci_unbind;
}
/*
- * 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.
+ * 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.
*
* 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))
- return -ENODEV;
+ goto out;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n",
- (char *) buffer.pointer));
- kfree(buffer.pointer);
+ if (dev->subordinate)
+ bus = dev->subordinate;
+ else
+ bus = dev->bus;
- status =
- acpi_get_data(device->handle, acpi_pci_data_handler,
- (void **)&data);
- if (ACPI_FAILURE(status)) {
- result = -ENODEV;
- goto end;
- }
+ acpi_pci_irq_add_prt(device->handle, bus);
- 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;
+out:
+ pci_dev_put(dev);
+ return 0;
}
-int
-acpi_pci_bind_root(struct acpi_device *device,
- struct acpi_pci_id *id, struct pci_bus *bus)
+int acpi_pci_bind_root(struct acpi_device *device)
{
- 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;
- 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;
+ return 0;
}
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 2faa9e2ac89..b794eb88ab9 100644
--- a/drivers/acpi/pci_irq.c
+++ b/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, int segment, int bus,
+static int acpi_pci_irq_add_entry(acpi_handle handle, struct pci_bus *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, int segment, int bus,
* 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert
* it here.
*/
- entry->id.segment = segment;
- entry->id.bus = bus;
+ entry->id.segment = pci_domain_nr(bus);
+ entry->id.bus = bus->number;
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, int segment, int bus,
return 0;
}
-int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
+int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *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, int segment, int bus)
entry = buffer.pointer;
while (entry && (entry->length > 0)) {
- acpi_pci_irq_add_entry(handle, segment, bus, entry);
+ acpi_pci_irq_add_entry(handle, bus, entry);
entry = (struct acpi_pci_routing_table *)
((unsigned long)entry + entry->length);
}
@@ -280,16 +280,17 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
return 0;
}
-void acpi_pci_irq_del_prt(int segment, int bus)
+void acpi_pci_irq_del_prt(struct pci_bus *bus)
{
struct acpi_prt_entry *entry, *tmp;
printk(KERN_DEBUG
"ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n",
- segment, bus);
+ pci_domain_nr(bus), bus->number);
spin_lock(&acpi_prt_lock);
list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) {
- if (segment == entry->id.segment && bus == entry->id.bus) {
+ if (pci_domain_nr(bus) == entry->id.segment
+ && bus->number == entry->id.bus) {
list_del(&entry->list);
kfree(entry);
}
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 196f97d0095..8a5bf3b356f 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -63,9 +63,10 @@ static struct acpi_driver acpi_pci_root_driver = {
struct acpi_pci_root {
struct list_head node;
- struct acpi_device * device;
- struct acpi_pci_id id;
+ struct acpi_device *device;
struct pci_bus *bus;
+ u16 segment;
+ u8 bus_nr;
u32 osc_support_set; /* _OSC state of support bits */
u32 osc_control_set; /* _OSC state of control bits */
@@ -82,7 +83,7 @@ static DEFINE_MUTEX(osc_lock);
int acpi_pci_register_driver(struct acpi_pci_driver *driver)
{
int n = 0;
- struct list_head *entry;
+ struct acpi_pci_root *root;
struct acpi_pci_driver **pptr = &sub_driver;
while (*pptr)
@@ -92,9 +93,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver)
if (!driver->add)
return 0;
- list_for_each(entry, &acpi_pci_roots) {
- struct acpi_pci_root *root;
- root = list_entry(entry, struct acpi_pci_root, node);
+ list_for_each_entry(root, &acpi_pci_roots, node) {
driver->add(root->device->handle);
n++;
}
@@ -106,7 +105,7 @@ EXPORT_SYMBOL(acpi_pci_register_driver);
void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
{
- struct list_head *entry;
+ struct acpi_pci_root *root;
struct acpi_pci_driver **pptr = &sub_driver;
while (*pptr) {
@@ -120,28 +119,48 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
if (!driver->remove)
return;
- list_for_each(entry, &acpi_pci_roots) {
- struct acpi_pci_root *root;
- root = list_entry(entry, struct acpi_pci_root, node);
+ list_for_each_entry(root, &acpi_pci_roots, node)
driver->remove(root->device->handle);
- }
}
EXPORT_SYMBOL(acpi_pci_unregister_driver);
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
{
- struct acpi_pci_root *tmp;
+ struct acpi_pci_root *root;
- list_for_each_entry(tmp, &acpi_pci_roots, node) {
- if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
- return tmp->device->handle;
- }
+ list_for_each_entry(root, &acpi_pci_roots, node)
+ if ((root->segment == (u16) seg) && (root->bus_nr == (u16) bus))
+ return root->device->handle;
return NULL;
}
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)
{
@@ -161,19 +180,22 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
return AE_OK;
}
-static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum)
+static acpi_status try_get_root_bridge_busnr(acpi_handle handle,
+ unsigned long long *bus)
{
acpi_status status;
+ int busnum;
- *busnum = -1;
+ busnum = -1;
status =
acpi_walk_resources(handle, METHOD_NAME__CRS,
- get_root_bridge_busnr_callback, busnum);
+ 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)
+ if (busnum == -1)
return AE_ERROR;
+ *bus = busnum;
return AE_OK;
}
@@ -298,6 +320,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
{
struct acpi_pci_root *root;
+
list_for_each_entry(root, &acpi_pci_roots, node) {
if (root->device->handle == handle)
return root;
@@ -305,6 +328,87 @@ 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
@@ -363,31 +467,46 @@ EXPORT_SYMBOL(acpi_pci_osc_control_set);
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;
+ unsigned long long segment, bus;
+ acpi_status status;
+ int result;
+ struct acpi_pci_root *root;
+ acpi_handle handle;
struct acpi_device *child;
u32 flags, base_flags;
+ segment = 0;
+ status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
+ &segment);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
+ return -ENODEV;
+ }
- if (!device)
- return -EINVAL;
+ /* Check _CRS first, then _BBN. If no _BBN, default to zero. */
+ bus = 0;
+ status = try_get_root_bridge_busnr(device->handle, &bus);
+ if (ACPI_FAILURE(status)) {
+ status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ printk(KERN_ERR PREFIX
+ "no bus number in _CRS and can't evaluate _BBN\n");
+ return -ENODEV;
+ }
+ }
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
return -ENOMEM;
- INIT_LIST_HEAD(&root->node);
+ INIT_LIST_HEAD(&root->node);
root->device = device;
+ root->segment = segment & 0xFFFF;
+ root->bus_nr = bus & 0xFF;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
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.
@@ -395,79 +514,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
acpi_pci_osc_support(root, flags);
- /*
- * Segment
- * -------
- * Obtained via _SEG, if exists, otherwise assumed to be zero (0).
- */
- 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"));
- root->id.segment = 0;
- break;
- default:
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SEG"));
- result = -ENODEV;
- goto end;
- }
-
- /*
- * Bus
- * ---
- * Obtained via _BBN, if exists, otherwise assumed to be zero (0).
- */
- 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;
- }
- }
- /*
- * Device & Function
- * -----------------
- * Obtained from _ADR (which has already been evaluated for us).
- */
- root->id.device = device->pnp.bus_address >> 16;
- root->id.function = device->pnp.bus_address & 0xFFFF;
-
/*
* TBD: Need PCI interface for enumeration/configuration of roots.
*/
@@ -477,7 +523,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n",
acpi_device_name(device), acpi_device_bid(device),
- root->id.segment, root->id.bus);
+ root->segment, root->bus_nr);
/*
* Scan the Root Bridge
@@ -486,11 +532,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
* PCI namespace does not get created until this call is made (and
* thus the root bridge's pci_dev does not exist).
*/
- root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus);
+ root->bus = pci_acpi_scan_root(device, segment, bus);
if (!root->bus) {
printk(KERN_ERR PREFIX
"Bus %04x:%02x not present in PCI namespace\n",
- root->id.segment, root->id.bus);
+ root->segment, root->bus_nr);
result = -ENODEV;
goto end;
}
@@ -500,7 +546,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, &root->id, root->bus);
+ result = acpi_pci_bind_root(device);
if (result)
goto end;
@@ -511,8 +557,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)