From f22ff5523af8b365167cb79189f8b91470d57c8c Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:34 +0800 Subject: [PATCH 01/20] ACPI / dock: avoid initializing acpi_dock_notifier_list multiple times Function dock_add() will be called multiple times if there are multiple dock stations, which causes acpi_dock_notifier_list to be initialized multiple times. To avoid that, move the initialization of acpi_dock_notifier_list from dock_add() to acpi_dock_init(). [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 826560753389..c36de862fd50 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -1007,7 +1007,6 @@ static int __init dock_add(acpi_handle handle) mutex_init(&dock_station->hp_lock); spin_lock_init(&dock_station->dd_lock); INIT_LIST_HEAD(&dock_station->sibling); - ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); INIT_LIST_HEAD(&dock_station->dependent_devices); /* we want the dock device to send uevents */ @@ -1078,6 +1077,7 @@ void __init acpi_dock_init(void) return; } + ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); register_acpi_bus_notifier(&dock_acpi_notifier); pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); From ed633e709fa633c6bc24f4d6ecb55ad0c14fd335 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:35 +0800 Subject: [PATCH 02/20] ACPI / dock: drop redundant spin lock in dock station object All dock station objects are created during initialization and don't change at runtime, so drop the redundant spin lock from struct dock_station. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c36de862fd50..750f958ef0bf 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -63,7 +63,6 @@ struct dock_station { acpi_handle handle; unsigned long last_dock_time; u32 flags; - spinlock_t dd_lock; struct mutex hp_lock; struct list_head dependent_devices; @@ -112,10 +111,7 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) dd->handle = handle; INIT_LIST_HEAD(&dd->list); - - spin_lock(&ds->dd_lock); list_add_tail(&dd->list, &ds->dependent_devices); - spin_unlock(&ds->dd_lock); return 0; } @@ -220,14 +216,10 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) { struct dock_dependent_device *dd; - spin_lock(&ds->dd_lock); - list_for_each_entry(dd, &ds->dependent_devices, list) { - if (handle == dd->handle) { - spin_unlock(&ds->dd_lock); + list_for_each_entry(dd, &ds->dependent_devices, list) + if (handle == dd->handle) return dd; - } - } - spin_unlock(&ds->dd_lock); + return NULL; } @@ -1005,7 +997,6 @@ static int __init dock_add(acpi_handle handle) dock_station->last_dock_time = jiffies - HZ; mutex_init(&dock_station->hp_lock); - spin_lock_init(&dock_station->dd_lock); INIT_LIST_HEAD(&dock_station->sibling); INIT_LIST_HEAD(&dock_station->dependent_devices); From d423c083ff3b3adc1e42a2f2c03c8430a6e0220f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:36 +0800 Subject: [PATCH 03/20] ACPI / dock: mark initialization functions with __init Mark all initialization functions with __init to reduce runtime memory consumption. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 750f958ef0bf..f3ec722ae85a 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -100,7 +100,7 @@ struct dock_dependent_device { * * Add the dependent device to the dock's dependent device list. */ -static int +static int __init add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) { struct dock_dependent_device *dd; @@ -244,7 +244,7 @@ static int is_dock(acpi_handle handle) return 1; } -static int is_ejectable(acpi_handle handle) +static int __init is_ejectable(acpi_handle handle) { acpi_status status; acpi_handle tmp; @@ -255,7 +255,7 @@ static int is_ejectable(acpi_handle handle) return 1; } -static int is_ata(acpi_handle handle) +static int __init is_ata(acpi_handle handle) { acpi_handle tmp; @@ -268,7 +268,7 @@ static int is_ata(acpi_handle handle) return 0; } -static int is_battery(acpi_handle handle) +static int __init is_battery(acpi_handle handle) { struct acpi_device_info *info; int ret = 1; @@ -284,7 +284,7 @@ static int is_battery(acpi_handle handle) return ret; } -static int is_ejectable_bay(acpi_handle handle) +static int __init is_ejectable_bay(acpi_handle handle) { acpi_handle phandle; @@ -848,7 +848,7 @@ static struct notifier_block dock_acpi_notifier = { * 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 +static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; From 472d963befe28b8614ea2789757b27536c8d79eb Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:37 +0800 Subject: [PATCH 04/20] ACPI / dock: simplify dock_create_acpi_device() The return value of dock_create_acpi_device() is not used at all, so change its signature to return void and simplify the implementation of it. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index f3ec722ae85a..1bdb1facc17b 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -351,10 +351,8 @@ static int dock_present(struct dock_station *ds) * 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. - * - * Returns a pointer to the acpi_device corresponding to the handle. */ -static struct acpi_device * dock_create_acpi_device(acpi_handle handle) +static void dock_create_acpi_device(acpi_handle handle) { struct acpi_device *device; int ret; @@ -367,10 +365,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle) ret = acpi_bus_scan(handle); if (ret) pr_debug("error adding bus, %x\n", -ret); - - acpi_bus_get_device(handle, &device); } - return device; } /** From 952c63e9512b63220886105cfc791507046fa39a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:38 +0800 Subject: [PATCH 05/20] ACPI: introduce helper function acpi_has_method() Introduce helper function acpi_has_method() and use it in a number of places to simplify code. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 11 +--- drivers/acpi/ec.c | 4 +- drivers/acpi/processor_perflib.c | 22 +++---- drivers/acpi/resource.c | 4 +- drivers/acpi/scan.c | 99 ++++++++++---------------------- drivers/acpi/utils.c | 15 +++++ drivers/acpi/video.c | 39 ++++--------- drivers/acpi/video_detect.c | 19 +++--- include/acpi/acpi_bus.h | 3 + 9 files changed, 80 insertions(+), 136 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 082b4dd252a8..a7627166e18b 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -548,12 +548,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery) static int acpi_battery_init_alarm(struct acpi_battery *battery) { - acpi_status status = AE_OK; - acpi_handle handle = NULL; - /* See if alarms are supported, and if so, set default */ - status = acpi_get_handle(battery->device->handle, "_BTP", &handle); - if (ACPI_FAILURE(status)) { + if (!acpi_has_method(battery->device->handle, "_BTP")) { clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags); return 0; } @@ -1066,7 +1062,7 @@ static int acpi_battery_add(struct acpi_device *device) { int result = 0; struct acpi_battery *battery = NULL; - acpi_handle handle; + if (!device) return -EINVAL; battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); @@ -1078,8 +1074,7 @@ static int acpi_battery_add(struct acpi_device *device) device->driver_data = battery; mutex_init(&battery->lock); mutex_init(&battery->sysfs_lock); - if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, - "_BIX", &handle))) + if (acpi_has_method(battery->device->handle, "_BIX")) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); result = acpi_battery_update(battery); if (result) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 80403c1a89f8..84bf06cec1f2 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1049,10 +1049,8 @@ int __init acpi_ec_ecdt_probe(void) * which needs it, has fake EC._INI method, so use it as flag. * Keep boot_ec struct as it will be needed soon. */ - acpi_handle dummy; if (!dmi_name_in_vendors("ASUS") || - ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", - &dummy))) + !acpi_has_method(boot_ec->handle, "_INI")) return -ENODEV; } install: diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 1e9732d809bf..51d7948611da 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -164,17 +164,12 @@ static void acpi_processor_ppc_ost(acpi_handle handle, int status) {.type = ACPI_TYPE_INTEGER,}, }; struct acpi_object_list arg_list = {2, params}; - acpi_handle temp; - params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; - params[1].integer.value = status; - - /* when there is no _OST , skip it */ - if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp))) - return; - - acpi_evaluate_object(handle, "_OST", &arg_list, NULL); - return; + 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); + } } int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) @@ -468,14 +463,11 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) int acpi_processor_get_performance_info(struct acpi_processor *pr) { int result = 0; - acpi_status status = AE_OK; - acpi_handle handle = NULL; if (!pr || !pr->performance || !pr->handle) return -EINVAL; - status = acpi_get_handle(pr->handle, "_PCT", &handle); - if (ACPI_FAILURE(status)) { + if (!acpi_has_method(pr->handle, "_PCT")) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI-based processor performance control unavailable\n")); return -ENODEV; @@ -501,7 +493,7 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr) */ update_bios: #ifdef CONFIG_X86 - if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){ + if (acpi_has_method(pr->handle, "_PPC")) { if(boot_cpu_has(X86_FEATURE_EST)) printk(KERN_WARNING FW_BUG "BIOS needs update for CPU " "frequency support\n"); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3322b47ab7ca..b7201fc6f1e1 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -505,14 +505,12 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, void *preproc_data) { struct res_proc_context c; - acpi_handle not_used; acpi_status status; if (!adev || !adev->handle || !list_empty(list)) return -EINVAL; - status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, ¬_used); - if (ACPI_FAILURE(status)) + if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) return 0; c.list = list; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 10985573aaa7..ada0b4cf2ba5 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -193,7 +193,6 @@ static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl, static int acpi_scan_hot_remove(struct acpi_device *device) { acpi_handle handle = device->handle; - acpi_handle not_used; struct acpi_object_list arg_list; union acpi_object arg; struct device *errdev; @@ -258,7 +257,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device) put_device(&device->dev); device = NULL; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", ¬_used))) { + if (acpi_has_method(handle, "_LCK")) { arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; @@ -652,7 +651,6 @@ static int acpi_device_setup_files(struct acpi_device *dev) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; - acpi_handle temp; unsigned long long sun; int result = 0; @@ -678,8 +676,7 @@ static int acpi_device_setup_files(struct acpi_device *dev) /* * If device has _STR, 'description' file is created */ - status = acpi_get_handle(dev->handle, "_STR", &temp); - if (ACPI_SUCCESS(status)) { + if (acpi_has_method(dev->handle, "_STR")) { status = acpi_evaluate_object(dev->handle, "_STR", NULL, &buffer); if (ACPI_FAILURE(status)) @@ -709,8 +706,7 @@ static int acpi_device_setup_files(struct acpi_device *dev) * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. */ - status = acpi_get_handle(dev->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) { + if (acpi_has_method(dev->handle, "_EJ0")) { result = device_create_file(&dev->dev, &dev_attr_eject); if (result) return result; @@ -732,9 +728,6 @@ end: static void acpi_device_remove_files(struct acpi_device *dev) { - acpi_status status; - acpi_handle temp; - if (dev->flags.power_manageable) { device_remove_file(&dev->dev, &dev_attr_power_state); if (dev->power.flags.power_resources) @@ -745,20 +738,17 @@ static void acpi_device_remove_files(struct acpi_device *dev) /* * If device has _STR, remove 'description' file */ - status = acpi_get_handle(dev->handle, "_STR", &temp); - if (ACPI_SUCCESS(status)) { + if (acpi_has_method(dev->handle, "_STR")) { kfree(dev->pnp.str_obj); device_remove_file(&dev->dev, &dev_attr_description); } /* * If device has _EJ0, remove 'eject' file. */ - status = acpi_get_handle(dev->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(dev->handle, "_EJ0")) device_remove_file(&dev->dev, &dev_attr_eject); - status = acpi_get_handle(dev->handle, "_SUN", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(dev->handle, "_SUN")) device_remove_file(&dev->dev, &dev_attr_sun); if (dev->pnp.unique_id) @@ -1334,13 +1324,10 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) { - acpi_handle temp; - acpi_status status = 0; int err; /* Presence of _PRW indicates wake capable */ - status = acpi_get_handle(device->handle, "_PRW", &temp); - if (ACPI_FAILURE(status)) + if (!acpi_has_method(device->handle, "_PRW")) return; err = acpi_bus_extract_wakeup_device_power_package(device->handle, @@ -1370,7 +1357,6 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state) struct acpi_device_power_state *ps = &device->power.states[state]; char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_handle handle; acpi_status status; INIT_LIST_HEAD(&ps->resources); @@ -1393,8 +1379,7 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state) /* Evaluate "_PSx" to see if we can do explicit sets */ pathname[2] = 'S'; - status = acpi_get_handle(device->handle, pathname, &handle); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, pathname)) ps->flags.explicit_set = 1; /* @@ -1413,28 +1398,21 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state) static void acpi_bus_get_power_flags(struct acpi_device *device) { - acpi_status status; - acpi_handle handle; u32 i; /* Presence of _PS0|_PR0 indicates 'power manageable' */ - status = acpi_get_handle(device->handle, "_PS0", &handle); - if (ACPI_FAILURE(status)) { - status = acpi_get_handle(device->handle, "_PR0", &handle); - if (ACPI_FAILURE(status)) - return; - } + if (!acpi_has_method(device->handle, "_PS0") && + !acpi_has_method(device->handle, "_PR0")) + return; device->flags.power_manageable = 1; /* * Power Management Flags */ - status = acpi_get_handle(device->handle, "_PSC", &handle); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_PSC")) device->power.flags.explicit_get = 1; - status = acpi_get_handle(device->handle, "_IRC", &handle); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_IRC")) device->power.flags.inrush_current = 1; /* @@ -1468,28 +1446,18 @@ static void acpi_bus_get_power_flags(struct acpi_device *device) static void acpi_bus_get_flags(struct acpi_device *device) { - acpi_status status = AE_OK; - acpi_handle temp = NULL; - /* Presence of _STA indicates 'dynamic_status' */ - status = acpi_get_handle(device->handle, "_STA", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_STA")) device->flags.dynamic_status = 1; /* Presence of _RMV indicates 'removable' */ - status = acpi_get_handle(device->handle, "_RMV", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_RMV")) device->flags.removable = 1; /* Presence of _EJD|_EJ0 indicates 'ejectable' */ - status = acpi_get_handle(device->handle, "_EJD", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_EJD") || + acpi_has_method(device->handle, "_EJ0")) device->flags.ejectable = 1; - else { - status = acpi_get_handle(device->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) - device->flags.ejectable = 1; - } } static void acpi_device_get_busid(struct acpi_device *device) @@ -1538,27 +1506,24 @@ static void acpi_device_get_busid(struct acpi_device *device) */ static int acpi_bay_match(acpi_handle handle) { - acpi_status status; - acpi_handle tmp; acpi_handle phandle; - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) + if (!acpi_has_method(handle, "_EJ0")) return -ENODEV; - if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + if (acpi_has_method(handle, "_GTF") || + acpi_has_method(handle, "_GTM") || + acpi_has_method(handle, "_STM") || + acpi_has_method(handle, "_SDD")) return 0; if (acpi_get_parent(handle, &phandle)) return -ENODEV; - if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp)))) + if (acpi_has_method(phandle, "_GTF") || + acpi_has_method(phandle, "_GTM") || + acpi_has_method(phandle, "_STM") || + acpi_has_method(phandle, "_SDD")) return 0; return -ENODEV; @@ -1610,7 +1575,6 @@ static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id) */ static int acpi_ibm_smbus_match(acpi_handle handle) { - acpi_handle h_dummy; struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; int result; @@ -1629,9 +1593,9 @@ static int acpi_ibm_smbus_match(acpi_handle handle) /* Does it have the necessary (but misnamed) methods? */ result = -ENODEV; - if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy))) + if (acpi_has_method(handle, "SBI") && + acpi_has_method(handle, "SBR") && + acpi_has_method(handle, "SBW")) result = 0; out: kfree(path.pointer); @@ -1898,7 +1862,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, struct acpi_device *device = NULL; int type; unsigned long long sta; - acpi_status status; int result; acpi_bus_get_device(handle, &device); @@ -1919,10 +1882,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, if (!(sta & ACPI_STA_DEVICE_PRESENT) && !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { struct acpi_device_wakeup wakeup; - acpi_handle temp; - status = acpi_get_handle(handle, "_PRW", &temp); - if (ACPI_SUCCESS(status)) { + if (acpi_has_method(handle, "_PRW")) { acpi_bus_extract_wakeup_device_power_package(handle, &wakeup); acpi_power_resources_list_free(&wakeup.resources); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 744371304313..b08d97376f84 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -495,3 +495,18 @@ acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...) kfree(buffer.pointer); } EXPORT_SYMBOL(acpi_handle_printk); + +/** + * acpi_has_method: Check whether @handle has a method named @name + * @handle: ACPI device handle + * @name: name of object or method + * + * Check whether @handle has a method named @name. + */ +bool acpi_has_method(acpi_handle handle, char *name) +{ + acpi_handle tmp; + + return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp)); +} +EXPORT_SYMBOL(acpi_has_method); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5d7075d25700..a84533e67b9d 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -875,28 +875,21 @@ out: static void acpi_video_device_find_cap(struct acpi_video_device *device) { - acpi_handle h_dummy1; - - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) { + if (acpi_has_method(device->dev->handle, "_ADR")) device->cap._ADR = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) { + if (acpi_has_method(device->dev->handle, "_BCL")) device->cap._BCL = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) { + if (acpi_has_method(device->dev->handle, "_BCM")) device->cap._BCM = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) + if (acpi_has_method(device->dev->handle, "_BQC")) { device->cap._BQC = 1; - else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ", - &h_dummy1))) { + } else if (acpi_has_method(device->dev->handle, "_BCQ")) { printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n"); device->cap._BCQ = 1; } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { + if (acpi_has_method(device->dev->handle, "_DDC")) device->cap._DDC = 1; - } if (acpi_video_backlight_support()) { struct backlight_properties props; @@ -984,26 +977,18 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) static void acpi_video_bus_find_cap(struct acpi_video_bus *video) { - acpi_handle h_dummy1; - - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_DOS")) video->cap._DOS = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_DOD")) video->cap._DOD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_ROM")) video->cap._ROM = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_GPD")) video->cap._GPD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_SPD")) video->cap._SPD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_VPO")) video->cap._VPO = 1; - } } /* diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index e6bd910bc6ed..ddefa5f954e2 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -51,14 +51,13 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, void **retyurn_value) { long *cap = context; - acpi_handle h_dummy; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) { + if (acpi_has_method(handle, "_BCM") && + acpi_has_method(handle, "_BCL")) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " "support\n")); *cap |= ACPI_VIDEO_BACKLIGHT; - if (ACPI_FAILURE(acpi_get_handle(handle, "_BQC", &h_dummy))) + if (!acpi_has_method(handle, "_BQC")) printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, " "cannot determine initial brightness\n"); /* We have backlight support, no need to scan further */ @@ -77,22 +76,20 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, */ long acpi_is_video_device(acpi_handle handle) { - acpi_handle h_dummy; long video_caps = 0; /* Is this device able to support video switching ? */ - if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) || - ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy))) + if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS")) video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; /* Is this device able to retrieve a video ROM ? */ - if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy))) + if (acpi_has_method(handle, "_ROM")) video_caps |= ACPI_VIDEO_ROM_AVAILABLE; /* Is this device able to configure which video head to be POSTed ? */ - if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy))) + if (acpi_has_method(handle, "_VPO") && + acpi_has_method(handle, "_GPD") && + acpi_has_method(handle, "_SPD")) video_caps |= ACPI_VIDEO_DEVICE_POSTING; /* Only check for backlight functionality if one of the above hit. */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 56e6b68c8d2f..62b2811bade4 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -56,6 +56,9 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, acpi_status acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld); + +bool acpi_has_method(acpi_handle handle, char *name); + #ifdef CONFIG_ACPI #include From 0db98202605c3d32e023d43c30b5bd878f520976 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:39 +0800 Subject: [PATCH 06/20] ACPI: introduce helper function acpi_execute_simple_method() Introduce helper function acpi_execute_simple_method() and use it in a number of places to simplify code. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 8 ++------ drivers/acpi/bus.c | 6 +----- drivers/acpi/power.c | 4 +--- drivers/acpi/sleep.c | 7 ++----- drivers/acpi/thermal.c | 18 ++++-------------- drivers/acpi/utils.c | 12 ++++++++++++ drivers/acpi/video.c | 17 +++++------------ include/acpi/acpi_bus.h | 2 ++ 8 files changed, 29 insertions(+), 45 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index a7627166e18b..74669ac4c615 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -525,18 +525,14 @@ static int acpi_battery_get_state(struct acpi_battery *battery) static int acpi_battery_set_alarm(struct acpi_battery *battery) { acpi_status status = 0; - union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &arg0 }; if (!acpi_battery_present(battery) || !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags)) return -ENODEV; - arg0.integer.value = battery->alarm; - mutex_lock(&battery->lock); - status = acpi_evaluate_object(battery->device->handle, "_BTP", - &arg_list, NULL); + status = acpi_execute_simple_method(battery->device->handle, "_BTP", + battery->alarm); mutex_unlock(&battery->lock); if (ACPI_FAILURE(status)) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a5bb33bab448..a5a032e2344e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -593,8 +593,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) static int __init acpi_bus_init_irq(void) { acpi_status status; - union acpi_object arg = { ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &arg }; char *message = NULL; @@ -623,9 +621,7 @@ static int __init acpi_bus_init_irq(void) printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message); - arg.integer.value = acpi_irq_model; - - status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL); + status = acpi_execute_simple_method(NULL, "\\_PIC", acpi_irq_model); if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC")); return -ENODEV; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5c28c894c0fc..1460c88a7c0e 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -637,9 +637,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev, } /* Execute _PSW */ - arg_list.count = 1; - in_arg[0].integer.value = enable; - status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); + status = acpi_execute_simple_method(dev->handle, "_PSW", enable); if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { printk(KERN_ERR PREFIX "_PSW execution failed\n"); dev->wakeup.flags.valid = 0; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 187ab61889e6..81b0f03d97db 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -31,12 +31,9 @@ static u8 sleep_states[ACPI_S_STATE_COUNT]; static void acpi_sleep_tts_switch(u32 acpi_state) { - union acpi_object in_arg = { ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &in_arg }; - acpi_status status = AE_OK; + acpi_status status; - in_arg.integer.value = acpi_state; - status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL); + status = acpi_execute_simple_method(NULL, "\\_TTS", acpi_state); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { /* * OS can't evaluate the _TTS object correctly. Some warning diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index a33821ca3895..94523c79dc5f 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -239,26 +239,16 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz) static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode) { - acpi_status status = AE_OK; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &arg0 }; - acpi_handle handle = NULL; - - if (!tz) return -EINVAL; - status = acpi_get_handle(tz->device->handle, "_SCP", &handle); - if (ACPI_FAILURE(status)) { + if (!acpi_has_method(tz->device->handle, "_SCP")) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n")); return -ENODEV; - } - - arg0.integer.value = mode; - - status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); - if (ACPI_FAILURE(status)) + } else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle, + "_SCP", mode))) { return -ENODEV; + } return 0; } diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index b08d97376f84..87b85882b5df 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -510,3 +510,15 @@ bool acpi_has_method(acpi_handle handle, char *name) return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp)); } EXPORT_SYMBOL(acpi_has_method); + +acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, + u64 arg) +{ + union acpi_object obj = { .type = ACPI_TYPE_INTEGER }; + struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, }; + + obj.integer.value = arg; + + return acpi_evaluate_object(handle, method, &arg_list, NULL); +} +EXPORT_SYMBOL(acpi_execute_simple_method); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index a84533e67b9d..b862c7f74941 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -353,14 +353,10 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) { int status; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; int state; - arg0.integer.value = level; - - status = acpi_evaluate_object(device->dev->handle, "_BCM", - &args, NULL); + status = acpi_execute_simple_method(device->dev->handle, + "_BCM", level); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Evaluating _BCM failed")); return -EIO; @@ -628,18 +624,15 @@ static int acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) { acpi_status status; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; if (!video->cap._DOS) return 0; if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) return -EINVAL; - arg0.integer.value = (lcd_flag << 2) | bios_flag; - video->dos_setting = arg0.integer.value; - status = acpi_evaluate_object(video->device->handle, "_DOS", - &args, NULL); + video->dos_setting = (lcd_flag << 2) | bios_flag; + status = acpi_execute_simple_method(video->device->handle, "_DOS", + (lcd_flag << 2) | bios_flag); if (ACPI_FAILURE(status)) return -EIO; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 62b2811bade4..e3862587b9de 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -58,6 +58,8 @@ acpi_status acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld); bool acpi_has_method(acpi_handle handle, char *name); +acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, + u64 arg); #ifdef CONFIG_ACPI From 7d2421f84b445dc48c68d33911f1fd6ce6853ee3 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:40 +0800 Subject: [PATCH 07/20] ACPI: introduce two helper functions for _EJ0 and _LCK Introduce two helper functions, acpi_evaluate_ej0() and acpi_evaluate_lck(), that will execute the _EJ0 and _LCK ACPI control methods, respectively, and use them to simplify the ACPI scan code. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 31 ++++++----------------------- drivers/acpi/utils.c | 43 +++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 2 ++ 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ada0b4cf2ba5..4c25c3b7ef81 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -193,8 +193,6 @@ static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl, static int acpi_scan_hot_remove(struct acpi_device *device) { acpi_handle handle = device->handle; - struct acpi_object_list arg_list; - union acpi_object arg; struct device *errdev; acpi_status status; unsigned long long sta; @@ -257,32 +255,15 @@ static int acpi_scan_hot_remove(struct acpi_device *device) put_device(&device->dev); device = NULL; - if (acpi_has_method(handle, "_LCK")) { - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 0; - acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); - } - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - + acpi_evaluate_lck(handle, 0); /* * TBD: _EJD support. */ - status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - if (status == AE_NOT_FOUND) { - return -ENODEV; - } else { - acpi_handle_warn(handle, "Eject failed (0x%x)\n", - status); - return -EIO; - } - } + status = acpi_evaluate_ej0(handle); + if (status == AE_NOT_FOUND) + return -ENODEV; + else if (ACPI_FAILURE(status)) + return -EIO; /* * Verify if eject was indeed successful. If not, log an error diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 87b85882b5df..552248b0005b 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -522,3 +522,46 @@ acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, return acpi_evaluate_object(handle, method, &arg_list, NULL); } EXPORT_SYMBOL(acpi_execute_simple_method); + +/** + * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations + * @handle: ACPI device handle + * + * Evaluate device's _EJ0 method for hotplug operations. + */ +acpi_status acpi_evaluate_ej0(acpi_handle handle) +{ + acpi_status status; + + status = acpi_execute_simple_method(handle, "_EJ0", 1); + if (status == AE_NOT_FOUND) + acpi_handle_warn(handle, "No _EJ0 support for device\n"); + else if (ACPI_FAILURE(status)) + acpi_handle_warn(handle, "Eject failed (0x%x)\n", status); + + return status; +} + +/** + * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device + * @handle: ACPI device handle + * @lock: lock device if non-zero, otherwise unlock device + * + * Evaluate device's _LCK method if present to lock/unlock device + */ +acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) +{ + acpi_status status; + + status = acpi_execute_simple_method(handle, "_LCK", !!lock); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + if (lock) + acpi_handle_warn(handle, + "Locking device failed (0x%x)\n", status); + else + acpi_handle_warn(handle, + "Unlocking device failed (0x%x)\n", status); + } + + return status; +} diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e3862587b9de..f499157b04e8 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -60,6 +60,8 @@ acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld bool acpi_has_method(acpi_handle handle, char *name); acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, u64 arg); +acpi_status acpi_evaluate_ej0(acpi_handle handle); +acpi_status acpi_evaluate_lck(acpi_handle handle, int lock); #ifdef CONFIG_ACPI From ebf4df8db0e7e5db9f7fca5fcd0c2b90ac954385 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:41 +0800 Subject: [PATCH 08/20] ACPI: Export acpi_(bay)|(dock)_match() from scan.c Functions acpi_dock_match() and acpi_bay_match() in scan.c can be shared with dock.c to reduce code duplication, so export them as global functions. Also add a new function acpi_ata_match() to check whether an ACPI device object represents an ATA device. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 77 +++++++++++++++++++---------------------- include/acpi/acpi_bus.h | 3 ++ 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4c25c3b7ef81..62e2055e8806 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1479,44 +1479,46 @@ static void acpi_device_get_busid(struct acpi_device *device) } } +/* + * acpi_ata_match - see if an acpi object is an ATA device + * + * If an acpi object has one of the ACPI ATA methods defined, + * then we can safely call it an ATA device. + */ +bool acpi_ata_match(acpi_handle handle) +{ + return acpi_has_method(handle, "_GTF") || + acpi_has_method(handle, "_GTM") || + acpi_has_method(handle, "_STM") || + acpi_has_method(handle, "_SDD"); +} + /* * acpi_bay_match - see if an acpi object is an ejectable driver bay * * If an acpi object is ejectable and has one of the ACPI ATA methods defined, * then we can safely call it an ejectable drive bay */ -static int acpi_bay_match(acpi_handle handle) +bool acpi_bay_match(acpi_handle handle) { acpi_handle phandle; if (!acpi_has_method(handle, "_EJ0")) - return -ENODEV; + return false; + if (acpi_ata_match(handle)) + return true; + if (ACPI_FAILURE(acpi_get_parent(handle, &phandle))) + return false; - if (acpi_has_method(handle, "_GTF") || - acpi_has_method(handle, "_GTM") || - acpi_has_method(handle, "_STM") || - acpi_has_method(handle, "_SDD")) - return 0; - - if (acpi_get_parent(handle, &phandle)) - return -ENODEV; - - if (acpi_has_method(phandle, "_GTF") || - acpi_has_method(phandle, "_GTM") || - acpi_has_method(phandle, "_STM") || - acpi_has_method(phandle, "_SDD")) - return 0; - - return -ENODEV; + return acpi_ata_match(phandle); } /* * acpi_dock_match - see if an acpi object has a _DCK method */ -static int acpi_dock_match(acpi_handle handle) +bool acpi_dock_match(acpi_handle handle) { - acpi_handle tmp; - return acpi_get_handle(handle, "_DCK", &tmp); + return acpi_has_method(handle, "_DCK"); } const char *acpi_device_hid(struct acpi_device *device) @@ -1554,33 +1556,26 @@ static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id) * lacks the SMBUS01 HID and the methods do not have the necessary "_" * prefix. Work around this. */ -static int acpi_ibm_smbus_match(acpi_handle handle) +static bool acpi_ibm_smbus_match(acpi_handle handle) { - struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; - int result; + char node_name[ACPI_PATH_SEGMENT_LENGTH]; + struct acpi_buffer path = { sizeof(node_name), node_name }; if (!dmi_name_in_vendors("IBM")) - return -ENODEV; + return false; /* Look for SMBS object */ - result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path); - if (result) - return result; - - if (strcmp("SMBS", path.pointer)) { - result = -ENODEV; - goto out; - } + if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &path)) || + strcmp("SMBS", path.pointer)) + return false; /* Does it have the necessary (but misnamed) methods? */ - result = -ENODEV; if (acpi_has_method(handle, "SBI") && acpi_has_method(handle, "SBR") && acpi_has_method(handle, "SBW")) - result = 0; -out: - kfree(path.pointer); - return result; + return true; + + return false; } static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, @@ -1628,11 +1623,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, */ if (acpi_is_video_device(handle)) acpi_add_id(pnp, ACPI_VIDEO_HID); - else if (ACPI_SUCCESS(acpi_bay_match(handle))) + else if (acpi_bay_match(handle)) acpi_add_id(pnp, ACPI_BAY_HID); - else if (ACPI_SUCCESS(acpi_dock_match(handle))) + else if (acpi_dock_match(handle)) acpi_add_id(pnp, ACPI_DOCK_HID); - else if (!acpi_ibm_smbus_match(handle)) + 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 */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index f499157b04e8..facc0ba6dd21 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -62,6 +62,9 @@ acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, u64 arg); acpi_status acpi_evaluate_ej0(acpi_handle handle); acpi_status acpi_evaluate_lck(acpi_handle handle, int lock); +bool acpi_ata_match(acpi_handle handle); +bool acpi_bay_match(acpi_handle handle); +bool acpi_dock_match(acpi_handle handle); #ifdef CONFIG_ACPI From c9b5471f8866956919955b70ab27b4737b8bce30 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:42 +0800 Subject: [PATCH 09/20] ACPI: simplify dock driver with new helper functions Use helper functions introduced previously to simplify the ACPI dock driver. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 122 +++++--------------------------------------- 1 file changed, 12 insertions(+), 110 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 1bdb1facc17b..810d1d720b1f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -226,48 +226,6 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) /***************************************************************************** * Dock functions * *****************************************************************************/ -/** - * is_dock - see if a device is a dock station - * @handle: acpi handle of the device - * - * If an acpi object has a _DCK method, then it is by definition a dock - * station, so return true. - */ -static int is_dock(acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - - status = acpi_get_handle(handle, "_DCK", &tmp); - if (ACPI_FAILURE(status)) - return 0; - return 1; -} - -static int __init is_ejectable(acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) - return 0; - return 1; -} - -static int __init is_ata(acpi_handle handle) -{ - acpi_handle tmp; - - if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) - return 1; - - return 0; -} - static int __init is_battery(acpi_handle handle) { struct acpi_device_info *info; @@ -284,17 +242,13 @@ static int __init is_battery(acpi_handle handle) return ret; } -static int __init is_ejectable_bay(acpi_handle handle) +/* Check whether ACPI object is an ejectable battery or disk bay */ +static bool __init is_ejectable_bay(acpi_handle handle) { - acpi_handle phandle; + if (acpi_has_method(handle, "_EJ0") && is_battery(handle)) + return true; - if (!is_ejectable(handle)) - return 0; - if (is_battery(handle) || is_ata(handle)) - return 1; - if (!acpi_get_parent(handle, &phandle) && is_ata(phandle)) - return 1; - return 0; + return acpi_bay_match(handle); } /** @@ -312,7 +266,7 @@ int is_dock_device(acpi_handle handle) if (!dock_station_count) return 0; - if (is_dock(handle)) + if (acpi_dock_match(handle)) return 1; list_for_each_entry(dock_station, &dock_stations, sibling) @@ -446,37 +400,6 @@ static void dock_event(struct dock_station *ds, u32 event, int num) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } -/** - * eject_dock - respond to a dock eject request - * @ds: the dock station - * - * This is called after _DCK is called, to execute the dock station's - * _EJ0 method. - */ -static void eject_dock(struct dock_station *ds) -{ - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status; - acpi_handle tmp; - - /* all dock devices should have _EJ0, but check anyway */ - status = acpi_get_handle(ds->handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) { - pr_debug("No _EJ0 support for dock device\n"); - return; - } - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) - pr_debug("Failed to evaluate _EJ0!\n"); -} - /** * handle_dock - handle a dock event * @ds: the dock station @@ -537,27 +460,6 @@ static inline void complete_undock(struct dock_station *ds) ds->flags &= ~(DOCK_UNDOCKING); } -static void dock_lock(struct dock_station *ds, int lock) -{ - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status; - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = !!lock; - status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - if (lock) - acpi_handle_warn(ds->handle, - "Locking device failed (0x%x)\n", status); - else - acpi_handle_warn(ds->handle, - "Unlocking device failed (0x%x)\n", status); - } -} - /** * dock_in_progress - see if we are in the middle of handling a dock event * @ds: the dock station @@ -692,8 +594,8 @@ static int handle_eject_request(struct dock_station *ds, u32 event) hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); undock(ds); - dock_lock(ds, 0); - eject_dock(ds); + acpi_evaluate_lck(ds->handle, 0); + acpi_evaluate_ej0(ds->handle); if (dock_present(ds)) { acpi_handle_err(ds->handle, "Unable to undock!\n"); return -EBUSY; @@ -752,7 +654,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) hotplug_dock_devices(ds, event); complete_dock(ds); dock_event(ds, event, DOCK_EVENT); - dock_lock(ds, 1); + acpi_evaluate_lck(ds->handle, 1); acpi_update_all_gpes(); break; } @@ -998,9 +900,9 @@ static int __init dock_add(acpi_handle handle) /* we want the dock device to send uevents */ dev_set_uevent_suppress(&dd->dev, 0); - if (is_dock(handle)) + if (acpi_dock_match(handle)) dock_station->flags |= DOCK_IS_DOCK; - if (is_ata(handle)) + if (acpi_ata_match(handle)) dock_station->flags |= DOCK_IS_ATA; if (is_battery(handle)) dock_station->flags |= DOCK_IS_BAT; @@ -1043,7 +945,7 @@ err_unregister: static __init acpi_status find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) { - if (is_dock(handle) || is_ejectable_bay(handle)) + if (acpi_dock_match(handle) || is_ejectable_bay(handle)) dock_add(handle); return AE_OK; From ecd046da57d3327367b930478234e58f01bc9f0f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:43 +0800 Subject: [PATCH 10/20] ACPI: simplify acpiphp driver with new helper functions Use the new helper functions introduced previously to simplify the ACPI-based PCI hotplug (acpiphp) driver. [rjw: Changelog] Signed-off-by: Jiang Liu Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 59df8575a48c..a0a7133a1d12 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -201,7 +201,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; - acpi_handle tmp; acpi_status status = AE_OK; unsigned long long adr, sun; int device, function, retval, found = 0; @@ -232,19 +231,19 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) newfunc->handle = handle; newfunc->function = function; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) + if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) + if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) + if (acpi_has_method(handle, "_PS0")) newfunc->flags |= FUNC_HAS_PS0; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) + if (acpi_has_method(handle, "_PS3")) newfunc->flags |= FUNC_HAS_PS3; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) + if (acpi_has_method(handle, "_DCK")) newfunc->flags |= FUNC_HAS_DCK; status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); @@ -843,25 +842,14 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) */ int acpiphp_eject_slot(struct acpiphp_slot *slot) { - acpi_status status; struct acpiphp_func *func; - struct acpi_object_list arg_list; - union acpi_object arg; list_for_each_entry(func, &slot->funcs, sibling) { /* We don't want to call _EJ0 on non-existing functions. */ if ((func->flags & FUNC_HAS_EJ0)) { - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __func__); + if (ACPI_FAILURE(acpi_evaluate_ej0(func->handle))) return -1; - } else + else break; } } @@ -1171,7 +1159,6 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, */ void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) { - acpi_handle dummy_handle; struct acpiphp_bridge *bridge; if (acpiphp_disabled) @@ -1200,8 +1187,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) get_device(&bus->dev); if (!pci_is_root_bus(bridge->pci_bus) && - ACPI_SUCCESS(acpi_get_handle(bridge->handle, - "_EJ0", &dummy_handle))) { + acpi_has_method(bridge->handle, "_EJ0")) { dbg("found ejectable p2p bridge\n"); bridge->flags |= BRIDGE_HAS_EJ0; bridge->func = acpiphp_bridge_handle_to_function(handle); From d460acebd7959cc91e7edc594d90adb9b72a0b05 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:42:51 +0200 Subject: [PATCH 11/20] ACPI / dock: Drop the hp_lock mutex from struct dock_station The only existing user of the hp_lock mutex in struct dock_station, hotplug_dock_devices(), is always called under acpi_scan_lock and cannot race with another instance of itself, so drop the mutex which is not necessary. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 810d1d720b1f..c10761533d6f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -63,7 +63,6 @@ struct dock_station { acpi_handle handle; unsigned long last_dock_time; u32 flags; - struct mutex hp_lock; struct list_head dependent_devices; struct list_head sibling; @@ -351,8 +350,6 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) { struct dock_dependent_device *dd; - mutex_lock(&ds->hp_lock); - /* * First call driver specific hotplug functions */ @@ -371,7 +368,6 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) else dock_create_acpi_device(dd->handle); } - mutex_unlock(&ds->hp_lock); } static void dock_event(struct dock_station *ds, u32 event, int num) @@ -893,7 +889,6 @@ static int __init dock_add(acpi_handle handle) dock_station->dock_device = dd; dock_station->last_dock_time = jiffies - HZ; - mutex_init(&dock_station->hp_lock); INIT_LIST_HEAD(&dock_station->sibling); INIT_LIST_HEAD(&dock_station->dependent_devices); From 96c0a4d4902c3d5f56bde95d3e2d96689ca64b6d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:46:02 +0200 Subject: [PATCH 12/20] ACPI / dock: Rework and simplify find_dock_devices() Since acpi_walk_namespace() calls find_dock_devices() during tree pre-order visit, the latter doesn't need to add devices whose parents have _EJD pointing to the docking station to the list of that station's dependent devices, because those parents are going to be added to that list anyway and the removal of a parent will take care of the removal of its children in those cases. For this reason, rework find_dock_devices() to only call add_dock_dependent_device() for devices whose _EJD point directy to the docking station represented by its context argument and simplify it slightly. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/dock.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c10761533d6f..7c86d01346e6 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -741,29 +741,16 @@ static struct notifier_block dock_acpi_notifier = { * 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) +static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, + void *context, void **rv) { - acpi_status status; - acpi_handle tmp, parent; struct dock_station *ds = context; + acpi_handle ejd = NULL; - status = acpi_bus_get_ejd(handle, &tmp); - if (ACPI_FAILURE(status)) { - /* try the parent device as well */ - status = acpi_get_parent(handle, &parent); - if (ACPI_FAILURE(status)) - goto fdd_out; - /* see if parent is dependent on dock */ - status = acpi_bus_get_ejd(parent, &tmp); - if (ACPI_FAILURE(status)) - goto fdd_out; - } - - if (tmp == ds->handle) + acpi_bus_get_ejd(handle, &ejd); + if (ejd == ds->handle) add_dock_dependent_device(ds, handle); -fdd_out: return AE_OK; } From 37f908778f20bbcc35ab9a98a5b584329c6abf08 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:46:42 +0200 Subject: [PATCH 13/20] ACPI / dock: Walk list in reverse order during removal of devices If there are indirect dependencies between devices in a dock station's dependent devices list, they may be broken if the devices are removed in the same order in which they have been added. For this reason, make the code in handle_eject_request() walk the list of dependent devices in reverse order. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/dock.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 7c86d01346e6..41c5d04a89c1 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -337,9 +337,29 @@ static void dock_remove_acpi_device(acpi_handle handle) } /** - * hotplug_dock_devices - insert or remove devices on the dock station + * hot_remove_dock_devices - Remove dock station devices. + * @ds: Dock station. + */ +static void hot_remove_dock_devices(struct dock_station *ds) +{ + struct dock_dependent_device *dd; + + /* + * Walk the list in reverse order so that devices that have been added + * last are removed first (in case there are some indirect dependencies + * between them). + */ + list_for_each_entry_reverse(dd, &ds->dependent_devices, list) + 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); +} + +/** + * hotplug_dock_devices - Insert devices on a dock station. * @ds: the dock station - * @event: either bus check or eject request + * @event: either bus check or device check request * * Some devices on the dock station need to have drivers called * to perform hotplug operations after a dock event has occurred. @@ -350,24 +370,17 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) { struct dock_dependent_device *dd; - /* - * First call driver specific hotplug functions - */ + /* Call driver specific hotplug functions. */ list_for_each_entry(dd, &ds->dependent_devices, list) dock_hotplug_event(dd, event, false); /* - * Now make sure that an acpi_device is created for each - * dependent device, or removed if this is an eject request. - * This will cause acpi_drivers to be stopped/started if they - * exist + * 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. */ - list_for_each_entry(dd, &ds->dependent_devices, list) { - if (event == ACPI_NOTIFY_EJECT_REQUEST) - dock_remove_acpi_device(dd->handle); - else - dock_create_acpi_device(dd->handle); - } + list_for_each_entry(dd, &ds->dependent_devices, list) + dock_create_acpi_device(dd->handle); } static void dock_event(struct dock_station *ds, u32 event, int num) @@ -588,7 +601,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) */ dock_event(ds, event, UNDOCK_EVENT); - hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); + hot_remove_dock_devices(ds); undock(ds); acpi_evaluate_lck(ds->handle, 0); acpi_evaluate_ej0(ds->handle); From 4ec24065a65b4debfdeb591cc01a4aa092651f53 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:47:14 +0200 Subject: [PATCH 14/20] ACPI / dock: Simplify dock_init_hotplug() and dock_release_hotplug() Make dock_init_hotplug() and dock_release_hotplug() slightly simpler and move some checks in those functions to the code paths where they are needed. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/dock.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 41c5d04a89c1..b1170d60a836 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -130,19 +130,16 @@ static int dock_init_hotplug(struct dock_dependent_device *dd, int ret = 0; mutex_lock(&hotplug_lock); - - if (dd->hp_context) { + 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); } - - if (!WARN_ON(ret) && init) - init(context); - mutex_unlock(&hotplug_lock); return ret; } @@ -157,22 +154,17 @@ static int dock_init_hotplug(struct dock_dependent_device *dd, */ static void dock_release_hotplug(struct dock_dependent_device *dd) { - void (*release)(void *) = NULL; - void *context = NULL; - 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; - context = dd->hp_context; dd->hp_context = NULL; - release = dd->hp_release; dd->hp_release = NULL; + if (release) + release(context); } - - if (release && context) - release(context); - mutex_unlock(&hotplug_lock); } From 59401ccce8729e5c43f9781cc5570da5ca470e27 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:48:49 +0200 Subject: [PATCH 15/20] ACPI / dock: Rework the handling of notifications The ACPI dock driver uses register_acpi_bus_notifier() which installs a notifier triggered globally for all system notifications. That first of all is inefficient, because the dock driver is only interested in notifications associated with the devices it handles, but it has to handle all system notifies for all devices. Moreover, it does that even if no docking stations are present in the system (CONFIG_ACPI_DOCK set is sufficient for that to happen). Besides, that is inconvenient, because it requires the driver to do extra work for each notification to find the target dock station object. For these reasons, rework the dock driver to install a notify handler individually for each dock station in the system using acpi_install_notify_handler(). This allows the dock station object to be passed directly to the notify handler and makes it possible to simplify the dock driver quite a bit. It also reduces the overhead related to the handling of all system notifies when CONFIG_ACPI_DOCK is set. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/dock.c | 67 ++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index b1170d60a836..a326c7993f4f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -607,18 +607,17 @@ static int handle_eject_request(struct dock_station *ds, u32 event) /** * dock_notify - act upon an acpi dock notification - * @handle: the dock station handle + * @ds: dock station * @event: the acpi event - * @data: our driver data struct * * 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(acpi_handle handle, u32 event, void *data) +static void dock_notify(struct dock_station *ds, u32 event) { - struct dock_station *ds = data; - struct acpi_device *tmp; + acpi_handle handle = ds->handle; + struct acpi_device *ad; int surprise_removal = 0; /* @@ -641,8 +640,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle, - &tmp)) { + if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) { begin_dock(ds); dock(ds); if (!dock_present(ds)) { @@ -679,9 +677,8 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) } struct dock_data { - acpi_handle handle; - unsigned long event; struct dock_station *ds; + u32 event; }; static void acpi_dock_deferred_cb(void *context) @@ -689,52 +686,31 @@ static void acpi_dock_deferred_cb(void *context) struct dock_data *data = context; acpi_scan_lock_acquire(); - dock_notify(data->handle, data->event, data->ds); + dock_notify(data->ds, data->event); acpi_scan_lock_release(); kfree(data); } -static int acpi_dock_notifier_call(struct notifier_block *this, - unsigned long event, void *data) +static void dock_notify_handler(acpi_handle handle, u32 event, void *data) { - struct dock_station *dock_station; - acpi_handle handle = data; + struct dock_data *dd; if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK && event != ACPI_NOTIFY_EJECT_REQUEST) - return 0; + return; - acpi_scan_lock_acquire(); + dd = kmalloc(sizeof(*dd), GFP_KERNEL); + if (dd) { + acpi_status status; - list_for_each_entry(dock_station, &dock_stations, sibling) { - if (dock_station->handle == handle) { - struct dock_data *dd; - acpi_status status; - - dd = kmalloc(sizeof(*dd), GFP_KERNEL); - if (!dd) - break; - - dd->handle = handle; - dd->event = event; - dd->ds = dock_station; - status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, - dd); - if (ACPI_FAILURE(status)) - kfree(dd); - - break; - } + dd->ds = data; + dd->event = event; + status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd); + if (ACPI_FAILURE(status)) + kfree(dd); } - - acpi_scan_lock_release(); - return 0; } -static struct notifier_block dock_acpi_notifier = { - .notifier_call = acpi_dock_notifier_call, -}; - /** * find_dock_devices - find devices on the dock station * @handle: the handle of the device we are examining @@ -868,6 +844,7 @@ static int __init dock_add(acpi_handle handle) int ret, id; struct dock_station ds, *dock_station; struct platform_device *dd; + acpi_status status; id = dock_station_count; memset(&ds, 0, sizeof(ds)); @@ -908,6 +885,11 @@ static int __init dock_add(acpi_handle handle) if (ret) goto err_rmgroup; + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + dock_notify_handler, dock_station); + if (ACPI_FAILURE(status)) + goto err_rmgroup; + dock_station_count++; list_add(&dock_station->sibling, &dock_stations); return 0; @@ -953,7 +935,6 @@ void __init acpi_dock_init(void) } ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); - register_acpi_bus_notifier(&dock_acpi_notifier); pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); } From f716fc2ac037c45a6c641eb9f20ec602e8d04e14 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:49:55 +0200 Subject: [PATCH 16/20] ACPI: Drop ACPI bus notifier call chain There are no users of the ACPI bus notifier call chain, acpi_bus_notify_list, any more, so drop it. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 16 ---------------- include/acpi/acpi_bus.h | 2 -- 2 files changed, 18 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a5a032e2344e..6fd27a9abcda 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -499,19 +499,6 @@ static void acpi_bus_check_scope(acpi_handle handle) */ } -static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); -int register_acpi_bus_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&acpi_bus_notify_list, nb); -} -EXPORT_SYMBOL_GPL(register_acpi_bus_notifier); - -void unregister_acpi_bus_notifier(struct notifier_block *nb) -{ - blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); - /** * acpi_bus_notify * --------------- @@ -525,9 +512,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", type, handle)); - blocking_notifier_call_chain(&acpi_bus_notify_list, - type, (void *)handle); - switch (type) { case ACPI_NOTIFY_BUS_CHECK: diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index facc0ba6dd21..71f3fd429fd1 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -366,8 +366,6 @@ extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); extern int register_acpi_notifier(struct notifier_block *); extern int unregister_acpi_notifier(struct notifier_block *); -extern int register_acpi_bus_notifier(struct notifier_block *nb); -extern void unregister_acpi_bus_notifier(struct notifier_block *nb); /* * External Functions */ From a30c4c5ee85680bb66ed8a6c0b0bf4921125c378 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:50:24 +0200 Subject: [PATCH 17/20] ACPI / dock: Do not leak memory on falilures to add a dock station The function creating and registering dock station objects, dock_add(), leaks memory if there's an error after it's walked the ACPI namespace calling find_dock_devices(), because it doesn't free the list of dependent devices it's just created in those cases. Fix that issue by adding the missing code to free the list of dependent devices on errors. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index a326c7993f4f..3e20b13fa272 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -115,6 +115,16 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) return 0; } +static void remove_dock_dependent_devices(struct dock_station *ds) +{ + struct dock_dependent_device *dd, *aux; + + list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) { + list_del(&dd->list); + kfree(dd); + } +} + /** * dock_init_hotplug - Initialize a hotplug device on a docking station. * @dd: Dock-dependent device. @@ -895,6 +905,7 @@ static int __init dock_add(acpi_handle handle) return 0; err_rmgroup: + remove_dock_dependent_devices(dock_station); sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); err_unregister: platform_device_unregister(dd); From e6c215f15a1cbf4cdd6996d95fba0c0d6c0f3ccc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:02:25 +0200 Subject: [PATCH 18/20] ACPI / dock: Do not check CONFIG_ACPI_DOCK_MODULE Since commit 94add0f (ACPI / dock: Initialize ACPI dock subsystem upfront) the ACPI dock driver cannot be a module, so CONFIG_ACPI_DOCK_MODULE is never set. For this reason, simplify the preprocessor conditional in include/acpi/acpi_drivers.h referring to that sybbol unnecessarily. Signed-off-by: Rafael J. Wysocki --- include/acpi/acpi_drivers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index b420939f5eb5..0cf85786ed21 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -117,7 +117,7 @@ struct acpi_dock_ops { acpi_notify_handler uevent; }; -#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE) +#ifdef CONFIG_ACPI_DOCK extern int is_dock_device(acpi_handle handle); extern int register_dock_notifier(struct notifier_block *nb); extern void unregister_dock_notifier(struct notifier_block *nb); @@ -150,6 +150,6 @@ static inline int register_hotplug_dock_device(acpi_handle handle, static inline void unregister_hotplug_dock_device(acpi_handle handle) { } -#endif +#endif /* CONFIG_ACPI_DOCK */ #endif /*__ACPI_DRIVERS_H__*/ From f09ce741a03ad7de591aa47e760fbeee28567b63 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:03:25 +0200 Subject: [PATCH 19/20] ACPI / dock / PCI: Drop ACPI dock notifier chain The only user of the ACPI dock notifier chain is the ACPI-based PCI hotplug (acpiphp) driver that uses it to carry out post-dock fixups needed by some systems with broken _DCK. However, it is not necessary to use a separate notifier chain for that, as it can be simply replaced with a new callback in struct acpi_dock_ops. For this reason, add a new .fixup() callback to struct acpi_dock_ops and make hotplug_dock_devices() execute it for all dock devices with hotplug operations registered. Accordingly, make acpiphp point that callback to the function carrying out the post-dock fixups and do not register a separate dock notifier for each device registering dock operations. Finally, drop the ACPI dock notifier chain that has no more users. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 66 +++++++++++------------------- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_glue.c | 18 ++------ include/acpi/acpi_drivers.h | 10 +---- 4 files changed, 30 insertions(+), 65 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 3e20b13fa272..c89a9c3b48b4 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -51,8 +51,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " " the driver to wait for userspace to write the undock sysfs file " " before undocking"); -static struct atomic_notifier_head dock_notifier_list; - static const struct acpi_device_id dock_device_ids[] = { {"LNXDOCK", 0}, {"", 0}, @@ -89,6 +87,12 @@ struct dock_dependent_device { #define DOCK_EVENT 3 #define UNDOCK_EVENT 2 +enum dock_callback_type { + DOCK_CALL_HANDLER, + DOCK_CALL_FIXUP, + DOCK_CALL_UEVENT, +}; + /***************************************************************************** * Dock Dependent device functions * *****************************************************************************/ @@ -179,7 +183,7 @@ static void dock_release_hotplug(struct dock_dependent_device *dd) } static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, - bool uevent) + enum dock_callback_type cb_type) { acpi_notify_handler cb = NULL; bool run = false; @@ -189,8 +193,18 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, if (dd->hp_context) { run = true; dd->hp_refcount++; - if (dd->hp_ops) - cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler; + 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; + } + } } mutex_unlock(&hotplug_lock); @@ -372,9 +386,13 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) { struct dock_dependent_device *dd; + /* Call driver specific post-dock fixups. */ + list_for_each_entry(dd, &ds->dependent_devices, list) + dock_hotplug_event(dd, event, DOCK_CALL_FIXUP); + /* Call driver specific hotplug functions. */ list_for_each_entry(dd, &ds->dependent_devices, list) - dock_hotplug_event(dd, event, false); + dock_hotplug_event(dd, event, DOCK_CALL_HANDLER); /* * Now make sure that an acpi_device is created for each dependent @@ -405,7 +423,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); list_for_each_entry(dd, &ds->dependent_devices, list) - dock_hotplug_event(dd, event, true); + dock_hotplug_event(dd, event, DOCK_CALL_UEVENT); if (num != DOCK_EVENT) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); @@ -487,37 +505,6 @@ static int dock_in_progress(struct dock_station *ds) return 0; } -/** - * register_dock_notifier - add yourself to the dock notifier list - * @nb: the callers notifier block - * - * If a driver wishes to be notified about dock events, they can - * use this function to put a notifier block on the dock notifier list. - * this notifier call chain will be called after a dock event, but - * before hotplugging any new devices. - */ -int register_dock_notifier(struct notifier_block *nb) -{ - if (!dock_station_count) - return -ENODEV; - - return atomic_notifier_chain_register(&dock_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(register_dock_notifier); - -/** - * unregister_dock_notifier - remove yourself from the dock notifier list - * @nb: the callers notifier block - */ -void unregister_dock_notifier(struct notifier_block *nb) -{ - if (!dock_station_count) - return; - - atomic_notifier_chain_unregister(&dock_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_dock_notifier); - /** * register_hotplug_dock_device - register a hotplug function * @handle: the handle of the device @@ -658,8 +645,6 @@ static void dock_notify(struct dock_station *ds, u32 event) complete_dock(ds); break; } - atomic_notifier_call_chain(&dock_notifier_list, - event, NULL); hotplug_dock_devices(ds, event); complete_dock(ds); dock_event(ds, event, DOCK_EVENT); @@ -945,7 +930,6 @@ void __init acpi_dock_init(void) return; } - ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); } diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 6fdd49c6f0b9..6c781edabcc6 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -122,7 +122,6 @@ struct acpiphp_func { struct acpiphp_slot *slot; /* parent */ struct list_head sibling; - struct notifier_block nb; acpi_handle handle; u8 function; /* pci function# */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a0a7133a1d12..8bfad0dc29ab 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -119,15 +119,14 @@ static void free_bridge(struct kref *kref) * TBD - figure out a way to only call fixups for * systems that require them. */ -static int post_dock_fixups(struct notifier_block *nb, unsigned long val, - void *v) +static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { - struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb); + struct acpiphp_func *func = data; struct pci_bus *bus = func->slot->bridge->pci_bus; u32 buses; if (!bus->self) - return NOTIFY_OK; + return; /* fixup bad _DCK function that rewrites * secondary bridge on slot @@ -143,11 +142,11 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, | ((unsigned int)(bus->busn_res.end) << 16); pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); } - return NOTIFY_OK; } static const struct acpi_dock_ops acpiphp_dock_ops = { + .fixup = post_dock_fixups, .handler = hotplug_event_func, }; @@ -315,14 +314,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) &acpiphp_dock_ops, newfunc, acpiphp_dock_init, acpiphp_dock_release)) dbg("failed to register dock device\n"); - - /* we need to be notified when dock events happen - * outside of the hotplug operation, since we may - * need to do fixups before we can hotplug. - */ - newfunc->nb.notifier_call = post_dock_fixups; - if (register_dock_notifier(&newfunc->nb)) - dbg("failed to register a dock notifier"); } /* install notify handler */ @@ -472,7 +463,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) list_for_each_entry(func, &slot->funcs, sibling) { if (is_dock_device(func->handle)) { unregister_hotplug_dock_device(func->handle); - unregister_dock_notifier(&func->nb); } if (!(func->flags & FUNC_HAS_DCK)) { status = acpi_remove_notify_handler(func->handle, diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 0cf85786ed21..1cedfcb1bd88 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -113,14 +113,13 @@ void pci_acpi_crs_quirks(void); Dock Station -------------------------------------------------------------------------- */ struct acpi_dock_ops { + acpi_notify_handler fixup; acpi_notify_handler handler; acpi_notify_handler uevent; }; #ifdef CONFIG_ACPI_DOCK extern int is_dock_device(acpi_handle handle); -extern int register_dock_notifier(struct notifier_block *nb); -extern void unregister_dock_notifier(struct notifier_block *nb); extern int register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, void *context, @@ -132,13 +131,6 @@ static inline int is_dock_device(acpi_handle handle) { return 0; } -static inline int register_dock_notifier(struct notifier_block *nb) -{ - return -ENODEV; -} -static inline void unregister_dock_notifier(struct notifier_block *nb) -{ -} static inline int register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, void *context, From 2efbca4dfc7b43951de6dd1647f9eebda9d4372b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:23:36 +0200 Subject: [PATCH 20/20] ACPI / dock: Drop unnecessary local variable from dock_add() The local variable id in dock_add() is not necessary, so drop it. While we're at it, use an initializer to clear the local variable ds and drop the memset() used for this purpose. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c89a9c3b48b4..f601658a4ad2 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -836,14 +836,13 @@ static struct attribute_group dock_attribute_group = { */ static int __init dock_add(acpi_handle handle) { - int ret, id; - struct dock_station ds, *dock_station; + struct dock_station *dock_station, ds = { NULL, }; struct platform_device *dd; acpi_status status; + int ret; - id = dock_station_count; - memset(&ds, 0, sizeof(ds)); - dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds)); + dd = platform_device_register_data(NULL, "dock", dock_station_count, + &ds, sizeof(ds)); if (IS_ERR(dd)) return PTR_ERR(dd);