diff options
Diffstat (limited to 'drivers')
37 files changed, 797 insertions, 1054 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 19520221f41..c205653e964 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -43,19 +43,6 @@ config ACPI_SLEEP depends on SUSPEND || HIBERNATION default y -config ACPI_PROCFS - bool "Deprecated /proc/acpi files" - depends on PROC_FS - help - For backwards compatibility, this option allows - deprecated /proc/acpi/ files to exist, even when - they have been replaced by functions in /sys. - - This option has no effect on /proc/acpi/ files - and functions which do not yet exist in /sys. - - Say N to delete /proc/acpi/ files that have moved to /sys/ - config ACPI_EC_DEBUGFS tristate "EC read/write access through /sys/kernel/debug/ec" default n @@ -343,6 +330,19 @@ config ACPI_BGRT data from the firmware boot splash. It will appear under /sys/firmware/acpi/bgrt/ . +config ACPI_REDUCED_HARDWARE_ONLY + bool "Hardware-reduced ACPI support only" if EXPERT + def_bool n + depends on ACPI + help + This config item changes the way the ACPI code is built. When this + option is selected, the kernel will use a specialized version of + ACPICA that ONLY supports the ACPI "reduced hardware" mode. The + resulting kernel will be smaller but it will also be restricted to + running in ACPI reduced hardware mode ONLY. + + If you are unsure what to do, do not enable this option. + source "drivers/acpi/apei/Kconfig" config ACPI_EXTLOG diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 6f190bc2b8b..2c01c1da29c 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -33,6 +33,7 @@ #include <linux/platform_device.h> #include <linux/power_supply.h> #include <linux/acpi.h> +#include "battery.h" #define PREFIX "ACPI: " @@ -57,6 +58,7 @@ struct acpi_ac { struct power_supply charger; struct platform_device *pdev; unsigned long long state; + struct notifier_block battery_nb; }; #define to_acpi_ac(x) container_of(x, struct acpi_ac, charger) @@ -152,6 +154,26 @@ static void acpi_ac_notify_handler(acpi_handle handle, u32 event, void *data) return; } +static int acpi_ac_battery_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct acpi_ac *ac = container_of(nb, struct acpi_ac, battery_nb); + struct acpi_bus_event *event = (struct acpi_bus_event *)data; + + /* + * On HP Pavilion dv6-6179er AC status notifications aren't triggered + * when adapter is plugged/unplugged. However, battery status + * notifcations are triggered when battery starts charging or + * discharging. Re-reading AC status triggers lost AC notifications, + * if AC status has changed. + */ + if (strcmp(event->device_class, ACPI_BATTERY_CLASS) == 0 && + event->type == ACPI_BATTERY_NOTIFY_STATUS) + acpi_ac_get_state(ac); + + return NOTIFY_OK; +} + static int thinkpad_e530_quirk(const struct dmi_system_id *d) { ac_sleep_before_get_state_ms = 1000; @@ -215,6 +237,8 @@ static int acpi_ac_probe(struct platform_device *pdev) acpi_device_name(adev), acpi_device_bid(adev), ac->state ? "on-line" : "off-line"); + ac->battery_nb.notifier_call = acpi_ac_battery_notify; + register_acpi_notifier(&ac->battery_nb); end: if (result) kfree(ac); @@ -261,6 +285,7 @@ static int acpi_ac_remove(struct platform_device *pdev) ac = platform_get_drvdata(pdev); if (ac->charger.dev) power_supply_unregister(&ac->charger); + unregister_acpi_notifier(&ac->battery_nb); kfree(ac); diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c index 84190ed89c0..961b45d18a5 100644 --- a/drivers/acpi/acpi_cmos_rtc.c +++ b/drivers/acpi/acpi_cmos_rtc.c @@ -18,8 +18,6 @@ #include "internal.h" -#define PREFIX "ACPI: " - ACPI_MODULE_NAME("cmos rtc"); static const struct acpi_device_id acpi_cmos_rtc_ids[] = { diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 6745fe137b9..8c2bae980fa 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -102,6 +102,16 @@ static struct lpss_device_desc lpt_sdio_dev_desc = { .ltr_required = true, }; +static struct lpss_shared_clock pwm_clock = { + .name = "pwm_clk", + .rate = 25000000, +}; + +static struct lpss_device_desc byt_pwm_dev_desc = { + .clk_required = true, + .shared_clock = &pwm_clock, +}; + static struct lpss_shared_clock uart_clock = { .name = "uart_clk", .rate = 44236800, @@ -157,6 +167,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { { "INT33C7", }, /* BayTrail LPSS devices */ + { "80860F09", (unsigned long)&byt_pwm_dev_desc }, { "80860F0A", (unsigned long)&byt_uart_dev_desc }, { "80860F0E", (unsigned long)&byt_spi_dev_desc }, { "80860F14", (unsigned long)&byt_sdio_dev_desc }, diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index df96a0fe489..37d73024b82 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -408,28 +408,14 @@ static int acpi_pad_pur(acpi_handle handle) return num; } -/* Notify firmware how many CPUs are idle */ -static void acpi_pad_ost(acpi_handle handle, int stat, - uint32_t idle_cpus) -{ - union acpi_object params[3] = { - {.type = ACPI_TYPE_INTEGER,}, - {.type = ACPI_TYPE_INTEGER,}, - {.type = ACPI_TYPE_BUFFER,}, - }; - struct acpi_object_list arg_list = {3, params}; - - params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY; - params[1].integer.value = stat; - params[2].buffer.length = 4; - params[2].buffer.pointer = (void *)&idle_cpus; - acpi_evaluate_object(handle, "_OST", &arg_list, NULL); -} - static void acpi_pad_handle_notify(acpi_handle handle) { int num_cpus; uint32_t idle_cpus; + struct acpi_buffer param = { + .length = 4, + .pointer = (void *)&idle_cpus, + }; mutex_lock(&isolated_cpus_lock); num_cpus = acpi_pad_pur(handle); @@ -439,7 +425,7 @@ static void acpi_pad_handle_notify(acpi_handle handle) } acpi_pad_idle_cpus(num_cpus); idle_cpus = acpi_pad_idle_cpus_num(); - acpi_pad_ost(handle, 0, idle_cpus); + acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY, 0, ¶m); mutex_unlock(&isolated_cpus_lock); } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 1f0c28ba50d..d6b33bc7bab 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data) /******************************************************************************* * - * FUNCTION: acpi_get_data + * FUNCTION: acpi_get_data_full * * PARAMETERS: obj_handle - Namespace node * handler - Handler used in call to attach_data * data - Where the data is returned + * callback - function to execute before returning * * RETURN: Status * - * DESCRIPTION: Retrieve data that was previously attached to a namespace node. + * DESCRIPTION: Retrieve data that was previously attached to a namespace node + * and execute a callback before returning. * ******************************************************************************/ acpi_status -acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) +acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler, + void **data, void (*callback)(void *)) { struct acpi_namespace_node *node; acpi_status status; @@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) } status = acpi_ns_get_attached_data(node, handler, data); + if (ACPI_SUCCESS(status) && callback) { + callback(*data); + } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); } +ACPI_EXPORT_SYMBOL(acpi_get_data_full) + +/******************************************************************************* + * + * FUNCTION: acpi_get_data + * + * PARAMETERS: obj_handle - Namespace node + * handler - Handler used in call to attach_data + * data - Where the data is returned + * + * RETURN: Status + * + * DESCRIPTION: Retrieve data that was previously attached to a namespace node. + * + ******************************************************************************/ +acpi_status +acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) +{ + return acpi_get_data_full(obj_handle, handler, data, NULL); +} + ACPI_EXPORT_SYMBOL(acpi_get_data) diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index 3650b218322..c4dac715096 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -12,7 +12,7 @@ config ACPI_APEI config ACPI_APEI_GHES bool "APEI Generic Hardware Error Source" - depends on ACPI_APEI && X86 + depends on ACPI_APEI select ACPI_HED select IRQ_WORK select GENERIC_ALLOCATOR diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 797a6938d05..9a2c63b2005 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -39,15 +39,13 @@ #include <linux/acpi.h> #include <linux/power_supply.h> +#include "battery.h" + #define PREFIX "ACPI: " #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF -#define ACPI_BATTERY_CLASS "battery" #define ACPI_BATTERY_DEVICE_NAME "Battery" -#define ACPI_BATTERY_NOTIFY_STATUS 0x80 -#define ACPI_BATTERY_NOTIFY_INFO 0x81 -#define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 /* Battery power unit: 0 means mW, 1 means mA */ #define ACPI_BATTERY_POWER_UNIT_MA 1 @@ -736,6 +734,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, acpi_battery_present(battery)); + acpi_notifier_call_chain(device, event, acpi_battery_present(battery)); /* acpi_battery_update could remove power_supply object */ if (old && battery->bat.dev) power_supply_changed(&battery->bat); diff --git a/drivers/acpi/battery.h b/drivers/acpi/battery.h new file mode 100644 index 00000000000..6c084976987 --- /dev/null +++ b/drivers/acpi/battery.h @@ -0,0 +1,10 @@ +#ifndef __ACPI_BATTERY_H +#define __ACPI_BATTERY_H + +#define ACPI_BATTERY_CLASS "battery" + +#define ACPI_BATTERY_NOTIFY_STATUS 0x80 +#define ACPI_BATTERY_NOTIFY_INFO 0x81 +#define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 + +#endif diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index fcb59c21c68..e7e5844c87d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -311,9 +311,7 @@ static void acpi_bus_osc_support(void) capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT; #endif -#ifdef ACPI_HOTPLUG_OST capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT; -#endif if (!ghes_disable) capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT; @@ -340,60 +338,77 @@ static void acpi_bus_osc_support(void) */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { - struct acpi_device *device = NULL; + struct acpi_device *adev; struct acpi_driver *driver; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", - type, handle)); + acpi_status status; + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); break; case ACPI_NOTIFY_DEVICE_CHECK: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); break; case ACPI_NOTIFY_DEVICE_WAKE: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n"); break; case ACPI_NOTIFY_EJECT_REQUEST: - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n"); /* TBD: Exactly what does 'light' mean? */ break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); break; case ACPI_NOTIFY_POWER_FAULT: - /* TBD */ + acpi_handle_err(handle, "Device has suffered a power fault\n"); break; default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); - break; + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; + goto err; } - acpi_bus_get_device(handle, &device); - if (device) { - driver = device->driver; - if (driver && driver->ops.notify && - (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) - driver->ops.notify(device, type); + adev = acpi_bus_get_acpi_device(handle); + if (!adev) + goto err; + + driver = adev->driver; + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(adev, type); + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + case ACPI_NOTIFY_EJECT_REQUEST: + status = acpi_hotplug_schedule(adev, type); + if (ACPI_SUCCESS(status)) + return; + default: + break; } + acpi_bus_put_acpi_device(adev); + return; + + err: + acpi_evaluate_ost(handle, type, ost_code, NULL); } /* -------------------------------------------------------------------------- diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 714e957a871..db35594d4df 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -302,6 +302,10 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) input_sync(input); pm_wakeup_event(&device->dev, 0); + acpi_bus_generate_netlink_event( + device->pnp.device_class, + dev_name(&device->dev), + event, ++button->pushed); } break; default: diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 368f9ddb848..63119d09b35 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -31,8 +31,6 @@ #include "internal.h" -#define PREFIX "ACPI: " - #define _COMPONENT ACPI_CONTAINER_COMPONENT ACPI_MODULE_NAME("container"); @@ -68,6 +66,9 @@ static int container_device_attach(struct acpi_device *adev, struct device *dev; int ret; + if (adev->flags.is_dock_station) + return 0; + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); if (!cdev) return -ENOMEM; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 5bfd769fc91..f0fc6260266 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -1,7 +1,9 @@ /* * dock.c - ACPI dock station driver * - * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com> + * Copyright (C) 2006, 2014, Intel Corp. + * Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com> + * Rafael J. Wysocki <rafael.j.wysocki@intel.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -35,8 +37,6 @@ #include "internal.h" -#define PREFIX "ACPI: " - #define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" ACPI_MODULE_NAME("dock"); @@ -68,15 +68,10 @@ struct dock_station { }; static LIST_HEAD(dock_stations); static int dock_station_count; -static DEFINE_MUTEX(hotplug_lock); struct dock_dependent_device { struct list_head list; - acpi_handle handle; - const struct acpi_dock_ops *hp_ops; - void *hp_context; - unsigned int hp_refcount; - void (*hp_release)(void *); + struct acpi_device *adev; }; #define DOCK_DOCKING 0x00000001 @@ -98,13 +93,13 @@ enum dock_callback_type { *****************************************************************************/ /** * add_dock_dependent_device - associate a device with the dock station - * @ds: The dock station - * @handle: handle of the dependent device + * @ds: Dock station. + * @adev: Dependent ACPI device object. * * Add the dependent device to the dock's dependent device list. */ -static int __init -add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) +static int add_dock_dependent_device(struct dock_station *ds, + struct acpi_device *adev) { struct dock_dependent_device *dd; @@ -112,180 +107,120 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) if (!dd) return -ENOMEM; - dd->handle = handle; + dd->adev = adev; INIT_LIST_HEAD(&dd->list); list_add_tail(&dd->list, &ds->dependent_devices); return 0; } -static void remove_dock_dependent_devices(struct dock_station *ds) +static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, + enum dock_callback_type cb_type) { - struct dock_dependent_device *dd, *aux; + struct acpi_device *adev = dd->adev; - list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) { - list_del(&dd->list); - kfree(dd); - } -} + acpi_lock_hp_context(); -/** - * dock_init_hotplug - Initialize a hotplug device on a docking station. - * @dd: Dock-dependent device. - * @ops: Dock operations to attach to the dependent device. - * @context: Data to pass to the @ops callbacks and @release. - * @init: Optional initialization routine to run after setting up context. - * @release: Optional release routine to run on removal. - */ -static int dock_init_hotplug(struct dock_dependent_device *dd, - const struct acpi_dock_ops *ops, void *context, - void (*init)(void *), void (*release)(void *)) -{ - int ret = 0; + if (!adev->hp) + goto out; - mutex_lock(&hotplug_lock); - if (WARN_ON(dd->hp_context)) { - ret = -EEXIST; - } else { - dd->hp_refcount = 1; - dd->hp_ops = ops; - dd->hp_context = context; - dd->hp_release = release; - if (init) - init(context); - } - mutex_unlock(&hotplug_lock); - return ret; -} + if (cb_type == DOCK_CALL_FIXUP) { + void (*fixup)(struct acpi_device *); -/** - * dock_release_hotplug - Decrement hotplug reference counter of dock device. - * @dd: Dock-dependent device. - * - * Decrement the reference counter of @dd and if 0, detach its hotplug - * operations from it, reset its context pointer and run the optional release - * routine if present. - */ -static void dock_release_hotplug(struct dock_dependent_device *dd) -{ - mutex_lock(&hotplug_lock); - if (dd->hp_context && !--dd->hp_refcount) { - void (*release)(void *) = dd->hp_release; - void *context = dd->hp_context; - - dd->hp_ops = NULL; - dd->hp_context = NULL; - dd->hp_release = NULL; - if (release) - release(context); - } - mutex_unlock(&hotplug_lock); -} + fixup = adev->hp->fixup; + if (fixup) { + acpi_unlock_hp_context(); + fixup(adev); + return; + } + } else if (cb_type == DOCK_CALL_UEVENT) { + void (*uevent)(struct acpi_device *, u32); + + uevent = adev->hp->uevent; + if (uevent) { + acpi_unlock_hp_context(); + uevent(adev, event); + return; + } + } else { + int (*notify)(struct acpi_device *, u32); -static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, - enum dock_callback_type cb_type) -{ - acpi_notify_handler cb = NULL; - bool run = false; - - mutex_lock(&hotplug_lock); - - if (dd->hp_context) { - run = true; - dd->hp_refcount++; - if (dd->hp_ops) { - switch (cb_type) { - case DOCK_CALL_FIXUP: - cb = dd->hp_ops->fixup; - break; - case DOCK_CALL_UEVENT: - cb = dd->hp_ops->uevent; - break; - default: - cb = dd->hp_ops->handler; - } + notify = adev->hp->notify; + if (notify) { + acpi_unlock_hp_context(); + notify(adev, event); + return; } } - mutex_unlock(&hotplug_lock); + out: + acpi_unlock_hp_context(); +} - if (!run) - return; +static struct dock_station *find_dock_station(acpi_handle handle) +{ + struct dock_station *ds; - if (cb) - cb(dd->handle, event, dd->hp_context); + list_for_each_entry(ds, &dock_stations, sibling) + if (ds->handle == handle) + return ds; - dock_release_hotplug(dd); + return NULL; } /** * find_dock_dependent_device - get a device dependent on this dock * @ds: the dock station - * @handle: the acpi_handle of the device we want + * @adev: ACPI device object to find. * * iterate over the dependent device list for this dock. If the * dependent device matches the handle, return. */ static struct dock_dependent_device * -find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) +find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev) { struct dock_dependent_device *dd; list_for_each_entry(dd, &ds->dependent_devices, list) - if (handle == dd->handle) + if (adev == dd->adev) return dd; return NULL; } -/***************************************************************************** - * Dock functions * - *****************************************************************************/ -static int __init is_battery(acpi_handle handle) +void register_dock_dependent_device(struct acpi_device *adev, + acpi_handle dshandle) { - struct acpi_device_info *info; - int ret = 1; + struct dock_station *ds = find_dock_station(dshandle); - if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) - return 0; - if (!(info->valid & ACPI_VALID_HID)) - ret = 0; - else - ret = !strcmp("PNP0C0A", info->hardware_id.string); - - kfree(info); - return ret; + if (ds && !find_dock_dependent_device(ds, adev)) + add_dock_dependent_device(ds, adev); } -/* Check whether ACPI object is an ejectable battery or disk bay */ -static bool __init is_ejectable_bay(acpi_handle handle) -{ - if (acpi_has_method(handle, "_EJ0") && is_battery(handle)) - return true; - - return acpi_bay_match(handle); -} +/***************************************************************************** + * Dock functions * + *****************************************************************************/ /** * is_dock_device - see if a device is on a dock station - * @handle: acpi handle of the device + * @adev: ACPI device object to check. * * If this device is either the dock station itself, * or is a device dependent on the dock station, then it * is a dock device */ -int is_dock_device(acpi_handle handle) +int is_dock_device(struct acpi_device *adev) { struct dock_station *dock_station; if (!dock_station_count) return 0; - if (acpi_dock_match(handle)) + if (acpi_dock_match(adev->handle)) return 1; list_for_each_entry(dock_station, &dock_stations, sibling) - if (find_dock_dependent_device(dock_station, handle)) + if (find_dock_dependent_device(dock_station, adev)) return 1; return 0; @@ -313,43 +248,6 @@ static int dock_present(struct dock_station *ds) } /** - * dock_create_acpi_device - add new devices to acpi - * @handle - handle of the device to add - * - * This function will create a new acpi_device for the given - * handle if one does not exist already. This should cause - * acpi to scan for drivers for the given devices, and call - * matching driver's add routine. - */ -static void dock_create_acpi_device(acpi_handle handle) -{ - struct acpi_device *device = NULL; - int ret; - - acpi_bus_get_device(handle, &device); - if (!acpi_device_enumerated(device)) { - ret = acpi_bus_scan(handle); - if (ret) - pr_debug("error adding bus, %x\n", -ret); - } -} - -/** - * dock_remove_acpi_device - remove the acpi_device struct from acpi - * @handle - the handle of the device to remove - * - * Tell acpi to remove the acpi_device. This should cause any loaded - * driver to have it's remove routine called. - */ -static void dock_remove_acpi_device(acpi_handle handle) -{ - struct acpi_device *device; - - if (!acpi_bus_get_device(handle, &device)) - acpi_bus_trim(device); -} - -/** * hot_remove_dock_devices - Remove dock station devices. * @ds: Dock station. */ @@ -366,7 +264,7 @@ static void hot_remove_dock_devices(struct dock_station *ds) dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false); list_for_each_entry_reverse(dd, &ds->dependent_devices, list) - dock_remove_acpi_device(dd->handle); + acpi_bus_trim(dd->adev); } /** @@ -392,12 +290,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) dock_hotplug_event(dd, event, DOCK_CALL_HANDLER); /* - * Now make sure that an acpi_device is created for each dependent - * device. That will cause scan handlers to be attached to device - * objects or acpi_drivers to be stopped/started if they are present. + * Check if all devices have been enumerated already. If not, run + * acpi_bus_scan() for them and that will cause scan handlers to be + * attached to device objects or acpi_drivers to be stopped/started if + * they are present. */ - list_for_each_entry(dd, &ds->dependent_devices, list) - dock_create_acpi_device(dd->handle); + list_for_each_entry(dd, &ds->dependent_devices, list) { + struct acpi_device *adev = dd->adev; + + if (!acpi_device_enumerated(adev)) { + int ret = acpi_bus_scan(adev->handle); + if (ret) + dev_dbg(&adev->dev, "scan error %d\n", -ret); + } + } } static void dock_event(struct dock_station *ds, u32 event, int num) @@ -501,71 +407,6 @@ static int dock_in_progress(struct dock_station *ds) } /** - * register_hotplug_dock_device - register a hotplug function - * @handle: the handle of the device - * @ops: handlers to call after docking - * @context: device specific data - * @init: Optional initialization routine to run after registration - * @release: Optional release routine to run on unregistration - * - * If a driver would like to perform a hotplug operation after a dock - * event, they can register an acpi_notifiy_handler to be called by - * the dock driver after _DCK is executed. - */ -int register_hotplug_dock_device(acpi_handle handle, - const struct acpi_dock_ops *ops, void *context, - void (*init)(void *), void (*release)(void *)) -{ - struct dock_dependent_device *dd; - struct dock_station *dock_station; - int ret = -EINVAL; - - if (WARN_ON(!context)) - return -EINVAL; - - if (!dock_station_count) - return -ENODEV; - - /* - * make sure this handle is for a device dependent on the dock, - * this would include the dock station itself - */ - list_for_each_entry(dock_station, &dock_stations, sibling) { - /* - * An ATA bay can be in a dock and itself can be ejected - * separately, so there are two 'dock stations' which need the - * ops - */ - dd = find_dock_dependent_device(dock_station, handle); - if (dd && !dock_init_hotplug(dd, ops, context, init, release)) - ret = 0; - } - - return ret; -} -EXPORT_SYMBOL_GPL(register_hotplug_dock_device); - -/** - * unregister_hotplug_dock_device - remove yourself from the hotplug list - * @handle: the acpi handle of the device - */ -void unregister_hotplug_dock_device(acpi_handle handle) -{ - struct dock_dependent_device *dd; - struct dock_station *dock_station; - - if (!dock_station_count) - return; - - list_for_each_entry(dock_station, &dock_stations, sibling) { - dd = find_dock_dependent_device(dock_station, handle); - if (dd) - dock_release_hotplug(dd); - } -} -EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); - -/** * handle_eject_request - handle an undock request checking for error conditions * * Check to make sure the dock device is still present, then undock and @@ -598,20 +439,23 @@ static int handle_eject_request(struct dock_station *ds, u32 event) } /** - * dock_notify - act upon an acpi dock notification - * @ds: dock station - * @event: the acpi event + * dock_notify - Handle ACPI dock notification. + * @adev: Dock station's ACPI device object. + * @event: Event code. * * If we are notified to dock, then check to see if the dock is * present and then dock. Notify all drivers of the dock event, * and then hotplug and devices that may need hotplugging. */ -static void dock_notify(struct dock_station *ds, u32 event) +int dock_notify(struct acpi_device *adev, u32 event) { - acpi_handle handle = ds->handle; - struct acpi_device *adev = NULL; + acpi_handle handle = adev->handle; + struct dock_station *ds = find_dock_station(handle); int surprise_removal = 0; + if (!ds) + return -ENODEV; + /* * According to acpi spec 3.0a, if a DEVICE_CHECK notification * is sent and _DCK is present, it is assumed to mean an undock @@ -632,7 +476,6 @@ static void dock_notify(struct dock_station *ds, u32 event) switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - acpi_bus_get_device(handle, &adev); if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { begin_dock(ds); dock(ds); @@ -662,49 +505,8 @@ static void dock_notify(struct dock_station *ds, u32 event) else dock_event(ds, event, UNDOCK_EVENT); break; - default: - acpi_handle_err(handle, "Unknown dock event %d\n", event); } -} - -static void acpi_dock_deferred_cb(void *data, u32 event) -{ - acpi_scan_lock_acquire(); - dock_notify(data, event); - acpi_scan_lock_release(); -} - -static void dock_notify_handler(acpi_handle handle, u32 event, void *data) -{ - if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK - && event != ACPI_NOTIFY_EJECT_REQUEST) - return; - - acpi_hotplug_execute(acpi_dock_deferred_cb, data, event); -} - -/** - * find_dock_devices - find devices on the dock station - * @handle: the handle of the device we are examining - * @lvl: unused - * @context: the dock station private data - * @rv: unused - * - * This function is called by acpi_walk_namespace. It will - * check to see if an object has an _EJD method. If it does, then it - * will see if it is dependent on the dock station. - */ -static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, - void *context, void **rv) -{ - struct dock_station *ds = context; - acpi_handle ejd = NULL; - - acpi_bus_get_ejd(handle, &ejd); - if (ejd == ds->handle) - add_dock_dependent_device(ds, handle); - - return AE_OK; + return 0; } /* @@ -803,23 +605,28 @@ static struct attribute_group dock_attribute_group = { }; /** - * dock_add - add a new dock station - * @handle: the dock station handle + * acpi_dock_add - Add a new dock station + * @adev: Dock station ACPI device object. * - * allocated and initialize a new dock station device. Find all devices - * that are on the dock station, and register for dock event notifications. + * allocated and initialize a new dock station device. */ -static int __init dock_add(acpi_handle handle) +void acpi_dock_add(struct acpi_device *adev) { struct dock_station *dock_station, ds = { NULL, }; + struct platform_device_info pdevinfo; + acpi_handle handle = adev->handle; struct platform_device *dd; - acpi_status status; int ret; - dd = platform_device_register_data(NULL, "dock", dock_station_count, - &ds, sizeof(ds)); + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.name = "dock"; + pdevinfo.id = dock_station_count; + pdevinfo.acpi_node.companion = adev; + pdevinfo.data = &ds; + pdevinfo.size_data = sizeof(ds); + dd = platform_device_register_full(&pdevinfo); if (IS_ERR(dd)) - return PTR_ERR(dd); + return; dock_station = dd->dev.platform_data; @@ -837,72 +644,29 @@ static int __init dock_add(acpi_handle handle) dock_station->flags |= DOCK_IS_DOCK; if (acpi_ata_match(handle)) dock_station->flags |= DOCK_IS_ATA; - if (is_battery(handle)) + if (acpi_device_is_battery(adev)) dock_station->flags |= DOCK_IS_BAT; ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); if (ret) goto err_unregister; - /* Find dependent devices */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock_devices, NULL, - dock_station, NULL); - /* add the dock station as a device dependent on itself */ - ret = add_dock_dependent_device(dock_station, handle); + ret = add_dock_dependent_device(dock_station, adev); if (ret) goto err_rmgroup; - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - dock_notify_handler, dock_station); - if (ACPI_FAILURE(status)) { - ret = -ENODEV; - goto err_rmgroup; - } - dock_station_count++; list_add(&dock_station->sibling, &dock_stations); - return 0; + adev->flags.is_dock_station = true; + dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n", + dock_station_count); + return; err_rmgroup: - remove_dock_dependent_devices(dock_station); sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); + err_unregister: platform_device_unregister(dd); acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); - return ret; -} - -/** - * find_dock_and_bay - look for dock stations and bays - * @handle: acpi handle of a device - * @lvl: unused - * @context: unused - * @rv: unused - * - * This is called by acpi_walk_namespace to look for dock stations and bays. - */ -static acpi_status __init -find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - if (acpi_dock_match(handle) || is_ejectable_bay(handle)) - dock_add(handle); - - return AE_OK; -} - -void __init acpi_dock_init(void) -{ - /* look for dock stations and bays */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); - - if (!dock_station_count) { - pr_info(PREFIX "No dock devices found.\n"); - return; - } - - pr_info(PREFIX "%s: %d docks/bays found\n", - ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); } diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 09e423f3d8a..8acf53e6296 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -55,11 +55,16 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids); #ifdef CONFIG_PM_SLEEP static int acpi_fan_suspend(struct device *dev); static int acpi_fan_resume(struct device *dev); +static struct dev_pm_ops acpi_fan_pm = { + .resume = acpi_fan_resume, + .freeze = acpi_fan_suspend, + .thaw = acpi_fan_resume, + .restore = acpi_fan_resume, +}; +#define FAN_PM_OPS_PTR (&acpi_fan_pm) #else -#define acpi_fan_suspend NULL -#define acpi_fan_resume NULL +#define FAN_PM_OPS_PTR NULL #endif -static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume); static struct acpi_driver acpi_fan_driver = { .name = "fan", @@ -69,7 +74,7 @@ static struct acpi_driver acpi_fan_driver = { .add = acpi_fan_add, .remove = acpi_fan_remove, }, - .drv.pm = &acpi_fan_pm, + .drv.pm = FAN_PM_OPS_PTR, }; /* thermal cooling device callbacks */ diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index dedbb2d802f..957391306cb 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -37,9 +37,15 @@ void acpi_container_init(void); static inline void acpi_container_init(void) {} #endif #ifdef CONFIG_ACPI_DOCK -void acpi_dock_init(void); +void register_dock_dependent_device(struct acpi_device *adev, + acpi_handle dshandle); +int dock_notify(struct acpi_device *adev, u32 event); +void acpi_dock_add(struct acpi_device *adev); #else -static inline void acpi_dock_init(void) {} +static inline void register_dock_dependent_device(struct acpi_device *adev, + acpi_handle dshandle) {} +static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; } +static inline void acpi_dock_add(struct acpi_device *adev) {} #endif #ifdef CONFIG_ACPI_HOTPLUG_MEMORY void acpi_memory_hotplug_init(void); @@ -72,7 +78,9 @@ void acpi_lpss_init(void); static inline void acpi_lpss_init(void) {} #endif +acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src); bool acpi_queue_hotplug_work(struct work_struct *work); +void acpi_device_hotplug(struct acpi_device *adev, u32 src); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); /* -------------------------------------------------------------------------- @@ -90,6 +98,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); int acpi_bind_one(struct device *dev, struct acpi_device *adev); int acpi_unbind_one(struct device *dev); bool acpi_device_is_present(struct acpi_device *adev); +bool acpi_device_is_battery(struct acpi_device *adev); /* -------------------------------------------------------------------------- Power Resource diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index fc1aa790969..67cdaf583bd 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -52,7 +52,7 @@ #define _COMPONENT ACPI_OS_SERVICES ACPI_MODULE_NAME("osl"); -#define PREFIX "ACPI: " + struct acpi_os_dpc { acpi_osd_exec_callback function; void *context; @@ -1168,8 +1168,7 @@ void acpi_os_wait_events_complete(void) struct acpi_hp_work { struct work_struct work; - acpi_hp_callback func; - void *data; + struct acpi_device *adev; u32 src; }; @@ -1178,25 +1177,24 @@ static void acpi_hotplug_work_fn(struct work_struct *work) struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work); acpi_os_wait_events_complete(); - hpw->func(hpw->data, hpw->src); + acpi_device_hotplug(hpw->adev, hpw->src); kfree(hpw); } -acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src) +acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src) { struct acpi_hp_work *hpw; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Scheduling function [%p(%p, %u)] for deferred execution.\n", - func, data, src)); + "Scheduling hotplug event (%p, %u) for deferred execution.\n", + adev, src)); hpw = kmalloc(sizeof(*hpw), GFP_KERNEL); if (!hpw) return AE_NO_MEMORY; INIT_WORK(&hpw->work, acpi_hotplug_work_fn); - hpw->func = func; - hpw->data = data; + hpw->adev = adev; hpw->src = src; /* * We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 361b40c10c3..9c62340c236 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -370,6 +370,30 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) return NULL; } +#if IS_ENABLED(CONFIG_ISA) || IS_ENABLED(CONFIG_EISA) +static int acpi_isa_register_gsi(struct pci_dev *dev) +{ + u32 dev_gsi; + + /* Interrupt Line values above 0xF are forbidden */ + if (dev->irq > 0 && (dev->irq <= 0xF) && + (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) { + dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n", + pin_name(dev->pin), dev->irq); + acpi_register_gsi(&dev->dev, dev_gsi, + ACPI_LEVEL_SENSITIVE, + ACPI_ACTIVE_LOW); + return 0; + } + return -EINVAL; +} +#else +static inline int acpi_isa_register_gsi(struct pci_dev *dev) +{ + return -ENODEV; +} +#endif + int acpi_pci_irq_enable(struct pci_dev *dev) { struct acpi_prt_entry *entry; @@ -416,19 +440,9 @@ int acpi_pci_irq_enable(struct pci_dev *dev) * driver reported one, then use it. Exit in any case. */ if (gsi < 0) { - u32 dev_gsi; - /* Interrupt Line values above 0xF are forbidden */ - if (dev->irq > 0 && (dev->irq <= 0xF) && - (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) { - dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n", - pin_name(pin), dev->irq); - acpi_register_gsi(&dev->dev, dev_gsi, - ACPI_LEVEL_SENSITIVE, - ACPI_ACTIVE_LOW); - } else { + if (acpi_isa_register_gsi(dev)) dev_warn(&dev->dev, "PCI INT %c: no GSI\n", pin_name(pin)); - } kfree(entry); return 0; diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 9418c7a1f78..cfd7581cc19 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -43,8 +43,6 @@ #include "internal.h" -#define PREFIX "ACPI: " - #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_link"); #define ACPI_PCI_LINK_CLASS "pci_irq_routing" diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c1c4102e647..d388f13d48b 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -39,8 +39,6 @@ #include "internal.h" -#define PREFIX "ACPI: " - #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_root"); #define ACPI_PCI_ROOT_CLASS "pci_bridge" @@ -51,7 +49,7 @@ static void acpi_pci_root_remove(struct acpi_device *device); static int acpi_pci_root_scan_dependent(struct acpi_device *adev) { - acpiphp_check_host_bridge(adev->handle); + acpiphp_check_host_bridge(adev); return 0; } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index ad7da686e6e..e0bcfb642b5 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -46,8 +46,6 @@ #include "sleep.h" #include "internal.h" -#define PREFIX "ACPI: " - #define _COMPONENT ACPI_POWER_COMPONENT ACPI_MODULE_NAME("power"); #define ACPI_POWER_CLASS "power_resource" diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index a4eea9a508d..57e0769656c 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -15,7 +15,6 @@ #include "internal.h" -#define PREFIX "ACPI: " #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_core"); diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index c1c35623550..7f70f3182d5 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -41,8 +41,6 @@ #include "internal.h" -#define PREFIX "ACPI: " - #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82 diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index ff90054f04f..cfc8aba72f8 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -156,17 +156,9 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) */ static void acpi_processor_ppc_ost(acpi_handle handle, int status) { - union acpi_object params[2] = { - {.type = ACPI_TYPE_INTEGER,}, - {.type = ACPI_TYPE_INTEGER,}, - }; - struct acpi_object_list arg_list = {2, params}; - - if (acpi_has_method(handle, "_OST")) { - params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; - params[1].integer.value = status; - acpi_evaluate_object(handle, "_OST", &arg_list, NULL); - } + if (acpi_has_method(handle, "_OST")) + acpi_evaluate_ost(handle, ACPI_PROCESSOR_NOTIFY_PERFORMANCE, + status, NULL); } int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index dbd48498b93..366ca40a6f7 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -37,12 +37,12 @@ #include <linux/power_supply.h> #include "sbshc.h" +#include "battery.h" #define PREFIX "ACPI: " #define ACPI_SBS_CLASS "sbs" #define ACPI_AC_CLASS "ac_adapter" -#define ACPI_BATTERY_CLASS "battery" #define ACPI_SBS_DEVICE_NAME "Smart Battery System" #define ACPI_SBS_FILE_INFO "info" #define ACPI_SBS_FILE_STATE "state" diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 57b053f424d..1870223cb1a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); DEFINE_MUTEX(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); +static DEFINE_MUTEX(acpi_hp_context_lock); struct acpi_device_bus_id{ char bus_id[15]; @@ -60,6 +61,27 @@ void acpi_scan_lock_release(void) } EXPORT_SYMBOL_GPL(acpi_scan_lock_release); +void acpi_lock_hp_context(void) +{ + mutex_lock(&acpi_hp_context_lock); +} + +void acpi_unlock_hp_context(void) +{ + mutex_unlock(&acpi_hp_context_lock); +} + +void acpi_initialize_hp_context(struct acpi_device *adev, + struct acpi_hotplug_context *hp, + int (*notify)(struct acpi_device *, u32), + void (*uevent)(struct acpi_device *, u32)) +{ + acpi_lock_hp_context(); + acpi_set_hp_context(adev, hp, notify, uevent, NULL); + acpi_unlock_hp_context(); +} +EXPORT_SYMBOL_GPL(acpi_initialize_hp_context); + int acpi_scan_add_handler(struct acpi_scan_handler *handler) { if (!handler || !handler->attach) @@ -439,90 +461,75 @@ static int acpi_scan_bus_check(struct acpi_device *adev) return 0; } -static void acpi_device_hotplug(void *data, u32 src) +static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) { - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - struct acpi_device *adev = data; - int error; - - lock_device_hotplug(); - mutex_lock(&acpi_scan_lock); - - /* - * The device object's ACPI handle cannot become invalid as long as we - * are holding acpi_scan_lock, but it may have become invalid before - * that lock was acquired. - */ - if (adev->handle == INVALID_ACPI_HANDLE) - goto out; - - switch (src) { + switch (type) { case ACPI_NOTIFY_BUS_CHECK: - error = acpi_scan_bus_check(adev); - break; + return acpi_scan_bus_check(adev); case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); - break; + return acpi_scan_device_check(adev); case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: - error = acpi_scan_hot_remove(adev); - break; - default: - error = -EINVAL; - break; + if (adev->handler && !adev->handler->hotplug.enabled) { + dev_info(&adev->dev, "Eject disabled\n"); + return -EPERM; + } + acpi_evaluate_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); + return acpi_scan_hot_remove(adev); } - if (!error) - ost_code = ACPI_OST_SC_SUCCESS; - - out: - acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); - put_device(&adev->dev); - mutex_unlock(&acpi_scan_lock); - unlock_device_hotplug(); + return -EINVAL; } -static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) +void acpi_device_hotplug(struct acpi_device *adev, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - struct acpi_device *adev; - acpi_status status; + int error = -ENODEV; - if (acpi_bus_get_device(handle, &adev)) - goto err_out; + lock_device_hotplug(); + mutex_lock(&acpi_scan_lock); - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); - break; - case ACPI_NOTIFY_DEVICE_CHECK: - acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); - break; - case ACPI_NOTIFY_EJECT_REQUEST: - acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!adev->handler) - goto err_out; + /* + * The device object's ACPI handle cannot become invalid as long as we + * are holding acpi_scan_lock, but it might have become invalid before + * that lock was acquired. + */ + if (adev->handle == INVALID_ACPI_HANDLE) + goto err_out; - if (!adev->handler->hotplug.enabled) { - acpi_handle_err(handle, "Eject disabled\n"); + if (adev->flags.is_dock_station) { + error = dock_notify(adev, src); + } else if (adev->flags.hotplug_notify) { + error = acpi_generic_hotplug_event(adev, src); + if (error == -EPERM) { ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; goto err_out; } - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); - break; - default: - /* non-hotplug event; possibly handled by other handler */ - return; - } - get_device(&adev->dev); - status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); - if (ACPI_SUCCESS(status)) - return; + } else { + int (*notify)(struct acpi_device *, u32); - put_device(&adev->dev); + acpi_lock_hp_context(); + notify = adev->hp ? adev->hp->notify : NULL; + acpi_unlock_hp_context(); + /* + * There may be additional notify handlers for device objects + * without the .event() callback, so ignore them here. + */ + if (notify) + error = notify(adev, src); + else + goto out; + } + if (!error) + ost_code = ACPI_OST_SC_SUCCESS; err_out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); + acpi_evaluate_ost(adev->handle, src, ost_code, NULL); + + out: + acpi_bus_put_acpi_device(adev); + mutex_unlock(&acpi_scan_lock); + unlock_device_hotplug(); } static ssize_t real_power_state_show(struct device *dev, @@ -570,17 +577,14 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) return -ENODEV; - acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); get_device(&acpi_device->dev); - status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, - ACPI_OST_EC_OSPM_EJECT); + status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT); if (ACPI_SUCCESS(status)) return count; put_device(&acpi_device->dev); - acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, - ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); + acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, + ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; } @@ -1114,14 +1118,16 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context) mutex_unlock(&acpi_device_del_lock); } -int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) +static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device, + void (*callback)(void *)) { acpi_status status; if (!device) return -EINVAL; - status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device); + status = acpi_get_data_full(handle, acpi_scan_drop_device, + (void **)device, callback); if (ACPI_FAILURE(status) || !*device) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", handle)); @@ -1129,8 +1135,32 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) } return 0; } + +int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) +{ + return acpi_get_device_data(handle, device, NULL); +} EXPORT_SYMBOL(acpi_bus_get_device); +static void get_acpi_device(void *dev) +{ + if (dev) + get_device(&((struct acpi_device *)dev)->dev); +} + +struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle) +{ + struct acpi_device *adev = NULL; + + acpi_get_device_data(handle, &adev, get_acpi_device); + return adev; +} + +void acpi_bus_put_acpi_device(struct acpi_device *adev) +{ + put_device(&adev->dev); +} + int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)) { @@ -1641,6 +1671,27 @@ bool acpi_bay_match(acpi_handle handle) return acpi_ata_match(phandle); } +bool acpi_device_is_battery(struct acpi_device *adev) +{ + struct acpi_hardware_id *hwid; + + list_for_each_entry(hwid, &adev->pnp.ids, list) + if (!strcmp("PNP0C0A", hwid->id)) + return true; + + return false; +} + +static bool is_ejectable_bay(struct acpi_device *adev) +{ + acpi_handle handle = adev->handle; + + if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(adev)) + return true; + + return acpi_bay_match(handle); +} + /* * acpi_dock_match - see if an acpi object has a _DCK method */ @@ -1706,6 +1757,20 @@ static bool acpi_ibm_smbus_match(acpi_handle handle) return false; } +static bool acpi_object_is_system_bus(acpi_handle handle) +{ + acpi_handle tmp; + + if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_SB", &tmp)) && + tmp == handle) + return true; + if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_TZ", &tmp)) && + tmp == handle) + return true; + + return false; +} + static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, int device_type) { @@ -1757,8 +1822,10 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, acpi_add_id(pnp, ACPI_DOCK_HID); else if (acpi_ibm_smbus_match(handle)) acpi_add_id(pnp, ACPI_SMBUS_IBM_HID); - else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) { - acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ + else if (list_empty(&pnp->ids) && + acpi_object_is_system_bus(handle)) { + /* \_SB, \_TZ, LNXSYBUS */ + acpi_add_id(pnp, ACPI_BUS_HID); strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME); strcpy(pnp->device_class, ACPI_BUS_CLASS); } @@ -1941,33 +2008,23 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val) mutex_unlock(&acpi_scan_lock); } -static void acpi_scan_init_hotplug(acpi_handle handle, int type) +static void acpi_scan_init_hotplug(struct acpi_device *adev) { - struct acpi_device_pnp pnp = {}; struct acpi_hardware_id *hwid; - struct acpi_scan_handler *handler; - INIT_LIST_HEAD(&pnp.ids); - acpi_set_pnp_ids(handle, &pnp, type); - - if (!pnp.type.hardware_id) - goto out; + if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev)) { + acpi_dock_add(adev); + return; + } + list_for_each_entry(hwid, &adev->pnp.ids, list) { + struct acpi_scan_handler *handler; - /* - * This relies on the fact that acpi_install_notify_handler() will not - * install the same notify handler routine twice for the same handle. - */ - list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); if (handler) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - acpi_hotplug_notify_cb, handler); + adev->flags.hotplug_notify = true; break; } } - -out: - acpi_free_pnp_ids(&pnp); } static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, @@ -1991,12 +2048,12 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, return AE_OK; } - acpi_scan_init_hotplug(handle, type); - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; + acpi_scan_init_hotplug(device); + out: if (!*return_value) *return_value = device; @@ -2030,8 +2087,12 @@ static int acpi_scan_attach_handler(struct acpi_device *device) static void acpi_bus_attach(struct acpi_device *device) { struct acpi_device *child; + acpi_handle ejd; int ret; + if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd))) + register_dock_dependent_device(device, ejd); + acpi_bus_get_status(device); /* Skip devices that are not present. */ if (!acpi_device_is_present(device)) { @@ -2184,7 +2245,6 @@ int __init acpi_scan_init(void) acpi_cmos_rtc_init(); acpi_container_init(); acpi_memory_hotplug_init(); - acpi_dock_init(); mutex_lock(&acpi_scan_lock); /* diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 91a32cefb11..38cb9782d4b 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -12,8 +12,6 @@ #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("sysfs"); -#define PREFIX "ACPI: " - #ifdef CONFIG_ACPI_DEBUG /* * ACPI debug sysfs I/F, including: diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 5837f857ac2..21782290df4 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -23,6 +23,8 @@ * */ +#define pr_fmt(fmt) "ACPI: " fmt + #include <linux/init.h> #include <linux/kernel.h> #include <linux/smp.h> @@ -33,8 +35,6 @@ #include <linux/acpi.h> #include <linux/bootmem.h> -#define PREFIX "ACPI: " - #define ACPI_MAX_TABLES 128 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; @@ -55,10 +55,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_local_apic *p = (struct acpi_madt_local_apic *)header; - printk(KERN_INFO PREFIX - "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n", - p->processor_id, p->id, - (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); + pr_info("LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n", + p->processor_id, p->id, + (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); } break; @@ -66,11 +65,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_local_x2apic *p = (struct acpi_madt_local_x2apic *)header; - printk(KERN_INFO PREFIX - "X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n", - p->local_apic_id, p->uid, - (p->lapic_flags & ACPI_MADT_ENABLED) ? - "enabled" : "disabled"); + pr_info("X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n", + p->local_apic_id, p->uid, + (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); } break; @@ -78,9 +75,8 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_io_apic *p = (struct acpi_madt_io_apic *)header; - printk(KERN_INFO PREFIX - "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", - p->id, p->address, p->global_irq_base); + pr_info("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", + p->id, p->address, p->global_irq_base); } break; @@ -88,18 +84,15 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_interrupt_override *p = (struct acpi_madt_interrupt_override *)header; - printk(KERN_INFO PREFIX - "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n", - p->bus, p->source_irq, p->global_irq, - mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], - mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]); + pr_info("INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n", + p->bus, p->source_irq, p->global_irq, + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]); if (p->inti_flags & ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)) - printk(KERN_INFO PREFIX - "INT_SRC_OVR unexpected reserved flags: 0x%x\n", - p->inti_flags & + pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x\n", + p->inti_flags & ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)); - } break; @@ -107,11 +100,10 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_nmi_source *p = (struct acpi_madt_nmi_source *)header; - printk(KERN_INFO PREFIX - "NMI_SRC (%s %s global_irq %d)\n", - mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], - mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], - p->global_irq); + pr_info("NMI_SRC (%s %s global_irq %d)\n", + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], + p->global_irq); } break; @@ -119,12 +111,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_local_apic_nmi *p = (struct acpi_madt_local_apic_nmi *)header; - printk(KERN_INFO PREFIX - "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n", - p->processor_id, - mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ], - mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], - p->lint); + pr_info("LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n", + p->processor_id, + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], + p->lint); } break; @@ -137,12 +128,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK; trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2; - printk(KERN_INFO PREFIX - "X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n", - p->uid, - mps_inti_flags_polarity[polarity], - mps_inti_flags_trigger[trigger], - p->lint); + pr_info("X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n", + p->uid, + mps_inti_flags_polarity[polarity], + mps_inti_flags_trigger[trigger], + p->lint); } break; @@ -150,9 +140,8 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_local_apic_override *p = (struct acpi_madt_local_apic_override *)header; - printk(KERN_INFO PREFIX - "LAPIC_ADDR_OVR (address[%p])\n", - (void *)(unsigned long)p->address); + pr_info("LAPIC_ADDR_OVR (address[%p])\n", + (void *)(unsigned long)p->address); } break; @@ -160,10 +149,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_io_sapic *p = (struct acpi_madt_io_sapic *)header; - printk(KERN_INFO PREFIX - "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", - p->id, (void *)(unsigned long)p->address, - p->global_irq_base); + pr_info("IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", + p->id, (void *)(unsigned long)p->address, + p->global_irq_base); } break; @@ -171,10 +159,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_local_sapic *p = (struct acpi_madt_local_sapic *)header; - printk(KERN_INFO PREFIX - "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n", - p->processor_id, p->id, p->eid, - (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); + pr_info("LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n", + p->processor_id, p->id, p->eid, + (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); } break; @@ -182,19 +169,17 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { struct acpi_madt_interrupt_source *p = (struct acpi_madt_interrupt_source *)header; - printk(KERN_INFO PREFIX - "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", - mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], - mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], - p->type, p->id, p->eid, p->io_sapic_vector, - p->global_irq); + pr_info("PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], + p->type, p->id, p->eid, p->io_sapic_vector, + p->global_irq); } break; default: - printk(KERN_WARNING PREFIX - "Found unsupported MADT entry (type = 0x%x)\n", - header->type); + pr_warn("Found unsupported MADT entry (type = 0x%x)\n", + header->type); break; } } @@ -225,7 +210,7 @@ acpi_table_parse_entries(char *id, acpi_get_table_with_size(id, 0, &table_header, &tbl_size); if (!table_header) { - printk(KERN_WARNING PREFIX "%4.4s not present\n", id); + pr_warn("%4.4s not present\n", id); return -ENODEV; } @@ -248,7 +233,7 @@ acpi_table_parse_entries(char *id, * infinite loop. */ if (entry->length == 0) { - pr_err(PREFIX "[%4.4s:0x%02x] Invalid zero length\n", id, entry_id); + pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id); goto err; } @@ -256,8 +241,8 @@ acpi_table_parse_entries(char *id, ((unsigned long)entry + entry->length); } if (max_entries && count > max_entries) { - printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of " - "%i found\n", id, entry_id, count - max_entries, count); + pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n", + id, entry_id, count - max_entries, count); } early_acpi_os_unmap_memory((char *)table_header, tbl_size); @@ -322,13 +307,11 @@ static void __init check_multiple_madt(void) acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size); if (table) { - printk(KERN_WARNING PREFIX - "BIOS bug: multiple APIC/MADT found," - " using %d\n", acpi_apic_instance); - printk(KERN_WARNING PREFIX - "If \"acpi_apic_instance=%d\" works better, " - "notify linux-acpi@vger.kernel.org\n", - acpi_apic_instance ? 0 : 2); + pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n", + acpi_apic_instance); + pr_warn("If \"acpi_apic_instance=%d\" works better, " + "notify linux-acpi@vger.kernel.org\n", + acpi_apic_instance ? 0 : 2); early_acpi_os_unmap_memory(table, tbl_size); } else @@ -365,8 +348,7 @@ static int __init acpi_parse_apic_instance(char *str) acpi_apic_instance = simple_strtoul(str, NULL, 0); - printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n", - acpi_apic_instance); + pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance); return 0; } diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 08626c851be..96406855333 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -43,6 +43,7 @@ #include <linux/device.h> #include <linux/thermal.h> #include <linux/acpi.h> +#include <linux/workqueue.h> #include <asm/uaccess.h> #define PREFIX "ACPI: " @@ -90,6 +91,8 @@ static int psv; module_param(psv, int, 0644); MODULE_PARM_DESC(psv, "Disable or override all passive trip points."); +static struct workqueue_struct *acpi_thermal_pm_queue; + static int acpi_thermal_add(struct acpi_device *device); static int acpi_thermal_remove(struct acpi_device *device); static void acpi_thermal_notify(struct acpi_device *device, u32 event); @@ -101,11 +104,13 @@ static const struct acpi_device_id thermal_device_ids[] = { MODULE_DEVICE_TABLE(acpi, thermal_device_ids); #ifdef CONFIG_PM_SLEEP +static int acpi_thermal_suspend(struct device *dev); static int acpi_thermal_resume(struct device *dev); #else +#define acpi_thermal_suspend NULL #define acpi_thermal_resume NULL #endif -static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume); +static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume); static struct acpi_driver acpi_thermal_driver = { .name = "thermal", @@ -186,6 +191,7 @@ struct acpi_thermal { struct thermal_zone_device *thermal_zone; int tz_enabled; int kelvin_offset; + struct work_struct thermal_check_work; }; /* -------------------------------------------------------------------------- @@ -1064,6 +1070,13 @@ static void acpi_thermal_guess_offset(struct acpi_thermal *tz) tz->kelvin_offset = 2732; } +static void acpi_thermal_check_fn(struct work_struct *work) +{ + struct acpi_thermal *tz = container_of(work, struct acpi_thermal, + thermal_check_work); + acpi_thermal_check(tz); +} + static int acpi_thermal_add(struct acpi_device *device) { int result = 0; @@ -1093,6 +1106,8 @@ static int acpi_thermal_add(struct acpi_device *device) if (result) goto free_memory; + INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn); + pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device), acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature)); goto end; @@ -1110,6 +1125,7 @@ static int acpi_thermal_remove(struct acpi_device *device) if (!device || !acpi_driver_data(device)) return -EINVAL; + flush_workqueue(acpi_thermal_pm_queue); tz = acpi_driver_data(device); acpi_thermal_unregister_thermal_zone(tz); @@ -1118,6 +1134,13 @@ static int acpi_thermal_remove(struct acpi_device *device) } #ifdef CONFIG_PM_SLEEP +static int acpi_thermal_suspend(struct device *dev) +{ + /* Make sure the previously queued thermal check work has been done */ + flush_workqueue(acpi_thermal_pm_queue); + return 0; +} + static int acpi_thermal_resume(struct device *dev) { struct acpi_thermal *tz; @@ -1148,7 +1171,7 @@ static int acpi_thermal_resume(struct device *dev) tz->state.active |= tz->trips.active[i].flags.enabled; } - acpi_thermal_check(tz); + queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); return AE_OK; } @@ -1240,16 +1263,22 @@ static int __init acpi_thermal_init(void) return -ENODEV; } + acpi_thermal_pm_queue = create_workqueue("acpi_thermal_pm"); + if (!acpi_thermal_pm_queue) + return -ENODEV; + result = acpi_bus_register_driver(&acpi_thermal_driver); - if (result < 0) + if (result < 0) { + destroy_workqueue(acpi_thermal_pm_queue); return -ENODEV; + } return 0; } static void __exit acpi_thermal_exit(void) { - + destroy_workqueue(acpi_thermal_pm_queue); acpi_bus_unregister_driver(&acpi_thermal_driver); return; diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 85e3b612bdc..0f5f78fa654 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -422,7 +422,7 @@ out: EXPORT_SYMBOL(acpi_get_physical_device_location); /** - * acpi_evaluate_hotplug_ost: Evaluate _OST for hotplug operations + * acpi_evaluate_ost: Evaluate _OST for hotplug operations * @handle: ACPI device handle * @source_event: source event code * @status_code: status code @@ -433,17 +433,15 @@ EXPORT_SYMBOL(acpi_get_physical_device_location); * When the platform does not support _OST, this function has no effect. */ acpi_status -acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, - u32 status_code, struct acpi_buffer *status_buf) +acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code, + struct acpi_buffer *status_buf) { -#ifdef ACPI_HOTPLUG_OST union acpi_object params[3] = { {.type = ACPI_TYPE_INTEGER,}, {.type = ACPI_TYPE_INTEGER,}, {.type = ACPI_TYPE_BUFFER,} }; struct acpi_object_list arg_list = {3, params}; - acpi_status status; params[0].integer.value = source_event; params[1].integer.value = status_code; @@ -455,13 +453,9 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, params[2].buffer.length = 0; } - status = acpi_evaluate_object(handle, "_OST", &arg_list, NULL); - return status; -#else - return AE_OK; -#endif + return acpi_evaluate_object(handle, "_OST", &arg_list, NULL); } -EXPORT_SYMBOL(acpi_evaluate_hotplug_ost); +EXPORT_SYMBOL(acpi_evaluate_ost); /** * acpi_handle_printk: Print message with ACPI prefix and object path diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index b6ba88ed31a..48c7e8af9c9 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -45,8 +45,6 @@ #include "internal.h" -#define PREFIX "ACPI: " - #define ACPI_VIDEO_BUS_NAME "Video Bus" #define ACPI_VIDEO_DEVICE_NAME "Video Device" #define ACPI_VIDEO_NOTIFY_SWITCH 0x80 diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 19080c8e2f2..33e3db548a2 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -40,8 +40,6 @@ #include "internal.h" -#define PREFIX "ACPI: " - ACPI_MODULE_NAME("video"); #define _COMPONENT ACPI_VIDEO_COMPONENT diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 9e69a530869..acb95dffdb6 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct ata_device *dev) dev->gtf_cache = NULL; } +struct ata_acpi_hotplug_context { + struct acpi_hotplug_context hp; + union { + struct ata_port *ap; + struct ata_device *dev; + } data; +}; + +#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data) + /** * ata_dev_acpi_handle - provide the acpi_handle for an ata_device * @dev: the acpi_handle returned will correspond to this device @@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, ata_port_wait_eh(ap); } -static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) +static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event) { - struct ata_device *dev = data; - + struct ata_device *dev = ata_hotplug_data(adev->hp).dev; ata_acpi_handle_hotplug(dev->link->ap, dev, event); + return 0; } -static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) +static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event) { - struct ata_port *ap = data; - - ata_acpi_handle_hotplug(ap, NULL, event); + ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event); + return 0; } static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, @@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, } } -static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event) { - ata_acpi_uevent(data, NULL, event); + ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event); } -static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event) { - struct ata_device *dev = data; + struct ata_device *dev = ata_hotplug_data(adev->hp).dev; ata_acpi_uevent(dev->link->ap, dev, event); } -static const struct acpi_dock_ops ata_acpi_dev_dock_ops = { - .handler = ata_acpi_dev_notify_dock, - .uevent = ata_acpi_dev_uevent, -}; - -static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { - .handler = ata_acpi_ap_notify_dock, - .uevent = ata_acpi_ap_uevent, -}; - /* bind acpi handle to pata port */ void ata_acpi_bind_port(struct ata_port *ap) { struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); + struct acpi_device *adev; + struct ata_acpi_hotplug_context *context; if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion) return; @@ -188,9 +189,17 @@ void ata_acpi_bind_port(struct ata_port *ap) if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; - /* we might be on a docking station */ - register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev), - &ata_acpi_ap_dock_ops, ap, NULL, NULL); + adev = ACPI_COMPANION(&ap->tdev); + if (!adev || adev->hp) + return; + + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return; + + context->data.ap = ap; + acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock, + ata_acpi_ap_uevent); } void ata_acpi_bind_dev(struct ata_device *dev) @@ -198,7 +207,8 @@ void ata_acpi_bind_dev(struct ata_device *dev) struct ata_port *ap = dev->link->ap; struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); - struct acpi_device *parent; + struct acpi_device *parent, *adev; + struct ata_acpi_hotplug_context *context; u64 adr; /* @@ -221,9 +231,17 @@ void ata_acpi_bind_dev(struct ata_device *dev) } acpi_preset_companion(&dev->tdev, parent, adr); + adev = ACPI_COMPANION(&dev->tdev); + if (!adev || adev->hp) + return; + + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return; - register_hotplug_dock_device(ata_dev_acpi_handle(dev), - &ata_acpi_dev_dock_ops, dev, NULL, NULL); + context->data.dev = dev; + acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock, + ata_acpi_dev_uevent); } /** diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index b6162be4df4..2b859249303 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -93,7 +93,6 @@ struct acpiphp_slot { struct list_head funcs; /* one slot may have different objects (i.e. for each function) */ struct slot *slot; - struct mutex crit_sect; u8 device; /* pci device# */ u32 flags; /* see below */ @@ -117,20 +116,30 @@ struct acpiphp_func { }; struct acpiphp_context { - acpi_handle handle; + struct acpi_hotplug_context hp; struct acpiphp_func func; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); } +static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) +{ + return func_to_context(func)->hp.self; +} + static inline acpi_handle func_to_handle(struct acpiphp_func *func) { - return func_to_context(func)->handle; + return func_to_acpi_device(func)->handle; } /* @@ -158,7 +167,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7c7a388c85a..828acf422c1 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -58,71 +58,59 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static DEFINE_MUTEX(acpiphp_context_lock); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type); +static void acpiphp_post_dock_fixup(struct acpi_device *adev); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); -static void hotplug_event(acpi_handle handle, u32 type, void *data); +static void hotplug_event(u32 type, struct acpiphp_context *context); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) -{ - /* Intentionally empty. */ -} - /** * acpiphp_init_context - Create hotplug context and grab a reference to it. - * @handle: ACPI object handle to create the context for. + * @adev: ACPI device object to create the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->handle = handle; context->refcount = 1; - status = acpi_attach_data(handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_notify, NULL, + acpiphp_post_dock_fixup); return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context; - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + if (!adev->hp) + return NULL; + + context = to_acpiphp_context(adev->hp); + context->refcount++; return context; } /** * acpiphp_put_context - Drop a reference to ACPI hotplug context. - * @handle: ACPI object handle to put the context for. + * @context: ACPI hotplug context to drop a reference to. * * The context object is removed if there are no more references to it. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static void acpiphp_put_context(struct acpiphp_context *context) { @@ -130,7 +118,7 @@ static void acpiphp_put_context(struct acpiphp_context *context) return; WARN_ON(context->bridge); - acpi_detach_data(context->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -144,6 +132,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge) kref_put(&bridge->ref, free_bridge); } +static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev) +{ + struct acpiphp_context *context; + + acpi_lock_hp_context(); + context = acpiphp_get_context(adev); + if (!context || context->func.parent->is_going_away) { + acpi_unlock_hp_context(); + return NULL; + } + get_bridge(context->func.parent); + acpiphp_put_context(context); + acpi_unlock_hp_context(); + return context; +} + +static void acpiphp_let_context_go(struct acpiphp_context *context) +{ + put_bridge(context->func.parent); +} + static void free_bridge(struct kref *kref) { struct acpiphp_context *context; @@ -151,7 +160,7 @@ static void free_bridge(struct kref *kref) struct acpiphp_slot *slot, *next; struct acpiphp_func *func, *tmp; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = container_of(kref, struct acpiphp_bridge, ref); @@ -175,31 +184,32 @@ static void free_bridge(struct kref *kref) pci_dev_put(bridge->pci_dev); kfree(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } -/* - * the _DCK method can do funny things... and sometimes not - * hah-hah funny. +/** + * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices. + * @adev: ACPI device object corresponding to a PCI device. * - * TBD - figure out a way to only call fixups for - * systems that require them. + * TBD - figure out a way to only call fixups for systems that require them. */ -static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) +static void acpiphp_post_dock_fixup(struct acpi_device *adev) { - struct acpiphp_context *context = data; - struct pci_bus *bus = context->func.slot->bus; + struct acpiphp_context *context = acpiphp_grab_context(adev); + struct pci_bus *bus; u32 buses; - if (!bus->self) + if (!context) return; + bus = context->func.slot->bus; + if (!bus->self) + goto out; + /* fixup bad _DCK function that rewrites * secondary bridge on slot */ - pci_read_config_dword(bus->self, - PCI_PRIMARY_BUS, - &buses); + pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses); if (((buses >> 8) & 0xff) != bus->busn_res.start) { buses = (buses & 0xff000000) @@ -208,33 +218,11 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) | ((unsigned int)(bus->busn_res.end) << 16); pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); } -} - -static void dock_event(acpi_handle handle, u32 type, void *data) -{ - struct acpiphp_context *context; - - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->handle != handle) - || context->func.parent->is_going_away) { - mutex_unlock(&acpiphp_context_lock); - return; - } - get_bridge(context->func.parent); - acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); - - hotplug_event(handle, type, data); - put_bridge(context->func.parent); + out: + acpiphp_let_context_go(context); } -static const struct acpi_dock_ops acpiphp_dock_ops = { - .fixup = post_dock_fixups, - .handler = dock_event, -}; - /* Check whether the PCI device is managed by native PCIe hotplug driver */ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) { @@ -264,26 +252,19 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) return true; } -static void acpiphp_dock_init(void *data) -{ - struct acpiphp_context *context = data; - - get_bridge(context->func.parent); -} - -static void acpiphp_dock_release(void *data) -{ - struct acpiphp_context *context = data; - - put_bridge(context->func.parent); -} - -/* callback routine to register each ACPI PCI slot object */ -static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, - void **rv) +/** + * acpiphp_add_context - Add ACPIPHP context to an ACPI device object. + * @handle: ACPI handle of the object to add a context to. + * @lvl: Not used. + * @data: The object's parent ACPIPHP bridge. + * @rv: Not used. + */ +static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, + void **rv) { struct acpiphp_bridge *bridge = data; struct acpiphp_context *context; + struct acpi_device *adev; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; @@ -293,9 +274,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, struct pci_dev *pdev = bridge->pci_dev; u32 val; - if (pdev && device_is_managed_by_native_pciehp(pdev)) - return AE_OK; - status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) @@ -303,31 +281,34 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, "can't evaluate _ADR (%#x)\n", status); return AE_OK; } + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; device = (adr >> 16) & 0xffff; function = adr & 0xffff; - mutex_lock(&acpiphp_context_lock); - context = acpiphp_init_context(handle); + acpi_lock_hp_context(); + context = acpiphp_init_context(adev); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); acpi_handle_err(handle, "No hotplug context\n"); return AE_NOT_EXIST; } newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); - if (acpi_has_method(handle, "_EJ0")) + /* + * If this is a dock device, its _EJ0 should be executed by the dock + * notify handler after calling _DCK. + */ + if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; - if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; - /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) if (slot->device == device) @@ -335,19 +316,26 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - status = AE_NO_MEMORY; - goto err; + acpi_lock_hp_context(); + acpiphp_put_context(context); + acpi_unlock_hp_context(); + return AE_NO_MEMORY; } slot->bus = bridge->pci_bus; slot->device = device; INIT_LIST_HEAD(&slot->funcs); - mutex_init(&slot->crit_sect); list_add_tail(&slot->node, &bridge->slots); - /* Register slots for ejectable functions only. */ - if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) { + /* + * Expose slots to user space for functions that have _EJ0 or _RMV or + * are located in dock stations. Do not expose them for devices handled + * by the native PCIe hotplug (PCIeHP), becuase that code is supposed to + * expose slots to user space in those cases. + */ + if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev)) + && !(pdev && device_is_managed_by_native_pciehp(pdev))) { unsigned long long sun; int retval; @@ -381,44 +369,16 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, &val, 60*1000)) slot->flags |= SLOT_ENABLED; - if (is_dock_device(handle)) { - /* we don't want to call this device's _EJ0 - * because we want the dock notify handler - * to call it after it calls _DCK - */ - newfunc->flags &= ~FUNC_HAS_EJ0; - if (register_hotplug_dock_device(handle, - &acpiphp_dock_ops, context, - acpiphp_dock_init, acpiphp_dock_release)) - pr_debug("failed to register dock device\n"); - } - - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } - return AE_OK; - - err: - mutex_lock(&acpiphp_context_lock); - acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); - return status; } -static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) +static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) { struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); + acpi_lock_hp_context(); + context = acpiphp_get_context(adev); if (context) { bridge = context->bridge; if (bridge) @@ -426,7 +386,7 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) acpiphp_put_context(context); } - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return bridge; } @@ -434,22 +394,15 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { - acpi_handle handle = func_to_handle(func); - - if (is_dock_device(handle)) - unregister_hotplug_dock_device(handle); + struct acpi_device *adev = func_to_acpi_device(func); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + acpi_lock_hp_context(); + adev->hp->notify = NULL; + adev->hp->fixup = NULL; + acpi_unlock_hp_context(); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -460,9 +413,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) list_del(&bridge->list); mutex_unlock(&bridge_mutex); - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge->is_going_away = true; - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } /** @@ -492,33 +445,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) return max; } -/** - * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. - * @handle: ACPI device object handle to start from. - */ -static void acpiphp_bus_trim(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); - if (adev) - acpi_bus_trim(adev); -} - -/** - * acpiphp_bus_add - Scan ACPI namespace subtree. - * @handle: ACPI object handle to start the scan from. - */ -static void acpiphp_bus_add(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_scan(handle); - acpi_bus_get_device(handle, &adev); - if (acpi_device_enumerated(adev)) - acpi_device_set_power(adev, ACPI_STATE_D0); -} - static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) { struct acpiphp_func *func; @@ -558,9 +484,13 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot) { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_add(func_to_handle(func)); + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = func_to_acpi_device(func); + acpi_bus_scan(adev->handle); + if (acpi_device_enumerated(adev)) + acpi_device_set_power(adev, ACPI_STATE_D0); + } return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); } @@ -625,32 +555,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot) } } -/* return first device in slot, acquiring a reference on it */ -static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) -{ - struct pci_bus *bus = slot->bus; - struct pci_dev *dev; - struct pci_dev *ret = NULL; - - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) - if (PCI_SLOT(dev->devfn) == slot->device) { - ret = pci_dev_get(dev); - break; - } - up_read(&pci_bus_sem); - - return ret; -} - /** * disable_slot - disable a slot * @slot: ACPI PHP slot */ static void disable_slot(struct acpiphp_slot *slot) { + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *prev; struct acpiphp_func *func; - struct pci_dev *pdev; /* * enable_slot() enumerates all functions in this device via @@ -658,22 +571,18 @@ static void disable_slot(struct acpiphp_slot *slot) * methods (_EJ0, etc.) or not. Therefore, we remove all functions * here. */ - while ((pdev = dev_in_slot(slot))) { - pci_stop_and_remove_bus_device(pdev); - pci_dev_put(pdev); - } + list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + pci_stop_and_remove_bus_device(dev); list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_trim(func_to_handle(func)); + acpi_bus_trim(func_to_acpi_device(func)); slot->flags &= (~SLOT_ENABLED); } -static bool acpiphp_no_hotplug(acpi_handle handle) +static bool acpiphp_no_hotplug(struct acpi_device *adev) { - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); return adev && adev->flags.no_hotplug; } @@ -682,7 +591,7 @@ static bool slot_no_hotplug(struct acpiphp_slot *slot) struct acpiphp_func *func; list_for_each_entry(func, &slot->funcs, sibling) - if (acpiphp_no_hotplug(func_to_handle(func))) + if (acpiphp_no_hotplug(func_to_acpi_device(func))) return true; return false; @@ -747,28 +656,25 @@ static inline bool device_status_valid(unsigned int sta) */ static void trim_stale_devices(struct pci_dev *dev) { - acpi_handle handle = ACPI_HANDLE(&dev->dev); + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); struct pci_bus *bus = dev->subordinate; bool alive = false; - if (handle) { + if (adev) { acpi_status status; unsigned long long sta; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) - || acpiphp_no_hotplug(handle); + || acpiphp_no_hotplug(adev); } - if (!alive) { - u32 v; + if (!alive) + alive = pci_device_is_present(dev); - /* Check if the device responds. */ - alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0); - } if (!alive) { pci_stop_and_remove_bus_device(dev); - if (handle) - acpiphp_bus_trim(handle); + if (adev) + acpi_bus_trim(adev); } else if (bus) { struct pci_dev *child, *tmp; @@ -800,7 +706,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) struct pci_bus *bus = slot->bus; struct pci_dev *dev, *tmp; - mutex_lock(&slot->crit_sect); if (slot_no_hotplug(slot)) { ; /* do nothing */ } else if (device_status_valid(get_slot_status(slot))) { @@ -815,7 +720,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) } else { disable_slot(slot); } - mutex_unlock(&slot->crit_sect); } } @@ -855,11 +759,11 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) * ACPI event handlers */ -void acpiphp_check_host_bridge(acpi_handle handle) +void acpiphp_check_host_bridge(struct acpi_device *adev) { struct acpiphp_bridge *bridge; - bridge = acpiphp_handle_to_bridge(handle); + bridge = acpiphp_dev_to_bridge(adev); if (bridge) { pci_lock_rescan_remove(); @@ -872,73 +776,52 @@ void acpiphp_check_host_bridge(acpi_handle handle) static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); -static void hotplug_event(acpi_handle handle, u32 type, void *data) +static void hotplug_event(u32 type, struct acpiphp_context *context) { - struct acpiphp_context *context = data; + acpi_handle handle = context->hp.self->handle; struct acpiphp_func *func = &context->func; + struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = context->bridge; if (bridge) get_bridge(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); pci_lock_rescan_remove(); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ - pr_debug("%s: Bus check notify on %s\n", __func__, objname); - pr_debug("%s: re-enumerating slots under %s\n", - __func__, objname); - if (bridge) { + acpi_handle_debug(handle, "Bus check in %s()\n", __func__); + if (bridge) acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; - - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - - mutex_lock(&slot->crit_sect); + else if (!(slot->flags & SLOT_IS_GOING_AWAY)) enable_slot(slot); - mutex_unlock(&slot->crit_sect); - } + break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ - pr_debug("%s: Device check notify on %s\n", __func__, objname); + acpi_handle_debug(handle, "Device check in %s()\n", __func__); if (bridge) { acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; - int ret; - - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - + } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { /* * Check if anything has changed in the slot and rescan * from the parent if that's the case. */ - mutex_lock(&slot->crit_sect); - ret = acpiphp_rescan_slot(slot); - mutex_unlock(&slot->crit_sect); - if (ret) + if (acpiphp_rescan_slot(slot)) acpiphp_check_bridge(func->parent); } break; case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ - pr_debug("%s: Device eject notify on %s\n", __func__, objname); - acpiphp_disable_and_eject_slot(func->slot); + acpi_handle_debug(handle, "Eject request in %s()\n", __func__); + acpiphp_disable_and_eject_slot(slot); break; } @@ -947,106 +830,41 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) +static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type) { - struct acpiphp_context *context = data; - acpi_handle handle = context->handle; - - acpi_scan_lock_acquire(); + struct acpiphp_context *context; - hotplug_event(handle, type, context); + context = acpiphp_grab_context(adev); + if (!context) + return -ENODATA; - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); - put_bridge(context->func.parent); + hotplug_event(type, context); + acpiphp_let_context_go(context); + return 0; } /** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure + * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus. + * @bus: PCI bus to enumerate the slots for. * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) -{ - struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_SUCCESS; - acpi_status status; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } - - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (!context || WARN_ON(context->handle != handle) - || context->func.parent->is_going_away) - goto err_out; - - get_bridge(context->func.parent); - acpiphp_put_context(context); - status = acpi_hotplug_execute(hotplug_event_work, context, type); - if (ACPI_SUCCESS(status)) { - mutex_unlock(&acpiphp_context_lock); - return; - } - put_bridge(context->func.parent); - - err_out: - mutex_unlock(&acpiphp_context_lock); - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); -} - -/* - * Create hotplug slots for the PCI bus. - * It should always return 0 to avoid skipping following notifiers. + * A "slot" is an object associated with a PCI device number. All functions + * (PCI devices) with the same bus and device number belong to the same slot. */ void acpiphp_enumerate_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; + struct acpi_device *adev; acpi_handle handle; acpi_status status; if (acpiphp_disabled) return; - handle = ACPI_HANDLE(bus->bridge); - if (!handle) + adev = ACPI_COMPANION(bus->bridge); + if (!adev) return; + handle = adev->handle; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (!bridge) { acpi_handle_err(handle, "No memory for bridge object\n"); @@ -1074,10 +892,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) * parent is going to be handled by pciehp, in which case this * bridge is not interesting to us either. */ - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); + acpi_lock_hp_context(); + context = acpiphp_get_context(adev); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); put_device(&bus->dev); pci_dev_put(bridge->pci_dev); kfree(bridge); @@ -1087,17 +905,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) context->bridge = bridge; /* Get a reference to the parent bridge. */ get_bridge(context->func.parent); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } - /* must be added to the list prior to calling register_slot */ + /* Must be added to the list prior to calling acpiphp_add_context(). */ mutex_lock(&bridge_mutex); list_add(&bridge->list, &bridge_list); mutex_unlock(&bridge_mutex); /* register all slot objects under this bridge */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - register_slot, NULL, bridge, NULL); + acpiphp_add_context, NULL, bridge, NULL); if (ACPI_FAILURE(status)) { acpi_handle_err(handle, "failed to register slots\n"); cleanup_bridge(bridge); @@ -1105,7 +923,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) } } -/* Destroy hotplug slots associated with the PCI bus */ +/** + * acpiphp_remove_slots - Remove slot objects associated with a given bus. + * @bus: PCI bus to remove the slot objects for. + */ void acpiphp_remove_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; @@ -1136,13 +957,10 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); /* configure all functions */ if (!(slot->flags & SLOT_ENABLED)) enable_slot(slot); - mutex_unlock(&slot->crit_sect); - pci_unlock_rescan_remove(); return 0; } @@ -1158,8 +976,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); - /* unconfigure all functions */ disable_slot(slot); @@ -1173,7 +989,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) break; } - mutex_unlock(&slot->crit_sect); return 0; } @@ -1181,9 +996,15 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) { int ret; + /* + * Acquire acpi_scan_lock to ensure that the execution of _EJ0 in + * acpiphp_disable_and_eject_slot() will be synchronized properly. + */ + acpi_scan_lock_acquire(); pci_lock_rescan_remove(); ret = acpiphp_disable_and_eject_slot(slot); pci_unlock_rescan_remove(); + acpi_scan_lock_release(); return ret; } diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c index 80875fb770e..3e62ee4b3b6 100644 --- a/drivers/xen/xen-acpi-cpuhotplug.c +++ b/drivers/xen/xen-acpi-cpuhotplug.c @@ -313,7 +313,7 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, goto out; } - (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL); + (void) acpi_evaluate_ost(handle, event, ost_code, NULL); out: acpi_scan_lock_release(); diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c index f8d18626969..34e40b733f9 100644 --- a/drivers/xen/xen-acpi-memhotplug.c +++ b/drivers/xen/xen-acpi-memhotplug.c @@ -285,7 +285,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) return; } - (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL); + (void) acpi_evaluate_ost(handle, event, ost_code, NULL); return; } diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c index 40c4bc06b5f..f83b754505f 100644 --- a/drivers/xen/xen-acpi-pad.c +++ b/drivers/xen/xen-acpi-pad.c @@ -77,27 +77,14 @@ static int acpi_pad_pur(acpi_handle handle) return num; } -/* Notify firmware how many CPUs are idle */ -static void acpi_pad_ost(acpi_handle handle, int stat, - uint32_t idle_nums) -{ - union acpi_object params[3] = { - {.type = ACPI_TYPE_INTEGER,}, - {.type = ACPI_TYPE_INTEGER,}, - {.type = ACPI_TYPE_BUFFER,}, - }; - struct acpi_object_list arg_list = {3, params}; - - params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY; - params[1].integer.value = stat; - params[2].buffer.length = 4; - params[2].buffer.pointer = (void *)&idle_nums; - acpi_evaluate_object(handle, "_OST", &arg_list, NULL); -} - static void acpi_pad_handle_notify(acpi_handle handle) { int idle_nums; + struct acpi_buffer param = { + .length = 4, + .pointer = (void *)&idle_nums, + }; + mutex_lock(&xen_cpu_lock); idle_nums = acpi_pad_pur(handle); @@ -109,7 +96,8 @@ static void acpi_pad_handle_notify(acpi_handle handle) idle_nums = xen_acpi_pad_idle_cpus(idle_nums) ?: xen_acpi_pad_idle_cpus_num(); if (idle_nums >= 0) - acpi_pad_ost(handle, 0, idle_nums); + acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY, + 0, ¶m); mutex_unlock(&xen_cpu_lock); } |