diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/Kconfig | 4 | ||||
-rw-r--r-- | drivers/acpi/container.c | 2 | ||||
-rw-r--r-- | drivers/acpi/pci_bind.c | 27 | ||||
-rw-r--r-- | drivers/acpi/pci_irq.c | 3 | ||||
-rw-r--r-- | drivers/acpi/pci_link.c | 38 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 24 | ||||
-rw-r--r-- | drivers/acpi/processor_core.c | 2 | ||||
-rw-r--r-- | drivers/acpi/processor_idle.c | 2 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 130 | ||||
-rw-r--r-- | drivers/acpi/sleep/poweroff.c | 34 |
10 files changed, 183 insertions, 83 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 281a64040f3..ba13896cae4 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -55,8 +55,8 @@ if ACPI_INTERPRETER config ACPI_SLEEP bool "Sleep States (EXPERIMENTAL)" - depends on X86 - depends on EXPERIMENTAL + depends on X86 && (!SMP || SUSPEND_SMP) + depends on EXPERIMENTAL && PM default y ---help--- This option adds support for ACPI suspend states. diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 5a0adbf8bc0..97013ddfa20 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle) return_VALUE(-ENODEV); } - result = acpi_bus_scan(*device); + result = acpi_bus_start(*device); return_VALUE(result); } diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 5d19b39e9e2..5148f3c10b5 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -61,15 +61,14 @@ acpi_pci_data_handler ( /** - * acpi_os_get_pci_id + * 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. */ -#ifdef ACPI_FUTURE_USAGE acpi_status -acpi_os_get_pci_id ( +acpi_get_pci_id ( acpi_handle handle, struct acpi_pci_id *id) { @@ -78,7 +77,7 @@ acpi_os_get_pci_id ( struct acpi_device *device = NULL; struct acpi_pci_data *data = NULL; - ACPI_FUNCTION_TRACE("acpi_os_get_pci_id"); + ACPI_FUNCTION_TRACE("acpi_get_pci_id"); if (!id) return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -92,7 +91,7 @@ acpi_os_get_pci_id ( } status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data); - if (ACPI_FAILURE(status) || !data || !data->dev) { + if (ACPI_FAILURE(status) || !data) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid ACPI-PCI context for device %s\n", acpi_device_bid(device))); @@ -115,7 +114,7 @@ acpi_os_get_pci_id ( return_ACPI_STATUS(AE_OK); } -#endif /* ACPI_FUTURE_USAGE */ +EXPORT_SYMBOL(acpi_get_pci_id); int @@ -129,6 +128,8 @@ acpi_pci_bind ( char *pathname = NULL; struct acpi_buffer buffer = {0, NULL}; acpi_handle handle = NULL; + struct pci_dev *dev; + struct pci_bus *bus; ACPI_FUNCTION_TRACE("acpi_pci_bind"); @@ -193,8 +194,20 @@ acpi_pci_bind ( * 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.). + * We cannot simply search the global pci device list, since + * PCI devices are added to the global pci list when the root + * bridge start ops are run, which may not have happened yet. */ - data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function)); + bus = pci_find_bus(data->id.segment, data->id.bus); + if (bus) { + list_for_each_entry(dev, &bus->devices, bus_list) { + if (dev->devfn == PCI_DEVFN(data->id.device, + data->id.function)) { + data->dev = dev; + break; + } + } + } if (!data->dev) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %02x:%02x:%02x.%02x not present in PCI namespace\n", diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index c536ccfc541..bb973d2109a 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -465,8 +465,9 @@ acpi_pci_irq_enable ( printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI", pci_name(dev), ('A' + pin)); /* Interrupt Line values above 0xF are forbidden */ - if (dev->irq >= 0 && (dev->irq <= 0xF)) { + if (dev->irq > 0 && (dev->irq <= 0xF)) { printk(" - using IRQ %d\n", dev->irq); + acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); return_VALUE(0); } else { diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 0091dbdf7ef..65cea07abbc 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -787,15 +787,25 @@ end: } static int -irqrouter_suspend( - struct sys_device *dev, - u32 state) +acpi_pci_link_resume( + struct acpi_pci_link *link) +{ + ACPI_FUNCTION_TRACE("acpi_pci_link_resume"); + + if (link->refcnt && link->irq.active && link->irq.initialized) + return_VALUE(acpi_pci_link_set(link, link->irq.active)); + else + return_VALUE(0); +} + +static int +irqrouter_resume( + struct sys_device *dev) { struct list_head *node = NULL; struct acpi_pci_link *link = NULL; - int ret = 0; - ACPI_FUNCTION_TRACE("irqrouter_suspend"); + ACPI_FUNCTION_TRACE("irqrouter_resume"); list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); @@ -804,21 +814,9 @@ irqrouter_suspend( "Invalid link context\n")); continue; } - if (link->irq.initialized && link->refcnt != 0 - /* We ignore legacy IDE device irq */ - && link->irq.active != 14 && link->irq.active !=15) { - printk(KERN_WARNING PREFIX - "%d drivers with interrupt %d neglected to call" - " pci_disable_device at .suspend\n", - link->refcnt, - link->irq.active); - printk(KERN_WARNING PREFIX - "Fix the driver, or rmmod before suspend\n"); - link->refcnt = 0; - ret = -EINVAL; - } + acpi_pci_link_resume(link); } - return_VALUE(ret); + return_VALUE(0); } @@ -933,7 +931,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set); /* FIXME: we will remove this interface after all drivers call pci_disable_device */ static struct sysdev_class irqrouter_sysdev_class = { set_kset_name("irqrouter"), - .suspend = irqrouter_suspend, + .resume = irqrouter_resume, }; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 7e6b8e3b2ed..5d2f77fcd50 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -46,6 +46,7 @@ ACPI_MODULE_NAME ("pci_root") 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, @@ -54,6 +55,7 @@ static struct acpi_driver acpi_pci_root_driver = { .ops = { .add = acpi_pci_root_add, .remove = acpi_pci_root_remove, + .start = acpi_pci_root_start, }, }; @@ -169,6 +171,7 @@ acpi_pci_root_add ( if (!root) return_VALUE(-ENOMEM); memset(root, 0, sizeof(struct acpi_pci_root)); + INIT_LIST_HEAD(&root->node); root->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); @@ -298,12 +301,31 @@ acpi_pci_root_add ( root->id.bus); end: - if (result) + if (result) { + if (!list_empty(&root->node)) + list_del(&root->node); kfree(root); + } return_VALUE(result); } +static int +acpi_pci_root_start ( + struct acpi_device *device) +{ + struct acpi_pci_root *root; + + ACPI_FUNCTION_TRACE("acpi_pci_root_start"); + + list_for_each_entry(root, &acpi_pci_roots, node) { + if (root->handle == device->handle) { + pci_bus_add_devices(root->bus); + return_VALUE(0); + } + } + return_VALUE(-ENODEV); +} static int acpi_pci_root_remove ( diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e421842888b..d56a439ac61 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -760,7 +760,7 @@ int acpi_processor_device_add( return_VALUE(-ENODEV); } - acpi_bus_scan(*device); + acpi_bus_start(*device); pr = acpi_driver_data(*device); if (!pr) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 8f7836678b2..2c04740c654 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -178,7 +178,7 @@ static void acpi_processor_idle (void) int sleep_ticks = 0; u32 t1, t2 = 0; - pr = processors[_smp_processor_id()]; + pr = processors[raw_smp_processor_id()]; if (!pr) return; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7c26fed0bdf..cbcda30c172 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -65,14 +65,14 @@ static ssize_t acpi_device_attr_show(struct kobject *kobj, { struct acpi_device *device = to_acpi_device(kobj); struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->show ? attribute->show(device, buf) : 0; + return attribute->show ? attribute->show(device, buf) : -EIO; } static ssize_t acpi_device_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) { struct acpi_device *device = to_acpi_device(kobj); struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->store ? attribute->store(device, buf, len) : len; + return attribute->store ? attribute->store(device, buf, len) : -EIO; } static struct sysfs_ops acpi_device_sysfs_ops = { @@ -553,20 +553,29 @@ acpi_bus_driver_init ( * upon possible configuration and currently allocated resources. */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); + return_VALUE(0); +} + +int +acpi_start_single_object ( + struct acpi_device *device) +{ + int result = 0; + struct acpi_driver *driver; + + ACPI_FUNCTION_TRACE("acpi_start_single_object"); + + if (!(driver = device->driver)) + return_VALUE(0); + if (driver->ops.start) { result = driver->ops.start(device); if (result && driver->ops.remove) driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); - return_VALUE(result); } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); - - if (driver->ops.scan) { - driver->ops.scan(device); - } - - return_VALUE(0); + return_VALUE(result); } static int acpi_driver_attach(struct acpi_driver * drv) @@ -586,6 +595,7 @@ static int acpi_driver_attach(struct acpi_driver * drv) if (!acpi_bus_match(dev, drv)) { if (!acpi_bus_driver_init(dev, drv)) { + acpi_start_single_object(dev); atomic_inc(&drv->references); count++; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", @@ -1009,8 +1019,8 @@ acpi_bus_remove ( } -int -acpi_bus_add ( +static int +acpi_add_single_object ( struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, @@ -1019,7 +1029,7 @@ acpi_bus_add ( int result = 0; struct acpi_device *device = NULL; - ACPI_FUNCTION_TRACE("acpi_bus_add"); + ACPI_FUNCTION_TRACE("acpi_add_single_object"); if (!child) return_VALUE(-EINVAL); @@ -1142,7 +1152,7 @@ acpi_bus_add ( * * TBD: Assumes LDM provides driver hot-plug capability. */ - acpi_bus_find_driver(device); + result = acpi_bus_find_driver(device); end: if (!result) @@ -1155,10 +1165,10 @@ end: return_VALUE(result); } -EXPORT_SYMBOL(acpi_bus_add); -int acpi_bus_scan (struct acpi_device *start) +static int acpi_bus_scan (struct acpi_device *start, + struct acpi_bus_ops *ops) { acpi_status status = AE_OK; struct acpi_device *parent = NULL; @@ -1231,9 +1241,20 @@ int acpi_bus_scan (struct acpi_device *start) continue; } - status = acpi_bus_add(&child, parent, chandle, type); - if (ACPI_FAILURE(status)) - continue; + if (ops->acpi_op_add) + status = acpi_add_single_object(&child, parent, + chandle, type); + else + status = acpi_bus_get_device(chandle, &child); + + if (ACPI_FAILURE(status)) + continue; + + if (ops->acpi_op_start) { + status = acpi_start_single_object(child); + if (ACPI_FAILURE(status)) + continue; + } /* * If the device is present, enabled, and functioning then @@ -1259,8 +1280,50 @@ int acpi_bus_scan (struct acpi_device *start) return_VALUE(0); } -EXPORT_SYMBOL(acpi_bus_scan); +int +acpi_bus_add ( + struct acpi_device **child, + struct acpi_device *parent, + acpi_handle handle, + int type) +{ + int result; + struct acpi_bus_ops ops; + + ACPI_FUNCTION_TRACE("acpi_bus_add"); + + result = acpi_add_single_object(child, parent, handle, type); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + result = acpi_bus_scan(*child, &ops); + } + return_VALUE(result); +} +EXPORT_SYMBOL(acpi_bus_add); + +int +acpi_bus_start ( + struct acpi_device *device) +{ + int result; + struct acpi_bus_ops ops; + + ACPI_FUNCTION_TRACE("acpi_bus_start"); + + if (!device) + return_VALUE(-EINVAL); + + result = acpi_start_single_object(device); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_start = 1; + result = acpi_bus_scan(device, &ops); + } + return_VALUE(result); +} +EXPORT_SYMBOL(acpi_bus_start); static int acpi_bus_trim(struct acpi_device *start, @@ -1333,13 +1396,19 @@ acpi_bus_scan_fixed ( /* * Enumerate all fixed-feature devices. */ - if (acpi_fadt.pwr_button == 0) - result = acpi_bus_add(&device, acpi_root, + if (acpi_fadt.pwr_button == 0) { + result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_POWER_BUTTON); + if (!result) + result = acpi_start_single_object(device); + } - if (acpi_fadt.sleep_button == 0) - result = acpi_bus_add(&device, acpi_root, + if (acpi_fadt.sleep_button == 0) { + result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); + if (!result) + result = acpi_start_single_object(device); + } return_VALUE(result); } @@ -1348,6 +1417,7 @@ acpi_bus_scan_fixed ( static int __init acpi_scan_init(void) { int result; + struct acpi_bus_ops ops; ACPI_FUNCTION_TRACE("acpi_scan_init"); @@ -1359,17 +1429,23 @@ static int __init acpi_scan_init(void) /* * Create the root device in the bus's device tree */ - result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, + result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SYSTEM); if (result) goto Done; + result = acpi_start_single_object(acpi_root); + /* * Enumerate devices in the ACPI namespace. */ result = acpi_bus_scan_fixed(acpi_root); - if (!result) - result = acpi_bus_scan(acpi_root); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; + result = acpi_bus_scan(acpi_root, &ops); + } if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index 1fc86e6b5ab..186b182c582 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -19,8 +19,6 @@ int acpi_sleep_prepare(u32 acpi_state) { - /* Flag to do not allow second time invocation for S5 state */ - static int shutdown_prepared = 0; #ifdef CONFIG_ACPI_SLEEP /* do we have a wakeup address for S2 and S3? */ /* Here, we support only S4BIOS, those we set the wakeup address */ @@ -38,28 +36,23 @@ int acpi_sleep_prepare(u32 acpi_state) acpi_enable_wakeup_device_prep(acpi_state); #endif if (acpi_state == ACPI_STATE_S5) { - /* Check if we were already called */ - if (shutdown_prepared) - return 0; acpi_wakeup_gpe_poweroff_prepare(); - shutdown_prepared = 1; } acpi_enter_sleep_state_prep(acpi_state); return 0; } +#ifdef CONFIG_PM + void acpi_power_off(void) { + /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ printk("%s called\n", __FUNCTION__); - acpi_sleep_prepare(ACPI_STATE_S5); local_irq_disable(); /* Some SMP machines only can poweroff in boot CPU */ - set_cpus_allowed(current, cpumask_of_cpu(0)); acpi_enter_sleep_state(ACPI_STATE_S5); } -#ifdef CONFIG_PM - static int acpi_shutdown(struct sys_device *x) { return acpi_sleep_prepare(ACPI_STATE_S5); @@ -75,8 +68,6 @@ static struct sys_device device_acpi = { .cls = &acpi_sysclass, }; -#endif - static int acpi_poweroff_init(void) { if (!acpi_disabled) { @@ -86,19 +77,18 @@ static int acpi_poweroff_init(void) status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); if (ACPI_SUCCESS(status)) { - pm_power_off = acpi_power_off; -#ifdef CONFIG_PM - { - int error; - error = sysdev_class_register(&acpi_sysclass); - if (!error) - error = sysdev_register(&device_acpi); - return error; - } -#endif + int error; + error = sysdev_class_register(&acpi_sysclass); + if (!error) + error = sysdev_register(&device_acpi); + if (!error) + pm_power_off = acpi_power_off; + return error; } } return 0; } late_initcall(acpi_poweroff_init); + +#endif /* CONFIG_PM */ |