From f22ff5523af8b365167cb79189f8b91470d57c8c Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:34 +0800 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 8265607..c36de86 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); -- cgit v0.10.2 From ed633e709fa633c6bc24f4d6ecb55ad0c14fd335 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:35 +0800 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c36de86..750f958 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); -- cgit v0.10.2 From d423c083ff3b3adc1e42a2f2c03c8430a6e0220f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:36 +0800 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 750f958..f3ec722 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; -- cgit v0.10.2 From 472d963befe28b8614ea2789757b27536c8d79eb Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:37 +0800 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index f3ec722..1bdb1fa 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; } /** -- cgit v0.10.2 From 952c63e9512b63220886105cfc791507046fa39a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:38 +0800 Subject: 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 diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 082b4dd..a762716 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 80403c1..84bf06c 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 1e9732d..51d7948 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 3322b47..b7201fc 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 1098557..ada0b4c 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 74437130..b08d973 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 5d7075d..a84533e 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 e6bd910..ddefa5f 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 56e6b68..62b2811 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 -- cgit v0.10.2 From 0db98202605c3d32e023d43c30b5bd878f520976 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:39 +0800 Subject: 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 diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index a762716..74669ac 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 a5bb33b..a5a032e 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 5c28c89..1460c88 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 187ab61..81b0f03 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 a33821c..94523c7 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 b08d973..87b8588 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 a84533e..b862c7f 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 62b2811..e386258 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 -- cgit v0.10.2 From 7d2421f84b445dc48c68d33911f1fd6ce6853ee3 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:40 +0800 Subject: 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 diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ada0b4c..4c25c3b 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 87b8588..552248b 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 e386258..f499157 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 -- cgit v0.10.2 From ebf4df8db0e7e5db9f7fca5fcd0c2b90ac954385 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:41 +0800 Subject: 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 diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4c25c3b..62e2055 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1480,43 +1480,45 @@ 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 f499157..facc0ba 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 -- cgit v0.10.2 From c9b5471f8866956919955b70ab27b4737b8bce30 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:42 +0800 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 1bdb1fa..810d1d7 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) @@ -447,37 +401,6 @@ static void dock_event(struct dock_station *ds, u32 event, int num) } /** - * 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 * @dock: to dock, or undock - that is the question @@ -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; -- cgit v0.10.2 From ecd046da57d3327367b930478234e58f01bc9f0f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:43 +0800 Subject: 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 diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 59df857..a0a7133 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); -- cgit v0.10.2 From d460acebd7959cc91e7edc594d90adb9b72a0b05 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:42:51 +0200 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 810d1d7..c107615 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); -- cgit v0.10.2 From 96c0a4d4902c3d5f56bde95d3e2d96689ca64b6d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:46:02 +0200 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c107615..7c86d01 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; } -- cgit v0.10.2 From 37f908778f20bbcc35ab9a98a5b584329c6abf08 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:46:42 +0200 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 7c86d01..41c5d04 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); -- cgit v0.10.2 From 4ec24065a65b4debfdeb591cc01a4aa092651f53 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:47:14 +0200 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 41c5d04..b1170d6 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); } -- cgit v0.10.2 From 59401ccce8729e5c43f9781cc5570da5ca470e27 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:48:49 +0200 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index b1170d6..a326c79 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; - - acpi_scan_lock_acquire(); - - 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; + return; - 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); + dd = kmalloc(sizeof(*dd), GFP_KERNEL); + if (dd) { + acpi_status status; - 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); } -- cgit v0.10.2 From f716fc2ac037c45a6c641eb9f20ec602e8d04e14 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:49:55 +0200 Subject: 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 diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a5a032e..6fd27a9 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 facc0ba..71f3fd4 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 */ -- cgit v0.10.2 From a30c4c5ee85680bb66ed8a6c0b0bf4921125c378 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:50:24 +0200 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index a326c79..3e20b13 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); -- cgit v0.10.2 From e6c215f15a1cbf4cdd6996d95fba0c0d6c0f3ccc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:02:25 +0200 Subject: 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 diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index b420939..0cf8578 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__*/ -- cgit v0.10.2 From f09ce741a03ad7de591aa47e760fbeee28567b63 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:03:25 +0200 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 3e20b13..c89a9c3 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); @@ -488,37 +506,6 @@ static int dock_in_progress(struct dock_station *ds) } /** - * 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 * @ops: handlers to call after docking @@ -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 6fdd49c..6c781ed 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 a0a7133..8bfad0d 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 0cf8578..1cedfcb 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, -- cgit v0.10.2 From 2efbca4dfc7b43951de6dd1647f9eebda9d4372b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:23:36 +0200 Subject: 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 diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c89a9c3..f601658 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); -- cgit v0.10.2 From 137b944e100278d696826cf25c83014ac17473fe Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:48 +0200 Subject: cpuidle: Make it clear that governors cannot be modules cpufreq governors are defined as modules in the code, but the Kconfig options do not allow them to be built as modules. This is not really a problem, but the cpuidle init ordering is: the cpuidle init functions (framework and driver) and then the governors. That leads to some weirdness in the cpuidle framework. Namely, cpuidle_register_device() calls cpuidle_enable_device() which fails at the first attempt, because governors have not been registered yet. When a governor is registered, the framework calls cpuidle_enable_device() again which runs __cpuidle_register_device() only then. Of course, for that to work, the cpuidle_enable_device() return value has to be ignored by cpuidle_register_device(). Instead of having this cyclic call graph and relying on a positive side effects of the hackish back and forth cpuidle_enable_device() calls it is better to fix the cpuidle init ordering. To that end, replace the module init code with postcore_initcall() so we have: * cpuidle framework : core_initcall * cpuidle governors : postcore_initcall * cpuidle drivers : device_initcall and remove the corresponding module exit code as it is dead anyway (governors can't be built as modules). [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 9b78405..9f08e8c 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -192,14 +192,4 @@ static int __init init_ladder(void) return cpuidle_register_governor(&ladder_governor); } -/** - * exit_ladder - exits the governor - */ -static void __exit exit_ladder(void) -{ - cpuidle_unregister_governor(&ladder_governor); -} - -MODULE_LICENSE("GPL"); -module_init(init_ladder); -module_exit(exit_ladder); +postcore_initcall(init_ladder); diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index fe343a0..743138c 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -540,14 +540,4 @@ static int __init init_menu(void) return cpuidle_register_governor(&menu_governor); } -/** - * exit_menu - exits the governor - */ -static void __exit exit_menu(void) -{ - cpuidle_unregister_governor(&menu_governor); -} - -MODULE_LICENSE("GPL"); -module_init(init_menu); -module_exit(exit_menu); +postcore_initcall(init_menu); -- cgit v0.10.2 From 10b9d3f8a4d5c82bff5b232a0063669dc0e0d725 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:49 +0200 Subject: cpuidle: Check cpuidle_enable_device() return value We previously changed the ordering of the cpuidle framework initialization so that the governors are registered before the drivers which can register their devices right from the start. Now, we can safely remove the __cpuidle_register_device() call hack in cpuidle_enable_device() and check if the driver has been registered before enabling it. Then, cpuidle_register_device() can consistently check the cpuidle_enable_device() return value when enabling the device. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index fdc432f..4deed97 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -292,15 +292,12 @@ int cpuidle_enable_device(struct cpuidle_device *dev) if (!drv || !cpuidle_curr_governor) return -EIO; + if (!dev->registered) + return -EINVAL; + if (!dev->state_count) dev->state_count = drv->state_count; - if (dev->registered == 0) { - ret = __cpuidle_register_device(dev); - if (ret) - return ret; - } - poll_idle_init(drv); ret = cpuidle_add_device_sysfs(dev); @@ -415,13 +412,17 @@ int cpuidle_register_device(struct cpuidle_device *dev) return ret; } - cpuidle_enable_device(dev); + ret = cpuidle_enable_device(dev); + if (ret) { + mutex_unlock(&cpuidle_lock); + return ret; + } + cpuidle_install_idle_handler(); mutex_unlock(&cpuidle_lock); return 0; - } EXPORT_SYMBOL_GPL(cpuidle_register_device); -- cgit v0.10.2 From f89ae89e2790341587f7132f0552c941342115e9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:50 +0200 Subject: cpuidle: Fix white space to follow CodingStyle Fix white space in the cpuidle code to follow the rules described in CodingStyle. No changes in behavior should result from this. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 428754a..7d4448a 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -33,7 +33,8 @@ static ssize_t show_available_governors(struct device *dev, mutex_lock(&cpuidle_lock); list_for_each_entry(tmp, &cpuidle_governors, governor_list) { - if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2)) + if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - + CPUIDLE_NAME_LEN - 2)) goto out; i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name); } @@ -168,11 +169,13 @@ struct cpuidle_attr { #define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj) #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr) -static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf) + +static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr, + char *buf) { int ret = -EIO; struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); - struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr); + struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); if (cattr->show) { mutex_lock(&cpuidle_lock); @@ -182,12 +185,12 @@ static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char return ret; } -static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { int ret = -EIO; struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); - struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr); + struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); if (cattr->store) { mutex_lock(&cpuidle_lock); @@ -237,8 +240,8 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \ #define define_store_state_ull_function(_name) \ static ssize_t store_state_##_name(struct cpuidle_state *state, \ - struct cpuidle_state_usage *state_usage, \ - const char *buf, size_t size) \ + struct cpuidle_state_usage *state_usage, \ + const char *buf, size_t size) \ { \ unsigned long long value; \ int err; \ @@ -256,14 +259,16 @@ static ssize_t store_state_##_name(struct cpuidle_state *state, \ #define define_show_state_ull_function(_name) \ static ssize_t show_state_##_name(struct cpuidle_state *state, \ - struct cpuidle_state_usage *state_usage, char *buf) \ + struct cpuidle_state_usage *state_usage, \ + char *buf) \ { \ return sprintf(buf, "%llu\n", state_usage->_name);\ } #define define_show_state_str_function(_name) \ static ssize_t show_state_##_name(struct cpuidle_state *state, \ - struct cpuidle_state_usage *state_usage, char *buf) \ + struct cpuidle_state_usage *state_usage, \ + char *buf) \ { \ if (state->_name[0] == '\0')\ return sprintf(buf, "\n");\ @@ -309,8 +314,9 @@ struct cpuidle_state_kobj { #define kobj_to_state(k) (kobj_to_state_obj(k)->state) #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) -static ssize_t cpuidle_state_show(struct kobject * kobj, - struct attribute * attr ,char * buf) + +static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr, + char * buf) { int ret = -EIO; struct cpuidle_state *state = kobj_to_state(kobj); @@ -323,8 +329,8 @@ static ssize_t cpuidle_state_show(struct kobject * kobj, return ret; } -static ssize_t cpuidle_state_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t size) +static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) { int ret = -EIO; struct cpuidle_state *state = kobj_to_state(kobj); @@ -449,8 +455,8 @@ static void cpuidle_driver_sysfs_release(struct kobject *kobj) complete(&driver_kobj->kobj_unregister); } -static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr, - char * buf) +static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute *attr, + char *buf) { int ret = -EIO; struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); -- cgit v0.10.2 From 728ce22b696f9f1404a74d7b2279a65933553a1b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:51 +0200 Subject: cpuidle: Make cpuidle's sysfs directory dynamically allocated The cpuidle sysfs code is designed to have a single instance of per CPU cpuidle directory. It is not possible to remove the sysfs entry and create it again. This is not a problem with the current code but future changes will add CPU hotplug support to enable/disable the device, so it will need to remove the sysfs entry like other subsystems do. That won't be possible without this change, because the kobj is a static object which can't be reused for kobj_init_and_add(). Add cpuidle_device_kobj to be allocated dynamically when adding/removing a sysfs entry which is consistent with the other cpuidle's sysfs entries. An added benefit is that the sysfs code is now more self-contained and the includes needed for sysfs can be moved from cpuidle.h directly into sysfs.c so as to reduce the total number of headers dragged along with cpuidle.h. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 7d4448a..8739cc0 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -11,8 +11,10 @@ #include #include #include +#include #include #include +#include #include "cpuidle.h" @@ -167,14 +169,27 @@ struct cpuidle_attr { #define define_one_rw(_name, show, store) \ static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store) -#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj) #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr) +struct cpuidle_device_kobj { + struct cpuidle_device *dev; + struct completion kobj_unregister; + struct kobject kobj; +}; + +static inline struct cpuidle_device *to_cpuidle_device(struct kobject *kobj) +{ + struct cpuidle_device_kobj *kdev = + container_of(kobj, struct cpuidle_device_kobj, kobj); + + return kdev->dev; +} + static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr, char *buf) { int ret = -EIO; - struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); + struct cpuidle_device *dev = to_cpuidle_device(kobj); struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); if (cattr->show) { @@ -189,7 +204,7 @@ static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { int ret = -EIO; - struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); + struct cpuidle_device *dev = to_cpuidle_device(kobj); struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); if (cattr->store) { @@ -207,9 +222,10 @@ static const struct sysfs_ops cpuidle_sysfs_ops = { static void cpuidle_sysfs_release(struct kobject *kobj) { - struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); + struct cpuidle_device_kobj *kdev = + container_of(kobj, struct cpuidle_device_kobj, kobj); - complete(&dev->kobj_unregister); + complete(&kdev->kobj_unregister); } static struct kobj_type ktype_cpuidle = { @@ -377,6 +393,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) { int i, ret = -ENOMEM; struct cpuidle_state_kobj *kobj; + struct cpuidle_device_kobj *kdev = device->kobj_dev; struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); /* state statistics */ @@ -389,7 +406,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) init_completion(&kobj->kobj_unregister); ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, - &device->kobj, "state%d", i); + &kdev->kobj, "state%d", i); if (ret) { kfree(kobj); goto error_state; @@ -506,6 +523,7 @@ static struct kobj_type ktype_driver_cpuidle = { static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) { struct cpuidle_driver_kobj *kdrv; + struct cpuidle_device_kobj *kdev = dev->kobj_dev; struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); int ret; @@ -517,7 +535,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) init_completion(&kdrv->kobj_unregister); ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, - &dev->kobj, "driver"); + &kdev->kobj, "driver"); if (ret) { kfree(kdrv); return ret; @@ -586,16 +604,28 @@ void cpuidle_remove_device_sysfs(struct cpuidle_device *device) */ int cpuidle_add_sysfs(struct cpuidle_device *dev) { + struct cpuidle_device_kobj *kdev; struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); int error; - init_completion(&dev->kobj_unregister); + kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); + if (!kdev) + return -ENOMEM; + kdev->dev = dev; + dev->kobj_dev = kdev; + + init_completion(&kdev->kobj_unregister); + + error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj, + "cpuidle"); + if (error) { + kfree(kdev); + return error; + } - error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, - "cpuidle"); - if (!error) - kobject_uevent(&dev->kobj, KOBJ_ADD); - return error; + kobject_uevent(&kdev->kobj, KOBJ_ADD); + + return 0; } /** @@ -604,6 +634,9 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev) */ void cpuidle_remove_sysfs(struct cpuidle_device *dev) { - kobject_put(&dev->kobj); - wait_for_completion(&dev->kobj_unregister); + struct cpuidle_device_kobj *kdev = dev->kobj_dev; + + kobject_put(&kdev->kobj); + wait_for_completion(&kdev->kobj_unregister); + kfree(kdev); } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 0bc4b74..b922db5 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -13,8 +13,6 @@ #include #include -#include -#include #include #define CPUIDLE_STATE_MAX 10 @@ -61,6 +59,8 @@ struct cpuidle_state { #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) +struct cpuidle_device_kobj; + struct cpuidle_device { unsigned int registered:1; unsigned int enabled:1; @@ -71,9 +71,8 @@ struct cpuidle_device { struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; struct cpuidle_driver_kobj *kobj_driver; + struct cpuidle_device_kobj *kobj_dev; struct list_head device_list; - struct kobject kobj; - struct completion kobj_unregister; #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED int safe_state_index; -- cgit v0.10.2 From 1a7064380e6639e1cc5ed609ceb1ed46f3f188e3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:52 +0200 Subject: cpuidle: Add missing forward declarations of structures Add missing forward declarations of struct cpuidle_state_kobj and struct cpuidle_driver_kobj in cpuidle.h. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index b922db5..781addc 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -60,6 +60,8 @@ struct cpuidle_state { #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) struct cpuidle_device_kobj; +struct cpuidle_state_kobj; +struct cpuidle_driver_kobj; struct cpuidle_device { unsigned int registered:1; -- cgit v0.10.2 From f6bb51a53a7535c79d6c65862d6b48e83340b337 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:53 +0200 Subject: cpuidle: Introduce __cpuidle_unregister_device() To reduce code duplication related to the unregistration of cpuidle devices, introduce __cpuidle_unregister_device() and move all of the unregistration code to that function. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 4deed97..d78c6d8 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -42,8 +42,6 @@ void disable_cpuidle(void) off = 1; } -static int __cpuidle_register_device(struct cpuidle_device *dev); - /** * cpuidle_play_dead - cpu off-lining * @@ -357,6 +355,15 @@ void cpuidle_disable_device(struct cpuidle_device *dev) EXPORT_SYMBOL_GPL(cpuidle_disable_device); +static void __cpuidle_unregister_device(struct cpuidle_device *dev) +{ + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); + + list_del(&dev->device_list); + per_cpu(cpuidle_devices, dev->cpu) = NULL; + module_put(drv->owner); +} + /** * __cpuidle_register_device - internal register function called before register * and enable routines @@ -374,24 +381,15 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); - ret = cpuidle_add_sysfs(dev); - if (ret) - goto err_sysfs; ret = cpuidle_coupled_register_device(dev); - if (ret) - goto err_coupled; + if (ret) { + __cpuidle_unregister_device(dev); + return ret; + } dev->registered = 1; return 0; - -err_coupled: - cpuidle_remove_sysfs(dev); -err_sysfs: - list_del(&dev->device_list); - per_cpu(cpuidle_devices, dev->cpu) = NULL; - module_put(drv->owner); - return ret; } /** @@ -407,22 +405,30 @@ int cpuidle_register_device(struct cpuidle_device *dev) mutex_lock(&cpuidle_lock); - if ((ret = __cpuidle_register_device(dev))) { - mutex_unlock(&cpuidle_lock); - return ret; - } + ret = __cpuidle_register_device(dev); + if (ret) + goto out_unlock; + + ret = cpuidle_add_sysfs(dev); + if (ret) + goto out_unregister; ret = cpuidle_enable_device(dev); - if (ret) { - mutex_unlock(&cpuidle_lock); - return ret; - } + if (ret) + goto out_sysfs; cpuidle_install_idle_handler(); +out_unlock: mutex_unlock(&cpuidle_lock); - return 0; + return ret; + +out_sysfs: + cpuidle_remove_sysfs(dev); +out_unregister: + __cpuidle_unregister_device(dev); + goto out_unlock; } EXPORT_SYMBOL_GPL(cpuidle_register_device); @@ -433,8 +439,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device); */ void cpuidle_unregister_device(struct cpuidle_device *dev) { - struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); - if (dev->registered == 0) return; @@ -443,14 +447,12 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) cpuidle_disable_device(dev); cpuidle_remove_sysfs(dev); - list_del(&dev->device_list); - per_cpu(cpuidle_devices, dev->cpu) = NULL; + + __cpuidle_unregister_device(dev); cpuidle_coupled_unregister_device(dev); cpuidle_resume_and_unlock(); - - module_put(drv->owner); } EXPORT_SYMBOL_GPL(cpuidle_unregister_device); -- cgit v0.10.2 From 5df0aa7341bd94ca2023a60c64c63faeb6ec209d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:54 +0200 Subject: cpuidle: Introduce __cpuidle_device_init() Add __cpuidle_device_init() for initializing the cpuidle_device structure. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index d78c6d8..5b63185 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -276,7 +276,7 @@ static void poll_idle_init(struct cpuidle_driver *drv) {} */ int cpuidle_enable_device(struct cpuidle_device *dev) { - int ret, i; + int ret; struct cpuidle_driver *drv; if (!dev) @@ -306,12 +306,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) (ret = cpuidle_curr_governor->enable(drv, dev))) goto fail_sysfs; - for (i = 0; i < dev->state_count; i++) { - dev->states_usage[i].usage = 0; - dev->states_usage[i].time = 0; - } - dev->last_residency = 0; - smp_wmb(); dev->enabled = 1; @@ -364,6 +358,14 @@ static void __cpuidle_unregister_device(struct cpuidle_device *dev) module_put(drv->owner); } +static int __cpuidle_device_init(struct cpuidle_device *dev) +{ + memset(dev->states_usage, 0, sizeof(dev->states_usage)); + dev->last_residency = 0; + + return 0; +} + /** * __cpuidle_register_device - internal register function called before register * and enable routines @@ -405,6 +407,10 @@ int cpuidle_register_device(struct cpuidle_device *dev) mutex_lock(&cpuidle_lock); + ret = __cpuidle_device_init(dev); + if (ret) + goto out_unlock; + ret = __cpuidle_register_device(dev); if (ret) goto out_unlock; -- cgit v0.10.2 From c878a52d3c7cabab5b24460825c24eafd8be7058 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:55 +0200 Subject: cpuidle: Check if device is already registered Make __cpuidle_register_device() check whether or not the device has been registered already and return -EBUSY immediately if that's the case. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 5b63185..d75040d 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -400,13 +400,16 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) */ int cpuidle_register_device(struct cpuidle_device *dev) { - int ret; + int ret = -EBUSY; if (!dev) return -EINVAL; mutex_lock(&cpuidle_lock); + if (dev->registered) + goto out_unlock; + ret = __cpuidle_device_init(dev); if (ret) goto out_unlock; -- cgit v0.10.2 From 1696d9dc57e062ce5200f6a42a6aaada15b434bb Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 15 Jul 2013 10:15:09 +0200 Subject: ACPI: Remove the old /proc/acpi/event interface It is quite some time that this one has been deprecated. Get rid of it. Should some really important user be overseen, it may be reverted and the userspace program worked on first, but it is time to do something to get rid of this old stuff... Signed-off-by: Thomas Renninger Acked-by: Matthew Garrett Acked-by: Henrique de Moraes Holschuh Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/laptops/asus-laptop.txt b/Documentation/laptops/asus-laptop.txt index 69f9fb3..79a1bc6 100644 --- a/Documentation/laptops/asus-laptop.txt +++ b/Documentation/laptops/asus-laptop.txt @@ -8,8 +8,8 @@ http://acpi4asus.sf.net/ This driver provides support for extra features of ACPI-compatible ASUS laptops. It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or - VICTOR XP7210 for example). It makes all the extra buttons generate standard - ACPI events that go through /proc/acpi/events and input events (like keyboards). + VICTOR XP7210 for example). It makes all the extra buttons generate input + events (like keyboards). On some models adds support for changing the display brightness and output, switching the LCD backlight on and off, and most importantly, allows you to blink those fancy LEDs intended for reporting mail and wireless status. @@ -55,8 +55,8 @@ Usage DSDT) to me. That's all, now, all the events generated by the hotkeys of your laptop - should be reported in your /proc/acpi/event entry. You can check with - "acpi_listen". + should be reported via netlink events. You can check with + "acpi_genl monitor" (part of the acpica project). Hotkeys are also reported as input keys (like keyboards) you can check which key are supported using "xev" under X11. diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt index 0d5ac7f..978b1e6 100644 --- a/Documentation/laptops/sony-laptop.txt +++ b/Documentation/laptops/sony-laptop.txt @@ -12,10 +12,10 @@ Fn keys (hotkeys): ------------------ Some models report hotkeys through the SNC or SPIC devices, such events are reported both through the ACPI subsystem as acpi events and through the INPUT -subsystem. See the logs of acpid or /proc/acpi/event and -/proc/bus/input/devices to find out what those events are and which input -devices are created by the driver. Additionally, loading the driver with the -debug option will report all events in the kernel log. +subsystem. See the logs of /proc/bus/input/devices to find out what those +events are and which input devices are created by the driver. +Additionally, loading the driver with the debug option will report all events +in the kernel log. The "scancodes" passed to the input system (that can be remapped with udev) are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 100bd72..3278a21 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -91,24 +91,6 @@ config ACPI_EC_DEBUGFS Thus this option is a debug option that helps to write ACPI drivers and can be used to identify ACPI code or EC firmware bugs. -config ACPI_PROC_EVENT - bool "Deprecated /proc/acpi/event support" - depends on PROC_FS - default y - help - A user-space daemon, acpid, typically reads /proc/acpi/event - and handles all ACPI-generated events. - - These events are now delivered to user-space either - via the input layer or as netlink events. - - This build option enables the old code for legacy - user-space implementation. After some time, this will - be moved under CONFIG_ACPI_PROCFS, and then deleted. - - Say Y here to retain the old behaviour. Say N if your - user-space is newer than kernel 2.6.23 (September 2007). - config ACPI_AC tristate "AC Adapter" depends on X86 diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 4f4e741..f37beaa3 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -267,7 +267,6 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event) msleep(ac_sleep_before_get_state_ms); acpi_ac_get_state(ac); - acpi_bus_generate_proc_event(device, event, (u32) ac->state); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, (u32) ac->state); diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 27bb6a9..6230637 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -452,7 +452,6 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, switch (event) { case ACPI_PROCESSOR_AGGREGATOR_NOTIFY: acpi_pad_handle_notify(handle); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 082b4dd..33dfa85 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1034,8 +1034,6 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) if (event == ACPI_BATTERY_NOTIFY_INFO) acpi_battery_refresh(battery); acpi_battery_update(battery); - acpi_bus_generate_proc_event(device, event, - acpi_battery_present(battery)); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, acpi_battery_present(battery)); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a5bb33b..b6e9a37 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -346,104 +346,6 @@ static void acpi_bus_osc_support(void) } /* -------------------------------------------------------------------------- - Event Management - -------------------------------------------------------------------------- */ - -#ifdef CONFIG_ACPI_PROC_EVENT -static DEFINE_SPINLOCK(acpi_bus_event_lock); - -LIST_HEAD(acpi_bus_event_list); -DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue); - -extern int event_is_open; - -int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data) -{ - struct acpi_bus_event *event; - unsigned long flags; - - /* drop event on the floor if no one's listening */ - if (!event_is_open) - return 0; - - event = kzalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC); - if (!event) - return -ENOMEM; - - strcpy(event->device_class, device_class); - strcpy(event->bus_id, bus_id); - event->type = type; - event->data = data; - - spin_lock_irqsave(&acpi_bus_event_lock, flags); - list_add_tail(&event->node, &acpi_bus_event_list); - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - - wake_up_interruptible(&acpi_bus_event_queue); - - return 0; - -} - -EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4); - -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) -{ - if (!device) - return -EINVAL; - return acpi_bus_generate_proc_event4(device->pnp.device_class, - device->pnp.bus_id, type, data); -} - -EXPORT_SYMBOL(acpi_bus_generate_proc_event); - -int acpi_bus_receive_event(struct acpi_bus_event *event) -{ - unsigned long flags; - struct acpi_bus_event *entry = NULL; - - DECLARE_WAITQUEUE(wait, current); - - - if (!event) - return -EINVAL; - - if (list_empty(&acpi_bus_event_list)) { - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&acpi_bus_event_queue, &wait); - - if (list_empty(&acpi_bus_event_list)) - schedule(); - - remove_wait_queue(&acpi_bus_event_queue, &wait); - set_current_state(TASK_RUNNING); - - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&acpi_bus_event_lock, flags); - if (!list_empty(&acpi_bus_event_list)) { - entry = list_entry(acpi_bus_event_list.next, - struct acpi_bus_event, node); - list_del(&entry->node); - } - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - - if (!entry) - return -ENODEV; - - memcpy(event, entry, sizeof(struct acpi_bus_event)); - - kfree(entry); - - return 0; -} - -#endif /* CONFIG_ACPI_PROC_EVENT */ - -/* -------------------------------------------------------------------------- Notification Handling -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index d2e617b..a557738 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -303,8 +303,6 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) pm_wakeup_event(&device->dev, 0); } - - acpi_bus_generate_proc_event(device, event, ++button->pushed); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 1442737..8247fcd 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -21,100 +21,6 @@ #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("event"); -#ifdef CONFIG_ACPI_PROC_EVENT -/* Global vars for handling event proc entry */ -static DEFINE_SPINLOCK(acpi_system_event_lock); -int event_is_open = 0; -extern struct list_head acpi_bus_event_list; -extern wait_queue_head_t acpi_bus_event_queue; - -static int acpi_system_open_event(struct inode *inode, struct file *file) -{ - spin_lock_irq(&acpi_system_event_lock); - - if (event_is_open) - goto out_busy; - - event_is_open = 1; - - spin_unlock_irq(&acpi_system_event_lock); - return 0; - - out_busy: - spin_unlock_irq(&acpi_system_event_lock); - return -EBUSY; -} - -static ssize_t -acpi_system_read_event(struct file *file, char __user * buffer, size_t count, - loff_t * ppos) -{ - int result = 0; - struct acpi_bus_event event; - static char str[ACPI_MAX_STRING]; - static int chars_remaining = 0; - static char *ptr; - - if (!chars_remaining) { - memset(&event, 0, sizeof(struct acpi_bus_event)); - - if ((file->f_flags & O_NONBLOCK) - && (list_empty(&acpi_bus_event_list))) - return -EAGAIN; - - result = acpi_bus_receive_event(&event); - if (result) - return result; - - chars_remaining = sprintf(str, "%s %s %08x %08x\n", - event.device_class ? event. - device_class : "", - event.bus_id ? event. - bus_id : "", event.type, - event.data); - ptr = str; - } - - if (chars_remaining < count) { - count = chars_remaining; - } - - if (copy_to_user(buffer, ptr, count)) - return -EFAULT; - - *ppos += count; - chars_remaining -= count; - ptr += count; - - return count; -} - -static int acpi_system_close_event(struct inode *inode, struct file *file) -{ - spin_lock_irq(&acpi_system_event_lock); - event_is_open = 0; - spin_unlock_irq(&acpi_system_event_lock); - return 0; -} - -static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) -{ - poll_wait(file, &acpi_bus_event_queue, wait); - if (!list_empty(&acpi_bus_event_list)) - return POLLIN | POLLRDNORM; - return 0; -} - -static const struct file_operations acpi_system_event_ops = { - .owner = THIS_MODULE, - .open = acpi_system_open_event, - .read = acpi_system_read_event, - .release = acpi_system_close_event, - .poll = acpi_system_poll_event, - .llseek = default_llseek, -}; -#endif /* CONFIG_ACPI_PROC_EVENT */ - /* ACPI notifier chain */ static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); @@ -280,9 +186,6 @@ static int acpi_event_genetlink_init(void) static int __init acpi_event_init(void) { -#ifdef CONFIG_ACPI_PROC_EVENT - struct proc_dir_entry *entry; -#endif int error = 0; if (acpi_disabled) @@ -293,15 +196,6 @@ static int __init acpi_event_init(void) if (error) printk(KERN_WARNING PREFIX "Failed to create genetlink family for ACPI event\n"); - -#ifdef CONFIG_ACPI_PROC_EVENT - /* 'event' [R] */ - entry = proc_create("event", S_IRUSR, acpi_root_dir, - &acpi_system_event_ops); - if (!entry) - return -ENODEV; -#endif - return 0; } diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 823be116..94b7b3b 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -91,21 +91,17 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) acpi_processor_ppc_has_changed(pr, 1); if (saved == pr->performance_platform_limit) break; - acpi_bus_generate_proc_event(device, event, - pr->performance_platform_limit); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, pr->performance_platform_limit); break; case ACPI_PROCESSOR_NOTIFY_POWER: acpi_processor_cst_has_changed(pr); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; case ACPI_PROCESSOR_NOTIFY_THROTTLING: acpi_processor_tstate_has_changed(pr); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index b6241ee..aef7e1c 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -873,14 +873,9 @@ static void acpi_sbs_callback(void *context) u8 saved_charger_state = sbs->charger_present; u8 saved_battery_state; acpi_ac_get_present(sbs); - if (sbs->charger_present != saved_charger_state) { -#ifdef CONFIG_ACPI_PROC_EVENT - acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, - ACPI_SBS_NOTIFY_STATUS, - sbs->charger_present); -#endif + if (sbs->charger_present != saved_charger_state) kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE); - } + if (sbs->manager_present) { for (id = 0; id < MAX_SBS_BAT; ++id) { if (!(sbs->batteries_supported & (1 << id))) @@ -890,12 +885,6 @@ static void acpi_sbs_callback(void *context) acpi_battery_read(bat); if (saved_battery_state == bat->present) continue; -#ifdef CONFIG_ACPI_PROC_EVENT - acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, - bat->name, - ACPI_SBS_NOTIFY_STATUS, - bat->present); -#endif kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE); } } diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index a33821c..547a906 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -769,7 +769,6 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip, else return 0; - acpi_bus_generate_proc_event(tz->device, type, 1); acpi_bus_generate_netlink_event(tz->device->pnp.device_class, dev_name(&tz->device->dev), type, 1); @@ -980,14 +979,12 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) case ACPI_THERMAL_NOTIFY_THRESHOLDS: acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS); acpi_thermal_check(tz); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; case ACPI_THERMAL_NOTIFY_DEVICES: acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES); acpi_thermal_check(tz); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5d7075d..8f91a37 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1556,7 +1556,6 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) switch (event) { case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, * most likely via hotkey. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; @@ -1564,20 +1563,16 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) * connector. */ acpi_video_device_enumerate(video); acpi_video_device_rebind(video); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_VIDEO_NEXT; break; case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_VIDEO_PREV; break; @@ -1620,31 +1615,26 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESS_CYCLE; break; case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESSUP; break; case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESSDOWN; break; case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESS_ZERO; break; case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_DISPLAY_OFF; break; default: diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index bf2349db..7cc1fe22 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -876,11 +876,6 @@ found: if (useinput) sonypi_report_input_event(event); -#ifdef CONFIG_ACPI - if (sonypi_acpi_device) - acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event); -#endif - kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event, sizeof(event), &sonypi_device.fifo_lock); kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index c35e8ad..5394fff 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -270,7 +270,6 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context) if (subevent == 0x80) { dbg("%s: generationg bus event\n", __func__); - acpi_bus_generate_proc_event(note->device, note->event, detail); acpi_bus_generate_netlink_event(note->device->pnp.device_class, dev_name(¬e->device->dev), note->event, detail); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 8e268da..0e9c169 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1543,7 +1543,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) /* TODO Find a better way to handle events count. */ count = asus->event_count[event % 128]++; - acpi_bus_generate_proc_event(asus->device, event, count); acpi_bus_generate_netlink_event(asus->device->pnp.device_class, dev_name(&asus->device->dev), event, count); diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 5d26e70..a6afd41 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1269,7 +1269,6 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event) if (event > ACPI_MAX_SYS_NOTIFY) return; count = eeepc->event_count[event % 128]++; - acpi_bus_generate_proc_event(device, event, count); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, count); diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1c9386e..52b8a97 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -773,8 +773,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event) else set_lcd_level(newb); } - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); keycode = KEY_BRIGHTNESSUP; } else if (oldb > newb) { if (disable_brightness_adjust != 1) { @@ -783,8 +781,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event) else set_lcd_level(newb); } - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); keycode = KEY_BRIGHTNESSDOWN; } break; diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 4add9a3..984253d 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -464,9 +464,6 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) "error getting hotkey status\n")); return; } - - acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result); - if (!sparse_keymap_report_event(hotk_input_dev, result & 0xf, result & 0x80, false)) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 2ac045f..069821b 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1275,9 +1275,6 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) ev_type = HOTKEY; sony_laptop_report_input_event(real_ev); } - - acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev); - acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class, dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev); } @@ -4243,7 +4240,6 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) found: sony_laptop_report_input_event(device_event); - acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); sonypi_compat_report_event(device_event); return IRQ_HANDLED; } diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 54d31c0..e946c0d 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2282,10 +2282,6 @@ static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; static void tpacpi_hotkey_send_key(unsigned int scancode) { tpacpi_input_send_key_masked(scancode); - if (hotkey_report_mode < 2) { - acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, - 0x80, TP_HKEY_EV_HOTKEY_BASE + scancode); - } } static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) @@ -3737,13 +3733,6 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) "event happened to %s\n", TPACPI_MAIL); } - /* Legacy events */ - if (!ignore_acpi_ev && - (send_acpi_ev || hotkey_report_mode < 2)) { - acpi_bus_generate_proc_event(ibm->acpi->device, - event, hkey); - } - /* netlink events */ if (!ignore_acpi_ev && send_acpi_ev) { acpi_bus_generate_netlink_event( diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 56e6b68..2650d1f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -383,15 +383,6 @@ bool acpi_bus_can_wakeup(acpi_handle handle); static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; } #endif -#ifdef CONFIG_ACPI_PROC_EVENT -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data); -int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data); -int acpi_bus_receive_event(struct acpi_bus_event *event); -#else -static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) - { return 0; } -#endif - void acpi_scan_lock_acquire(void); void acpi_scan_lock_release(void); int acpi_scan_add_handler(struct acpi_scan_handler *handler); -- cgit v0.10.2 From 8b5301c5ff2568236c6e3b3d0c93a3e4194ec3f5 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Wed, 3 Jul 2013 14:48:39 +0200 Subject: platform / thinkpad: Remove deprecated hotkey_report_mode parameter It is somewhat strange that the default value to support the depracated interface is set (1). Anyway this has existed for years. The previous patch already removed the functionality to still export events through /proc. Now this param is useless and should vanish too. Signed-off-by: Thomas Renninger Acked-by: Matthew Garrett Acked-by: Henrique de Moraes Holschuh Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index cf7bc6c..86c5236 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -329,20 +329,6 @@ sysfs notes: This attribute has poll()/select() support. - hotkey_report_mode: - Returns the state of the procfs ACPI event report mode - filter for hot keys. If it is set to 1 (the default), - all hot key presses are reported both through the input - layer and also as ACPI events through procfs (but not - through netlink). If it is set to 2, hot key presses - are reported only through the input layer. - - This attribute is read-only in kernels 2.6.23 or later, - and read-write on earlier kernels. - - May return -EPERM (write access locked out by module - parameter) or -EACCES (read-only). - wakeup_reason: Set to 1 if the system is waking up because the user requested a bay ejection. Set to 2 if the system is @@ -518,24 +504,21 @@ SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A Non hotkey ACPI HKEY event map: ------------------------------- -Events that are not propagated by the driver, except for legacy -compatibility purposes when hotkey_report_mode is set to 1: - -0x5001 Lid closed -0x5002 Lid opened -0x5009 Tablet swivel: switched to tablet mode -0x500A Tablet swivel: switched to normal mode -0x7000 Radio Switch may have changed state - Events that are never propagated by the driver: 0x2304 System is waking up from suspend to undock 0x2305 System is waking up from suspend to eject bay 0x2404 System is waking up from hibernation to undock 0x2405 System is waking up from hibernation to eject bay +0x5001 Lid closed +0x5002 Lid opened +0x5009 Tablet swivel: switched to tablet mode +0x500A Tablet swivel: switched to normal mode 0x5010 Brightness level changed/control event 0x6000 KEYBOARD: Numlock key pressed 0x6005 KEYBOARD: Fn key pressed (TO BE VERIFIED) +0x7000 Radio Switch may have changed state + Events that are propagated by the driver to userspace: @@ -574,50 +557,6 @@ operating system is to force either an immediate suspend or hibernate cycle, or a system shutdown. Obviously, something is very wrong if this happens. -Compatibility notes: - -ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never -supported the input layer, and sent events over the procfs ACPI event -interface. - -To avoid sending duplicate events over the input layer and the ACPI -event interface, thinkpad-acpi 0.16 implements a module parameter -(hotkey_report_mode), and also a sysfs device attribute with the same -name. - -Make no mistake here: userspace is expected to switch to using the input -layer interface of thinkpad-acpi, together with the ACPI netlink event -interface in kernels 2.6.23 and later, or with the ACPI procfs event -interface in kernels 2.6.22 and earlier. - -If no hotkey_report_mode module parameter is specified (or it is set to -zero), the driver defaults to mode 1 (see below), and on kernels 2.6.22 -and earlier, also allows one to change the hotkey_report_mode through -sysfs. In kernels 2.6.23 and later, where the netlink ACPI event -interface is available, hotkey_report_mode cannot be changed through -sysfs (it is read-only). - -If the hotkey_report_mode module parameter is set to 1 or 2, it cannot -be changed later through sysfs (any writes will return -EPERM to signal -that hotkey_report_mode was locked. On 2.6.23 and later, where -hotkey_report_mode cannot be changed at all, writes will return -EACCES). - -hotkey_report_mode set to 1 makes the driver export through the procfs -ACPI event interface all hot key presses (which are *also* sent to the -input layer). This is a legacy compatibility behaviour, and it is also -the default mode of operation for the driver. - -hotkey_report_mode set to 2 makes the driver filter out the hot key -presses from the procfs ACPI event interface, so these events will only -be sent through the input layer. Userspace that has been updated to use -the thinkpad-acpi input layer interface should set hotkey_report_mode to -2. - -Hot key press events are never sent to the ACPI netlink event interface. -Really up-to-date userspace under kernel 2.6.23 and later is to use the -netlink interface and the input layer interface, and don't bother at all -with hotkey_report_mode. - Brightness hotkey notes: diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e946c0d..be67e5e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2022,8 +2022,6 @@ static u32 hotkey_driver_mask; /* events needed by the driver */ static u32 hotkey_user_mask; /* events visible to userspace */ static u32 hotkey_acpi_mask; /* events enabled in firmware */ -static unsigned int hotkey_report_mode; - static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; @@ -2878,18 +2876,6 @@ static void hotkey_tablet_mode_notify_change(void) "hotkey_tablet_mode"); } -/* sysfs hotkey report_mode -------------------------------------------- */ -static ssize_t hotkey_report_mode_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - (hotkey_report_mode != 0) ? hotkey_report_mode : 1); -} - -static struct device_attribute dev_attr_hotkey_report_mode = - __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); - /* sysfs wakeup reason (pollable) -------------------------------------- */ static ssize_t hotkey_wakeup_reason_show(struct device *dev, struct device_attribute *attr, @@ -2931,7 +2917,6 @@ static struct attribute *hotkey_attributes[] __initdata = { &dev_attr_hotkey_enable.attr, &dev_attr_hotkey_bios_enabled.attr, &dev_attr_hotkey_bios_mask.attr, - &dev_attr_hotkey_report_mode.attr, &dev_attr_hotkey_wakeup_reason.attr, &dev_attr_hotkey_wakeup_hotunplug_complete.attr, &dev_attr_hotkey_mask.attr, @@ -3435,11 +3420,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) "initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n", hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask); - dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "legacy ibm/hotkey event reporting over procfs %s\n", - (hotkey_report_mode < 2) ? - "enabled" : "disabled"); - tpacpi_inputdev->open = &hotkey_inputdev_open; tpacpi_inputdev->close = &hotkey_inputdev_close; @@ -8829,11 +8809,6 @@ module_param(brightness_enable, uint, 0444); MODULE_PARM_DESC(brightness_enable, "Enables backlight control when 1, disables when 0"); -module_param(hotkey_report_mode, uint, 0444); -MODULE_PARM_DESC(hotkey_report_mode, - "used for backwards compatibility with userspace, " - "see documentation"); - #ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT module_param_named(volume_mode, volume_mode, uint, 0444); MODULE_PARM_DESC(volume_mode, @@ -8964,10 +8939,6 @@ static int __init thinkpad_acpi_module_init(void) tpacpi_lifecycle = TPACPI_LIFE_INIT; - /* Parameter checking */ - if (hotkey_report_mode > 2) - return -EINVAL; - /* Driver-level probe */ ret = get_thinkpad_model_data(&thinkpad_id); -- cgit v0.10.2 From a7d5caf6d21814a855422df75c2d8c093cb2019a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 17 Jul 2013 09:48:15 +0800 Subject: ACPICA: Update comments about behavior when _STA does not exist No functional change. Add some comments concerning behavior when the _STA method does not exist. According to the ACPI specification, in this case the device should be assumed to be present, functional, and enabled. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index f3a4d95..21a2ef3 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -379,9 +379,14 @@ acpi_get_object_info(acpi_handle handle, * Get extra info for ACPI Device/Processor objects only: * Run the _STA, _ADR and, sx_w, and _sx_d methods. * - * Note: none of these methods are required, so they may or may + * Notes: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used * to indicate which methods were found and run successfully. + * + * For _STA, if the method does not exist, then (as per the ACPI + * specification), the returned current_status flags will indicate + * that the device is present/functional/enabled. Otherwise, the + * current_status flags reflect the value returned from _STA. */ /* Execute the Device._STA method */ diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index ee83adb..4fd6897 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -239,7 +239,8 @@ acpi_ut_evaluate_numeric_object(char *object_name, * RETURN: Status * * DESCRIPTION: Executes _STA for selected device and stores results in - * *Flags. + * *Flags. If _STA does not exist, then the device is assumed + * to be present/functional/enabled (as per the ACPI spec). * * NOTE: Internal function, no parameter validation * @@ -257,6 +258,11 @@ acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags) ACPI_BTYPE_INTEGER, &obj_desc); if (ACPI_FAILURE(status)) { if (AE_NOT_FOUND == status) { + /* + * if _STA does not exist, then (as per the ACPI specification), + * the returned flags will indicate that the device is present, + * functional, and enabled. + */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "_STA on %4.4s was not found, assuming device is present\n", acpi_ut_get_node_name(device_node))); -- cgit v0.10.2 From 57987ca2b7c3b16aeeaeacb69b52372181cb7c58 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 17 Jul 2013 09:48:27 +0800 Subject: ACPICA: TableManager: Export acpi_tb_scan_memory_for_rsdp() This patch exports this function to be used by other ACPICA utilities. Chao Guan, Bob Moore. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 7755e91..917315e 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -47,6 +47,11 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count); /* + * tbxfroot - Root pointer utilities + */ +u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length); + +/* * tbfadt - FADT parse/convert/validate */ void acpi_tb_parse_fadt(u32 table_index); diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 7c2ecfb..e76ed0f 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -49,8 +49,6 @@ ACPI_MODULE_NAME("tbxfroot") /* Local prototypes */ -static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length); - static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); /******************************************************************************* @@ -231,7 +229,7 @@ acpi_status acpi_find_root_pointer(acpi_size *table_address) * DESCRIPTION: Search a block of memory for the RSDP signature * ******************************************************************************/ -static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length) +u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length) { acpi_status status; u8 *mem_rover; -- cgit v0.10.2 From 0fb3adf8099160c0a1b1952b6ccf7ac05c218d38 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 17 Jul 2013 09:48:40 +0800 Subject: ACPICA: Disassembler: Expand maximum output string length to 64K Was 256 bytes max. The original purpose of this constraint was to limit the amount of debug output. However, the string function in question (UtPrintString) is now used for the disassembler also, where 256 bytes is insufficient. Reported by RehabMan@GitHub. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 3c76ede..4c081c4 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -616,7 +616,7 @@ int acpi_ut_stricmp(char *string1, char *string2); acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer); -void acpi_ut_print_string(char *string, u8 max_length); +void acpi_ut_print_string(char *string, u16 max_length); void ut_convert_backslashes(char *pathname); diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index c53759b..cb1e9cc 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -333,7 +333,8 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) * FUNCTION: acpi_ut_print_string * * PARAMETERS: string - Null terminated ASCII string - * max_length - Maximum output length + * max_length - Maximum output length. Used to constrain the + * length of strings during debug output only. * * RETURN: None * @@ -342,7 +343,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) * ******************************************************************************/ -void acpi_ut_print_string(char *string, u8 max_length) +void acpi_ut_print_string(char *string, u16 max_length) { u32 i; -- cgit v0.10.2 From 2c48e3eacb0998dc483860e63da47909313c314e Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 17 Jul 2013 09:48:50 +0800 Subject: ACPICA: Remove restriction of 256 maximum GPEs in any GPE block The FADT can support over 1000 GPEs, so remove any restriction on the GPE numbers. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 9037f17..7842700 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -125,7 +125,6 @@ acpi_status acpi_ev_gpe_initialize(void) /* GPE block 0 exists (has both length and address > 0) */ register_count0 = (u16)(acpi_gbl_FADT.gpe0_block_length / 2); - gpe_number_max = (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1; @@ -204,16 +203,6 @@ acpi_status acpi_ev_gpe_initialize(void) goto cleanup; } - /* Check for Max GPE number out-of-range */ - - if (gpe_number_max > ACPI_GPE_MAX) { - ACPI_ERROR((AE_INFO, - "Maximum GPE number from FADT is too large: 0x%X", - gpe_number_max)); - status = AE_BAD_VALUE; - goto cleanup; - } - cleanup: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(AE_OK); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 22b03c9..787a977 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -668,13 +668,6 @@ typedef u32 acpi_event_status; #define ACPI_EVENT_FLAG_SET (acpi_event_status) 0x04 #define ACPI_EVENT_FLAG_HANDLE (acpi_event_status) 0x08 -/* - * General Purpose Events (GPE) - */ -#define ACPI_GPE_INVALID 0xFF -#define ACPI_GPE_MAX 0xFF -#define ACPI_NUM_GPE 256 - /* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */ #define ACPI_GPE_ENABLE 0 -- cgit v0.10.2 From bbe707eddca7f5d03613f38ad8d6b0253a47f5a8 Mon Sep 17 00:00:00 2001 From: Jung-uk Kim Date: Wed, 17 Jul 2013 09:48:58 +0800 Subject: ACPICA: Fix compiler warnings for casting issues (only some compilers) Fixes compiler warnings from GCC 4.2 and perhaps other compilers. Jung-uk Kim Signed-off-by: Jung-uk Kim Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index c740f24..4d046fa 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -338,6 +338,7 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, { u8 *target; char *name; + const char *reference_name; u8 count; if (!info) { @@ -426,10 +427,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, case ACPI_EXD_REFERENCE: + reference_name = acpi_ut_get_reference_name(obj_desc); acpi_ex_out_string("Class Name", - ACPI_CAST_PTR(char, - acpi_ut_get_reference_name - (obj_desc))); + ACPI_CAST_PTR(char, reference_name)); acpi_ex_dump_reference_obj(obj_desc); break; diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 21a2ef3..83c1644 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -158,6 +158,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) { acpi_status status; struct acpi_namespace_node *node; + char *node_name; /* Parameter validation */ @@ -202,7 +203,8 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) /* Just copy the ACPI name from the Node and zero terminate it */ - ACPI_MOVE_NAME(buffer->pointer, acpi_ut_get_node_name(node)); + node_name = acpi_ut_get_node_name(node); + ACPI_MOVE_NAME(buffer->pointer, node_name); ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; status = AE_OK; -- cgit v0.10.2 From 53b1631e3a274f84686853fa2531d1aa918ee36c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 17 Jul 2013 09:49:08 +0800 Subject: ACPICA: Update version to 20130626 Version 20130626. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 22d497e..292af0c 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20130517 +#define ACPI_CA_VERSION 0x20130626 #include #include -- cgit v0.10.2 From c70d65052a1c792bae8d1bb84845f15526b74997 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 3 Jul 2013 17:04:48 +0300 Subject: x86 / PCI: prevent re-allocation of already existing bridge and ROM resources In hotplug case (especially with Thunderbolt enabled systems) we might need to call pcibios_resource_survey_bus() several times for a bus. The function ends up calling pci_claim_resource() for each bridge resource that then fails claiming that the resource exists already (which it does). Once this happens the resource is invalidated thus preventing devices behind the bridge to allocate their resources. To fix this we do what has been done in pcibios_allocate_dev_resources() and check 'parent' of the given resource. If it is non-NULL it means that the resource has been allocated already and we can skip it. We do the same for ROM resources as well. Signed-off-by: Mika Westerberg Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 94919e3..db6b1ab 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -210,6 +210,8 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev) r = &dev->resource[idx]; if (!r->flags) continue; + if (r->parent) /* Already allocated */ + continue; if (!r->start || pci_claim_resource(dev, idx) < 0) { /* * Something is wrong with the region. @@ -318,6 +320,8 @@ static void pcibios_allocate_dev_rom_resource(struct pci_dev *dev) r = &dev->resource[PCI_ROM_RESOURCE]; if (!r->flags || !r->start) return; + if (r->parent) /* Already allocated */ + return; if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) { r->end -= r->start; -- cgit v0.10.2 From be1c9de98d8904c75a5ab8b2a0d97bea0f7c07cc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:23 +0200 Subject: ACPI / PCI: Make bus registration and unregistration symmetric Since acpi_pci_slot_enumerate() and acpiphp_enumerate_slots() can get the ACPI device handle they need from bus->bridge, it is not necessary to pass that handle to them as an argument. Drop the second argument of acpi_pci_slot_enumerate() and acpiphp_enumerate_slots(), rework them to obtain the ACPI handle from bus->bridge and make acpi_pci_add_bus() and acpi_pci_remove_bus() entirely symmetrical. Tested-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 033d117..d678a18 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -159,12 +159,16 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } -void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle) +void acpi_pci_slot_enumerate(struct pci_bus *bus) { - mutex_lock(&slot_list_lock); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - register_slot, NULL, bus, NULL); - mutex_unlock(&slot_list_lock); + acpi_handle handle = ACPI_HANDLE(bus->bridge); + + if (handle) { + mutex_lock(&slot_list_lock); + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + register_slot, NULL, bus, NULL); + mutex_unlock(&slot_list_lock); + } } void acpi_pci_slot_remove(struct pci_bus *bus) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 8bfad0d..a203ba5 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1147,14 +1147,16 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, * Create hotplug slots for the PCI bus. * It should always return 0 to avoid skipping following notifiers. */ -void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) +void acpiphp_enumerate_slots(struct pci_bus *bus) { + acpi_handle handle; struct acpiphp_bridge *bridge; if (acpiphp_disabled) return; - if (detect_ejectable_slots(handle) <= 0) + handle = ACPI_HANDLE(bus->bridge); + if (!handle || detect_ejectable_slots(handle) <= 0) return; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index dbdc5f7..c78cc43 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -290,24 +290,16 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = { void acpi_pci_add_bus(struct pci_bus *bus) { - acpi_handle handle = NULL; - - if (bus->bridge) - handle = ACPI_HANDLE(bus->bridge); - if (acpi_pci_disabled || handle == NULL) + if (acpi_pci_disabled || !bus->bridge) return; - acpi_pci_slot_enumerate(bus, handle); - acpiphp_enumerate_slots(bus, handle); + acpi_pci_slot_enumerate(bus); + acpiphp_enumerate_slots(bus); } void acpi_pci_remove_bus(struct pci_bus *bus) { - /* - * bus->bridge->acpi_node.handle has already been reset to NULL - * when acpi_pci_remove_bus() is called, so don't check ACPI handle. - */ - if (acpi_pci_disabled) + if (acpi_pci_disabled || !bus->bridge) return; acpiphp_remove_slots(bus); diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 1704479..d006f0c 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -47,24 +47,22 @@ void acpi_pci_remove_bus(struct pci_bus *bus); #ifdef CONFIG_ACPI_PCI_SLOT void acpi_pci_slot_init(void); -void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle); +void acpi_pci_slot_enumerate(struct pci_bus *bus); void acpi_pci_slot_remove(struct pci_bus *bus); #else static inline void acpi_pci_slot_init(void) { } -static inline void acpi_pci_slot_enumerate(struct pci_bus *bus, - acpi_handle handle) { } +static inline void acpi_pci_slot_enumerate(struct pci_bus *bus) { } static inline void acpi_pci_slot_remove(struct pci_bus *bus) { } #endif #ifdef CONFIG_HOTPLUG_PCI_ACPI void acpiphp_init(void); -void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle); +void acpiphp_enumerate_slots(struct pci_bus *bus); void acpiphp_remove_slots(struct pci_bus *bus); void acpiphp_check_host_bridge(acpi_handle handle); #else static inline void acpiphp_init(void) { } -static inline void acpiphp_enumerate_slots(struct pci_bus *bus, - acpi_handle handle) { } +static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { } static inline void acpiphp_remove_slots(struct pci_bus *bus) { } static inline void acpiphp_check_host_bridge(acpi_handle handle) { } #endif -- cgit v0.10.2 From 2552002a46cd6a7a262ea1718db33d1a1517008e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:23 +0200 Subject: ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() The acpiphp_enumerate_slots() function is now split into two parts, acpiphp_enumerate_slots() proper and init_bridge_misc() which is only called by the former. If these functions are combined, it is possible to make the code easier to follow and to clean up the error handling (to prevent memory leaks on error from happening in particular), so do that. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a203ba5..68c3809 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -353,46 +353,6 @@ static int detect_ejectable_slots(acpi_handle handle) return found; } -/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ -static void init_bridge_misc(struct acpiphp_bridge *bridge) -{ - acpi_status status; - - /* must be added to the list prior to calling register_slot */ - 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, bridge->handle, (u32)1, - register_slot, NULL, bridge, NULL); - if (ACPI_FAILURE(status)) { - mutex_lock(&bridge_mutex); - list_del(&bridge->list); - mutex_unlock(&bridge_mutex); - return; - } - - /* install notify handler for P2P bridges */ - if (!pci_is_root_bus(bridge->pci_bus)) { - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { - status = acpi_remove_notify_handler(bridge->func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - } - status = acpi_install_notify_handler(bridge->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, - bridge); - - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - } - } -} - /* find acpiphp_func from acpiphp_bridge */ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) @@ -1149,8 +1109,9 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, */ void acpiphp_enumerate_slots(struct pci_bus *bus) { - acpi_handle handle; struct acpiphp_bridge *bridge; + acpi_handle handle; + acpi_status status; if (acpiphp_disabled) return; @@ -1178,14 +1139,51 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) */ get_device(&bus->dev); - if (!pci_is_root_bus(bridge->pci_bus) && - 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); + /* must be added to the list prior to calling register_slot */ + 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, bridge->handle, 1, + register_slot, NULL, bridge, NULL); + if (ACPI_FAILURE(status)) { + acpi_handle_err(bridge->handle, "failed to register slots\n"); + goto err; + } + + if (pci_is_root_bus(bridge->pci_bus)) + return; + + /* install notify handler for P2P bridges */ + status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, + bridge); + if (ACPI_FAILURE(status)) { + acpi_handle_err(bridge->handle, + "failed to register notify handler\n"); + goto err; + } + + if (!acpi_has_method(bridge->handle, "_EJ0")) + return; + + dbg("found ejectable p2p bridge\n"); + bridge->flags |= BRIDGE_HAS_EJ0; + bridge->func = acpiphp_bridge_handle_to_function(bridge->handle); + if (bridge->func) { + status = acpi_remove_notify_handler(bridge->func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func); + if (ACPI_FAILURE(status)) + acpi_handle_err(bridge->func->handle, + "failed to remove notify handler\n"); } + return; - init_bridge_misc(bridge); + err: + cleanup_bridge(bridge); + put_bridge(bridge); } /* Destroy hotplug slots associated with the PCI bus */ -- cgit v0.10.2 From 2e862c51904ddd12be2d256513160e1f87beafee Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:23 +0200 Subject: ACPI / hotplug / PCI: Always return success after adding a function When a new ACPIPHP function is added by register_slot() and the notify handler cannot be installed for it, register_slot() returns an error status without cleaning up, which causes the entire namespace walk in acpiphp_enumerate_slots() to be aborted, although it still may be possible to successfully install the function notify handler for other device objects under the given brigde. To address this issue make register_slot() return success after a new function has been added, even if the addition of the notify handler for it has failed. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 68c3809..d75ba7e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -325,10 +325,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) if (ACPI_FAILURE(status)) err("failed to register interrupt notify handler\n"); - } else - status = AE_OK; + } - return status; + return AE_OK; err_exit: bridge->nr_slots--; -- cgit v0.10.2 From cb7b8cedf6c88b9d1d08e0565e8da52180921071 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Hotplug context objects for bridges and functions When either a new hotplug bridge or a new hotplug function is added by the ACPI-based PCI hotplug (ACPIPHP) code, attach a context object to its ACPI handle to store hotplug-related information in it. To start with, put the handle's bridge and function pointers into that object. Count references to the context objects and drop them when they are not needed any more. First of all, this makes it possible to find out if the given bridge has been registered as a function already in a much more straightforward way and acpiphp_bridge_handle_to_function() can be dropped (Yay!). This also will allow some more simplifications to be made going forward. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 6c781ed..f946e47 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -49,6 +49,7 @@ #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) +struct acpiphp_context; struct acpiphp_bridge; struct acpiphp_slot; @@ -77,6 +78,7 @@ struct acpiphp_bridge { struct kref ref; acpi_handle handle; + struct acpiphp_context *context; /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ struct acpiphp_func *func; @@ -119,6 +121,7 @@ struct acpiphp_slot { * typically 8 objects per slot (i.e. for each PCI function) */ struct acpiphp_func { + struct acpiphp_context *context; struct acpiphp_slot *slot; /* parent */ struct list_head sibling; @@ -128,6 +131,13 @@ struct acpiphp_func { u32 flags; /* see below */ }; +struct acpiphp_context { + acpi_handle handle; + struct acpiphp_func *func; + struct acpiphp_bridge *bridge; + unsigned int refcount; +}; + /* * struct acpiphp_attention_info - device specific attention registration * diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index d75ba7e..a0c518c 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -55,6 +55,7 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); +static DEFINE_MUTEX(acpiphp_context_lock); #define MY_NAME "acpiphp_glue" @@ -79,6 +80,74 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) } } +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. + * + * Call under acpiphp_context_lock. + */ +static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) +{ + 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; + } + return context; +} + +/** + * acpiphp_get_context - Get hotplug context and grab a reference to it. + * @handle: ACPI object handle to get the context for. + * + * Call under acpiphp_context_lock. + */ +static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +{ + struct acpiphp_context *context = NULL; + acpi_status status; + void *data; + + status = acpi_get_data(handle, acpiphp_context_handler, &data); + if (ACPI_SUCCESS(status)) { + context = data; + context->refcount++; + } + return context; +} + +/** + * acpiphp_put_context - Drop a reference to ACPI hotplug context. + * @handle: ACPI object handle to put the context for. + * + * The context object is removed if there are no more references to it. + * + * Call under acpiphp_context_lock. + */ +static void acpiphp_put_context(struct acpiphp_context *context) +{ + if (--context->refcount) + return; + + WARN_ON(context->func || context->bridge); + acpi_detach_data(context->handle, acpiphp_context_handler); + kfree(context); +} + static inline void get_bridge(struct acpiphp_bridge *bridge) { kref_get(&bridge->ref); @@ -91,25 +160,37 @@ static inline void put_bridge(struct acpiphp_bridge *bridge) static void free_bridge(struct kref *kref) { + struct acpiphp_context *context; struct acpiphp_bridge *bridge; struct acpiphp_slot *slot, *next; struct acpiphp_func *func, *tmp; + mutex_lock(&acpiphp_context_lock); + bridge = container_of(kref, struct acpiphp_bridge, ref); list_for_each_entry_safe(slot, next, &bridge->slots, node) { list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { + context = func->context; + context->func = NULL; + acpiphp_put_context(context); kfree(func); } kfree(slot); } - /* Release reference acquired by acpiphp_bridge_handle_to_function() */ + /* Release the reference acquired by acpiphp_enumerate_slots(). */ if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) put_bridge(bridge->func->slot->bridge); + put_device(&bridge->pci_bus->dev); pci_dev_put(bridge->pci_dev); + context = bridge->context; + context->bridge = NULL; + acpiphp_put_context(context); kfree(bridge); + + mutex_unlock(&acpiphp_context_lock); } /* @@ -194,10 +275,11 @@ static void acpiphp_dock_release(void *data) } /* callback routine to register each ACPI PCI slot object */ -static acpi_status -register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) +static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, + void **rv) { - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; + struct acpiphp_bridge *bridge = data; + struct acpiphp_context *context; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; @@ -230,6 +312,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) newfunc->handle = handle; newfunc->function = function; + mutex_lock(&acpiphp_context_lock); + context = acpiphp_init_context(handle); + if (!context) { + mutex_unlock(&acpiphp_context_lock); + acpi_handle_err(handle, "No hotplug context\n"); + kfree(newfunc); + return AE_NOT_EXIST; + } + newfunc->context = context; + context->func = newfunc; + mutex_unlock(&acpiphp_context_lock); + if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; @@ -266,8 +360,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) if (!found) { slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - kfree(newfunc); - return AE_NO_MEMORY; + status = AE_NO_MEMORY; + goto err_out; } slot->bridge = bridge; @@ -291,7 +385,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) else warn("acpiphp_register_hotplug_slot failed " "(err code = 0x%x)\n", retval); - goto err_exit; + + status = AE_OK; + goto err; } } @@ -329,15 +425,20 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; - err_exit: + err: bridge->nr_slots--; mutex_lock(&bridge_mutex); list_del(&slot->node); mutex_unlock(&bridge_mutex); kfree(slot); - kfree(newfunc); - return AE_OK; + err_out: + mutex_lock(&acpiphp_context_lock); + context->func = NULL; + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + kfree(newfunc); + return status; } @@ -352,32 +453,6 @@ static int detect_ejectable_slots(acpi_handle handle) return found; } - -/* find acpiphp_func from acpiphp_bridge */ -static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) -{ - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - struct acpiphp_func *func = NULL; - - mutex_lock(&bridge_mutex); - list_for_each_entry(bridge, &bridge_list, list) { - list_for_each_entry(slot, &bridge->slots, node) { - list_for_each_entry(func, &slot->funcs, sibling) { - if (func->handle == handle) { - get_bridge(func->slot->bridge); - mutex_unlock(&bridge_mutex); - return func; - } - } - } - } - mutex_unlock(&bridge_mutex); - - return NULL; -} - - static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { struct acpiphp_bridge *bridge; @@ -1108,6 +1183,7 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, */ void acpiphp_enumerate_slots(struct pci_bus *bus) { + struct acpiphp_context *context; struct acpiphp_bridge *bridge; acpi_handle handle; acpi_status status; @@ -1120,8 +1196,8 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) return; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); - if (bridge == NULL) { - err("out of memory\n"); + if (!bridge) { + acpi_handle_err(handle, "No memory for bridge object\n"); return; } @@ -1131,6 +1207,21 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) bridge->pci_dev = pci_dev_get(bus->self); bridge->pci_bus = bus; + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (!context) { + context = acpiphp_init_context(handle); + if (!context) { + mutex_unlock(&acpiphp_context_lock); + acpi_handle_err(handle, "No hotplug context\n"); + kfree(bridge); + return; + } + } + bridge->context = context; + context->bridge = bridge; + mutex_unlock(&acpiphp_context_lock); + /* * Grab a ref to the subordinate PCI bus in case the bus is * removed via PCI core logical hotplug. The ref pins the bus @@ -1169,13 +1260,15 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) dbg("found ejectable p2p bridge\n"); bridge->flags |= BRIDGE_HAS_EJ0; - bridge->func = acpiphp_bridge_handle_to_function(bridge->handle); - if (bridge->func) { - status = acpi_remove_notify_handler(bridge->func->handle, - ACPI_SYSTEM_NOTIFY, + if (context->func) { + get_bridge(context->func->slot->bridge); + bridge->func = context->func; + handle = context->handle; + WARN_ON(bridge->handle != handle); + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_func); if (ACPI_FAILURE(status)) - acpi_handle_err(bridge->func->handle, + acpi_handle_err(handle, "failed to remove notify handler\n"); } return; -- cgit v0.10.2 From 87831273438d66167dddc6d73e42d49671cb56bb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Unified notify handler for hotplug events Using the hotplug context objects introduced previously rework the ACPI-based PCI hotplug (ACPIPHP) core code so that all notifications for ACPI device objects corresponding to the hotplug PCI devices are handled by one function, handle_hotplug_event(), which recognizes whether it has to handle a bridge or a function. In addition to code size reduction it allows some ugly pieces of code where notify handlers have to be uninstalled and installed again to go away. Moreover, it fixes a theoretically possible race between handle_hotplug_event() and free_bridge() tearing down data structures for the same handle. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index f946e47..b96a8a9 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -136,6 +136,7 @@ struct acpiphp_context { struct acpiphp_func *func; struct acpiphp_bridge *bridge; unsigned int refcount; + bool handler_for_func; }; /* diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a0c518c..ef7b25c 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -59,11 +59,10 @@ static DEFINE_MUTEX(acpiphp_context_lock); #define MY_NAME "acpiphp_glue" -static void handle_hotplug_event_bridge (acpi_handle, u32, void *); +static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event_func(acpi_handle handle, u32 type, void *context); -static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); static void free_bridge(struct kref *kref); /* callback routine to check for the existence of a pci dock device */ @@ -179,13 +178,13 @@ static void free_bridge(struct kref *kref) kfree(slot); } + context = bridge->context; /* Release the reference acquired by acpiphp_enumerate_slots(). */ - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) + if (context->handler_for_func) put_bridge(bridge->func->slot->bridge); put_device(&bridge->pci_bus->dev); pci_dev_put(bridge->pci_dev); - context = bridge->context; context->bridge = NULL; acpiphp_put_context(context); kfree(bridge); @@ -414,12 +413,12 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, /* install notify handler */ if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - newfunc); - - if (ACPI_FAILURE(status)) + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event, + context); + if (ACPI_SUCCESS(status)) + context->handler_for_func = true; + else err("failed to register interrupt notify handler\n"); } @@ -476,32 +475,23 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) acpi_status status; acpi_handle handle = bridge->handle; - if (!pci_is_root_bus(bridge->pci_bus)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); + if (!bridge->context->handler_for_func) { + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); } - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { - status = acpi_install_notify_handler(bridge->func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - bridge->func); - if (ACPI_FAILURE(status)) - err("failed to install interrupt notify handler\n"); - } - list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { if (is_dock_device(func->handle)) { unregister_hotplug_dock_device(func->handle); } if (!(func->flags & FUNC_HAS_DCK)) { + func->context->handler_for_func = false; status = acpi_remove_notify_handler(func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); } @@ -1071,31 +1061,6 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) put_bridge(bridge); } -/** - * handle_hotplug_event_bridge - handle ACPI event on bridges - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_bridge structure - * - * Handles ACPI event notification on {host,p2p} bridges. - */ -static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, - void *context) -{ - struct acpiphp_bridge *bridge = context; - - /* - * Currently the code adds all hotplug events to the kacpid_wq - * queue when it should add hotplug events to the kacpi_hotplug_wq. - * The proper way to fix this is to reorganize the code so that - * drivers (dock, etc.) do not call acpi_os_execute(), etc. - * For now just re-add this work to the kacpi_hotplug_wq so we - * don't deadlock on hotplug actions. - */ - get_bridge(bridge); - alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge); -} - static void hotplug_event_func(acpi_handle handle, u32 type, void *context) { struct acpiphp_func *func = context; @@ -1153,17 +1118,33 @@ static void _handle_hotplug_event_func(struct work_struct *work) } /** - * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) + * handle_hotplug_event - handle ACPI hotplug event * @handle: Notify()'ed acpi_handle * @type: Notify code - * @context: pointer to acpiphp_func structure + * @data: pointer to acpiphp_context structure * * Handles ACPI event notification on slots. */ -static void handle_hotplug_event_func(acpi_handle handle, u32 type, - void *context) +static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_func *func = context; + struct acpiphp_context *context; + void (*work_func)(struct work_struct *work) = NULL; + + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (context) { + if (context->bridge) { + get_bridge(context->bridge); + data = context->bridge; + work_func = _handle_hotplug_event_bridge; + } else if (context->func) { + get_bridge(context->func->slot->bridge); + data = context->func; + work_func = _handle_hotplug_event_func; + } + acpiphp_put_context(context); + } + mutex_unlock(&acpiphp_context_lock); /* * Currently the code adds all hotplug events to the kacpid_wq @@ -1173,8 +1154,8 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, * For now just re-add this work to the kacpi_hotplug_wq so we * don't deadlock on hotplug actions. */ - get_bridge(func->slot->bridge); - alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); + if (work_func) + alloc_acpi_hp_work(handle, type, data, work_func); } /* @@ -1245,33 +1226,24 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) if (pci_is_root_bus(bridge->pci_bus)) return; - /* install notify handler for P2P bridges */ - status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, - bridge); - if (ACPI_FAILURE(status)) { - acpi_handle_err(bridge->handle, - "failed to register notify handler\n"); - goto err; + if (acpi_has_method(bridge->handle, "_EJ0")) { + dbg("found ejectable p2p bridge\n"); + bridge->flags |= BRIDGE_HAS_EJ0; + } + if (context->handler_for_func) { + /* Notify handler already installed. */ + bridge->func = context->func; + get_bridge(context->func->slot->bridge); + return; } - if (!acpi_has_method(bridge->handle, "_EJ0")) + /* install notify handler for P2P bridges */ + status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event, NULL); + if (ACPI_SUCCESS(status)) return; - dbg("found ejectable p2p bridge\n"); - bridge->flags |= BRIDGE_HAS_EJ0; - if (context->func) { - get_bridge(context->func->slot->bridge); - bridge->func = context->func; - handle = context->handle; - WARN_ON(bridge->handle != handle); - status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to remove notify handler\n"); - } - return; + acpi_handle_err(bridge->handle, "failed to register notify handler\n"); err: cleanup_bridge(bridge); -- cgit v0.10.2 From ed13febf8fac1a08f939f97378574937a7d2f121 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge() Using the hotplug context objects introduced previously rework the ACPI-based PCI hotplug (ACPIPHP) core code to get to acpiphp_bridge objects associated with hotplug bridges from those context objects rather than from the global list of hotplug bridges. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index ef7b25c..6cfd8a6 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -454,18 +454,20 @@ static int detect_ejectable_slots(acpi_handle handle) static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { - struct acpiphp_bridge *bridge; + struct acpiphp_context *context; + struct acpiphp_bridge *bridge = NULL; - mutex_lock(&bridge_mutex); - list_for_each_entry(bridge, &bridge_list, list) - if (bridge->handle == handle) { + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (context) { + bridge = context->bridge; + if (bridge) get_bridge(bridge); - mutex_unlock(&bridge_mutex); - return bridge; - } - mutex_unlock(&bridge_mutex); - return NULL; + acpiphp_put_context(context); + } + mutex_unlock(&acpiphp_context_lock); + return bridge; } static void cleanup_bridge(struct acpiphp_bridge *bridge) -- cgit v0.10.2 From c8ebcf1ff91a8f64b09c4df0ee21ae80a953c39c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Pass hotplug context objects to event handlers Modify handle_hotplug_event() to pass the entire context object (instead of its fields individually) to work functions started by it. This change makes the subsequent consolidation of the event handling work functions a bit more straightforward. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 6cfd8a6..b5a98f4 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -989,6 +989,7 @@ void acpiphp_check_host_bridge(acpi_handle handle) static void _handle_hotplug_event_bridge(struct work_struct *work) { + struct acpiphp_context *context; struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), @@ -1000,7 +1001,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) hp_work = container_of(work, struct acpi_hp_work, work); handle = hp_work->handle; type = hp_work->type; - bridge = (struct acpiphp_bridge *)hp_work->context; + context = hp_work->context; + bridge = context->bridge; acpi_scan_lock_acquire(); @@ -1105,18 +1107,18 @@ static void hotplug_event_func(acpi_handle handle, u32 type, void *context) static void _handle_hotplug_event_func(struct work_struct *work) { + struct acpiphp_context *context; struct acpi_hp_work *hp_work; - struct acpiphp_func *func; hp_work = container_of(work, struct acpi_hp_work, work); - func = hp_work->context; + context = hp_work->context; acpi_scan_lock_acquire(); - hotplug_event_func(hp_work->handle, hp_work->type, func); + hotplug_event_func(hp_work->handle, hp_work->type, context->func); acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event_func */ - put_bridge(func->slot->bridge); + put_bridge(context->func->slot->bridge); } /** @@ -1137,11 +1139,9 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) if (context) { if (context->bridge) { get_bridge(context->bridge); - data = context->bridge; work_func = _handle_hotplug_event_bridge; } else if (context->func) { get_bridge(context->func->slot->bridge); - data = context->func; work_func = _handle_hotplug_event_func; } acpiphp_put_context(context); @@ -1157,7 +1157,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) * don't deadlock on hotplug actions. */ if (work_func) - alloc_acpi_hp_work(handle, type, data, work_func); + alloc_acpi_hp_work(handle, type, context, work_func); } /* -- cgit v0.10.2 From 43e5c091c797616170b11f4a1b32ea8c81ad0100 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Merge hotplug event handling functions There are separate handling event functions for hotplug bridges and for hotplug functions, but they may be combined into one common hotplug event handling function which simplifies the code slightly. That also allows a theoretical bug to be dealt with which in principle may occur if a hotplug bridge is on a dock station, because in that case the bridge-specific notification should be used instead of the function-specific one, but the dock station always uses the latter. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b5a98f4..e2f9ea0 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -62,7 +62,7 @@ static DEFINE_MUTEX(acpiphp_context_lock); static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); -static void hotplug_event_func(acpi_handle handle, u32 type, void *context); +static void hotplug_event(acpi_handle handle, u32 type, void *data); static void free_bridge(struct kref *kref); /* callback routine to check for the existence of a pci dock device */ @@ -201,8 +201,8 @@ static void free_bridge(struct kref *kref) */ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { - struct acpiphp_func *func = data; - struct pci_bus *bus = func->slot->bridge->pci_bus; + struct acpiphp_context *context = data; + struct pci_bus *bus = context->func->slot->bridge->pci_bus; u32 buses; if (!bus->self) @@ -227,7 +227,7 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) static const struct acpi_dock_ops acpiphp_dock_ops = { .fixup = post_dock_fixups, - .handler = hotplug_event_func, + .handler = hotplug_event, }; /* Check whether the PCI device is managed by native PCIe hotplug driver */ @@ -261,16 +261,16 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) static void acpiphp_dock_init(void *data) { - struct acpiphp_func *func = data; + struct acpiphp_context *context = data; - get_bridge(func->slot->bridge); + get_bridge(context->func->slot->bridge); } static void acpiphp_dock_release(void *data) { - struct acpiphp_func *func = data; + struct acpiphp_context *context = data; - put_bridge(func->slot->bridge); + put_bridge(context->func->slot->bridge); } /* callback routine to register each ACPI PCI slot object */ @@ -406,7 +406,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, */ newfunc->flags &= ~FUNC_HAS_EJ0; if (register_hotplug_dock_device(handle, - &acpiphp_dock_ops, newfunc, + &acpiphp_dock_ops, context, acpiphp_dock_init, acpiphp_dock_release)) dbg("failed to register dock device\n"); } @@ -987,24 +987,26 @@ void acpiphp_check_host_bridge(acpi_handle handle) ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); } -static void _handle_hotplug_event_bridge(struct work_struct *work) +static void hotplug_event(acpi_handle handle, u32 type, void *data) { - struct acpiphp_context *context; + struct acpiphp_context *context = data; struct acpiphp_bridge *bridge; + struct acpiphp_func *func; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; - struct acpi_hp_work *hp_work; - acpi_handle handle; - u32 type; - hp_work = container_of(work, struct acpi_hp_work, work); - handle = hp_work->handle; - type = hp_work->type; - context = hp_work->context; + mutex_lock(&acpiphp_context_lock); bridge = context->bridge; + if (bridge) + get_bridge(bridge); - acpi_scan_lock_acquire(); + /* + * If context->func is not NULL, we are holding a reference to its + * parent bridge, so it won't go away until we drop that reference. + */ + func = context->func; + mutex_unlock(&acpiphp_context_lock); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1013,15 +1015,24 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) /* bus re-enumerate */ dbg("%s: Bus check notify on %s\n", __func__, objname); dbg("%s: re-enumerating slots under %s\n", __func__, objname); - acpiphp_check_bridge(bridge); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); + if (bridge) { + acpiphp_check_bridge(bridge); + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, check_sub_bridges, + NULL, NULL, NULL); + } else { + acpiphp_enable_slot(func->slot); + } break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ dbg("%s: Device check notify on %s\n", __func__, objname); - acpiphp_check_bridge(bridge); + if (bridge) + acpiphp_check_bridge(bridge); + else + acpiphp_check_bridge(func->slot->bridge); + break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -1032,12 +1043,15 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { - struct acpiphp_slot *slot; - slot = bridge->func->slot; - if (!acpiphp_disable_slot(slot)) - acpiphp_eject_slot(slot); - } + if (!func) + break; + + if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0)) + break; + + if (!(acpiphp_disable_slot(func->slot))) + acpiphp_eject_slot(func->slot); + break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: @@ -1056,56 +1070,16 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) break; default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); + warn("notify_handler: unknown event type 0x%x for %s\n", type, + objname); break; } - acpi_scan_lock_release(); - kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ - put_bridge(bridge); -} - -static void hotplug_event_func(acpi_handle handle, u32 type, void *context) -{ - struct acpiphp_func *func = context; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus re-enumerate */ - dbg("%s: Bus check notify on %s\n", __func__, objname); - acpiphp_enable_slot(func->slot); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check : re-enumerate from parent bus */ - dbg("%s: Device check notify on %s\n", __func__, objname); - acpiphp_check_bridge(func->slot->bridge); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __func__, objname); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - dbg("%s: Device eject notify on %s\n", __func__, objname); - if (!(acpiphp_disable_slot(func->slot))) - acpiphp_eject_slot(func->slot); - break; - - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } + if (bridge) + put_bridge(bridge); } -static void _handle_hotplug_event_func(struct work_struct *work) +static void hotplug_event_work(struct work_struct *work) { struct acpiphp_context *context; struct acpi_hp_work *hp_work; @@ -1114,11 +1088,18 @@ static void _handle_hotplug_event_func(struct work_struct *work) context = hp_work->context; acpi_scan_lock_acquire(); - hotplug_event_func(hp_work->handle, hp_work->type, context->func); + hotplug_event(hp_work->handle, hp_work->type, context); acpi_scan_lock_release(); - kfree(hp_work); /* allocated in handle_hotplug_event_func */ - put_bridge(context->func->slot->bridge); + kfree(hp_work); /* allocated in handle_hotplug_event() */ + + mutex_lock(&acpiphp_context_lock); + if (context->func) + put_bridge(context->func->slot->bridge); + else + acpiphp_put_context(context); + + mutex_unlock(&acpiphp_context_lock); } /** @@ -1132,22 +1113,19 @@ static void _handle_hotplug_event_func(struct work_struct *work) static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context; - void (*work_func)(struct work_struct *work) = NULL; mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { - if (context->bridge) { - get_bridge(context->bridge); - work_func = _handle_hotplug_event_bridge; - } else if (context->func) { + if (context->func) { get_bridge(context->func->slot->bridge); - work_func = _handle_hotplug_event_func; + acpiphp_put_context(context); + } else if (!context->bridge) { + acpiphp_put_context(context); + context = NULL; } - acpiphp_put_context(context); } mutex_unlock(&acpiphp_context_lock); - /* * Currently the code adds all hotplug events to the kacpid_wq * queue when it should add hotplug events to the kacpi_hotplug_wq. @@ -1156,8 +1134,8 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) * For now just re-add this work to the kacpi_hotplug_wq so we * don't deadlock on hotplug actions. */ - if (work_func) - alloc_acpi_hp_work(handle, type, context, work_func); + if (context) + alloc_acpi_hp_work(handle, type, context, hotplug_event_work); } /* -- cgit v0.10.2 From f28181109e85b49b5b4b1c381d889b4ea7315988 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge Since the func pointer in struct acpiphp_context can always be used instead of the func pointer in struct acpiphp_bridge, drop the latter. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index b96a8a9..4980ff4 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -79,8 +79,6 @@ struct acpiphp_bridge { acpi_handle handle; struct acpiphp_context *context; - /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ - struct acpiphp_func *func; int nr_slots; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e2f9ea0..a83ce9d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -181,7 +181,7 @@ static void free_bridge(struct kref *kref) context = bridge->context; /* Release the reference acquired by acpiphp_enumerate_slots(). */ if (context->handler_for_func) - put_bridge(bridge->func->slot->bridge); + put_bridge(context->func->slot->bridge); put_device(&bridge->pci_bus->dev); pci_dev_put(bridge->pci_dev); @@ -1212,7 +1212,6 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) } if (context->handler_for_func) { /* Notify handler already installed. */ - bridge->func = context->func; get_bridge(context->func->slot->bridge); return; } -- cgit v0.10.2 From ac372338b750648355bcc64bb0bca13fc6f0a3d5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Refactor slot allocation code in register_slot() To make the code in register_slot() a bit easier to follow, change the way the slot allocation part is organized. Drop one local variable that's not used any more after that modification. This code change should not lead to any changes in behavior. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a83ce9d..95af39c 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -283,7 +283,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, struct acpiphp_func *newfunc; acpi_status status = AE_OK; unsigned long long adr, sun; - int device, function, retval, found = 0; + int device, function, retval; struct pci_bus *pbus = bridge->pci_bus; struct pci_dev *pdev; u32 val; @@ -352,44 +352,49 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (slot->device == device) { if (slot->sun != sun) warn("sibling found, but _SUN doesn't match!\n"); - found = 1; - break; - } - if (!found) { - slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); - if (!slot) { - status = AE_NO_MEMORY; - goto err_out; + goto slot_found; } - slot->bridge = bridge; - slot->device = device; - slot->sun = sun; - INIT_LIST_HEAD(&slot->funcs); - mutex_init(&slot->crit_sect); + slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); + if (!slot) { + status = AE_NO_MEMORY; + goto err; + } + + slot->bridge = bridge; + slot->device = device; + slot->sun = sun; + INIT_LIST_HEAD(&slot->funcs); + mutex_init(&slot->crit_sect); + mutex_lock(&bridge_mutex); + list_add_tail(&slot->node, &bridge->slots); + mutex_unlock(&bridge_mutex); + bridge->nr_slots++; + + dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", + slot->sun, pci_domain_nr(pbus), pbus->number, device); + + retval = acpiphp_register_hotplug_slot(slot); + if (retval) { + if (retval == -EBUSY) + warn("Slot %llu already registered by another " + "hotplug driver\n", slot->sun); + else + warn("acpiphp_register_hotplug_slot failed " + "(err code = 0x%x)\n", retval); + + bridge->nr_slots--; mutex_lock(&bridge_mutex); - list_add_tail(&slot->node, &bridge->slots); + list_del(&slot->node); mutex_unlock(&bridge_mutex); - bridge->nr_slots++; - - dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(pbus), pbus->number, device); - retval = acpiphp_register_hotplug_slot(slot); - if (retval) { - if (retval == -EBUSY) - warn("Slot %llu already registered by another " - "hotplug driver\n", slot->sun); - else - warn("acpiphp_register_hotplug_slot failed " - "(err code = 0x%x)\n", retval); - - status = AE_OK; - goto err; - } + kfree(slot); + status = AE_OK; + goto err; } + slot_found: newfunc->slot = slot; mutex_lock(&bridge_mutex); list_add_tail(&newfunc->sibling, &slot->funcs); @@ -425,13 +430,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, return AE_OK; err: - bridge->nr_slots--; - mutex_lock(&bridge_mutex); - list_del(&slot->node); - mutex_unlock(&bridge_mutex); - kfree(slot); - - err_out: mutex_lock(&acpiphp_context_lock); context->func = NULL; acpiphp_put_context(context); -- cgit v0.10.2 From bbd34fcdd1b201e996235731a7c98fd5197d9e51 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:24 +0200 Subject: ACPI / hotplug / PCI: Register all devices under the given bridge Rework register_slot() to create a struct acpiphp_func object for every function it is called for and to create acpiphp slots for all of them. Although acpiphp_register_hotplug_slot() is only called for the slots whose functions are identified as "ejectable", so that user space can manipulate them, the ACPIPHP notify handler, handle_hotplug_event(), is now installed for all of the registered functions (that aren't dock stations) and hotplug events may be handled for all of them. As a result, essentially, all PCI bridges represented by objects in the ACPI namespace are now going to be "hotplug" bridges and that may affect resources allocation in general, although it shouldn't lead to problems. This allows the code to be simplified substantially and addresses the problem where bus check or device check notifications for some PCI bridges or devices are not handled, because those devices are not recognized as "ejectable" or there appear to be no "ejectable" devices under those bridges. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 4980ff4..76a1c97 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -134,7 +134,6 @@ struct acpiphp_context { struct acpiphp_func *func; struct acpiphp_bridge *bridge; unsigned int refcount; - bool handler_for_func; }; /* diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 95af39c..b306e99 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -65,20 +65,6 @@ static void acpiphp_set_hpp_values(struct pci_bus *bus); static void hotplug_event(acpi_handle handle, u32 type, void *data); static void free_bridge(struct kref *kref); -/* callback routine to check for the existence of a pci dock device */ -static acpi_status -is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; - - if (is_dock_device(handle)) { - (*count)++; - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} - static void acpiphp_context_handler(acpi_handle handle, void *context) { /* Intentionally empty. */ @@ -179,14 +165,16 @@ static void free_bridge(struct kref *kref) } context = bridge->context; - /* Release the reference acquired by acpiphp_enumerate_slots(). */ - if (context->handler_for_func) + /* Root bridges will not have hotplug context. */ + if (context) { + /* Release the reference taken by acpiphp_enumerate_slots(). */ put_bridge(context->func->slot->bridge); + context->bridge = NULL; + acpiphp_put_context(context); + } put_device(&bridge->pci_bus->dev); pci_dev_put(bridge->pci_dev); - context->bridge = NULL; - acpiphp_put_context(context); kfree(bridge); mutex_unlock(&acpiphp_context_lock); @@ -282,28 +270,24 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; - unsigned long long adr, sun; - int device, function, retval; + unsigned long long adr; + int device, function; struct pci_bus *pbus = bridge->pci_bus; - struct pci_dev *pdev; + struct pci_dev *pdev = bridge->pci_dev; u32 val; - if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) + if (pdev && device_is_managed_by_native_pciehp(pdev)) return AE_OK; status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); if (ACPI_FAILURE(status)) { - warn("can't evaluate _ADR (%#x)\n", status); + acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status); return AE_OK; } device = (adr >> 16) & 0xffff; function = adr & 0xffff; - pdev = bridge->pci_dev; - if (pdev && device_is_managed_by_native_pciehp(pdev)) - return AE_OK; - newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); if (!newfunc) return AE_NO_MEMORY; @@ -338,23 +322,10 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (acpi_has_method(handle, "_DCK")) newfunc->flags |= FUNC_HAS_DCK; - status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); - if (ACPI_FAILURE(status)) { - /* - * use the count of the number of slots we've found - * for the number of the slot - */ - sun = bridge->nr_slots+1; - } - /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) - if (slot->device == device) { - if (slot->sun != sun) - warn("sibling found, but _SUN doesn't match!\n"); - + if (slot->device == device) goto slot_found; - } slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { @@ -364,34 +335,38 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, slot->bridge = bridge; slot->device = device; - slot->sun = sun; INIT_LIST_HEAD(&slot->funcs); mutex_init(&slot->crit_sect); mutex_lock(&bridge_mutex); list_add_tail(&slot->node, &bridge->slots); mutex_unlock(&bridge_mutex); - bridge->nr_slots++; - - dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(pbus), pbus->number, device); - retval = acpiphp_register_hotplug_slot(slot); - if (retval) { - if (retval == -EBUSY) - warn("Slot %llu already registered by another " - "hotplug driver\n", slot->sun); - else - warn("acpiphp_register_hotplug_slot failed " - "(err code = 0x%x)\n", retval); + /* Register slots for ejectable funtions only. */ + if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) { + unsigned long long sun; + int retval; - bridge->nr_slots--; - mutex_lock(&bridge_mutex); - list_del(&slot->node); - mutex_unlock(&bridge_mutex); - kfree(slot); - status = AE_OK; - goto err; + bridge->nr_slots++; + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); + if (ACPI_FAILURE(status)) + sun = bridge->nr_slots; + + slot->sun = sun; + dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", + slot->sun, pci_domain_nr(pbus), pbus->number, device); + + retval = acpiphp_register_hotplug_slot(slot); + if (retval) { + bridge->nr_slots--; + if (retval == -EBUSY) + warn("Slot %llu already registered by another " + "hotplug driver\n", slot->sun); + else + warn("acpiphp_register_hotplug_slot failed " + "(err code = 0x%x)\n", retval); + } + /* Even if the slot registration fails, we can still use it. */ } slot_found: @@ -421,10 +396,9 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event, context); - if (ACPI_SUCCESS(status)) - context->handler_for_func = true; - else - err("failed to register interrupt notify handler\n"); + if (ACPI_FAILURE(status)) + acpi_handle_err(handle, + "failed to install notify handler\n"); } return AE_OK; @@ -438,18 +412,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, return status; } - -/* see if it's worth looking at this bridge */ -static int detect_ejectable_slots(acpi_handle handle) -{ - int found = acpi_pci_detect_ejectable(handle); - if (!found) { - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - is_pci_dock_device, NULL, (void *)&found, NULL); - } - return found; -} - static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { struct acpiphp_context *context; @@ -473,14 +435,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) struct acpiphp_slot *slot; struct acpiphp_func *func; acpi_status status; - acpi_handle handle = bridge->handle; - - if (!bridge->context->handler_for_func) { - status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - } list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { @@ -488,7 +442,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) unregister_hotplug_dock_device(func->handle); } if (!(func->flags & FUNC_HAS_DCK)) { - func->context->handler_for_func = false; status = acpi_remove_notify_handler(func->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event); @@ -678,9 +631,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) list_for_each_entry(func, &slot->funcs, sibling) { if (PCI_FUNC(dev->devfn) == func->function) { - /* check if this bridge has ejectable slots */ - if ((detect_ejectable_slots(func->handle) > 0)) - dev->is_hotplug_bridge = 1; + dev->is_hotplug_bridge = 1; break; } } @@ -988,8 +939,8 @@ void acpiphp_check_host_bridge(acpi_handle handle) static void hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context = data; + struct acpiphp_func *func = context->func; struct acpiphp_bridge *bridge; - struct acpiphp_func *func; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; @@ -999,11 +950,6 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) if (bridge) get_bridge(bridge); - /* - * If context->func is not NULL, we are holding a reference to its - * parent bridge, so it won't go away until we drop that reference. - */ - func = context->func; mutex_unlock(&acpiphp_context_lock); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1041,9 +987,6 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if (!func) - break; - if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0)) break; @@ -1090,14 +1033,7 @@ static void hotplug_event_work(struct work_struct *work) acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event() */ - - mutex_lock(&acpiphp_context_lock); - if (context->func) - put_bridge(context->func->slot->bridge); - else - acpiphp_put_context(context); - - mutex_unlock(&acpiphp_context_lock); + put_bridge(context->func->slot->bridge); } /** @@ -1115,13 +1051,8 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { - if (context->func) { - get_bridge(context->func->slot->bridge); - acpiphp_put_context(context); - } else if (!context->bridge) { - acpiphp_put_context(context); - context = NULL; - } + get_bridge(context->func->slot->bridge); + acpiphp_put_context(context); } mutex_unlock(&acpiphp_context_lock); /* @@ -1142,7 +1073,6 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) */ void acpiphp_enumerate_slots(struct pci_bus *bus) { - struct acpiphp_context *context; struct acpiphp_bridge *bridge; acpi_handle handle; acpi_status status; @@ -1151,7 +1081,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) return; handle = ACPI_HANDLE(bus->bridge); - if (!handle || detect_ejectable_slots(handle) <= 0) + if (!handle) return; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); @@ -1166,21 +1096,6 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) bridge->pci_dev = pci_dev_get(bus->self); bridge->pci_bus = bus; - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (!context) { - context = acpiphp_init_context(handle); - if (!context) { - mutex_unlock(&acpiphp_context_lock); - acpi_handle_err(handle, "No hotplug context\n"); - kfree(bridge); - return; - } - } - bridge->context = context; - context->bridge = bridge; - mutex_unlock(&acpiphp_context_lock); - /* * Grab a ref to the subordinate PCI bus in case the bus is * removed via PCI core logical hotplug. The ref pins the bus @@ -1188,6 +1103,35 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) */ get_device(&bus->dev); + if (!pci_is_root_bus(bridge->pci_bus)) { + struct acpiphp_context *context; + + /* + * This bridge should have been registered as a hotplug function + * under its parent, so the context has to be there. If not, we + * are in deep goo. + */ + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (WARN_ON(!context || !context->func)) { + mutex_unlock(&acpiphp_context_lock); + put_device(&bus->dev); + kfree(bridge); + return; + } + bridge->context = context; + context->bridge = bridge; + /* Get a reference to the parent bridge. */ + get_bridge(context->func->slot->bridge); + mutex_unlock(&acpiphp_context_lock); + } + + status = acpi_get_handle(bridge->handle, "_EJ0", &handle); + if (ACPI_SUCCESS(status)) { + dbg("found ejectable p2p bridge\n"); + bridge->flags |= BRIDGE_HAS_EJ0; + } + /* must be added to the list prior to calling register_slot */ mutex_lock(&bridge_mutex); list_add(&bridge->list, &bridge_list); @@ -1198,33 +1142,9 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) register_slot, NULL, bridge, NULL); if (ACPI_FAILURE(status)) { acpi_handle_err(bridge->handle, "failed to register slots\n"); - goto err; - } - - if (pci_is_root_bus(bridge->pci_bus)) - return; - - if (acpi_has_method(bridge->handle, "_EJ0")) { - dbg("found ejectable p2p bridge\n"); - bridge->flags |= BRIDGE_HAS_EJ0; - } - if (context->handler_for_func) { - /* Notify handler already installed. */ - get_bridge(context->func->slot->bridge); - return; + cleanup_bridge(bridge); + put_bridge(bridge); } - - /* install notify handler for P2P bridges */ - status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, NULL); - if (ACPI_SUCCESS(status)) - return; - - acpi_handle_err(bridge->handle, "failed to register notify handler\n"); - - err: - cleanup_bridge(bridge); - put_bridge(bridge); } /* Destroy hotplug slots associated with the PCI bus */ -- cgit v0.10.2 From 7342798d0ab850a630877a362bc5a4f033100f37 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot If the slot unique number is passed as an additional argument to acpiphp_register_hotplug_slot(), the 'sun' field in struct acpiphp_slot is only used by ibm_[s|g]et_attention_status(), but then it's more efficient to store it in struct slot. Thus move the 'sun' field from struct acpiphp_slot to struct slot changing its data type to unsigned int in the process, and redefine acpiphp_register_hotplug_slot() to take the slot number as separate argument. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 76a1c97..4f10aec 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -60,6 +60,7 @@ struct slot { struct hotplug_slot *hotplug_slot; struct acpiphp_slot *acpi_slot; struct hotplug_slot_info info; + unsigned int sun; /* ACPI _SUN (Slot User Number) value */ }; static inline const char *slot_name(struct slot *slot) @@ -106,8 +107,6 @@ struct acpiphp_slot { struct mutex crit_sect; u8 device; /* pci device# */ - - unsigned long long sun; /* ACPI _SUN (slot unique number) */ u32 flags; /* see below */ }; @@ -179,7 +178,7 @@ struct acpiphp_attention_info /* acpiphp_core.c */ int acpiphp_register_attention(struct acpiphp_attention_info*info); int acpiphp_unregister_attention(struct acpiphp_attention_info *info); -int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot); +int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun); void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); /* acpiphp_glue.c */ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index ca81279..1798740 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -290,7 +290,8 @@ static void release_slot(struct hotplug_slot *hotplug_slot) } /* callback routine to initialize 'struct slot' for each slot */ -int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) +int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot, + unsigned int sun) { struct slot *slot; int retval = -ENOMEM; @@ -317,7 +318,8 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); acpiphp_slot->slot = slot; - snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun); + slot->sun = sun; + snprintf(name, SLOT_NAME_SIZE, "%u", sun); retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bridge->pci_bus, diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b306e99..a251071 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -352,16 +352,15 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (ACPI_FAILURE(status)) sun = bridge->nr_slots; - slot->sun = sun; dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(pbus), pbus->number, device); + sun, pci_domain_nr(pbus), pbus->number, device); - retval = acpiphp_register_hotplug_slot(slot); + retval = acpiphp_register_hotplug_slot(slot, sun); if (retval) { bridge->nr_slots--; if (retval == -EBUSY) warn("Slot %llu already registered by another " - "hotplug driver\n", slot->sun); + "hotplug driver\n", sun); else warn("acpiphp_register_hotplug_slot failed " "(err code = 0x%x)\n", retval); diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index c35e8ad..8d45f6d 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -66,7 +66,7 @@ do { \ #define IBM_HARDWARE_ID1 "IBM37D0" #define IBM_HARDWARE_ID2 "IBM37D4" -#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun) +#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun) /* union apci_descriptor - allows access to the * various device descriptors that are embedded in the -- cgit v0.10.2 From 75a33ed1b58005e455cb6533a7689ac0eb6bedd6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge The only bridge flag used by the ACPI-based PCI hotplug (ACPIPHP) code is BRIDGE_HAS_EJ0, but it is only used by the event handling function hotplug_event() and if that flag is set, the corresponding function flag FUNC_HAS_EJ0 is set as well, so that bridge flag is redundant. For this reason, drop BRIDGE_HAS_EJ0 and all code referring to it and since it is the only bridge flag defined, drop the flags field from struct acpiphp_bridge entirely. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 4f10aec..990fbfd 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -83,8 +83,6 @@ struct acpiphp_bridge { int nr_slots; - u32 flags; - /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ struct pci_bus *pci_bus; @@ -154,9 +152,6 @@ struct acpiphp_attention_info /* ACPI _STA method value (ignore bit 4; battery present) */ #define ACPI_STA_ALL (0x0000000f) -/* bridge flags */ -#define BRIDGE_HAS_EJ0 (0x00000001) - /* slot flags */ #define SLOT_POWEREDON (0x00000001) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a251071..5d79175 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -986,9 +986,6 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0)) - break; - if (!(acpiphp_disable_slot(func->slot))) acpiphp_eject_slot(func->slot); @@ -1125,12 +1122,6 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) mutex_unlock(&acpiphp_context_lock); } - status = acpi_get_handle(bridge->handle, "_EJ0", &handle); - if (ACPI_SUCCESS(status)) { - dbg("found ejectable p2p bridge\n"); - bridge->flags |= BRIDGE_HAS_EJ0; - } - /* must be added to the list prior to calling register_slot */ mutex_lock(&bridge_mutex); list_add(&bridge->list, &bridge_list); -- cgit v0.10.2 From bd4674dfc5fc704837148f36af41e1e0a640dfec Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context Since there has to be a struct acpiphp_func object for every struct acpiphp_context created by register_slot(), the struct acpiphp_func one can be embedded into the struct acpiphp_context one, which allows some code simplifications to be made. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 990fbfd..31c84bd 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -116,7 +116,6 @@ struct acpiphp_slot { * typically 8 objects per slot (i.e. for each PCI function) */ struct acpiphp_func { - struct acpiphp_context *context; struct acpiphp_slot *slot; /* parent */ struct list_head sibling; @@ -128,11 +127,16 @@ struct acpiphp_func { struct acpiphp_context { acpi_handle handle; - struct acpiphp_func *func; + struct acpiphp_func func; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) +{ + return container_of(func, struct acpiphp_context, func); +} + /* * struct acpiphp_attention_info - device specific attention registration * diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 5d79175..cc7453e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -128,7 +128,7 @@ static void acpiphp_put_context(struct acpiphp_context *context) if (--context->refcount) return; - WARN_ON(context->func || context->bridge); + WARN_ON(context->bridge); acpi_detach_data(context->handle, acpiphp_context_handler); kfree(context); } @@ -155,12 +155,9 @@ static void free_bridge(struct kref *kref) bridge = container_of(kref, struct acpiphp_bridge, ref); list_for_each_entry_safe(slot, next, &bridge->slots, node) { - list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { - context = func->context; - context->func = NULL; - acpiphp_put_context(context); - kfree(func); - } + list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) + acpiphp_put_context(func_to_context(func)); + kfree(slot); } @@ -168,7 +165,7 @@ static void free_bridge(struct kref *kref) /* Root bridges will not have hotplug context. */ if (context) { /* Release the reference taken by acpiphp_enumerate_slots(). */ - put_bridge(context->func->slot->bridge); + put_bridge(context->func.slot->bridge); context->bridge = NULL; acpiphp_put_context(context); } @@ -190,7 +187,7 @@ static void free_bridge(struct kref *kref) static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { struct acpiphp_context *context = data; - struct pci_bus *bus = context->func->slot->bridge->pci_bus; + struct pci_bus *bus = context->func.slot->bridge->pci_bus; u32 buses; if (!bus->self) @@ -251,14 +248,14 @@ static void acpiphp_dock_init(void *data) { struct acpiphp_context *context = data; - get_bridge(context->func->slot->bridge); + get_bridge(context->func.slot->bridge); } static void acpiphp_dock_release(void *data) { struct acpiphp_context *context = data; - put_bridge(context->func->slot->bridge); + put_bridge(context->func.slot->bridge); } /* callback routine to register each ACPI PCI slot object */ @@ -288,23 +285,16 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, device = (adr >> 16) & 0xffff; function = adr & 0xffff; - newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); - if (!newfunc) - return AE_NO_MEMORY; - - newfunc->handle = handle; - newfunc->function = function; - mutex_lock(&acpiphp_context_lock); context = acpiphp_init_context(handle); if (!context) { mutex_unlock(&acpiphp_context_lock); acpi_handle_err(handle, "No hotplug context\n"); - kfree(newfunc); return AE_NOT_EXIST; } - newfunc->context = context; - context->func = newfunc; + newfunc = &context->func; + newfunc->handle = handle; + newfunc->function = function; mutex_unlock(&acpiphp_context_lock); if (acpi_has_method(handle, "_EJ0")) @@ -404,10 +394,8 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, err: mutex_lock(&acpiphp_context_lock); - context->func = NULL; acpiphp_put_context(context); mutex_unlock(&acpiphp_context_lock); - kfree(newfunc); return status; } @@ -938,7 +926,7 @@ void acpiphp_check_host_bridge(acpi_handle handle) static void hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context = data; - struct acpiphp_func *func = context->func; + struct acpiphp_func *func = &context->func; struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), @@ -1029,7 +1017,7 @@ static void hotplug_event_work(struct work_struct *work) acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event() */ - put_bridge(context->func->slot->bridge); + put_bridge(context->func.slot->bridge); } /** @@ -1047,7 +1035,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { - get_bridge(context->func->slot->bridge); + get_bridge(context->func.slot->bridge); acpiphp_put_context(context); } mutex_unlock(&acpiphp_context_lock); @@ -1109,7 +1097,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) */ mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (WARN_ON(!context || !context->func)) { + if (WARN_ON(!context)) { mutex_unlock(&acpiphp_context_lock); put_device(&bus->dev); kfree(bridge); @@ -1118,7 +1106,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) bridge->context = context; context->bridge = bridge; /* Get a reference to the parent bridge. */ - get_bridge(context->func->slot->bridge); + get_bridge(context->func.slot->bridge); mutex_unlock(&acpiphp_context_lock); } -- cgit v0.10.2 From 5a3bc573ae32a71bb9e307812d4de1bdcab6b9fb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func The ACPI handle stored in struct acpiphp_func is also stored in the struct acpiphp_context object containing it and it is trivial to get from a struct acpiphp_func pointer to the handle field of the outer struct acpiphp_context. Hence, the handle field of struct acpiphp_func is redundant, so drop it and provide a helper function, func_to_handle(), allowing it users to get the ACPI handle for the given struct acpiphp_func pointer. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 31c84bd..dbb9425 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -119,7 +119,6 @@ struct acpiphp_func { struct acpiphp_slot *slot; /* parent */ struct list_head sibling; - acpi_handle handle; u8 function; /* pci function# */ u32 flags; /* see below */ @@ -137,6 +136,11 @@ static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) return container_of(func, struct acpiphp_context, func); } +static inline acpi_handle func_to_handle(struct acpiphp_func *func) +{ + return func_to_context(func)->handle; +} + /* * struct acpiphp_attention_info - device specific attention registration * diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cc7453e..9e4ad6f 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -293,7 +293,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, return AE_NOT_EXIST; } newfunc = &context->func; - newfunc->handle = handle; newfunc->function = function; mutex_unlock(&acpiphp_context_lock); @@ -425,11 +424,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { - if (is_dock_device(func->handle)) { - unregister_hotplug_dock_device(func->handle); - } + acpi_handle handle = func_to_handle(func); + + if (is_dock_device(handle)) + unregister_hotplug_dock_device(handle); + if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(func->handle, + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event); if (ACPI_FAILURE(status)) @@ -457,7 +458,8 @@ static int power_on_slot(struct acpiphp_slot *slot) list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_PS0) { dbg("%s: executing _PS0\n", __func__); - status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); + status = acpi_evaluate_object(func_to_handle(func), + "_PS0", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS0 failed\n", __func__); retval = -1; @@ -489,7 +491,8 @@ static int power_off_slot(struct acpiphp_slot *slot) list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_PS3) { - status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); + status = acpi_evaluate_object(func_to_handle(func), + "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __func__); retval = -1; @@ -543,10 +546,11 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) */ static int acpiphp_bus_add(struct acpiphp_func *func) { + acpi_handle handle = func_to_handle(func); struct acpi_device *device; int ret_val; - if (!acpi_bus_get_device(func->handle, &device)) { + if (!acpi_bus_get_device(handle, &device)) { dbg("bus exists... trim\n"); /* this shouldn't be in here, so remove * the bus then re-add it... @@ -554,9 +558,9 @@ static int acpiphp_bus_add(struct acpiphp_func *func) acpi_bus_trim(device); } - ret_val = acpi_bus_scan(func->handle); + ret_val = acpi_bus_scan(handle); if (!ret_val) - ret_val = acpi_bus_get_device(func->handle, &device); + ret_val = acpi_bus_get_device(handle, &device); if (ret_val) dbg("error adding bus, %x\n", -ret_val); @@ -598,7 +602,8 @@ static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) params[1].type = ACPI_TYPE_INTEGER; params[1].integer.value = 1; /* _REG is optional, we don't care about if there is failure */ - acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL); + acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list, + NULL); } } @@ -739,9 +744,8 @@ static int disable_device(struct acpiphp_slot *slot) pci_dev_put(pdev); } - list_for_each_entry(func, &slot->funcs, sibling) { - acpiphp_bus_trim(func->handle); - } + list_for_each_entry(func, &slot->funcs, sibling) + acpiphp_bus_trim(func_to_handle(func)); slot->flags &= (~SLOT_ENABLED); @@ -763,17 +767,20 @@ static int disable_device(struct acpiphp_slot *slot) */ static unsigned int get_slot_status(struct acpiphp_slot *slot) { - acpi_status status; unsigned long long sta = 0; - u32 dvid; struct acpiphp_func *func; list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_STA) { - status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); + acpi_status status; + + status = acpi_evaluate_integer(func_to_handle(func), + "_STA", NULL, &sta); if (ACPI_SUCCESS(status) && sta) break; } else { + u32 dvid; + pci_bus_read_config_dword(slot->bridge->pci_bus, PCI_DEVFN(slot->device, func->function), @@ -798,12 +805,13 @@ int acpiphp_eject_slot(struct acpiphp_slot *slot) 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)) { - if (ACPI_FAILURE(acpi_evaluate_ej0(func->handle))) - return -1; - else - break; - } + if (!(func->flags & FUNC_HAS_EJ0)) + continue; + + if (ACPI_FAILURE(acpi_evaluate_ej0(func_to_handle(func)))) + return -1; + else + break; } return 0; } -- cgit v0.10.2 From 89373a55d294b53e85792dbc636015b83d492f67 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge The handle field in struct acpiphp_bridge is only used by acpiphp_enumerate_slots(), but in that function the local handle variable can be used instead, so make that happen and drop handle from struct acpiphp_bridge. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index dbb9425..afd7110 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -77,7 +77,6 @@ struct acpiphp_bridge { struct list_head list; struct list_head slots; struct kref ref; - acpi_handle handle; struct acpiphp_context *context; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 9e4ad6f..bbbf8f4 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1084,7 +1084,6 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) INIT_LIST_HEAD(&bridge->slots); kref_init(&bridge->ref); - bridge->handle = handle; bridge->pci_dev = pci_dev_get(bus->self); bridge->pci_bus = bus; @@ -1124,10 +1123,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) mutex_unlock(&bridge_mutex); /* register all slot objects under this bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, 1, + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, register_slot, NULL, bridge, NULL); if (ACPI_FAILURE(status)) { - acpi_handle_err(bridge->handle, "failed to register slots\n"); + acpi_handle_err(handle, "failed to register slots\n"); cleanup_bridge(bridge); put_bridge(bridge); } -- cgit v0.10.2 From bda46dbb6626c923a800b4033c86fefa613cd64c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Store parent in functions and bus in slots To avoid chasing more pointers than necessary in some situations, move the bridge pointer from struct acpiphp_slot to struct acpiphp_func (and call it 'parent') and add a bus pointer to struct acpiphp_slot. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index afd7110..7d3251d 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -97,7 +97,7 @@ struct acpiphp_bridge { */ struct acpiphp_slot { struct list_head node; - struct acpiphp_bridge *bridge; /* parent */ + struct pci_bus *bus; struct list_head funcs; /* one slot may have different objects (i.e. for each function) */ struct slot *slot; @@ -115,7 +115,8 @@ struct acpiphp_slot { * typically 8 objects per slot (i.e. for each PCI function) */ struct acpiphp_func { - struct acpiphp_slot *slot; /* parent */ + struct acpiphp_bridge *parent; + struct acpiphp_slot *slot; struct list_head sibling; diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 1798740..8f20e60 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -321,10 +321,8 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot, slot->sun = sun; snprintf(name, SLOT_NAME_SIZE, "%u", sun); - retval = pci_hp_register(slot->hotplug_slot, - acpiphp_slot->bridge->pci_bus, - acpiphp_slot->device, - name); + retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus, + acpiphp_slot->device, name); if (retval == -EBUSY) goto error_hpslot; if (retval) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bbbf8f4..7ac315a 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -165,7 +165,7 @@ static void free_bridge(struct kref *kref) /* Root bridges will not have hotplug context. */ if (context) { /* Release the reference taken by acpiphp_enumerate_slots(). */ - put_bridge(context->func.slot->bridge); + put_bridge(context->func.parent); context->bridge = NULL; acpiphp_put_context(context); } @@ -187,7 +187,7 @@ static void free_bridge(struct kref *kref) static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { struct acpiphp_context *context = data; - struct pci_bus *bus = context->func.slot->bridge->pci_bus; + struct pci_bus *bus = context->func.slot->bus; u32 buses; if (!bus->self) @@ -248,14 +248,14 @@ static void acpiphp_dock_init(void *data) { struct acpiphp_context *context = data; - get_bridge(context->func.slot->bridge); + get_bridge(context->func.parent); } static void acpiphp_dock_release(void *data) { struct acpiphp_context *context = data; - put_bridge(context->func.slot->bridge); + put_bridge(context->func.parent); } /* callback routine to register each ACPI PCI slot object */ @@ -294,6 +294,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, } newfunc = &context->func; newfunc->function = function; + newfunc->parent = bridge; mutex_unlock(&acpiphp_context_lock); if (acpi_has_method(handle, "_EJ0")) @@ -322,7 +323,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, goto err; } - slot->bridge = bridge; + slot->bus = bridge->pci_bus; slot->device = device; INIT_LIST_HEAD(&slot->funcs); mutex_init(&slot->crit_sect); @@ -639,7 +640,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) static int __ref enable_device(struct acpiphp_slot *slot) { struct pci_dev *dev; - struct pci_bus *bus = slot->bridge->pci_bus; + struct pci_bus *bus = slot->bus; struct acpiphp_func *func; int num, max, pass; LIST_HEAD(add_list); @@ -709,7 +710,7 @@ static int __ref enable_device(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->bridge->pci_bus; + struct pci_bus *bus = slot->bus; struct pci_dev *dev; struct pci_dev *ret = NULL; @@ -781,7 +782,7 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) } else { u32 dvid; - pci_bus_read_config_dword(slot->bridge->pci_bus, + pci_bus_read_config_dword(slot->bus, PCI_DEVFN(slot->device, func->function), PCI_VENDOR_ID, &dvid); @@ -970,7 +971,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) if (bridge) acpiphp_check_bridge(bridge); else - acpiphp_check_bridge(func->slot->bridge); + acpiphp_check_bridge(func->parent); break; @@ -1025,7 +1026,7 @@ static void hotplug_event_work(struct work_struct *work) acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event() */ - put_bridge(context->func.slot->bridge); + put_bridge(context->func.parent); } /** @@ -1043,7 +1044,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { - get_bridge(context->func.slot->bridge); + get_bridge(context->func.parent); acpiphp_put_context(context); } mutex_unlock(&acpiphp_context_lock); @@ -1113,7 +1114,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) bridge->context = context; context->bridge = bridge; /* Get a reference to the parent bridge. */ - get_bridge(context->func.slot->bridge); + get_bridge(context->func.parent); mutex_unlock(&acpiphp_context_lock); } -- cgit v0.10.2 From 236e26245a6a437c4afbf33a5ad94cf61d1a7a7c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Rework namespace scanning and trimming routines The acpiphp_bus_trim() and acpiphp_bus_add() functions need not return error codes that are never checked, so redefine them and simplify them a bit. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7ac315a..b136eee 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -540,53 +540,27 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) return max; } - /** - * acpiphp_bus_add - add a new bus to acpi subsystem - * @func: acpiphp_func of the bridge + * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. + * @handle: ACPI device object handle to start from. */ -static int acpiphp_bus_add(struct acpiphp_func *func) +static void acpiphp_bus_trim(acpi_handle handle) { - acpi_handle handle = func_to_handle(func); - struct acpi_device *device; - int ret_val; - - if (!acpi_bus_get_device(handle, &device)) { - dbg("bus exists... trim\n"); - /* this shouldn't be in here, so remove - * the bus then re-add it... - */ - acpi_bus_trim(device); - } + struct acpi_device *adev = NULL; - ret_val = acpi_bus_scan(handle); - if (!ret_val) - ret_val = acpi_bus_get_device(handle, &device); - - if (ret_val) - dbg("error adding bus, %x\n", -ret_val); - - return ret_val; + acpi_bus_get_device(handle, &adev); + if (adev) + acpi_bus_trim(adev); } - /** - * acpiphp_bus_trim - trim a bus from acpi subsystem - * @handle: handle to acpi namespace + * acpiphp_bus_add - Scan ACPI namespace subtree. + * @handle: ACPI object handle to start the scan from. */ -static int acpiphp_bus_trim(acpi_handle handle) +static void acpiphp_bus_add(acpi_handle handle) { - struct acpi_device *device; - int retval; - - retval = acpi_bus_get_device(handle, &device); - if (retval) { - dbg("acpi_device not found\n"); - return retval; - } - - acpi_bus_trim(device); - return 0; + acpiphp_bus_trim(handle); + acpi_bus_scan(handle); } static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) @@ -649,7 +623,7 @@ static int __ref enable_device(struct acpiphp_slot *slot) goto err_exit; list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_add(func); + acpiphp_bus_add(func_to_handle(func)); num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); if (num == 0) { -- cgit v0.10.2 From 07bb735378919e4b5863077f5c1b4037b6ca1a99 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:25 +0200 Subject: ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge() Two checks in check_hotplug_bridge() are redundant (they have been done by the caller already), so drop them. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b136eee..f131512 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -586,16 +586,10 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) { struct acpiphp_func *func; - if (!dev->subordinate) - return; - /* quirk, or pcie could set it already */ if (dev->is_hotplug_bridge) return; - if (PCI_SLOT(dev->devfn) != slot->device) - return; - list_for_each_entry(func, &slot->funcs, sibling) { if (PCI_FUNC(dev->devfn) == func->function) { dev->is_hotplug_bridge = 1; -- cgit v0.10.2 From ad21d2d046a8a6bbf1b10c04770ec835a4e379e6 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Consolidate slot disabling and ejecting Both acpiphp_disable_slot() and acpiphp_eject_slot() are always called together so instead of calling each separately we can consolidate them into one function acpiphp_disable_and_eject_slot() that does both (but it will return success on _EJ0 failures that were ignored in the majority of call sites anyway). [rjw: Rebased plus minor tweaks] Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 7d3251d..fe6c79b 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -188,8 +188,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); int acpiphp_enable_slot(struct acpiphp_slot *slot); -int acpiphp_disable_slot(struct acpiphp_slot *slot); -int acpiphp_eject_slot(struct acpiphp_slot *slot); +int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); u8 acpiphp_get_power_status(struct acpiphp_slot *slot); u8 acpiphp_get_attention_status(struct acpiphp_slot *slot); u8 acpiphp_get_latch_status(struct acpiphp_slot *slot); diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 8f20e60..bf2203e 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -155,15 +155,11 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) static int disable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - int retval; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); /* disable the specified slot */ - retval = acpiphp_disable_slot(slot->acpi_slot); - if (!retval) - retval = acpiphp_eject_slot(slot->acpi_slot); - return retval; + return acpiphp_disable_and_eject_slot(slot->acpi_slot); } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index f131512..6db790e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -765,27 +765,6 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) } /** - * acpiphp_eject_slot - physically eject the slot - * @slot: ACPI PHP slot - */ -int acpiphp_eject_slot(struct acpiphp_slot *slot) -{ - struct acpiphp_func *func; - - 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)) - continue; - - if (ACPI_FAILURE(acpi_evaluate_ej0(func_to_handle(func)))) - return -1; - else - break; - } - return 0; -} - -/** * acpiphp_check_bridge - re-enumerate devices * @bridge: where to begin re-enumeration * @@ -805,13 +784,11 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) if (slot->flags & SLOT_ENABLED) { if (status == ACPI_STA_ALL) continue; - retval = acpiphp_disable_slot(slot); - if (retval) { - err("Error occurred in disabling\n"); + + retval = acpiphp_disable_and_eject_slot(slot); + if (retval) goto err_exit; - } else { - acpiphp_eject_slot(slot); - } + disabled++; } else { if (status != ACPI_STA_ALL) @@ -951,9 +928,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if (!(acpiphp_disable_slot(func->slot))) - acpiphp_eject_slot(func->slot); - + acpiphp_disable_and_eject_slot(func->slot); break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: @@ -1148,11 +1123,12 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) } /** - * acpiphp_disable_slot - power off slot + * acpiphp_disable_and_eject_slot - power off and eject slot * @slot: ACPI PHP slot */ -int acpiphp_disable_slot(struct acpiphp_slot *slot) +int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) { + struct acpiphp_func *func; int retval = 0; mutex_lock(&slot->crit_sect); @@ -1167,6 +1143,16 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) if (retval) goto err_exit; + list_for_each_entry(func, &slot->funcs, sibling) + if (func->flags & FUNC_HAS_EJ0) { + acpi_handle handle = func_to_handle(func); + + if (ACPI_FAILURE(acpi_evaluate_ej0(handle))) + acpi_handle_err(handle, "_EJ0 failed\n"); + + break; + } + err_exit: mutex_unlock(&slot->crit_sect); return retval; -- cgit v0.10.2 From 5c8d0e1dc475f0f35b5a774c92c68c3f7dbd3f5f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Do not queue up event handling work items in vain Modify handle_hotplug_event() to avoid queing up the execution of handle_hotplug_event_work_fn() as a work item on kacpi_hotplug_wq for non-hotplug events, such as ACPI_NOTIFY_DEVICE_WAKE. Move the code printing diagnostic messages for those events into handle_hotplug_event(). In addition to that, remove the bogus comment about how the core should distinguish between hotplug and non-hotplug events and queue them up on different workqueues. The core clearly cannot know in advance what events will be interesting to the given caller of acpi_install_notify_handler(). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 6db790e..44191db 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -920,36 +920,11 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) break; - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __func__, objname); - break; - case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); acpiphp_disable_and_eject_slot(func->slot); break; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - printk(KERN_ERR "Device %s cannot be configured due" - " to a frequency mismatch\n", objname); - break; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - printk(KERN_ERR "Device %s cannot be configured due" - " to a bus mode mismatch\n", objname); - break; - - case ACPI_NOTIFY_POWER_FAULT: - printk(KERN_ERR "Device %s has suffered a power fault\n", - objname); - break; - - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, - objname); - break; } if (bridge) @@ -984,23 +959,42 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context; + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + case ACPI_NOTIFY_EJECT_REQUEST: + 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"); + return; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); + return; + + case ACPI_NOTIFY_POWER_FAULT: + acpi_handle_err(handle, "Device has suffered a power fault\n"); + return; + + default: + acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); + return; + } + mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); if (context) { get_bridge(context->func.parent); acpiphp_put_context(context); + alloc_acpi_hp_work(handle, type, context, hotplug_event_work); } mutex_unlock(&acpiphp_context_lock); - /* - * Currently the code adds all hotplug events to the kacpid_wq - * queue when it should add hotplug events to the kacpi_hotplug_wq. - * The proper way to fix this is to reorganize the code so that - * drivers (dock, etc.) do not call acpi_os_execute(), etc. - * For now just re-add this work to the kacpi_hotplug_wq so we - * don't deadlock on hotplug actions. - */ - if (context) - alloc_acpi_hp_work(handle, type, context, hotplug_event_work); } /* -- cgit v0.10.2 From bc805a55392a7cb3e9b1251d00449c70e3967fc5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly The ACPI-based PCI hotplug (acpiphp) core code need not and really should not execute _PS0 and _PS3 directly for devices it handles. First of all, it is not necessary to put devices into D3 after acpi_bus_trim() has walked through them, because acpi_device_unregister() invoked by it puts each device into D3cold before returning. Thus after disable_device() the slot should be powered down already. Second, calling _PS0 directly on ACPI device objects may not be appropriate, because it may require power resources to be set up in a specific way in advance and that must be taken care of by the ACPI core. Thus modify acpiphp_bus_add() to power up the device using the appropriate interface after it has run acpi_bus_scan() on its handle. After that, the functions executing _PS0 and _PS3, power_on_slot() and power_off_slot(), are not necessary any more, so drop them and update the code calling them accordingly. Also drop the function flags related to device power states, since they aren't useful any more too. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index fe6c79b..ca2c91d 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -162,7 +162,6 @@ struct acpiphp_attention_info /* slot flags */ -#define SLOT_POWEREDON (0x00000001) #define SLOT_ENABLED (0x00000002) #define SLOT_MULTIFUNCTION (0x00000004) @@ -170,11 +169,7 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_PS0 (0x00000010) -#define FUNC_HAS_PS1 (0x00000020) -#define FUNC_HAS_PS2 (0x00000040) -#define FUNC_HAS_PS3 (0x00000080) -#define FUNC_HAS_DCK (0x00000100) +#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 44191db..b6691cc 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -303,12 +303,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; - if (acpi_has_method(handle, "_PS0")) - newfunc->flags |= FUNC_HAS_PS0; - - if (acpi_has_method(handle, "_PS3")) - newfunc->flags |= FUNC_HAS_PS3; - if (acpi_has_method(handle, "_DCK")) newfunc->flags |= FUNC_HAS_DCK; @@ -366,7 +360,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), &val, 60*1000)) - slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); + slot->flags |= SLOT_ENABLED; if (is_dock_device(handle)) { /* we don't want to call this device's _EJ0 @@ -446,73 +440,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) mutex_unlock(&bridge_mutex); } -static int power_on_slot(struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - int retval = 0; - - /* if already enabled, just skip */ - if (slot->flags & SLOT_POWEREDON) - goto err_exit; - - list_for_each_entry(func, &slot->funcs, sibling) { - if (func->flags & FUNC_HAS_PS0) { - dbg("%s: executing _PS0\n", __func__); - status = acpi_evaluate_object(func_to_handle(func), - "_PS0", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS0 failed\n", __func__); - retval = -1; - goto err_exit; - } else - break; - } - } - - /* TBD: evaluate _STA to check if the slot is enabled */ - - slot->flags |= SLOT_POWEREDON; - - err_exit: - return retval; -} - - -static int power_off_slot(struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - - int retval = 0; - - /* if already disabled, just skip */ - if ((slot->flags & SLOT_POWEREDON) == 0) - goto err_exit; - - list_for_each_entry(func, &slot->funcs, sibling) { - if (func->flags & FUNC_HAS_PS3) { - status = acpi_evaluate_object(func_to_handle(func), - "_PS3", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS3 failed\n", __func__); - retval = -1; - goto err_exit; - } else - break; - } - } - - /* TBD: evaluate _STA to check if the slot is disabled */ - - slot->flags &= (~SLOT_POWEREDON); - - err_exit: - return retval; -} - - - /** * acpiphp_max_busnr - return the highest reserved bus number under the given bus. * @bus: bus to start search with @@ -559,8 +486,13 @@ static void acpiphp_bus_trim(acpi_handle handle) */ static void acpiphp_bus_add(acpi_handle handle) { + struct acpi_device *adev = NULL; + acpiphp_bus_trim(handle); acpi_bus_scan(handle); + acpi_bus_get_device(handle, &adev); + if (adev) + acpi_device_set_power(adev, ACPI_STATE_D0); } static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) @@ -1095,23 +1027,8 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) int retval; mutex_lock(&slot->crit_sect); - - /* wake up all functions */ - retval = power_on_slot(slot); - if (retval) - goto err_exit; - - if (get_slot_status(slot) == ACPI_STA_ALL) { - /* configure all functions */ - retval = enable_device(slot); - if (retval) - power_off_slot(slot); - } else { - dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__); - power_off_slot(slot); - } - - err_exit: + /* configure all functions */ + retval = enable_device(slot); mutex_unlock(&slot->crit_sect); return retval; } @@ -1132,11 +1049,6 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) if (retval) goto err_exit; - /* power off all functions */ - retval = power_off_slot(slot); - if (retval) - goto err_exit; - list_for_each_entry(func, &slot->funcs, sibling) if (func->flags & FUNC_HAS_EJ0) { acpi_handle handle = func_to_handle(func); @@ -1159,7 +1071,7 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) */ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) { - return (slot->flags & SLOT_POWEREDON); + return (slot->flags & SLOT_ENABLED); } -- cgit v0.10.2 From 55502ddb2d83ada0661733361ec14b9cbef157a5 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device() With Thunderbolt you can daisy chain devices: connect new devices to an already plugged one. In that case the "hotplug slot" is already enabled, but we still want to look for new PCI devices behind it. Reuse enable_device() to scan for new PCI devices on enabled slots and push the SLOT_ENABLED check up into acpiphp_enable_slot(). [rjw: Rebased, modified the changelog] Signed-off-by: Kirill A. Shutemov Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b6691cc..c7a668e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -545,9 +545,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) int num, max, pass; LIST_HEAD(add_list); - if (slot->flags & SLOT_ENABLED) - goto err_exit; - list_for_each_entry(func, &slot->funcs, sibling) acpiphp_bus_add(func_to_handle(func)); @@ -1024,11 +1021,14 @@ void acpiphp_remove_slots(struct pci_bus *bus) */ int acpiphp_enable_slot(struct acpiphp_slot *slot) { - int retval; + int retval = 0; mutex_lock(&slot->crit_sect); + /* configure all functions */ - retval = enable_device(slot); + if (!(slot->flags & SLOT_ENABLED)) + retval = enable_device(slot); + mutex_unlock(&slot->crit_sect); return retval; } -- cgit v0.10.2 From b91182a67c53db227e34921838dd683090ecfabc Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Allow slots without new devices to be rescanned Currently, enable_device() checks the return value of pci_scan_slot() and returns immediately if that's 0 (meaning that no new functions have been found in the slot). However, if one of the functions in the slot is a bridge, some new devices may appear below it even if the bridge itself is present continuously, so it generally is necessary to do the rescan anyway just in case. [In particular, that's necessary with the Thunderbolt daisy chaining in which case new devices may be connected to the existing ones down the chain.] The correctness of this change relies on the ability of pcibios_resource_survey_bus() to detect if it has already been called for the given bus and to skip it if so. Failure to do that will lead to resource allocation conflicts. [rjw: Changelog] Signed-off-by: Kirill A. Shutemov Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index c7a668e..21a6269 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -542,18 +542,13 @@ static int __ref enable_device(struct acpiphp_slot *slot) struct pci_dev *dev; struct pci_bus *bus = slot->bus; struct acpiphp_func *func; - int num, max, pass; + int max, pass; LIST_HEAD(add_list); list_for_each_entry(func, &slot->funcs, sibling) acpiphp_bus_add(func_to_handle(func)); - num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); - if (num == 0) { - /* Maybe only part of funcs are added. */ - dbg("No new device found\n"); - goto err_exit; - } + pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); max = acpiphp_max_busnr(bus); for (pass = 0; pass < 2; pass++) { @@ -599,8 +594,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) } } - - err_exit: return 0; } -- cgit v0.10.2 From 4ebe34503baa0644c9352bcd76d4cf573bffe206 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 16 Jul 2013 22:10:35 +0200 Subject: ACPI / hotplug / PCI: Check for new devices on enabled slots The current implementation of acpiphp_check_bridge() is pretty dumb: - It enables a slot if it's not enabled and the slot status is ACPI_STA_ALL. - It disables a slot if it's enabled and the slot status is not ACPI_STA_ALL. This behavior is not sufficient to handle the Thunderbolt daisy chaining case properly, however, because in that case the bus behind the already enabled slot needs to be rescanned for new devices. For this reason, modify acpiphp_check_bridge() so that slots are disabled and stopped if they are not in the ACPI_STA_ALL state. For slots in the ACPI_STA_ALL state, devices behind them that don't respond are trimmed using a new function, trim_stale_devices(), introduced specifically for this purpose. That function walks the given bus and checks each device on it. If the device doesn't respond, it is assumed to be gone and is removed. Once all of the stale devices directy behind the slot have been removed, acpiphp_check_bridge() will start looking for new devices that might have appeared on the given bus. It will do that even if the slot is already enabled (SLOT_ENABLED is set for it). In addition to that, make the bus check notification ignore SLOT_ENABLED and go for enable_device() directly if bridge is NULL, so that devices behind the slot are re-enumerated in that case too. This change is based on earlier patches from Kirill A Shutemov and Mika Westerberg. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 21a6269..e2e5e30 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -687,47 +688,75 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) } /** + * trim_stale_devices - remove PCI devices that are not responding. + * @dev: PCI device to start walking the hierarchy from. + */ +static void trim_stale_devices(struct pci_dev *dev) +{ + acpi_handle handle = ACPI_HANDLE(&dev->dev); + struct pci_bus *bus = dev->subordinate; + bool alive = false; + + if (handle) { + acpi_status status; + unsigned long long sta; + + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL; + } + if (!alive) { + u32 v; + + /* 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); + } else if (bus) { + struct pci_dev *child, *tmp; + + /* The device is a bridge. so check the bus below it. */ + pm_runtime_get_sync(&dev->dev); + list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) + trim_stale_devices(child); + + pm_runtime_put(&dev->dev); + } +} + +/** * acpiphp_check_bridge - re-enumerate devices * @bridge: where to begin re-enumeration * * Iterate over all slots under this bridge and make sure that if a * card is present they are enabled, and if not they are disabled. */ -static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) +static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) { struct acpiphp_slot *slot; - int retval = 0; - int enabled, disabled; - - enabled = disabled = 0; list_for_each_entry(slot, &bridge->slots, node) { - unsigned int status = get_slot_status(slot); - if (slot->flags & SLOT_ENABLED) { - if (status == ACPI_STA_ALL) - continue; - - retval = acpiphp_disable_and_eject_slot(slot); - if (retval) - goto err_exit; - - disabled++; + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *tmp; + + mutex_lock(&slot->crit_sect); + /* wake up all functions */ + if (get_slot_status(slot) == ACPI_STA_ALL) { + /* remove stale devices if any */ + list_for_each_entry_safe(dev, tmp, &bus->devices, + bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + trim_stale_devices(dev); + + /* configure all functions */ + enable_device(slot); } else { - if (status != ACPI_STA_ALL) - continue; - retval = acpiphp_enable_slot(slot); - if (retval) { - err("Error occurred in enabling\n"); - goto err_exit; - } - enabled++; + disable_device(slot); } + mutex_unlock(&slot->crit_sect); } - - dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled); - - err_exit: - return retval; } static void acpiphp_set_hpp_values(struct pci_bus *bus) @@ -828,7 +857,11 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); } else { - acpiphp_enable_slot(func->slot); + struct acpiphp_slot *slot = func->slot; + + mutex_lock(&slot->crit_sect); + enable_device(slot); + mutex_unlock(&slot->crit_sect); } break; -- cgit v0.10.2 From c38f82cf1b7dc8aad2bce8e30113fd6aa3159dab Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h Drop some unused symbols from acpiphp.h and redefine SLOT_ENABLED (which is the only slot flag now) as 1. [rjw: Redefinition of SLOT_ENABLED, changelog] Signed-off-by: Mika Westerberg Signed-off-by: Kirill A. Shutemov Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index ca2c91d..f4e0289 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -154,16 +154,12 @@ struct acpiphp_attention_info struct module *owner; }; -/* PCI bus bridge HID */ -#define ACPI_PCI_HOST_HID "PNP0A03" - /* ACPI _STA method value (ignore bit 4; battery present) */ #define ACPI_STA_ALL (0x0000000f) /* slot flags */ -#define SLOT_ENABLED (0x00000002) -#define SLOT_MULTIFUNCTION (0x00000004) +#define SLOT_ENABLED (0x00000001) /* function flags */ -- cgit v0.10.2 From 1ad3790ac7cfac699993a3f2e189a69a82f8fe4d Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status() There is no need for a temporary variable and all the tricks with ternary operators in acpiphp_get_(latch)|(adapter)_status(). Change those functions to be a bit more straightforward. [rjw: Changelog] Signed-off-by: Kirill A. Shutemov Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e2e5e30..d8748a4 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1107,11 +1107,7 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) */ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) { - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1; + return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI); } @@ -1121,9 +1117,5 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) */ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) { - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta == 0) ? 0 : 1; + return !!get_slot_status(slot); } -- cgit v0.10.2 From a1d0abcea845730c4ff2f47897e28c2f11c79d4f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Redefine enable_device() and disable_device() Notice that functions enable_device() and disable_device() cannot fail and their return values are ignored in the majority of places, so redefine them as void and use the opportunity to change their names to enable_slot() and disable_slot(), respectively, which much better reflects what they do. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index d8748a4..18c9e54 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -532,13 +532,13 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) } /** - * enable_device - enable, configure a slot + * enable_slot - enable, configure a slot * @slot: slot to be enabled * * This function should be called per *physical slot*, * not per each slot object in ACPI namespace. */ -static int __ref enable_device(struct acpiphp_slot *slot) +static void __ref enable_slot(struct acpiphp_slot *slot) { struct pci_dev *dev; struct pci_bus *bus = slot->bus; @@ -556,6 +556,7 @@ static int __ref enable_device(struct acpiphp_slot *slot) list_for_each_entry(dev, &bus->devices, bus_list) { if (PCI_SLOT(dev->devfn) != slot->device) continue; + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { max = pci_scan_bridge(bus, dev, max, pass); @@ -594,8 +595,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) continue; } } - - return 0; } /* return first device in slot, acquiring a reference on it */ @@ -617,16 +616,16 @@ static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) } /** - * disable_device - disable a slot + * disable_slot - disable a slot * @slot: ACPI PHP slot */ -static int disable_device(struct acpiphp_slot *slot) +static void disable_slot(struct acpiphp_slot *slot) { struct acpiphp_func *func; struct pci_dev *pdev; /* - * enable_device() enumerates all functions in this device via + * enable_slot() enumerates all functions in this device via * pci_scan_slot(), whether they have associated ACPI hotplug * methods (_EJ0, etc.) or not. Therefore, we remove all functions * here. @@ -640,8 +639,6 @@ static int disable_device(struct acpiphp_slot *slot) acpiphp_bus_trim(func_to_handle(func)); slot->flags &= (~SLOT_ENABLED); - - return 0; } @@ -751,9 +748,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) trim_stale_devices(dev); /* configure all functions */ - enable_device(slot); + enable_slot(slot); } else { - disable_device(slot); + disable_slot(slot); } mutex_unlock(&slot->crit_sect); } @@ -860,7 +857,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) struct acpiphp_slot *slot = func->slot; mutex_lock(&slot->crit_sect); - enable_device(slot); + enable_slot(slot); mutex_unlock(&slot->crit_sect); } break; @@ -1047,16 +1044,13 @@ void acpiphp_remove_slots(struct pci_bus *bus) */ int acpiphp_enable_slot(struct acpiphp_slot *slot) { - int retval = 0; - mutex_lock(&slot->crit_sect); - /* configure all functions */ if (!(slot->flags & SLOT_ENABLED)) - retval = enable_device(slot); + enable_slot(slot); mutex_unlock(&slot->crit_sect); - return retval; + return 0; } /** @@ -1071,9 +1065,7 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) mutex_lock(&slot->crit_sect); /* unconfigure all functions */ - retval = disable_device(slot); - if (retval) - goto err_exit; + disable_slot(slot); list_for_each_entry(func, &slot->funcs, sibling) if (func->flags & FUNC_HAS_EJ0) { @@ -1085,7 +1077,6 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) break; } - err_exit: mutex_unlock(&slot->crit_sect); return retval; } -- cgit v0.10.2 From ff181e5a4f6b536e5f3f1601cd5c54e792cd9abc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 13 Jul 2013 23:27:26 +0200 Subject: ACPI / hotplug / PCI: Clean up bridge_mutex usage Do not acquire bridge_mutex around the addition of a slot to its bridge's list of slots and arount the addition of a function to its slot's list of functions, because that doesn't help anything right now (those lists are walked without any locking anyway). However, acquire bridge_mutex around the list walk in acpiphp_remove_slots() and use list_for_each_entry() there, because we terminate the walk as soon as we find the first matching entry. This prevents that list walk from colliding with bridge addition and removal. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 18c9e54..e4b7f2b 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -323,9 +323,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, INIT_LIST_HEAD(&slot->funcs); mutex_init(&slot->crit_sect); - mutex_lock(&bridge_mutex); list_add_tail(&slot->node, &bridge->slots); - mutex_unlock(&bridge_mutex); /* Register slots for ejectable funtions only. */ if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) { @@ -355,9 +353,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, slot_found: newfunc->slot = slot; - mutex_lock(&bridge_mutex); list_add_tail(&newfunc->sibling, &slot->funcs); - mutex_unlock(&bridge_mutex); if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), &val, 60*1000)) @@ -1025,17 +1021,21 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) /* Destroy hotplug slots associated with the PCI bus */ void acpiphp_remove_slots(struct pci_bus *bus) { - struct acpiphp_bridge *bridge, *tmp; + struct acpiphp_bridge *bridge; if (acpiphp_disabled) return; - list_for_each_entry_safe(bridge, tmp, &bridge_list, list) + mutex_lock(&bridge_mutex); + list_for_each_entry(bridge, &bridge_list, list) if (bridge->pci_bus == bus) { + mutex_unlock(&bridge_mutex); cleanup_bridge(bridge); put_bridge(bridge); - break; + return; } + + mutex_unlock(&bridge_mutex); } /** -- cgit v0.10.2 From 2d8b1d566a5f4874f4d92361f5cdbb50baa396f8 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 13 Jul 2013 20:09:59 +0300 Subject: ACPI / hotplug / PCI: Get rid of check_sub_bridges() Now that acpiphp_check_bridge() always enumerates devices behind the bridge, there is no need to do that for each sub-bridge anymore like it is done in the current ACPI-based PCI hotplug (ACPIPHP) code. Given this we don't need check_sub_bridges() anymore, so drop that function completely. This also simplifies the ACPIPHP code a bit. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e4b7f2b..05e463d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -788,25 +788,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) * ACPI event handlers */ -static acpi_status -check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - - bridge = acpiphp_handle_to_bridge(handle); - if (bridge) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - dbg("%s: re-enumerating slots under %s\n", - __func__, objname); - acpiphp_check_bridge(bridge); - put_bridge(bridge); - } - return AE_OK ; -} - void acpiphp_check_host_bridge(acpi_handle handle) { struct acpiphp_bridge *bridge; @@ -816,9 +797,6 @@ void acpiphp_check_host_bridge(acpi_handle handle) acpiphp_check_bridge(bridge); put_bridge(bridge); } - - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); } static void hotplug_event(acpi_handle handle, u32 type, void *data) @@ -846,9 +824,6 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) dbg("%s: re-enumerating slots under %s\n", __func__, objname); if (bridge) { acpiphp_check_bridge(bridge); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, check_sub_bridges, - NULL, NULL, NULL); } else { struct acpiphp_slot *slot = func->slot; -- cgit v0.10.2 From 2cf9f5bcc8d8cb31d6ea7baebac5056f39fb4f40 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 22 Jul 2013 16:08:16 +0800 Subject: ACPICA: Add acpi_update_interfaces() public interface Add new API to allow OSPM to disable/enable specific types of _OSI interface strings. ACPICA does not have the knowledge about whether an _OSI interface string is an OS vendor string or a feature group string and there isn't any API interface to allow OSPM to install a new interface string as a feature group string. This patch simply adds all feature group strings defined by ACPI specification into the acpi_default_supported_interfaces with ACPI_OSI_FEATURE flag set to fix this gap. This patch also adds codes to keep their default states as ACPI_OSI_INVALID before the initialization and after the termination. Signed-off-by: Lv Zheng Reviewed-by: Zhang Rui Signed-off-by: Bob Moore Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki Conflicts: include/acpi/actypes.h (with commit 242b228) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index d4a49016..b0e3d15 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -942,6 +942,9 @@ struct acpi_interface_info { #define ACPI_OSI_INVALID 0x01 #define ACPI_OSI_DYNAMIC 0x02 +#define ACPI_OSI_FEATURE 0x04 +#define ACPI_OSI_DEFAULT_INVALID 0x08 +#define ACPI_OSI_OPTIONAL_FEATURE (ACPI_OSI_FEATURE | ACPI_OSI_DEFAULT_INVALID | ACPI_OSI_INVALID) struct acpi_port_info { char *name; diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 4c081c4..d5a62a6 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -470,6 +470,8 @@ acpi_status acpi_ut_install_interface(acpi_string interface_name); acpi_status acpi_ut_remove_interface(acpi_string interface_name); +acpi_status acpi_ut_update_interfaces(u8 action); + struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name); acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state); diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 7e80772..8856bd3 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -77,21 +77,20 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = { /* Feature Group Strings */ - {"Extended Address Space Descriptor", NULL, 0, 0} + {"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0}, /* * All "optional" feature group strings (features that are implemented - * by the host) should be dynamically added by the host via - * acpi_install_interface and should not be manually added here. - * - * Examples of optional feature group strings: - * - * "Module Device" - * "Processor Device" - * "3.0 Thermal Model" - * "3.0 _SCP Extensions" - * "Processor Aggregator Device" + * by the host) should be dynamically modified to VALID by the host via + * acpi_install_interface or acpi_update_interfaces. Such optional feature + * group strings are set as INVALID by default here. */ + + {"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, + {"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, + {"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, + {"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, + {"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0} }; /******************************************************************************* @@ -158,11 +157,20 @@ acpi_status acpi_ut_interface_terminate(void) while (next_interface) { acpi_gbl_supported_interfaces = next_interface->next; - /* Only interfaces added at runtime can be freed */ - if (next_interface->flags & ACPI_OSI_DYNAMIC) { + + /* Only interfaces added at runtime can be freed */ + ACPI_FREE(next_interface->name); ACPI_FREE(next_interface); + } else { + /* Interface is in static list. Reset it to invalid or valid. */ + + if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) { + next_interface->flags |= ACPI_OSI_INVALID; + } else { + next_interface->flags &= ~ACPI_OSI_INVALID; + } } next_interface = acpi_gbl_supported_interfaces; @@ -278,6 +286,49 @@ acpi_status acpi_ut_remove_interface(acpi_string interface_name) /******************************************************************************* * + * FUNCTION: acpi_ut_update_interfaces + * + * PARAMETERS: action - Actions to be performed during the + * update + * + * RETURN: Status + * + * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor + * strings or/and feature group strings. + * Caller MUST hold acpi_gbl_osi_mutex + * + ******************************************************************************/ + +acpi_status acpi_ut_update_interfaces(u8 action) +{ + struct acpi_interface_info *next_interface; + + next_interface = acpi_gbl_supported_interfaces; + while (next_interface) { + if (((next_interface->flags & ACPI_OSI_FEATURE) && + (action & ACPI_FEATURE_STRINGS)) || + (!(next_interface->flags & ACPI_OSI_FEATURE) && + (action & ACPI_VENDOR_STRINGS))) { + if (action & ACPI_DISABLE_INTERFACES) { + + /* Mark the interfaces as invalid */ + + next_interface->flags |= ACPI_OSI_INVALID; + } else { + /* Mark the interfaces as valid */ + + next_interface->flags &= ~ACPI_OSI_INVALID; + } + } + + next_interface = next_interface->next; + } + + return (AE_OK); +} + +/******************************************************************************* + * * FUNCTION: acpi_ut_get_interface * * PARAMETERS: interface_name - The interface to find diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 6505774..03a211e 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -389,6 +389,34 @@ ACPI_EXPORT_SYMBOL(acpi_install_interface_handler) /***************************************************************************** * + * FUNCTION: acpi_update_interfaces + * + * PARAMETERS: action - Actions to be performed during the + * update + * + * RETURN: Status + * + * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor + * string or/and feature group strings. + * + ****************************************************************************/ +acpi_status acpi_update_interfaces(u8 action) +{ + acpi_status status; + + status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE(status)) { + return (status); + } + + status = acpi_ut_update_interfaces(action); + + acpi_os_release_mutex(acpi_gbl_osi_mutex); + return (status); +} + +/***************************************************************************** + * * FUNCTION: acpi_check_address_range * * PARAMETERS: space_id - Address space ID @@ -402,6 +430,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_interface_handler) * ASL operation region address ranges. * ****************************************************************************/ + u32 acpi_check_address_range(acpi_adr_space_type space_id, acpi_physical_address address, diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 292af0c..0dd03f2 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -147,6 +147,8 @@ acpi_status acpi_install_interface(acpi_string interface_name); acpi_status acpi_remove_interface(acpi_string interface_name); +acpi_status acpi_update_interfaces(u8 action); + u32 acpi_check_address_range(acpi_adr_space_type space_id, acpi_physical_address address, diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 787a977..eae55fb 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1152,4 +1152,18 @@ struct acpi_memory_list { #define ACPI_OSI_WIN_7 0x0B #define ACPI_OSI_WIN_8 0x0C +/* _OSI update actions */ + +#define ACPI_VENDOR_STRINGS 0x01 +#define ACPI_FEATURE_STRINGS 0x02 +#define ACPI_ENABLE_INTERFACES 0x00 +#define ACPI_DISABLE_INTERFACES 0x04 + +#define ACPI_DISABLE_ALL_VENDOR_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS) +#define ACPI_DISABLE_ALL_FEATURE_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_FEATURE_STRINGS) +#define ACPI_DISABLE_ALL_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) +#define ACPI_ENABLE_ALL_VENDOR_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS) +#define ACPI_ENABLE_ALL_FEATURE_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_FEATURE_STRINGS) +#define ACPI_ENABLE_ALL_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) + #endif /* __ACTYPES_H__ */ -- cgit v0.10.2 From 5dc17986fdc3d2425838cb8d699152c3c30d1208 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 22 Jul 2013 16:08:25 +0800 Subject: ACPI: Add facility to disable all _OSI OS vendor strings This patch introduces "acpi_osi=!" command line to force Linux replying "UNSUPPORTED" to all of the _OSI strings. This patch is based on an ACPICA enhancement - the new API acpi_update_interfaces(). The _OSI object provides the platform with the ability to query OSPM to determine the set of ACPI related interfaces, behaviors, or features that the operating system supports. The argument passed to the _OSI is a string like the followings: 1. Feature Group String, examples include Module Device Processor Device 3.0 _SCP Extensions Processor Aggregator Device ... 2. OS Vendor String, examples include Linux FreeBSD Windows ... There are AML codes provided in the ACPI namespace written in the following style to determine OSPM interfaces / features: Method(OSCK) { if (CondRefOf(_OSI, Local0)) { if (\_OSI("Windows")) { Return (One) } if (\_OSI("Windows 2006")) { Return (Ones) } Return (Zero) } Return (Zero) } There is a debugging facility implemented in Linux. Users can pass "acpi_osi=" boot parameters to the kernel to tune the _OSI evaluation result so that certain AML codes can be executed. Current implementation includes: 1. 'acpi_osi=' - this makes CondRefOf(_OSI, Local0) TRUE 2. 'acpi_osi="Windows"' - this makes \_OSI("Windows") TRUE 3. 'acpi_osi="!Windows"' - this makes \_OSI("Windows") FALSE The function to implement this feature is also used as a quirk mechanism in the Linux ACPI subystem. When _OSI is evaluatated by the AML codes, ACPICA replies "SUPPORTED" to all Windows operating system vendor strings. This is because Windows operating systems return "SUPPORTED" if the argument to the _OSI method specifies an earlier version of Windows. Please refer to the following MSDN document: How to Identify the Windows Version in ACPI by Using _OSI http://msdn.microsoft.com/en-us/library/hardware/gg463275.aspx This adds difficulties when developers want to feed specific Windows operating system vendor string to the BIOS codes for debugging purpose, multiple acpi_osi="!xxx" have to be specified in the command line to force Linux replying "UNSUPPORTED" to the Windows OS vendor strings listed in the AML codes. Signed-off-by: Lv Zheng Reviewed-by: Zhang Rui Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 15356ac..d0d9cf2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -235,10 +235,35 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Format: To spoof as Windows 98: ="Microsoft Windows" acpi_osi= [HW,ACPI] Modify list of supported OS interface strings - acpi_osi="string1" # add string1 -- only one string - acpi_osi="!string2" # remove built-in string2 + acpi_osi="string1" # add string1 + acpi_osi="!string2" # remove string2 + acpi_osi=! # disable all built-in OS vendor + strings acpi_osi= # disable all strings + 'acpi_osi=!' can be used in combination with single or + multiple 'acpi_osi="string1"' to support specific OS + vendor string(s). Note that such command can only + affect the default state of the OS vendor strings, thus + it cannot affect the default state of the feature group + strings and the current state of the OS vendor strings, + specifying it multiple times through kernel command line + is meaningless. + Examples: + 1. 'acpi_osi=! acpi_osi="Windows 2000"' is equivalent + to 'acpi_osi="Windows 2000" acpi_osi=!', they all + can make '_OSI("Windows 2000")' TRUE. + + 'acpi_osi=' cannot be used in combination with other + 'acpi_osi=' command lines, the _OSI method will not + exist in the ACPI namespace. NOTE that such command can + only affect the _OSI support state, thus specifying it + multiple times through kernel command line is also + meaningless. + Examples: + 1. 'acpi_osi=' can make 'CondRefOf(_OSI, Local1)' + FALSE. + acpi_pm_good [X86] Override the pmtimer bug detection: force the kernel to assume that this machine's pmtimer latches its value diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 6ab2c35..e8baa40 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -140,7 +140,8 @@ static struct osi_linux { unsigned int enable:1; unsigned int dmi:1; unsigned int cmdline:1; -} osi_linux = {0, 0, 0}; + unsigned int default_disabling:1; +} osi_linux = {0, 0, 0, 0}; static u32 acpi_osi_handler(acpi_string interface, u32 supported) { @@ -1376,6 +1377,10 @@ void __init acpi_osi_setup(char *str) if (*str == '!') { str++; + if (*str == '\0') { + osi_linux.default_disabling = 1; + return; + } enable = false; } @@ -1441,6 +1446,13 @@ static void __init acpi_osi_setup_late(void) int i; acpi_status status; + if (osi_linux.default_disabling) { + status = acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS); + + if (ACPI_SUCCESS(status)) + printk(KERN_INFO PREFIX "Disabled all _OSI OS vendors\n"); + } + for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { osi = &osi_setup_entries[i]; str = osi->string; -- cgit v0.10.2 From 741d81280ad2b31fc3d76c49fa5c1fe09f3a6f68 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 22 Jul 2013 16:08:36 +0800 Subject: ACPI: Add facility to remove all _OSI strings This patch changes the "acpi_osi=" boot parameter implementation so that: 1. "acpi_osi=!" can be used to disable all _OSI OS vendor strings by default. It is meaningless to specify "acpi_osi=!" multiple times as it can only affect the default state of the target _OSI strings. 2. "acpi_osi=!*" can be used to remove all _OSI OS vendor strings and all _OSI feature group strings. It is useful to specify "acpi_osi=!*" multiple times through kernel command line to override the current state of the target _OSI strings. Signed-off-by: Lv Zheng Reviewed-by: Zhang Rui Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d0d9cf2..5ec77aa 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -237,6 +237,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. acpi_osi= [HW,ACPI] Modify list of supported OS interface strings acpi_osi="string1" # add string1 acpi_osi="!string2" # remove string2 + acpi_osi=!* # remove all strings acpi_osi=! # disable all built-in OS vendor strings acpi_osi= # disable all strings @@ -248,7 +249,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. it cannot affect the default state of the feature group strings and the current state of the OS vendor strings, specifying it multiple times through kernel command line - is meaningless. + is meaningless. This command is useful when one do not + care about the state of the feature group strings which + should be controlled by the OSPM. Examples: 1. 'acpi_osi=! acpi_osi="Windows 2000"' is equivalent to 'acpi_osi="Windows 2000" acpi_osi=!', they all @@ -264,6 +267,29 @@ bytes respectively. Such letter suffixes can also be entirely omitted. 1. 'acpi_osi=' can make 'CondRefOf(_OSI, Local1)' FALSE. + 'acpi_osi=!*' can be used in combination with single or + multiple 'acpi_osi="string1"' to support specific + string(s). Note that such command can affect the + current state of both the OS vendor strings and the + feature group strings, thus specifying it multiple times + through kernel command line is meaningful. But it may + still not able to affect the final state of a string if + there are quirks related to this string. This command + is useful when one want to control the state of the + feature group strings to debug BIOS issues related to + the OSPM features. + Examples: + 1. 'acpi_osi="Module Device" acpi_osi=!*' can make + '_OSI("Module Device")' FALSE. + 2. 'acpi_osi=!* acpi_osi="Module Device"' can make + '_OSI("Module Device")' TRUE. + 3. 'acpi_osi=! acpi_osi=!* acpi_osi="Windows 2000"' is + equivalent to + 'acpi_osi=!* acpi_osi=! acpi_osi="Windows 2000"' + and + 'acpi_osi=!* acpi_osi="Windows 2000" acpi_osi=!', + they all will make '_OSI("Windows 2000")' TRUE. + acpi_pm_good [X86] Override the pmtimer bug detection: force the kernel to assume that this machine's pmtimer latches its value diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e8baa40..cc1ed12 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1380,6 +1380,13 @@ void __init acpi_osi_setup(char *str) if (*str == '\0') { osi_linux.default_disabling = 1; return; + } else if (*str == '*') { + acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS); + for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { + osi = &osi_setup_entries[i]; + osi->enable = false; + } + return; } enable = false; } -- cgit v0.10.2 From 0177f29fea534ef5e6af2d76e9a9be0fdd325c4d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 17 Jul 2013 08:33:25 +0800 Subject: ACPI / dock: fix error return code in dock_add() Fix to return -ENODEV in the acpi notify handler install error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index f601658..b527c1b 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -881,8 +881,10 @@ static int __init dock_add(acpi_handle handle) status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, dock_notify_handler, dock_station); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + ret = -ENODEV; goto err_rmgroup; + } dock_station_count++; list_add(&dock_station->sibling, &dock_stations); -- cgit v0.10.2 From 1129c92faa069581bf3acf34cae92477bd6161d8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 23 Jul 2013 16:11:55 +0800 Subject: ACPI: Cleanup sparse warning on acpi_os_initialize1() This patch cleans up the following sparse warning: # make C=2 drivers/acpi/osl.o ... drivers/acpi/osl.c:1775:20: warning: symbol 'acpi_os_initialize1' was not declared. Should it be static? ... CC drivers/acpi/osl.o Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b6e9a37..25b289f 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -617,7 +617,6 @@ static int __init acpi_bus_init(void) { int result; acpi_status status; - extern acpi_status acpi_os_initialize1(void); acpi_os_initialize1(); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 3a50a34..b636b74 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -23,6 +23,7 @@ #define PREFIX "ACPI: " +acpi_status acpi_os_initialize1(void); int init_acpi_device_notify(void); int acpi_scan_init(void); #ifdef CONFIG_ACPI_PCI_SLOT diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 6ab2c35..605718f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -52,6 +52,7 @@ #include #include #include +#include "internal.h" #define _COMPONENT ACPI_OS_SERVICES ACPI_MODULE_NAME("osl"); -- cgit v0.10.2 From 3831261eb08557a1390b29c1038a0217232d8fdb Mon Sep 17 00:00:00 2001 From: "Brandt, Todd E" Date: Thu, 11 Jul 2013 07:44:35 +0000 Subject: PM / Sleep: increase ftrace coverage in suspend/resume Change where ftrace is disabled and re-enabled during system suspend/resume to allow tracing of device driver pm callbacks. Ftrace will now be turned off when suspend reaches disable_nonboot_cpus() instead of at the very beginning of system suspend. Ftrace was disabled during suspend/resume back in 2008 by Steven Rostedt as he discovered there was a conflict in the enable_nonboot_cpus() call (see commit f42ac38 "ftrace: disable tracing for suspend to ram"). This change preserves his fix by disabling ftrace, but only at the function where it is known to cause problems. The new change allows tracing of the device level code for better debug. [rjw: Changelog] Signed-off-by: Todd Brandt Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index ece0422..62ee437 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -210,6 +210,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) goto Platform_wake; } + ftrace_stop(); error = disable_nonboot_cpus(); if (error || suspend_test(TEST_CPUS)) goto Enable_cpus; @@ -232,6 +233,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) Enable_cpus: enable_nonboot_cpus(); + ftrace_start(); Platform_wake: if (need_suspend_ops(state) && suspend_ops->wake) @@ -265,7 +267,6 @@ int suspend_devices_and_enter(suspend_state_t state) goto Close; } suspend_console(); - ftrace_stop(); suspend_test_start(); error = dpm_suspend_start(PMSG_SUSPEND); if (error) { @@ -285,7 +286,6 @@ int suspend_devices_and_enter(suspend_state_t state) suspend_test_start(); dpm_resume_end(PMSG_RESUME); suspend_test_finish("resume devices"); - ftrace_start(); resume_console(); Close: if (need_suspend_ops(state) && suspend_ops->end) -- cgit v0.10.2 From dfa5bb622555d9da0df21b50f46ebdeef390041b Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Wed, 5 Jun 2013 19:01:25 +0300 Subject: cpufreq: ondemand: Change the calculation of target frequency The ondemand governor calculates load in terms of frequency and increases it only if load_freq is greater than up_threshold multiplied by the current or average frequency. This appears to produce oscillations of frequency between min and max because, for example, a relatively small load can easily saturate minimum frequency and lead the CPU to the max. Then, it will decrease back to the min due to small load_freq. Change the calculation method of load and target frequency on the basis of the following two observations: - Load computation should not depend on the current or average measured frequency. For example, absolute load of 80% at 100MHz is not necessarily equivalent to 8% at 1000MHz in the next sampling interval. - It should be possible to increase the target frequency to any value present in the frequency table proportional to the absolute load, rather than to the max only, so that: Target frequency = C * load where we take C = policy->cpuinfo.max_freq / 100. Tested on Intel i7-3770 CPU @ 3.40GHz and on Quad core 1500MHz Krait. Phoronix benchmark of Linux Kernel Compilation 3.1 test shows an increase ~1.5% in performance. cpufreq_stats (time_in_state) shows that middle frequencies are used more, with this patch. Highest and lowest frequencies were used less by ~9%. [rjw: We have run multiple other tests on kernels with this change applied and in the vast majority of cases it turns out that the resulting performance improvement also leads to reduced consumption of energy. The change is additionally justified by the overall simplification of the code in question.] Signed-off-by: Stratos Karafotis Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 7b839a8..7409dbd 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -53,7 +53,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) policy = cdbs->cur_policy; - /* Get Absolute Load (in terms of freq for ondemand gov) */ + /* Get Absolute Load */ for_each_cpu(j, policy->cpus) { struct cpu_dbs_common_info *j_cdbs; u64 cur_wall_time, cur_idle_time; @@ -104,14 +104,6 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) load = 100 * (wall_time - idle_time) / wall_time; - if (dbs_data->cdata->governor == GOV_ONDEMAND) { - int freq_avg = __cpufreq_driver_getavg(policy, j); - if (freq_avg <= 0) - freq_avg = policy->cur; - - load *= freq_avg; - } - if (load > max_load) max_load = load; } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 6663ec3..0e0dd4c 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -169,7 +169,6 @@ struct od_dbs_tuners { unsigned int sampling_rate; unsigned int sampling_down_factor; unsigned int up_threshold; - unsigned int adj_up_threshold; unsigned int powersave_bias; unsigned int io_is_busy; }; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 93eb5cb..a3c5574 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -29,11 +29,9 @@ #include "cpufreq_governor.h" /* On-demand governor macros */ -#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) #define DEF_FREQUENCY_UP_THRESHOLD (80) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (100000) -#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) #define MICRO_FREQUENCY_UP_THRESHOLD (95) #define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) #define MIN_FREQUENCY_UP_THRESHOLD (11) @@ -161,14 +159,10 @@ static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) /* * Every sampling_rate, we check, if current idle time is less than 20% - * (default), then we try to increase frequency. Every sampling_rate, we look - * for the lowest frequency which can sustain the load while keeping idle time - * over 30%. If such a frequency exist, we try to decrease to this frequency. - * - * Any frequency increase takes it to the maximum frequency. Frequency reduction - * happens at minimum steps of 5% (default) of current frequency + * (default), then we try to increase frequency. Else, we adjust the frequency + * proportional to load. */ -static void od_check_cpu(int cpu, unsigned int load_freq) +static void od_check_cpu(int cpu, unsigned int load) { struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; @@ -178,29 +172,17 @@ static void od_check_cpu(int cpu, unsigned int load_freq) dbs_info->freq_lo = 0; /* Check for frequency increase */ - if (load_freq > od_tuners->up_threshold * policy->cur) { + if (load > od_tuners->up_threshold) { /* If switching to max speed, apply sampling_down_factor */ if (policy->cur < policy->max) dbs_info->rate_mult = od_tuners->sampling_down_factor; dbs_freq_increase(policy, policy->max); return; - } - - /* Check for frequency decrease */ - /* if we cannot reduce the frequency anymore, break out early */ - if (policy->cur == policy->min) - return; - - /* - * The optimal frequency is the frequency that is the lowest that can - * support the current CPU usage without triggering the up policy. To be - * safe, we focus 10 points under the threshold. - */ - if (load_freq < od_tuners->adj_up_threshold - * policy->cur) { + } else { + /* Calculate the next frequency proportional to load */ unsigned int freq_next; - freq_next = load_freq / od_tuners->adj_up_threshold; + freq_next = load * policy->cpuinfo.max_freq / 100; /* No longer fully busy, reset rate_mult */ dbs_info->rate_mult = 1; @@ -374,9 +356,6 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf, input < MIN_FREQUENCY_UP_THRESHOLD) { return -EINVAL; } - /* Calculate the new adj_up_threshold */ - od_tuners->adj_up_threshold += input; - od_tuners->adj_up_threshold -= od_tuners->up_threshold; od_tuners->up_threshold = input; return count; @@ -525,8 +504,6 @@ static int od_init(struct dbs_data *dbs_data) if (idle_time != -1ULL) { /* Idle micro accounting is supported. Use finer thresholds */ tuners->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; - tuners->adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD - - MICRO_FREQUENCY_DOWN_DIFFERENTIAL; /* * In nohz/micro accounting case we set the minimum frequency * not depending on HZ, but fixed (very low). The deferred @@ -535,8 +512,6 @@ static int od_init(struct dbs_data *dbs_data) dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; } else { tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD; - tuners->adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD - - DEF_FREQUENCY_DOWN_DIFFERENTIAL; /* For correct statistics, we need 10 ticks for each measure */ dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO * -- cgit v0.10.2 From 61c63e5ed3b9c472899d7152e961f2ffaafcf5a0 Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Wed, 5 Jun 2013 19:01:42 +0300 Subject: cpufreq: Remove unused APERF/MPERF support The target frequency calculation method in the ondemand governor has changed and it is now independent of the measured average frequency. Consequently, the APERF/MPERF support in cpufreq is not used any more, so drop it. [rjw: Changelog] Signed-off-by: Stratos Karafotis Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 24cf5ae..4f4a3d9 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -942,35 +942,6 @@ extern int set_tsc_mode(unsigned int val); extern u16 amd_get_nb_id(int cpu); -struct aperfmperf { - u64 aperf, mperf; -}; - -static inline void get_aperfmperf(struct aperfmperf *am) -{ - WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_APERFMPERF)); - - rdmsrl(MSR_IA32_APERF, am->aperf); - rdmsrl(MSR_IA32_MPERF, am->mperf); -} - -#define APERFMPERF_SHIFT 10 - -static inline -unsigned long calc_aperfmperf_ratio(struct aperfmperf *old, - struct aperfmperf *new) -{ - u64 aperf = new->aperf - old->aperf; - u64 mperf = new->mperf - old->mperf; - unsigned long ratio = aperf; - - mperf >>= APERFMPERF_SHIFT; - if (mperf) - ratio = div64_u64(aperf, mperf); - - return ratio; -} - extern unsigned long arch_align_stack(unsigned long sp); extern void free_init_pages(char *what, unsigned long begin, unsigned long end); diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index d345b5a..ad5866c 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o # powernow-k8 can load then. ACPI is preferred to all other hardware-specific drivers. # speedstep-* is preferred over p4-clockmod. -obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o +obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 3926402..e673670 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -45,7 +45,6 @@ #include #include #include -#include "mperf.h" MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); MODULE_DESCRIPTION("ACPI Processor P-States Driver"); @@ -861,10 +860,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) /* notify BIOS that we exist */ acpi_processor_notify_smm(THIS_MODULE); - /* Check for APERF/MPERF support in hardware */ - if (boot_cpu_has(X86_FEATURE_APERFMPERF)) - acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf; - pr_debug("CPU%u - ACPI performance management activated.\n", cpu); for (i = 0; i < perf->state_count; i++) pr_debug(" %cP%d: %d MHz, %d mW, %d uS\n", diff --git a/drivers/cpufreq/mperf.c b/drivers/cpufreq/mperf.c deleted file mode 100644 index 911e193..0000000 --- a/drivers/cpufreq/mperf.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "mperf.h" - -static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf); - -/* Called via smp_call_function_single(), on the target CPU */ -static void read_measured_perf_ctrs(void *_cur) -{ - struct aperfmperf *am = _cur; - - get_aperfmperf(am); -} - -/* - * Return the measured active (C0) frequency on this CPU since last call - * to this function. - * Input: cpu number - * Return: Average CPU frequency in terms of max frequency (zero on error) - * - * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance - * over a period of time, while CPU is in C0 state. - * IA32_MPERF counts at the rate of max advertised frequency - * IA32_APERF counts at the rate of actual CPU frequency - * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and - * no meaning should be associated with absolute values of these MSRs. - */ -unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy, - unsigned int cpu) -{ - struct aperfmperf perf; - unsigned long ratio; - unsigned int retval; - - if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1)) - return 0; - - ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf); - per_cpu(acfreq_old_perf, cpu) = perf; - - retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT; - - return retval; -} -EXPORT_SYMBOL_GPL(cpufreq_get_measured_perf); -MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/mperf.h b/drivers/cpufreq/mperf.h deleted file mode 100644 index 5dbf295..0000000 --- a/drivers/cpufreq/mperf.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * (c) 2010 Advanced Micro Devices, Inc. - * Your use of this code is subject to the terms and conditions of the - * GNU general public license version 2. See "COPYING" or - * http://www.gnu.org/licenses/gpl.html - */ - -unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy, - unsigned int cpu); -- cgit v0.10.2 From cffe4e0e7413eb29fb8bd035c8b12b33a4b8522a Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Wed, 5 Jun 2013 19:01:50 +0300 Subject: cpufreq: Remove unused function __cpufreq_driver_getavg() The target frequency calculation method in the ondemand governor has changed and it is now independent of the measured average frequency. Consequently, the __cpufreq_driver_getavg() function and getavg member of struct cpufreq_driver are not used any more, so drop them. [rjw: Changelog] Signed-off-by: Stratos Karafotis Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a4ad733..9a9d8ee 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1593,18 +1593,6 @@ fail: } EXPORT_SYMBOL_GPL(cpufreq_driver_target); -int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) -{ - if (cpufreq_disabled()) - return 0; - - if (!cpufreq_driver->getavg) - return 0; - - return cpufreq_driver->getavg(policy, cpu); -} -EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg); - /* * when "event" is CPUFREQ_GOV_LIMITS */ diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 90d5a15..e1fd215 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -216,10 +216,6 @@ extern int cpufreq_driver_target(struct cpufreq_policy *policy, extern int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation); - -extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy, - unsigned int cpu); - int cpufreq_register_governor(struct cpufreq_governor *governor); void cpufreq_unregister_governor(struct cpufreq_governor *governor); @@ -258,8 +254,6 @@ struct cpufreq_driver { unsigned int (*get) (unsigned int cpu); /* optional */ - unsigned int (*getavg) (struct cpufreq_policy *policy, - unsigned int cpu); int (*bios_limit) (int cpu, unsigned int *limit); int (*exit) (struct cpufreq_policy *policy); -- cgit v0.10.2 From 536446772f1181f3afdf332780b5325d1b6980c6 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 26 Jul 2013 13:30:20 -0600 Subject: PM / Sleep: new trace event to print device suspend and resume times A new trace event is added to PM events to print the time it takes to suspend and resume a device. It generates trace messages that include device, driver, parent information in addition to the type of PM ops invoked as well as the PM event and error status from the PM ops. Example trace below: bash-2239 [000] .... 290.883035: device_pm_report_time: backlight acpi_video0 parent=0000:00:02.0 state=freeze ops=class nsecs=332 err=0 bash-2239 [000] .... 290.883041: device_pm_report_time: rfkill rf kill3 parent=phy0 state=freeze ops=legacy class nsecs=216 err=0 bash-2239 [001] .... 290.973892: device_pm_report_time: ieee80211 phy0 parent=0000:01:00.0 state=freeze ops=legacy class nsecs=90846477 err=0 bash-2239 [001] .... 293.660129: device_pm_report_time: ieee80211 phy0 parent=0000:01:00.0 state=restore ops=legacy class nsecs=101295162 err=0 bash-2239 [001] .... 293.660147: device_pm_report_time: rfkill rfkill3 parent=phy0 state=restore ops=legacy class nsecs=1804 err=0 bash-2239 [001] .... 293.660157: device_pm_report_time: backlight acpi_video0 parent=0000:00:02.0 state=restore ops=class nsecs=757 err=0 Signed-off-by: Shuah Khan Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 5a9b656..9f098a8 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "../base.h" #include "power.h" @@ -56,6 +57,30 @@ static pm_message_t pm_transition; static int async_error; +static char *pm_verb(int event) +{ + switch (event) { + case PM_EVENT_SUSPEND: + return "suspend"; + case PM_EVENT_RESUME: + return "resume"; + case PM_EVENT_FREEZE: + return "freeze"; + case PM_EVENT_QUIESCE: + return "quiesce"; + case PM_EVENT_HIBERNATE: + return "hibernate"; + case PM_EVENT_THAW: + return "thaw"; + case PM_EVENT_RESTORE: + return "restore"; + case PM_EVENT_RECOVER: + return "recover"; + default: + return "(unknown PM event)"; + } +} + /** * device_pm_sleep_init - Initialize system suspend-related device fields. * @dev: Device object being initialized. @@ -172,16 +197,21 @@ static ktime_t initcall_debug_start(struct device *dev) } static void initcall_debug_report(struct device *dev, ktime_t calltime, - int error) + int error, pm_message_t state, char *info) { - ktime_t delta, rettime; + ktime_t rettime; + s64 nsecs; + + rettime = ktime_get(); + nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime)); if (pm_print_times_enabled) { - rettime = ktime_get(); - delta = ktime_sub(rettime, calltime); pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev), - error, (unsigned long long)ktime_to_ns(delta) >> 10); + error, (unsigned long long)nsecs >> 10); } + + trace_device_pm_report_time(dev, info, nsecs, pm_verb(state.event), + error); } /** @@ -309,30 +339,6 @@ static pm_callback_t pm_noirq_op(const struct dev_pm_ops *ops, pm_message_t stat return NULL; } -static char *pm_verb(int event) -{ - switch (event) { - case PM_EVENT_SUSPEND: - return "suspend"; - case PM_EVENT_RESUME: - return "resume"; - case PM_EVENT_FREEZE: - return "freeze"; - case PM_EVENT_QUIESCE: - return "quiesce"; - case PM_EVENT_HIBERNATE: - return "hibernate"; - case PM_EVENT_THAW: - return "thaw"; - case PM_EVENT_RESTORE: - return "restore"; - case PM_EVENT_RECOVER: - return "recover"; - default: - return "(unknown PM event)"; - } -} - static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info) { dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event), @@ -379,7 +385,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, error = cb(dev); suspend_report_result(cb, error); - initcall_debug_report(dev, calltime, error); + initcall_debug_report(dev, calltime, error, state, info); return error; } @@ -1027,7 +1033,8 @@ EXPORT_SYMBOL_GPL(dpm_suspend_end); * @cb: Suspend callback to execute. */ static int legacy_suspend(struct device *dev, pm_message_t state, - int (*cb)(struct device *dev, pm_message_t state)) + int (*cb)(struct device *dev, pm_message_t state), + char *info) { int error; ktime_t calltime; @@ -1037,7 +1044,7 @@ static int legacy_suspend(struct device *dev, pm_message_t state, error = cb(dev, state); suspend_report_result(cb, error); - initcall_debug_report(dev, calltime, error); + initcall_debug_report(dev, calltime, error, state, info); return error; } @@ -1097,7 +1104,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) goto Run; } else if (dev->class->suspend) { pm_dev_dbg(dev, state, "legacy class "); - error = legacy_suspend(dev, state, dev->class->suspend); + error = legacy_suspend(dev, state, dev->class->suspend, + "legacy class "); goto End; } } @@ -1108,7 +1116,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) callback = pm_op(dev->bus->pm, state); } else if (dev->bus->suspend) { pm_dev_dbg(dev, state, "legacy bus "); - error = legacy_suspend(dev, state, dev->bus->suspend); + error = legacy_suspend(dev, state, dev->bus->suspend, + "legacy bus "); goto End; } } diff --git a/include/trace/events/power.h b/include/trace/events/power.h index 8e42410..cda100d 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -66,6 +66,43 @@ TRACE_EVENT(machine_suspend, TP_printk("state=%lu", (unsigned long)__entry->state) ); +TRACE_EVENT(device_pm_report_time, + + TP_PROTO(struct device *dev, const char *pm_ops, s64 ops_time, + char *pm_event_str, int error), + + TP_ARGS(dev, pm_ops, ops_time, pm_event_str, error), + + TP_STRUCT__entry( + __string(device, dev_name(dev)) + __string(driver, dev_driver_string(dev)) + __string(parent, dev->parent ? dev_name(dev->parent) : "none") + __string(pm_ops, pm_ops ? pm_ops : "none ") + __string(pm_event_str, pm_event_str) + __field(s64, ops_time) + __field(int, error) + ), + + TP_fast_assign( + const char *tmp = dev->parent ? dev_name(dev->parent) : "none"; + const char *tmp_i = pm_ops ? pm_ops : "none "; + + __assign_str(device, dev_name(dev)); + __assign_str(driver, dev_driver_string(dev)); + __assign_str(parent, tmp); + __assign_str(pm_ops, tmp_i); + __assign_str(pm_event_str, pm_event_str); + __entry->ops_time = ops_time; + __entry->error = error; + ), + + /* ops_str has an extra space at the end */ + TP_printk("%s %s parent=%s state=%s ops=%snsecs=%lld err=%d", + __get_str(driver), __get_str(device), __get_str(parent), + __get_str(pm_event_str), __get_str(pm_ops), + __entry->ops_time, __entry->error) +); + DECLARE_EVENT_CLASS(wakeup_source, TP_PROTO(const char *name, unsigned int state), -- cgit v0.10.2 From eaf140b60ec961252083ab8adaf67aef29a362dd Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 26 Jul 2013 15:07:26 -0600 Subject: PNP: convert PNP driver bus legacy pm_ops to dev_pm_ops Convert drivers/pnp/driver.c bus legacy pm_ops to dev_pm_ops using existing suspend and resume routines. Add freeze interface to handle PM_EVENT_FREEZE correctly with dev_pm_ops. pm_op() looks for freeze interface when the event is PM_EVENT_FREEZE. Signed-off-by: Shuah Khan Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index 00e9403..12adb43 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -154,7 +154,7 @@ static int pnp_bus_match(struct device *dev, struct device_driver *drv) return 1; } -static int pnp_bus_suspend(struct device *dev, pm_message_t state) +static int __pnp_bus_suspend(struct device *dev, pm_message_t state) { struct pnp_dev *pnp_dev = to_pnp_dev(dev); struct pnp_driver *pnp_drv = pnp_dev->driver; @@ -180,6 +180,16 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state) return 0; } +static int pnp_bus_suspend(struct device *dev) +{ + return __pnp_bus_suspend(dev, PMSG_SUSPEND); +} + +static int pnp_bus_freeze(struct device *dev) +{ + return __pnp_bus_suspend(dev, PMSG_FREEZE); +} + static int pnp_bus_resume(struct device *dev) { struct pnp_dev *pnp_dev = to_pnp_dev(dev); @@ -210,14 +220,19 @@ static int pnp_bus_resume(struct device *dev) return 0; } +static const struct dev_pm_ops pnp_bus_dev_pm_ops = { + .suspend = pnp_bus_suspend, + .freeze = pnp_bus_freeze, + .resume = pnp_bus_resume, +}; + struct bus_type pnp_bus_type = { .name = "pnp", .match = pnp_bus_match, .probe = pnp_device_probe, .remove = pnp_device_remove, .shutdown = pnp_device_shutdown, - .suspend = pnp_bus_suspend, - .resume = pnp_bus_resume, + .pm = &pnp_bus_dev_pm_ops, .dev_attrs = pnp_interface_attrs, }; -- cgit v0.10.2 From b98e01ad4ed9da6882b41983319361502aded307 Mon Sep 17 00:00:00 2001 From: Sahara Date: Wed, 3 Jul 2013 17:49:55 +0900 Subject: cpuidle: Add Kconfig.arm and move calxeda, kirkwood and zynq Add Kconfig.arm for ARM cpuidle drivers and moves calxeda, kirkwood and zynq to Kconfig.arm. Like in the cpufreq menu, "CPU Idle" menu is added to drivers/cpuidle/Kconfig. Signed-off-by: Sahara diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 0e2cd5c..b3fb81d 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -1,5 +1,6 @@ +menu "CPU Idle" -menuconfig CPU_IDLE +config CPU_IDLE bool "CPU idle PM support" default y if ACPI || PPC_PSERIES select CPU_IDLE_GOV_LADDER if (!NO_HZ && !NO_HZ_IDLE) @@ -29,20 +30,13 @@ config CPU_IDLE_GOV_MENU bool "Menu governor (for tickless system)" default y -config CPU_IDLE_CALXEDA - bool "CPU Idle Driver for Calxeda processors" - depends on ARCH_HIGHBANK - select ARM_CPU_SUSPEND - help - Select this to enable cpuidle on Calxeda processors. - -config CPU_IDLE_ZYNQ - bool "CPU Idle Driver for Xilinx Zynq processors" - depends on ARCH_ZYNQ - help - Select this to enable cpuidle on Xilinx Zynq processors. +menu "ARM CPU Idle Drivers" +depends on ARM +source "drivers/cpuidle/Kconfig.arm" +endmenu endif config ARCH_NEEDS_CPU_IDLE_COUPLED def_bool n +endmenu diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm new file mode 100644 index 0000000..2c8f17d --- /dev/null +++ b/drivers/cpuidle/Kconfig.arm @@ -0,0 +1,21 @@ +# +# ARM CPU Idle drivers +# + +config ARM_HIGHBANK_CPUIDLE + bool "CPU Idle Driver for Calxeda processors" + depends on ARCH_HIGHBANK + select ARM_CPU_SUSPEND + help + Select this to enable cpuidle on Calxeda processors. + +config ARM_KIRKWOOD_CPUIDLE + bool "CPU Idle Driver for Marvell Kirkwood SoCs" + depends on ARCH_KIRKWOOD + help + This adds the CPU Idle driver for Marvell Kirkwood SoCs. + +config ARM_ZYNQ_CPUIDLE + bool "CPU Idle Driver for Xilinx Zynq processors" + depends on ARCH_ZYNQ + help diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 8767a7b..77cf767 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -5,6 +5,8 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o -obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o -obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o -obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o +################################################################################## +# ARM SoC drivers +obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE) += cpuidle-calxeda.o +obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o +obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o -- cgit v0.10.2 From 7006b8a1facc5dcafb2afa27a1209d924f99a2eb Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 28 Jun 2013 12:09:09 +0200 Subject: ARM: davinci: cpuidle: Fix target residency The commit 19976c2a88d125aec16b9255c7197c297bbdd637 changed the target residency to 100000, assuming this is a careless mistake. The same happened to the at91's cpuidle driver. Fix it by putting the initial value to 10000. Signed-off-by: Daniel Lezcano Acked-by: Sekhar Nori diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index 36aef3a..f1ac1c9 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -65,7 +65,7 @@ static struct cpuidle_driver davinci_idle_driver = { .states[1] = { .enter = davinci_enter_idle, .exit_latency = 10, - .target_residency = 100000, + .target_residency = 10000, .flags = CPUIDLE_FLAG_TIME_VALID, .name = "DDR SR", .desc = "WFI and DDR Self Refresh", -- cgit v0.10.2 From 8025395f39c97e332362c24f7c33c86acdd4cd90 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 10 Jul 2013 15:35:26 +0200 Subject: ARM: ux500: cpuidle: Instantiate the driver from platform device To break the dependency on the "id.h" file we move the cpuidle driver to a platform device. Now we only call the probe() on this driver if we find a corresponding platform device (which is spawned from the PRCMU MFD driver). Signed-off-by: Linus Walleij Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index a45dd09..c0cb37c 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c @@ -16,12 +16,12 @@ #include #include #include +#include #include #include #include "db8500-regs.h" -#include "id.h" static atomic_t master = ATOMIC_INIT(0); static DEFINE_SPINLOCK(master_lock); @@ -113,11 +113,8 @@ static struct cpuidle_driver ux500_idle_driver = { .state_count = 2, }; -int __init ux500_idle_init(void) +static int __init dbx500_cpuidle_probe(struct platform_device *pdev) { - if (!(cpu_is_u8500_family() || cpu_is_ux540_family())) - return -ENODEV; - /* Configure wake up reasons */ prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | PRCMU_WAKEUP(ABB)); @@ -125,4 +122,12 @@ int __init ux500_idle_init(void) return cpuidle_register(&ux500_idle_driver, NULL); } -device_initcall(ux500_idle_init); +static struct platform_driver dbx500_cpuidle_plat_driver = { + .driver = { + .name = "cpuidle-dbx500", + .owner = THIS_MODULE, + }, + .probe = dbx500_cpuidle_probe, +}; + +module_platform_driver(dbx500_cpuidle_plat_driver); diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 3c157fa..0d68eb1 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -3094,6 +3094,10 @@ static struct mfd_cell db8500_prcmu_devs[] = { .pdata_size = sizeof(db8500_cpufreq_table), }, { + .name = "cpuidle-dbx500", + .of_compatible = "stericsson,cpuidle-dbx500", + }, + { .name = "db8500-thermal", .num_resources = ARRAY_SIZE(db8500_thsens_resources), .resources = db8500_thsens_resources, -- cgit v0.10.2 From 8457246b106cc4e53f2534309dbe35a973c7d046 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 10 Jul 2013 15:52:01 +0200 Subject: ARM: ux500: cpuidle: Remove pointless include The db8500-regs.h file does not need to be included by the cpuidle driver. Signed-off-by: Linus Walleij Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index c0cb37c..e056465 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c @@ -21,8 +21,6 @@ #include #include -#include "db8500-regs.h" - static atomic_t master = ATOMIC_INIT(0); static DEFINE_SPINLOCK(master_lock); -- cgit v0.10.2 From d3f2950f2adeea3da0317e952914b59adaa4cdb3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 10 Jul 2013 16:02:04 +0200 Subject: ARM: ux500: cpuidle: Move ux500 cpuidle driver to drivers/cpuidle There is no more dependency with arch/arm headers, so we can safely move the driver to the drivers/cpuidle directory. Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index bf9b6be..fe1f3e2 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -4,7 +4,6 @@ obj-y := cpu.o devices.o devices-common.o \ id.o usb.o timer.o pm.o -obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o obj-$(CONFIG_MACH_MOP500) += board-mop500.o board-mop500-sdi.o \ diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c deleted file mode 100644 index e056465..0000000 --- a/arch/arm/mach-ux500/cpuidle.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2012 Linaro : Daniel Lezcano (IBM) - * - * Based on the work of Rickard Andersson - * and Jonas Aaberg . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static atomic_t master = ATOMIC_INIT(0); -static DEFINE_SPINLOCK(master_lock); - -static inline int ux500_enter_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) -{ - int this_cpu = smp_processor_id(); - bool recouple = false; - - if (atomic_inc_return(&master) == num_online_cpus()) { - - /* With this lock, we prevent the other cpu to exit and enter - * this function again and become the master */ - if (!spin_trylock(&master_lock)) - goto wfi; - - /* decouple the gic from the A9 cores */ - if (prcmu_gic_decouple()) { - spin_unlock(&master_lock); - goto out; - } - - /* If an error occur, we will have to recouple the gic - * manually */ - recouple = true; - - /* At this state, as the gic is decoupled, if the other - * cpu is in WFI, we have the guarantee it won't be wake - * up, so we can safely go to retention */ - if (!prcmu_is_cpu_in_wfi(this_cpu ? 0 : 1)) - goto out; - - /* The prcmu will be in charge of watching the interrupts - * and wake up the cpus */ - if (prcmu_copy_gic_settings()) - goto out; - - /* Check in the meantime an interrupt did - * not occur on the gic ... */ - if (prcmu_gic_pending_irq()) - goto out; - - /* ... and the prcmu */ - if (prcmu_pending_irq()) - goto out; - - /* Go to the retention state, the prcmu will wait for the - * cpu to go WFI and this is what happens after exiting this - * 'master' critical section */ - if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true)) - goto out; - - /* When we switch to retention, the prcmu is in charge - * of recoupling the gic automatically */ - recouple = false; - - spin_unlock(&master_lock); - } -wfi: - cpu_do_idle(); -out: - atomic_dec(&master); - - if (recouple) { - prcmu_gic_recouple(); - spin_unlock(&master_lock); - } - - return index; -} - -static struct cpuidle_driver ux500_idle_driver = { - .name = "ux500_idle", - .owner = THIS_MODULE, - .states = { - ARM_CPUIDLE_WFI_STATE, - { - .enter = ux500_enter_idle, - .exit_latency = 70, - .target_residency = 260, - .flags = CPUIDLE_FLAG_TIME_VALID | - CPUIDLE_FLAG_TIMER_STOP, - .name = "ApIdle", - .desc = "ARM Retention", - }, - }, - .safe_state_index = 0, - .state_count = 2, -}; - -static int __init dbx500_cpuidle_probe(struct platform_device *pdev) -{ - /* Configure wake up reasons */ - prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | - PRCMU_WAKEUP(ABB)); - - return cpuidle_register(&ux500_idle_driver, NULL); -} - -static struct platform_driver dbx500_cpuidle_plat_driver = { - .driver = { - .name = "cpuidle-dbx500", - .owner = THIS_MODULE, - }, - .probe = dbx500_cpuidle_probe, -}; - -module_platform_driver(dbx500_cpuidle_plat_driver); diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 2c8f17d..b330219 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -19,3 +19,11 @@ config ARM_ZYNQ_CPUIDLE bool "CPU Idle Driver for Xilinx Zynq processors" depends on ARCH_ZYNQ help + Select this to enable cpuidle on Xilinx Zynq processors. + +config ARM_U8500_CPUIDLE + bool "Cpu Idle Driver for the ST-E u8500 processors" + depends on ARCH_U8500 + help + Select this to enable cpuidle for ST-E u8500 processors + diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 77cf767..0b9d200 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE) += cpuidle-calxeda.o obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o +obj-$(CONFIG_ARM_U8500_CPUIDLE) += cpuidle-ux500.o diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c new file mode 100644 index 0000000..e056465 --- /dev/null +++ b/drivers/cpuidle/cpuidle-ux500.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2012 Linaro : Daniel Lezcano (IBM) + * + * Based on the work of Rickard Andersson + * and Jonas Aaberg . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static atomic_t master = ATOMIC_INIT(0); +static DEFINE_SPINLOCK(master_lock); + +static inline int ux500_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + int this_cpu = smp_processor_id(); + bool recouple = false; + + if (atomic_inc_return(&master) == num_online_cpus()) { + + /* With this lock, we prevent the other cpu to exit and enter + * this function again and become the master */ + if (!spin_trylock(&master_lock)) + goto wfi; + + /* decouple the gic from the A9 cores */ + if (prcmu_gic_decouple()) { + spin_unlock(&master_lock); + goto out; + } + + /* If an error occur, we will have to recouple the gic + * manually */ + recouple = true; + + /* At this state, as the gic is decoupled, if the other + * cpu is in WFI, we have the guarantee it won't be wake + * up, so we can safely go to retention */ + if (!prcmu_is_cpu_in_wfi(this_cpu ? 0 : 1)) + goto out; + + /* The prcmu will be in charge of watching the interrupts + * and wake up the cpus */ + if (prcmu_copy_gic_settings()) + goto out; + + /* Check in the meantime an interrupt did + * not occur on the gic ... */ + if (prcmu_gic_pending_irq()) + goto out; + + /* ... and the prcmu */ + if (prcmu_pending_irq()) + goto out; + + /* Go to the retention state, the prcmu will wait for the + * cpu to go WFI and this is what happens after exiting this + * 'master' critical section */ + if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true)) + goto out; + + /* When we switch to retention, the prcmu is in charge + * of recoupling the gic automatically */ + recouple = false; + + spin_unlock(&master_lock); + } +wfi: + cpu_do_idle(); +out: + atomic_dec(&master); + + if (recouple) { + prcmu_gic_recouple(); + spin_unlock(&master_lock); + } + + return index; +} + +static struct cpuidle_driver ux500_idle_driver = { + .name = "ux500_idle", + .owner = THIS_MODULE, + .states = { + ARM_CPUIDLE_WFI_STATE, + { + .enter = ux500_enter_idle, + .exit_latency = 70, + .target_residency = 260, + .flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_TIMER_STOP, + .name = "ApIdle", + .desc = "ARM Retention", + }, + }, + .safe_state_index = 0, + .state_count = 2, +}; + +static int __init dbx500_cpuidle_probe(struct platform_device *pdev) +{ + /* Configure wake up reasons */ + prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | + PRCMU_WAKEUP(ABB)); + + return cpuidle_register(&ux500_idle_driver, NULL); +} + +static struct platform_driver dbx500_cpuidle_plat_driver = { + .driver = { + .name = "cpuidle-dbx500", + .owner = THIS_MODULE, + }, + .probe = dbx500_cpuidle_probe, +}; + +module_platform_driver(dbx500_cpuidle_plat_driver); -- cgit v0.10.2 From 2c7d132a589077b31493b3ea82ac83b1f72c93e1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Jul 2013 14:34:00 +0200 Subject: ACPI / PM: Only set power states of devices that are power manageable Make acpi_device_set_power() check if the given device is power manageable before checking if the given power state is valid for that device. Otherwise it will print that "Device does not support" that power state into the kernel log, which may not make sense for some power states (D0 and D3cold are supported by all devices by definition). Tested-by: Yinghai Lu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 4ab807d..63324b8 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -159,7 +159,8 @@ int acpi_device_set_power(struct acpi_device *device, int state) int result = 0; bool cut_power = false; - if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) + if (!device || !device->flags.power_manageable + || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) return -EINVAL; /* Make sure this is a valid target state */ -- cgit v0.10.2 From b69137a74b7a9451b3da504d1ef9ead7cb393922 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Jul 2013 14:34:55 +0200 Subject: ACPI / PM: Make messages in acpi_device_set_power() print device names Modify acpi_device_set_power() so that diagnostic messages printed by it to the kernel log always contain the name of the device concerned to make it possible to identify the device that triggered the message if need be. Also replace printk(KERN_WARNING ) with dev_warn() everywhere in that function. Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 63324b8..8234e1f 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -166,20 +166,20 @@ int acpi_device_set_power(struct acpi_device *device, int state) /* Make sure this is a valid target state */ if (state == device->power.state) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n", + device->pnp.bus_id, acpi_power_state_string(state))); return 0; } if (!device->power.states[state].flags.valid) { - printk(KERN_WARNING PREFIX "Device does not support %s\n", - acpi_power_state_string(state)); + dev_warn(&device->dev, "Power state %s not supported\n", + acpi_power_state_string(state)); return -ENODEV; } if (device->parent && (state < device->parent->power.state)) { - printk(KERN_WARNING PREFIX - "Cannot set device to a higher-powered" - " state than parent\n"); + dev_warn(&device->dev, + "Cannot transition to a higher-powered state than parent\n"); return -ENODEV; } @@ -192,8 +192,8 @@ int acpi_device_set_power(struct acpi_device *device, int state) if (state < device->power.state && state != ACPI_STATE_D0 && device->power.state >= ACPI_STATE_D3_HOT) { - printk(KERN_WARNING PREFIX - "Cannot transition to non-D0 state from D3\n"); + dev_warn(&device->dev, + "Cannot transition to non-D0 state from D3\n"); return -ENODEV; } @@ -220,10 +220,8 @@ int acpi_device_set_power(struct acpi_device *device, int state) end: if (result) { - printk(KERN_WARNING PREFIX - "Device [%s] failed to transition to %s\n", - device->pnp.bus_id, - acpi_power_state_string(state)); + dev_warn(&device->dev, "Failed to change power state to %s\n", + acpi_power_state_string(state)); } else { device->power.state = state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, -- cgit v0.10.2 From 8ad928d52e63a9b7d69f0873d7318c4561e2f8cd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Jul 2013 14:36:20 +0200 Subject: ACPI / PM: Use ACPI_STATE_D3_COLD instead of ACPI_STATE_D3 everywhere There are several places in the tree where ACPI_STATE_D3 is used instead of ACPI_STATE_D3_COLD which should be used instead for clarity. Modify them all to use ACPI_STATE_D3_COLD as appropriate. [The definition of ACPI_STATE_D3 itself cannot go away at this point as it is part of ACPICA.] Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 5b02a0a..41ade65 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -93,7 +93,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long if (result) return result; - *state = (acpi_state == ACPI_STATE_D3 ? 0 : + *state = (acpi_state == ACPI_STATE_D3_COLD ? 0 : (acpi_state == ACPI_STATE_D0 ? 1 : -1)); return 0; } @@ -108,7 +108,7 @@ fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) return -EINVAL; result = acpi_bus_set_power(device->handle, - state ? ACPI_STATE_D0 : ACPI_STATE_D3); + state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); return result; } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5c28c89..4cdcc0c 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -786,7 +786,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state) } } - *state = ACPI_STATE_D3; + *state = ACPI_STATE_D3_COLD; return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 8a46c92..c30df3a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1450,8 +1450,8 @@ static void acpi_bus_get_power_flags(struct acpi_device *device) /* Set defaults for D0 and D3 states (always valid) */ device->power.states[ACPI_STATE_D0].flags.valid = 1; device->power.states[ACPI_STATE_D0].power = 100; - device->power.states[ACPI_STATE_D3].flags.valid = 1; - device->power.states[ACPI_STATE_D3].power = 0; + device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1; + device->power.states[ACPI_STATE_D3_COLD].power = 0; /* Set D3cold's explicit_set flag if _PS3 exists. */ if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index cf4e702..da8170d 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -947,11 +947,11 @@ static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state) continue; acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ? - ACPI_STATE_D0 : ACPI_STATE_D3); + ACPI_STATE_D0 : ACPI_STATE_D3_COLD); } if (!(state.event & PM_EVENT_RESUME)) - acpi_bus_set_power(port_handle, ACPI_STATE_D3); + acpi_bus_set_power(port_handle, ACPI_STATE_D3_COLD); } /** diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index f1a6796b..140c8ef 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -520,11 +520,12 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on) ide_port_for_each_present_dev(i, drive, hwif) { if (drive->acpidata->obj_handle) acpi_bus_set_power(drive->acpidata->obj_handle, - on ? ACPI_STATE_D0 : ACPI_STATE_D3); + on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); } if (!on) - acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3); + acpi_bus_set_power(hwif->acpidata->obj_handle, + ACPI_STATE_D3_COLD); } /** diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 55cd459..34049b0 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -131,7 +131,7 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ ret = 0; if (acpi_bus_power_manageable(handle)) - acpi_bus_set_power(handle, ACPI_STATE_D3); + acpi_bus_set_power(handle, ACPI_STATE_D3_COLD); /* continue even if acpi_bus_set_power() fails */ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DIS", NULL, NULL))) ret = -ENODEV; @@ -174,10 +174,10 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) if (acpi_bus_power_manageable(handle)) { int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL, - ACPI_STATE_D3); + ACPI_STATE_D3_COLD); if (power_state < 0) power_state = (state.event == PM_EVENT_ON) ? - ACPI_STATE_D0 : ACPI_STATE_D3; + ACPI_STATE_D0 : ACPI_STATE_D3_COLD; /* * acpi_bus_set_power() often fails (keyboard port can't be diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 56e6b68..916b189 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -478,7 +478,8 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m) if (p) *p = ACPI_STATE_D0; - return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3) ? m : ACPI_STATE_D0; + return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ? + m : ACPI_STATE_D0; } static inline void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev) {} -- cgit v0.10.2 From 7b4e0c4ac1809eab6fcfe6818ec8b70be79b41bc Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Wed, 31 Jul 2013 14:07:15 +0200 Subject: ACPI / PM: Remove redundant power manageable check from acpi_bus_set_power() Now that acpi_device_set_power() checks whether or not the given device is power manageable, it is not necessary to do this check in acpi_bus_set_power() any more, so remove it. Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 8234e1f..beb9625 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -243,13 +243,6 @@ int acpi_bus_set_power(acpi_handle handle, int state) if (result) return result; - if (!device->flags.power_manageable) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device [%s] is not power manageable\n", - dev_name(&device->dev))); - return -ENODEV; - } - return acpi_device_set_power(device, state); } EXPORT_SYMBOL(acpi_bus_set_power); -- cgit v0.10.2 From d6b47b122473885abc882e337ac2d321bbcfb378 Mon Sep 17 00:00:00 2001 From: Ben Guthro Date: Tue, 30 Jul 2013 08:24:52 -0400 Subject: ACPI / sleep: Introduce acpi_os_prepare_extended_sleep() for extended sleep path Like acpi_os_prepare_sleep(), register a callback for use in systems like tboot, and xen, which have system specific requirements outside of ACPICA. This mirrors the functionality in acpi_os_prepare_sleep(), called from acpi_hw_sleep() Signed-off-by: Ben Guthro Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 5e5f762..4140768 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -43,6 +43,7 @@ */ #include +#include #include "accommon.h" #define _COMPONENT ACPI_HARDWARE @@ -128,6 +129,14 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) ACPI_FLUSH_CPU_CACHE(); + status = acpi_os_prepare_extended_sleep(sleep_state, + acpi_gbl_sleep_type_a, + acpi_gbl_sleep_type_b); + if (ACPI_SKIP(status)) + return_ACPI_STATUS(AE_OK); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(status); + /* * Set the SLP_TYP and SLP_EN bits. * diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 6ab2c35..a934950 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -79,6 +79,8 @@ extern char line_buf[80]; static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl, u32 pm1b_ctrl); +static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a, + u32 val_b); static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; @@ -1779,6 +1781,28 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, __acpi_os_prepare_sleep = func; } +acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, + u32 val_b) +{ + int rc = 0; + if (__acpi_os_prepare_extended_sleep) + rc = __acpi_os_prepare_extended_sleep(sleep_state, + val_a, val_b); + if (rc < 0) + return AE_ERROR; + else if (rc > 0) + return AE_CTRL_SKIP; + + return AE_OK; +} + +void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, + u32 val_a, u32 val_b)) +{ + __acpi_os_prepare_extended_sleep = func; +} + + void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context, void (*func)(struct work_struct *work)) { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 353ba25..a5db4ae 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -481,6 +481,13 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control); + +void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, + u32 val_a, u32 val_b)); + +acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, + u32 val_a, u32 val_b); + #ifdef CONFIG_X86 void arch_reserve_mem_area(acpi_physical_address addr, size_t size); #else -- cgit v0.10.2 From be6b25d15f5e67bc49b90ed55feb1dd947f4df2c Mon Sep 17 00:00:00 2001 From: Ben Guthro Date: Tue, 30 Jul 2013 08:24:54 -0400 Subject: xen / ACPI: notify xen when reduced hardware sleep is available Use the acpi_os_prepare_extended_sleep() callback to notify xen to make use of the reduced hardware sleep functionality The xen hypervisor change underlying this is commit 62d1a69 ("ACPI: support v5 (reduced HW) sleep interface") on the master branch of git://xenbits.xen.org/xen.git. Signed-off-by: Jan Beulich Signed-off-by: Ben Guthro Acked-by: Konrad Wilk Signed-off-by: Rafael J. Wysocki diff --git a/drivers/xen/acpi.c b/drivers/xen/acpi.c index 119d42a..90307c0 100644 --- a/drivers/xen/acpi.c +++ b/drivers/xen/acpi.c @@ -35,28 +35,43 @@ #include #include -int xen_acpi_notify_hypervisor_state(u8 sleep_state, - u32 pm1a_cnt, u32 pm1b_cnt) +static int xen_acpi_notify_hypervisor_state(u8 sleep_state, + u32 val_a, u32 val_b, + bool extended) { + unsigned int bits = extended ? 8 : 16; + struct xen_platform_op op = { .cmd = XENPF_enter_acpi_sleep, .interface_version = XENPF_INTERFACE_VERSION, - .u = { - .enter_acpi_sleep = { - .pm1a_cnt_val = (u16)pm1a_cnt, - .pm1b_cnt_val = (u16)pm1b_cnt, - .sleep_state = sleep_state, - }, + .u.enter_acpi_sleep = { + .val_a = (u16)val_a, + .val_b = (u16)val_b, + .sleep_state = sleep_state, + .flags = extended ? XENPF_ACPI_SLEEP_EXTENDED : 0, }, }; - if ((pm1a_cnt & 0xffff0000) || (pm1b_cnt & 0xffff0000)) { - WARN(1, "Using more than 16bits of PM1A/B 0x%x/0x%x!" - "Email xen-devel@lists.xensource.com Thank you.\n", \ - pm1a_cnt, pm1b_cnt); + if (WARN((val_a & (~0 << bits)) || (val_b & (~0 << bits)), + "Using more than %u bits of sleep control values %#x/%#x!" + "Email xen-devel@lists.xen.org - Thank you.\n", \ + bits, val_a, val_b)) return -1; - } HYPERVISOR_dom0_op(&op); return 1; } + +int xen_acpi_notify_hypervisor_sleep(u8 sleep_state, + u32 pm1a_cnt, u32 pm1b_cnt) +{ + return xen_acpi_notify_hypervisor_state(sleep_state, pm1a_cnt, + pm1b_cnt, false); +} + +int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state, + u32 val_a, u32 val_b) +{ + return xen_acpi_notify_hypervisor_state(sleep_state, val_a, + val_b, true); +} diff --git a/include/xen/acpi.h b/include/xen/acpi.h index 46aa3d1..4ddd7dc 100644 --- a/include/xen/acpi.h +++ b/include/xen/acpi.h @@ -75,8 +75,10 @@ static inline int xen_acpi_get_pxm(acpi_handle h) return -ENXIO; } -int xen_acpi_notify_hypervisor_state(u8 sleep_state, +int xen_acpi_notify_hypervisor_sleep(u8 sleep_state, u32 pm1a_cnt, u32 pm1b_cnd); +int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state, + u32 val_a, u32 val_b); static inline int xen_acpi_suspend_lowlevel(void) { @@ -93,7 +95,9 @@ static inline void xen_acpi_sleep_register(void) { if (xen_initial_domain()) { acpi_os_set_prepare_sleep( - &xen_acpi_notify_hypervisor_state); + &xen_acpi_notify_hypervisor_sleep); + acpi_os_set_prepare_extended_sleep( + &xen_acpi_notify_hypervisor_extended_sleep); acpi_suspend_lowlevel = xen_acpi_suspend_lowlevel; } diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h index c57d5f6..f1331e3 100644 --- a/include/xen/interface/platform.h +++ b/include/xen/interface/platform.h @@ -152,10 +152,11 @@ DEFINE_GUEST_HANDLE_STRUCT(xenpf_firmware_info_t); #define XENPF_enter_acpi_sleep 51 struct xenpf_enter_acpi_sleep { /* IN variables */ - uint16_t pm1a_cnt_val; /* PM1a control value. */ - uint16_t pm1b_cnt_val; /* PM1b control value. */ + uint16_t val_a; /* PM1a control / sleep type A. */ + uint16_t val_b; /* PM1b control / sleep type B. */ uint32_t sleep_state; /* Which state to enter (Sn). */ - uint32_t flags; /* Must be zero. */ +#define XENPF_ACPI_SLEEP_EXTENDED 0x00000001 + uint32_t flags; /* XENPF_ACPI_SLEEP_*. */ }; DEFINE_GUEST_HANDLE_STRUCT(xenpf_enter_acpi_sleep_t); -- cgit v0.10.2 From 01c6a6afd50f07dfd66b2891fd194c4b789fca48 Mon Sep 17 00:00:00 2001 From: Ben Guthro Date: Tue, 30 Jul 2013 09:22:37 -0400 Subject: x86 / tboot / ACPI: Fail extended mode reduced hardware sleep Register for the extended sleep callback from ACPI. As tboot currently does not support the reduced hardware sleep interface, fail this extended sleep call. Signed-off-by: Jan Beulich Signed-off-by: Ben Guthro Cc: tboot-devel@lists.sourceforge.net Cc: Gang Wei Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index addf7b5..91a4496 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -301,6 +301,15 @@ static int tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control) return 0; } +static int tboot_extended_sleep(u8 sleep_state, u32 val_a, u32 val_b) +{ + if (!tboot_enabled()) + return 0; + + pr_warning("tboot is not able to suspend on platforms with reduced hardware sleep (ACPIv5)"); + return -ENODEV; +} + static atomic_t ap_wfs_count; static int tboot_wait_for_aps(int num_aps) @@ -422,6 +431,7 @@ static __init int tboot_late_init(void) #endif acpi_os_set_prepare_sleep(&tboot_sleep); + acpi_os_set_prepare_extended_sleep(&tboot_extended_sleep); return 0; } -- cgit v0.10.2 From d010e5769a5ab2ae8d2bcb36e77b98172c24d80c Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 30 Jul 2013 10:32:30 +0800 Subject: PCI / ACPI: Use dev_dbg() instead of dev_info() in acpi_pci_set_power_state() acpi_pci_set_power_state() uses dev_info() to print diagnostic messages regarding ACPI power state changes of devices, but that results in too much not really interesting output into the kernel log in some cases. For this reason, change it to use dev_dbg() instead and prevent kernel log from being spammed. [rjw: Changelog] References: https://bugzilla.kernel.org/show_bug.cgi?id=60636 Suggested-by: Alan Stern Signed-off-by: Lan Tianyu Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c78cc43..fb3522957 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -210,7 +210,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) } if (!error) - dev_info(&dev->dev, "power state changed by ACPI to %s\n", + dev_dbg(&dev->dev, "power state changed by ACPI to %s\n", acpi_power_state_string(state_conv[state])); return error; -- cgit v0.10.2 From 593298e68a3a53bd2fe942244250dfef4d68d477 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Sat, 3 Aug 2013 21:13:22 +0200 Subject: ACPI / PM: Add state information to error message in acpi_device_set_power() The state information can be useful to know what the problem is when an error message about a device can not being set to a higher power state than its parent appeared, so this patch adds such state information for both the target state of the device and the current state of its parent. Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index beb9625..59d3202 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -179,7 +179,9 @@ int acpi_device_set_power(struct acpi_device *device, int state) } if (device->parent && (state < device->parent->power.state)) { dev_warn(&device->dev, - "Cannot transition to a higher-powered state than parent\n"); + "Cannot transition to power state %s for parent in %s\n", + acpi_power_state_string(state), + acpi_power_state_string(device->parent->power.state)); return -ENODEV; } -- cgit v0.10.2 From 21fcb34e28e99291e91d83422f2824f11b3c9ce9 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Thu, 1 Aug 2013 18:43:59 -0500 Subject: ACPI / video: trivial costmetic cleanups Fix whitespace and comments in several places in drivers/acpi/video.c. [rjw: Changelog] Signed-off-by: Felipe Contreras Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 0ec434d..f021bf4 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1,5 +1,5 @@ /* - * video.c - ACPI Video Driver ($Revision:$) + * video.c - ACPI Video Driver * * Copyright (C) 2004 Luming Yu * Copyright (C) 2004 Bruno Ducrot @@ -118,26 +118,26 @@ struct acpi_video_bus_flags { }; struct acpi_video_bus_cap { - u8 _DOS:1; /*Enable/Disable output switching */ - u8 _DOD:1; /*Enumerate all devices attached to display adapter */ - u8 _ROM:1; /*Get ROM Data */ - u8 _GPD:1; /*Get POST Device */ - u8 _SPD:1; /*Set POST Device */ - u8 _VPO:1; /*Video POST Options */ + u8 _DOS:1; /* Enable/Disable output switching */ + u8 _DOD:1; /* Enumerate all devices attached to display adapter */ + u8 _ROM:1; /* Get ROM Data */ + u8 _GPD:1; /* Get POST Device */ + u8 _SPD:1; /* Set POST Device */ + u8 _VPO:1; /* Video POST Options */ u8 reserved:2; }; struct acpi_video_device_attrib { u32 display_index:4; /* A zero-based instance of the Display */ - u32 display_port_attachment:4; /*This field differentiates the display type */ - u32 display_type:4; /*Describe the specific type in use */ - u32 vendor_specific:4; /*Chipset Vendor Specific */ - u32 bios_can_detect:1; /*BIOS can detect the device */ - u32 depend_on_vga:1; /*Non-VGA output device whose power is related to + u32 display_port_attachment:4; /* This field differentiates the display type */ + u32 display_type:4; /* Describe the specific type in use */ + u32 vendor_specific:4; /* Chipset Vendor Specific */ + u32 bios_can_detect:1; /* BIOS can detect the device */ + u32 depend_on_vga:1; /* Non-VGA output device whose power is related to the VGA device. */ - u32 pipe_id:3; /*For VGA multiple-head devices. */ - u32 reserved:10; /*Must be 0 */ - u32 device_id_scheme:1; /*Device ID Scheme */ + u32 pipe_id:3; /* For VGA multiple-head devices. */ + u32 reserved:10; /* Must be 0 */ + u32 device_id_scheme:1; /* Device ID Scheme */ }; struct acpi_video_enumerated_device { @@ -174,17 +174,17 @@ struct acpi_video_device_flags { }; struct acpi_video_device_cap { - u8 _ADR:1; /*Return the unique ID */ - u8 _BCL:1; /*Query list of brightness control levels supported */ - u8 _BCM:1; /*Set the brightness level */ + u8 _ADR:1; /* Return the unique ID */ + u8 _BCL:1; /* Query list of brightness control levels supported */ + u8 _BCM:1; /* Set the brightness level */ u8 _BQC:1; /* Get current brightness level */ u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */ - u8 _DDC:1; /*Return the EDID for this device */ + u8 _DDC:1; /* Return the EDID for this device */ }; struct acpi_video_brightness_flags { u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ - u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/ + u8 _BCL_reversed:1; /* _BCL package is in a reversed order */ u8 _BCL_use_index:1; /* levels in _BCL are index values */ u8 _BCM_use_index:1; /* input of _BCM is an index value */ u8 _BQC_use_index:1; /* _BQC returns an index value */ @@ -231,7 +231,7 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, static int acpi_video_switch_brightness(struct acpi_video_device *device, int event); -/*backlight device sysfs support*/ +/* backlight device sysfs support */ static int acpi_video_get_brightness(struct backlight_device *bd) { unsigned long long cur_level; @@ -243,8 +243,10 @@ static int acpi_video_get_brightness(struct backlight_device *bd) return -EINVAL; for (i = 2; i < vd->brightness->count; i++) { if (vd->brightness->levels[i] == cur_level) - /* The first two entries are special - see page 575 - of the ACPI spec 3.0 */ + /* + * The first two entries are special - see page 575 + * of the ACPI spec 3.0 + */ return i-2; } return 0; @@ -316,9 +318,11 @@ static const struct thermal_cooling_device_ops video_cooling_ops = { .set_cur_state = video_set_cur_state, }; -/* -------------------------------------------------------------------------- - Video Management - -------------------------------------------------------------------------- */ +/* + * -------------------------------------------------------------------------- + * Video Management + * -------------------------------------------------------------------------- + */ static int acpi_video_device_lcd_query_levels(struct acpi_video_device *device, @@ -556,7 +560,8 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, buf)); device->cap._BQC = device->cap._BCQ = 0; } else { - /* Fixme: + /* + * Fixme: * should we return an error or ignore this failure? * dev->brightness->curr is a cached value which stores * the correct current backlight level in most cases. @@ -615,8 +620,8 @@ acpi_video_device_EDID(struct acpi_video_device *device, /* * Arg: - * video : video bus device pointer - * bios_flag : + * video : video bus device pointer + * bios_flag : * 0. The system BIOS should NOT automatically switch(toggle) * the active display output. * 1. The system BIOS should automatically switch (toggle) the @@ -628,9 +633,9 @@ acpi_video_device_EDID(struct acpi_video_device *device, * lcd_flag : * 0. The system BIOS should automatically control the brightness level * of the LCD when the power changes from AC to DC - * 1. The system BIOS should NOT automatically control the brightness + * 1. The system BIOS should NOT automatically control the brightness * level of the LCD when the power changes from AC to DC. - * Return Value: + * Return Value: * -EINVAL wrong arg. */ @@ -717,8 +722,8 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device, /* - * Arg: - * device : video output device (LCD, CRT, ..) + * Arg: + * device : video output device (LCD, CRT, ..) * * Return Value: * Maximum brightness level @@ -877,7 +882,7 @@ out: * device : video output device (LCD, CRT, ..) * * Return Value: - * None + * None * * Find out all required AML methods defined under the output * device. @@ -988,11 +993,11 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) } /* - * Arg: - * device : video output device (VGA) + * Arg: + * device : video output device (VGA) * * Return Value: - * None + * None * * Find out all required AML methods defined under the video bus device. */ @@ -1039,7 +1044,8 @@ static int acpi_video_bus_check(struct acpi_video_bus *video) return -ENODEV; pci_dev_put(dev); - /* Since there is no HID, CID and so on for VGA driver, we have + /* + * Since there is no HID, CID and so on for VGA driver, we have * to check well known required nodes. */ @@ -1069,9 +1075,11 @@ static int acpi_video_bus_check(struct acpi_video_bus *video) return status; } -/* -------------------------------------------------------------------------- - Driver Interface - -------------------------------------------------------------------------- */ +/* + * -------------------------------------------------------------------------- + * Driver Interface + * -------------------------------------------------------------------------- + */ /* device interface */ static struct acpi_video_device_attrib* @@ -1192,12 +1200,12 @@ acpi_video_bus_get_one_device(struct acpi_device *device, /* * Arg: - * video : video bus device + * video : video bus device * * Return: - * none - * - * Enumerate the video device list of the video bus, + * none + * + * Enumerate the video device list of the video bus, * bind the ids with the corresponding video devices * under the video bus. */ @@ -1216,13 +1224,13 @@ static void acpi_video_device_rebind(struct acpi_video_bus *video) /* * Arg: - * video : video bus device - * device : video output device under the video - * bus + * video : video bus device + * device : video output device under the video + * bus * * Return: - * none - * + * none + * * Bind the ids with the corresponding video devices * under the video bus. */ @@ -1245,11 +1253,11 @@ acpi_video_device_bind(struct acpi_video_bus *video, /* * Arg: - * video : video bus device + * video : video bus device * * Return: - * < 0 : error - * + * < 0 : error + * * Call _DOD to enumerate all devices attached to display adapter * */ -- cgit v0.10.2 From 915ea7e41439efa7793814cdf4338cb6b003538a Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 3 Aug 2013 22:12:50 +0200 Subject: ACPI / video: trivial style cleanups Fix several coding style defects in drivers/acpi/video.c: - Initialization of static variables. - Whitespace in expressions, variable definitions, function headers, etc. - Positioning of labels. - Braces around single statements. [rjw: Changelog] Signed-off-by: Felipe Contreras Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index f021bf4..fff5bb3 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -88,7 +88,7 @@ module_param(allow_duplicates, bool, 0644); static bool use_bios_initial_backlight = 1; module_param(use_bios_initial_backlight, bool, 0644); -static int register_count = 0; +static int register_count; static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device); static void acpi_video_bus_notify(struct acpi_device *device, u32 event); @@ -247,7 +247,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd) * The first two entries are special - see page 575 * of the ACPI spec 3.0 */ - return i-2; + return i - 2; } return 0; } @@ -304,11 +304,11 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st struct acpi_video_device *video = acpi_driver_data(device); int level; - if ( state >= video->brightness->count - 2) + if (state >= video->brightness->count - 2) return -EINVAL; state = video->brightness->count - state; - level = video->brightness->levels[state -1]; + level = video->brightness->levels[state - 1]; return acpi_video_device_lcd_set_level(video, level); } @@ -349,7 +349,7 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device, return 0; - err: +err: kfree(buffer.pointer); return status; @@ -550,7 +550,7 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, if (device->brightness->levels[i] == *level) { device->brightness->curr = *level; return 0; - } + } /* * BQC returned an invalid level. * Stop using it. @@ -892,16 +892,13 @@ 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_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) device->cap._ADR = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) { + if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) device->cap._BCL = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) { + if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) device->cap._BCM = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) + if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BQC", &h_dummy1))) device->cap._BQC = 1; else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ", &h_dummy1))) { @@ -909,9 +906,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) device->cap._BCQ = 1; } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { + if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) device->cap._DDC = 1; - } if (acpi_video_init_brightness(device)) return; @@ -922,7 +918,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) acpi_handle acpi_parent; struct device *parent = NULL; int result; - static int count = 0; + static int count; char *name; name = kasprintf(GFP_KERNEL, "acpi_video%d", count); @@ -1006,24 +1002,18 @@ 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_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) video->cap._DOS = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) { + if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) video->cap._DOD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) { + if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) video->cap._ROM = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) { + if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) video->cap._GPD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) { + if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) video->cap._SPD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) { + if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) video->cap._VPO = 1; - } } /* @@ -1082,7 +1072,7 @@ static int acpi_video_bus_check(struct acpi_video_bus *video) */ /* device interface */ -static struct acpi_video_device_attrib* +static struct acpi_video_device_attrib * acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) { struct acpi_video_enumerated_device *ids; @@ -1120,7 +1110,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device, unsigned long long device_id; int status, device_type; struct acpi_video_device *data; - struct acpi_video_device_attrib* attribute; + struct acpi_video_device_attrib *attribute; status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); @@ -1142,7 +1132,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device, attribute = acpi_video_get_device_attr(video, device_id); - if((attribute != NULL) && attribute->device_id_scheme) { + if (attribute && attribute->device_id_scheme) { switch (attribute->display_type) { case ACPI_VIDEO_DISPLAY_CRT: data->flags.crt = 1; @@ -1160,24 +1150,24 @@ acpi_video_bus_get_one_device(struct acpi_device *device, data->flags.unknown = 1; break; } - if(attribute->bios_can_detect) + if (attribute->bios_can_detect) data->flags.bios = 1; } else { /* Check for legacy IDs */ device_type = acpi_video_get_device_type(video, device_id); /* Ignore bits 16 and 18-20 */ switch (device_type & 0xffe2ffff) { - case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR: - data->flags.crt = 1; - break; - case ACPI_VIDEO_DISPLAY_LEGACY_PANEL: - data->flags.lcd = 1; - break; - case ACPI_VIDEO_DISPLAY_LEGACY_TV: - data->flags.tvout = 1; - break; - default: - data->flags.unknown = 1; + case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR: + data->flags.crt = 1; + break; + case ACPI_VIDEO_DISPLAY_LEGACY_PANEL: + data->flags.lcd = 1; + break; + case ACPI_VIDEO_DISPLAY_LEGACY_TV: + data->flags.tvout = 1; + break; + default: + data->flags.unknown = 1; } } @@ -1318,7 +1308,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video) video->attached_array = active_list; video->attached_count = count; - out: +out: kfree(buffer.pointer); return status; } @@ -1773,7 +1763,7 @@ static int acpi_video_bus_add(struct acpi_device *device) if (!strcmp(device->pnp.bus_id, "VID")) { if (instance) device->pnp.bus_id[3] = '0' + instance; - instance ++; + instance++; } /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */ if (!strcmp(device->pnp.bus_id, "VGA")) { -- cgit v0.10.2 From 7c364e79aab6246675436bfc8e50e1ffba15dd63 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 3 Aug 2013 22:15:21 +0200 Subject: ACPI / video: remove unnecessary type casting Remove type casting from assignments involving void pointers in two places in drivers/acpi/video.c. [rjw: Changelog] Signed-off-by: Felipe Contreras Reviewed-by: Aaron Lu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index fff5bb3..8681727 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -236,8 +236,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd) { unsigned long long cur_level; int i; - struct acpi_video_device *vd = - (struct acpi_video_device *)bl_get_data(bd); + struct acpi_video_device *vd = bl_get_data(bd); if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false)) return -EINVAL; @@ -255,8 +254,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd) static int acpi_video_set_brightness(struct backlight_device *bd) { int request_level = bd->props.brightness + 2; - struct acpi_video_device *vd = - (struct acpi_video_device *)bl_get_data(bd); + struct acpi_video_device *vd = bl_get_data(bd); return acpi_video_device_lcd_set_level(vd, vd->brightness->levels[request_level]); -- cgit v0.10.2 From d8648caf55051c7c7609cc3538174930cef205ac Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 3 Aug 2013 22:28:09 +0200 Subject: ACPI / video: drop unused fields from struct acpi_video_brightness_flags The _BCM_use_index and _BCL_use_index fields in struct acpi_video_brightness_flags are not used, so drop them. [rjw: Changelog] Signed-off-by: Felipe Contreras Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 8681727..159c935 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -185,8 +185,6 @@ struct acpi_video_device_cap { struct acpi_video_brightness_flags { u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ u8 _BCL_reversed:1; /* _BCL package is in a reversed order */ - u8 _BCL_use_index:1; /* levels in _BCL are index values */ - u8 _BCM_use_index:1; /* input of _BCM is an index value */ u8 _BQC_use_index:1; /* _BQC returns an index value */ }; @@ -809,16 +807,6 @@ acpi_video_init_brightness(struct acpi_video_device *device) br->count = count; device->brightness = br; - /* Check the input/output of _BQC/_BCL/_BCM */ - if ((max_level < 100) && (max_level <= (count - 2))) - br->flags._BCL_use_index = 1; - - /* - * _BCM is always consistent with _BCL, - * at least for all the laptops we have ever seen. - */ - br->flags._BCM_use_index = br->flags._BCL_use_index; - /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ br->curr = level = max_level; -- cgit v0.10.2 From cb7a386c6c25e85c2710cdb1a498a73794cda660 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Mon, 29 Jul 2013 14:20:58 -0500 Subject: ACPI: blacklist win8 OSI for ASUS Zenbook Prime UX31A Since v3.7 the ACPI backlight driver doesn't work at all on this machine, because presumably the backlight AML code in the ACPI tables contains a code path that triggers when the OS identifies itself as compatible with Windows 8 (which the kernel started to do in 3.7). That code path is never used by Windows and on this particular machine it turns out to be unusable at all. Work around this problem by blacklisting the win8 OSI, so we are back to v3.6 behavior (that is, we don't tell the BIOS that we are compatible with Windows 8). Since v3.7, users have been forced to work around the initial regression by modifying the boot arguments [1]. [1] https://wiki.archlinux.org/index.php/ASUS_Zenbook_Prime_UX31A [rjw: Changelog] Signed-off-by: Felipe Contreras Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index cb96296..a404127 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -192,6 +192,12 @@ static int __init dmi_disable_osi_win7(const struct dmi_system_id *d) acpi_osi_setup("!Windows 2009"); return 0; } +static int __init dmi_disable_osi_win8(const struct dmi_system_id *d) +{ + printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); + acpi_osi_setup("!Windows 2012"); + return 0; +} static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { { @@ -267,6 +273,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"), }, }, + { + .callback = dmi_disable_osi_win8, + .ident = "ASUS Zenbook Prime UX31A", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX31A"), + }, + }, /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. -- cgit v0.10.2 From 62eb4b07f0803d0426eb695bfe6755dd6a2cafb2 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 22 Jul 2013 16:51:20 -0700 Subject: ACPI / scan: Allow platform device creation without any IO resources Currently, ACPI platform device creation is aborted when there are no valid IO resources for the device. This approach will not work if the device has only GPIO as its resource or some custom resources. Remove zero resource check and allow platform device creation even without any valid IO resources. [rjw: Changelog] Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index fafec5d..32136b8 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -52,7 +52,7 @@ int acpi_create_platform_device(struct acpi_device *adev, struct platform_device_info pdevinfo; struct resource_list_entry *rentry; struct list_head resource_list; - struct resource *resources; + struct resource *resources = NULL; int count; /* If the ACPI node already has a physical device attached, skip it. */ @@ -61,9 +61,12 @@ int acpi_create_platform_device(struct acpi_device *adev, INIT_LIST_HEAD(&resource_list); count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); - if (count <= 0) + if (count < 0) return 0; + if (!count) + goto create_dev; + resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL); if (!resources) { dev_err(&adev->dev, "No memory for resources\n"); @@ -76,6 +79,7 @@ int acpi_create_platform_device(struct acpi_device *adev, acpi_dev_free_resource_list(&resource_list); +create_dev: memset(&pdevinfo, 0, sizeof(pdevinfo)); /* * If the ACPI node has a parent and that parent has a physical device -- cgit v0.10.2 From caf5c03f17c33a14ef0e7033000f89e4d0910f5a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Jul 2013 14:38:34 +0200 Subject: ACPI: Move acpi_bus_get_device() from bus.c to scan.c Move acpi_bus_get_device() from bus.c to scan.c which allows acpi_bus_data_handler() to become static and clean up the latter. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 25b289f..7df97d2 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -89,27 +89,6 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = { Device Management -------------------------------------------------------------------------- */ -int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) -{ - acpi_status status; - - if (!device) - return -EINVAL; - - /* TBD: Support fixed-feature devices */ - - status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device); - if (ACPI_FAILURE(status) || !*device) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", - handle)); - return -ENODEV; - } - - return 0; -} - -EXPORT_SYMBOL(acpi_bus_get_device); - acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1098557..4b26793 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -997,6 +997,28 @@ struct bus_type acpi_bus_type = { .uevent = acpi_device_uevent, }; +static void acpi_bus_data_handler(acpi_handle handle, void *context) +{ + /* Intentionally empty. */ +} + +int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) +{ + acpi_status status; + + if (!device) + return -EINVAL; + + status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device); + if (ACPI_FAILURE(status) || !*device) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", + handle)); + return -ENODEV; + } + return 0; +} +EXPORT_SYMBOL_GPL(acpi_bus_get_device); + int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)) { @@ -1208,14 +1230,6 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) } EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); -void acpi_bus_data_handler(acpi_handle handle, void *context) -{ - - /* TBD */ - - return; -} - static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, struct acpi_device_wakeup *wakeup) { diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 2650d1f..2a42cb3 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -363,7 +363,6 @@ extern void unregister_acpi_bus_notifier(struct notifier_block *nb); */ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); -void acpi_bus_data_handler(acpi_handle handle, void *context); acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); -- cgit v0.10.2 From b071f2b21acf27c2fddd36aa193e015033b9c357 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sun, 4 Aug 2013 01:23:41 +0200 Subject: PM / OPP: Export opp_add() Export opp_add() so that modules can use it. Signed-off-by: Viresh Kumar Acked-by: Nishanth Menon Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index c8ec186..ef89897 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -460,6 +460,7 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp); return 0; } +EXPORT_SYMBOL_GPL(opp_add); /** * opp_set_availability() - helper to set the availability of an opp -- cgit v0.10.2 From d2fe7251a36012bc552a4c95246d486a8e284043 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Aug 2013 01:11:33 +0200 Subject: ACPI / scan: Drop unnecessary label from acpi_create_platform_device() The create_dev label in acpi_create_platform_device() is not necessary, because the if statement causing the jump to it to happen may be rearranged to avoid that jump. Rework the code accordingly (no functional changes should result drom that). Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 32136b8..1bde127 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -61,25 +61,23 @@ int acpi_create_platform_device(struct acpi_device *adev, INIT_LIST_HEAD(&resource_list); count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); - if (count < 0) + if (count < 0) { return 0; + } else if (count > 0) { + resources = kmalloc(count * sizeof(struct resource), + GFP_KERNEL); + if (!resources) { + dev_err(&adev->dev, "No memory for resources\n"); + acpi_dev_free_resource_list(&resource_list); + return -ENOMEM; + } + count = 0; + list_for_each_entry(rentry, &resource_list, node) + resources[count++] = rentry->res; - if (!count) - goto create_dev; - - resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL); - if (!resources) { - dev_err(&adev->dev, "No memory for resources\n"); acpi_dev_free_resource_list(&resource_list); - return -ENOMEM; } - count = 0; - list_for_each_entry(rentry, &resource_list, node) - resources[count++] = rentry->res; - - acpi_dev_free_resource_list(&resource_list); -create_dev: memset(&pdevinfo, 0, sizeof(pdevinfo)); /* * If the ACPI node has a parent and that parent has a physical device -- cgit v0.10.2 From 23d328994b548d6822b88fe7e1903652afc354e0 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Tue, 30 Jul 2013 04:23:56 +0530 Subject: cpufreq: Fix misplaced call to cpufreq_update_policy() The call to cpufreq_update_policy() is placed in the CPU hotplug callback of cpufreq_stats, which has a higher priority than the CPU hotplug callback of cpufreq-core. As a result, during CPU_ONLINE/CPU_ONLINE_FROZEN, we end up calling cpufreq_update_policy() *before* calling cpufreq_add_dev() ! And for uninitialized CPUs, it just returns silently, not doing anything. To add to that, cpufreq_stats is not even the right place to call cpufreq_update_policy() to begin with. The cpufreq core ought to handle this in its own callback, from an elegance/relevance perspective. So move the invocation of cpufreq_update_policy() to cpufreq_cpu_callback, and place it *after* cpufreq_add_dev(). Signed-off-by: Srivatsa S. Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f0a5e2b..5b317b0 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1945,6 +1945,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, case CPU_ONLINE: case CPU_ONLINE_FROZEN: cpufreq_add_dev(dev, NULL); + cpufreq_update_policy(cpu); break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index d37568c..bc73be2 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -348,10 +348,6 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, unsigned int cpu = (unsigned long)hcpu; switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - cpufreq_update_policy(cpu); - break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: cpufreq_stats_free_sysfs(cpu); @@ -390,8 +386,6 @@ static int __init cpufreq_stats_init(void) return ret; register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); - for_each_online_cpu(cpu) - cpufreq_update_policy(cpu); ret = cpufreq_register_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); -- cgit v0.10.2 From e9698cc5d2749c5b74e137f94a95d7e505b097e8 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Tue, 30 Jul 2013 04:24:11 +0530 Subject: cpufreq: Add helper to perform alloc/free of policy structure Separate out the allocation of the cpufreq policy structure (along with its error handling) to a helper function. This makes the code easier to read and also helps with some upcoming code reorganization. Signed-off-by: Srivatsa S. Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5b317b0..18e58c1 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -944,6 +944,37 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, } #endif +static struct cpufreq_policy *cpufreq_policy_alloc(void) +{ + struct cpufreq_policy *policy; + + policy = kzalloc(sizeof(*policy), GFP_KERNEL); + if (!policy) + return NULL; + + if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) + goto err_free_policy; + + if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) + goto err_free_cpumask; + + return policy; + +err_free_cpumask: + free_cpumask_var(policy->cpus); +err_free_policy: + kfree(policy); + + return NULL; +} + +static void cpufreq_policy_free(struct cpufreq_policy *policy) +{ + free_cpumask_var(policy->related_cpus); + free_cpumask_var(policy->cpus); + kfree(policy); +} + /** * cpufreq_add_dev - add a CPU device * @@ -997,16 +1028,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) goto module_out; } - policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); + policy = cpufreq_policy_alloc(); if (!policy) goto nomem_out; - if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) - goto err_free_policy; - - if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) - goto err_free_cpumask; - policy->cpu = cpu; policy->governor = CPUFREQ_DEFAULT_GOVERNOR; cpumask_copy(policy->cpus, cpumask_of(cpu)); @@ -1071,11 +1096,7 @@ err_out_unregister: err_set_policy_cpu: per_cpu(cpufreq_policy_cpu, cpu) = -1; - free_cpumask_var(policy->related_cpus); -err_free_cpumask: - free_cpumask_var(policy->cpus); -err_free_policy: - kfree(policy); + cpufreq_policy_free(policy); nomem_out: module_put(cpufreq_driver->owner); module_out: @@ -1199,9 +1220,7 @@ static int __cpufreq_remove_dev(struct device *dev, if (cpufreq_driver->exit) cpufreq_driver->exit(data); - free_cpumask_var(data->related_cpus); - free_cpumask_var(data->cpus); - kfree(data); + cpufreq_policy_free(data); } else { pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); cpufreq_cpu_put(data); -- cgit v0.10.2 From e18f1682bce701ddcf88ba3651e07c7ee9b3ed60 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Tue, 30 Jul 2013 04:24:23 +0530 Subject: cpufreq: Extract non-interface related stuff from cpufreq_add_dev_interface cpufreq_add_dev_interface() includes the work of exposing the interface to the device, as well as a lot of unrelated stuff. Move the latter to cpufreq_add_dev(), where it is more appropriate. Signed-off-by: Srivatsa S. Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 18e58c1..f7c58c7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -835,11 +835,8 @@ static int cpufreq_add_dev_interface(unsigned int cpu, struct cpufreq_policy *policy, struct device *dev) { - struct cpufreq_policy new_policy; struct freq_attr **drv_attr; - unsigned long flags; int ret = 0; - unsigned int j; /* prepare interface data */ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, @@ -871,17 +868,23 @@ static int cpufreq_add_dev_interface(unsigned int cpu, goto err_out_kobj_put; } - write_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu(j, policy->cpus) { - per_cpu(cpufreq_cpu_data, j) = policy; - per_cpu(cpufreq_policy_cpu, j) = policy->cpu; - } - write_unlock_irqrestore(&cpufreq_driver_lock, flags); - ret = cpufreq_add_dev_symlink(cpu, policy); if (ret) goto err_out_kobj_put; + return ret; + +err_out_kobj_put: + kobject_put(&policy->kobj); + wait_for_completion(&policy->kobj_unregister); + return ret; +} + +static void cpufreq_init_policy(struct cpufreq_policy *policy) +{ + struct cpufreq_policy new_policy; + int ret = 0; + memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); /* assure that the starting sequence is run in __cpufreq_set_policy */ policy->governor = NULL; @@ -896,12 +899,6 @@ static int cpufreq_add_dev_interface(unsigned int cpu, if (cpufreq_driver->exit) cpufreq_driver->exit(policy); } - return ret; - -err_out_kobj_put: - kobject_put(&policy->kobj); - wait_for_completion(&policy->kobj_unregister); - return ret; } #ifdef CONFIG_HOTPLUG_CPU @@ -1075,10 +1072,19 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) } #endif + write_lock_irqsave(&cpufreq_driver_lock, flags); + for_each_cpu(j, policy->cpus) { + per_cpu(cpufreq_cpu_data, j) = policy; + per_cpu(cpufreq_policy_cpu, j) = policy->cpu; + } + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + ret = cpufreq_add_dev_interface(cpu, policy, dev); if (ret) goto err_out_unregister; + cpufreq_init_policy(policy); + kobject_uevent(&policy->kobj, KOBJ_ADD); module_put(cpufreq_driver->owner); pr_debug("initialization complete\n"); @@ -1087,8 +1093,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) err_out_unregister: write_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu(j, policy->cpus) + for_each_cpu(j, policy->cpus) { per_cpu(cpufreq_cpu_data, j) = NULL; + if (j != cpu) + per_cpu(cpufreq_policy_cpu, j) = -1; + } write_unlock_irqrestore(&cpufreq_driver_lock, flags); kobject_put(&policy->kobj); -- cgit v0.10.2 From f9ba680d23ea7e2fc31b4b7106a482d90ec62a24 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Tue, 30 Jul 2013 04:24:36 +0530 Subject: cpufreq: Extract the handover of policy cpu to a helper function During cpu offline, when the policy->cpu is going down, some other CPU present in the policy->cpus mask is nominated as the new policy->cpu. Extract this functionality from __cpufreq_remove_dev() and implement it in a helper function. This helps in upcoming code reorganization. Signed-off-by: Srivatsa S. Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f7c58c7..0611ae4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1129,6 +1129,38 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) CPUFREQ_UPDATE_POLICY_CPU, policy); } +static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, + unsigned int old_cpu) +{ + struct device *cpu_dev; + unsigned long flags; + int ret; + + /* first sibling now owns the new sysfs dir */ + cpu_dev = get_cpu_device(cpumask_first(data->cpus)); + sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); + ret = kobject_move(&data->kobj, &cpu_dev->kobj); + if (ret) { + pr_err("%s: Failed to move kobj: %d", __func__, ret); + + WARN_ON(lock_policy_rwsem_write(old_cpu)); + cpumask_set_cpu(old_cpu, data->cpus); + + write_lock_irqsave(&cpufreq_driver_lock, flags); + per_cpu(cpufreq_cpu_data, old_cpu) = data; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + + unlock_policy_rwsem_write(old_cpu); + + ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, + "cpufreq"); + + return -EINVAL; + } + + return cpu_dev->id; +} + /** * __cpufreq_remove_dev - remove a CPU device * @@ -1139,12 +1171,12 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) { - unsigned int cpu = dev->id, ret, cpus; + unsigned int cpu = dev->id, cpus; + int new_cpu; unsigned long flags; struct cpufreq_policy *data; struct kobject *kobj; struct completion *cmp; - struct device *cpu_dev; pr_debug("%s: unregistering CPU %u\n", __func__, cpu); @@ -1179,32 +1211,15 @@ static int __cpufreq_remove_dev(struct device *dev, if (cpu != data->cpu) { sysfs_remove_link(&dev->kobj, "cpufreq"); } else if (cpus > 1) { - /* first sibling now owns the new sysfs dir */ - cpu_dev = get_cpu_device(cpumask_first(data->cpus)); - sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); - ret = kobject_move(&data->kobj, &cpu_dev->kobj); - if (ret) { - pr_err("%s: Failed to move kobj: %d", __func__, ret); + new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu); + if (new_cpu >= 0) { WARN_ON(lock_policy_rwsem_write(cpu)); - cpumask_set_cpu(cpu, data->cpus); - - write_lock_irqsave(&cpufreq_driver_lock, flags); - per_cpu(cpufreq_cpu_data, cpu) = data; - write_unlock_irqrestore(&cpufreq_driver_lock, flags); - + update_policy_cpu(data, new_cpu); unlock_policy_rwsem_write(cpu); - - ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, - "cpufreq"); - return -EINVAL; + pr_debug("%s: policy Kobject moved to cpu: %d " + "from: %d\n",__func__, new_cpu, cpu); } - - WARN_ON(lock_policy_rwsem_write(cpu)); - update_policy_cpu(data, cpu_dev->id); - unlock_policy_rwsem_write(cpu); - pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", - __func__, cpu_dev->id, cpu); } /* If cpu is last user of policy, free policy */ -- cgit v0.10.2 From a82fab292898f88ea9ca99dd10c1773dcada08b6 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Tue, 30 Jul 2013 04:24:49 +0530 Subject: cpufreq: Introduce a flag ('frozen') to separate full vs temporary init/teardown During suspend/resume we would like to do a light-weight init/teardown of CPUs in the cpufreq subsystem and preserve certain things such as sysfs files etc across suspend/resume transitions. Add a flag called 'frozen' to help distinguish the full init/teardown sequence from the light-weight one. Signed-off-by: Srivatsa S. Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0611ae4..1d041af 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -903,7 +903,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) #ifdef CONFIG_HOTPLUG_CPU static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, - struct device *dev) + struct device *dev, bool frozen) { struct cpufreq_policy *policy; int ret = 0, has_target = !!cpufreq_driver->target; @@ -931,13 +931,18 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); } - ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); - if (ret) { + /* Don't touch sysfs links during light-weight init */ + if (frozen) { + /* Drop the extra refcount that we took above */ cpufreq_cpu_put(policy); - return ret; + return 0; } - return 0; + ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); + if (ret) + cpufreq_cpu_put(policy); + + return ret; } #endif @@ -972,16 +977,8 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) kfree(policy); } -/** - * cpufreq_add_dev - add a CPU device - * - * Adds the cpufreq interface for a CPU device. - * - * The Oracle says: try running cpufreq registration/unregistration concurrently - * with with cpu hotplugging and all hell will break loose. Tried to clean this - * mess up, but more thorough testing is needed. - Mathieu - */ -static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) +static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, + bool frozen) { unsigned int j, cpu = dev->id; int ret = -ENOMEM; @@ -1013,7 +1010,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - return cpufreq_add_policy_cpu(cpu, sibling, dev); + return cpufreq_add_policy_cpu(cpu, sibling, dev, + frozen); } } read_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -1079,9 +1077,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) } write_unlock_irqrestore(&cpufreq_driver_lock, flags); - ret = cpufreq_add_dev_interface(cpu, policy, dev); - if (ret) - goto err_out_unregister; + if (!frozen) { + ret = cpufreq_add_dev_interface(cpu, policy, dev); + if (ret) + goto err_out_unregister; + } cpufreq_init_policy(policy); @@ -1112,6 +1112,20 @@ module_out: return ret; } +/** + * cpufreq_add_dev - add a CPU device + * + * Adds the cpufreq interface for a CPU device. + * + * The Oracle says: try running cpufreq registration/unregistration concurrently + * with with cpu hotplugging and all hell will break loose. Tried to clean this + * mess up, but more thorough testing is needed. - Mathieu + */ +static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) +{ + return __cpufreq_add_dev(dev, sif, false); +} + static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) { int j; @@ -1130,7 +1144,7 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) } static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, - unsigned int old_cpu) + unsigned int old_cpu, bool frozen) { struct device *cpu_dev; unsigned long flags; @@ -1138,6 +1152,11 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, /* first sibling now owns the new sysfs dir */ cpu_dev = get_cpu_device(cpumask_first(data->cpus)); + + /* Don't touch sysfs files during light-weight tear-down */ + if (frozen) + return cpu_dev->id; + sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); ret = kobject_move(&data->kobj, &cpu_dev->kobj); if (ret) { @@ -1169,7 +1188,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, * This routine frees the rwsem before returning. */ static int __cpufreq_remove_dev(struct device *dev, - struct subsys_interface *sif) + struct subsys_interface *sif, bool frozen) { unsigned int cpu = dev->id, cpus; int new_cpu; @@ -1208,17 +1227,20 @@ static int __cpufreq_remove_dev(struct device *dev, cpumask_clear_cpu(cpu, data->cpus); unlock_policy_rwsem_write(cpu); - if (cpu != data->cpu) { + if (cpu != data->cpu && !frozen) { sysfs_remove_link(&dev->kobj, "cpufreq"); } else if (cpus > 1) { - new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu); + new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu, frozen); if (new_cpu >= 0) { WARN_ON(lock_policy_rwsem_write(cpu)); update_policy_cpu(data, new_cpu); unlock_policy_rwsem_write(cpu); - pr_debug("%s: policy Kobject moved to cpu: %d " - "from: %d\n",__func__, new_cpu, cpu); + + if (!frozen) { + pr_debug("%s: policy Kobject moved to cpu: %d " + "from: %d\n",__func__, new_cpu, cpu); + } } } @@ -1266,7 +1288,7 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) if (cpu_is_offline(cpu)) return 0; - retval = __cpufreq_remove_dev(dev, sif); + retval = __cpufreq_remove_dev(dev, sif, false); return retval; } @@ -1992,7 +2014,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: - __cpufreq_remove_dev(dev, NULL); + __cpufreq_remove_dev(dev, NULL, false); break; case CPU_DOWN_FAILED: case CPU_DOWN_FAILED_FROZEN: -- cgit v0.10.2 From 8414809c6a1e8479e331e09254adb58b33a36d25 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Tue, 30 Jul 2013 04:25:10 +0530 Subject: cpufreq: Preserve policy structure across suspend/resume To perform light-weight cpu-init and teardown in the cpufreq subsystem during suspend/resume, we need to separate out the 2 main functionalities of the cpufreq CPU hotplug callbacks, as outlined below: 1. Init/tear-down of core cpufreq and CPU-specific components, which are critical to the correct functioning of the cpufreq subsystem. 2. Init/tear-down of cpufreq sysfs files during suspend/resume. The first part requires accurate updates to the policy structure such as its ->cpus and ->related_cpus masks, whereas the second part requires that the policy->kobj structure is not released or re-initialized during suspend/resume. To handle both these requirements, we need to allow updates to the policy structure throughout suspend/resume, but prevent the structure from getting freed up. Also, we must have a mechanism by which the cpu-up callbacks can restore the policy structure, without allocating things afresh. (That also helps avoid memory leaks). To achieve this, we use 2 schemes: a. Use a fallback per-cpu storage area for preserving the policy structures during suspend, so that they can be restored during resume appropriately. b. Use the 'frozen' flag to determine when to free or allocate the policy structure vs when to restore the policy from the saved fallback storage. Thus we can successfully preserve the structure across suspend/resume. Effectively, this helps us complete the separation of the 'light-weight' and the 'full' init/tear-down sequences in the cpufreq subsystem, so that this can be made use of in the suspend/resume scenario. Signed-off-by: Srivatsa S. Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1d041af..e0ace3d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -44,6 +44,7 @@ */ static struct cpufreq_driver *cpufreq_driver; static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); +static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); static DEFINE_RWLOCK(cpufreq_driver_lock); static DEFINE_MUTEX(cpufreq_governor_lock); @@ -946,6 +947,20 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, } #endif +static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu) +{ + struct cpufreq_policy *policy; + unsigned long flags; + + write_lock_irqsave(&cpufreq_driver_lock, flags); + + policy = per_cpu(cpufreq_cpu_data_fallback, cpu); + + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + + return policy; +} + static struct cpufreq_policy *cpufreq_policy_alloc(void) { struct cpufreq_policy *policy; @@ -1023,7 +1038,12 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, goto module_out; } - policy = cpufreq_policy_alloc(); + if (frozen) + /* Restore the saved policy when doing light-weight init */ + policy = cpufreq_policy_restore(cpu); + else + policy = cpufreq_policy_alloc(); + if (!policy) goto nomem_out; @@ -1204,6 +1224,10 @@ static int __cpufreq_remove_dev(struct device *dev, data = per_cpu(cpufreq_cpu_data, cpu); per_cpu(cpufreq_cpu_data, cpu) = NULL; + /* Save the policy somewhere when doing a light-weight tear-down */ + if (frozen) + per_cpu(cpufreq_cpu_data_fallback, cpu) = data; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); if (!data) { @@ -1249,27 +1273,40 @@ static int __cpufreq_remove_dev(struct device *dev, if (cpufreq_driver->target) __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); - lock_policy_rwsem_read(cpu); - kobj = &data->kobj; - cmp = &data->kobj_unregister; - unlock_policy_rwsem_read(cpu); - kobject_put(kobj); + if (!frozen) { + lock_policy_rwsem_read(cpu); + kobj = &data->kobj; + cmp = &data->kobj_unregister; + unlock_policy_rwsem_read(cpu); + kobject_put(kobj); + + /* + * We need to make sure that the underlying kobj is + * actually not referenced anymore by anybody before we + * proceed with unloading. + */ + pr_debug("waiting for dropping of refcount\n"); + wait_for_completion(cmp); + pr_debug("wait complete\n"); + } - /* we need to make sure that the underlying kobj is actually - * not referenced anymore by anybody before we proceed with - * unloading. + /* + * Perform the ->exit() even during light-weight tear-down, + * since this is a core component, and is essential for the + * subsequent light-weight ->init() to succeed. */ - pr_debug("waiting for dropping of refcount\n"); - wait_for_completion(cmp); - pr_debug("wait complete\n"); - if (cpufreq_driver->exit) cpufreq_driver->exit(data); - cpufreq_policy_free(data); + if (!frozen) + cpufreq_policy_free(data); } else { - pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); - cpufreq_cpu_put(data); + + if (!frozen) { + pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); + cpufreq_cpu_put(data); + } + if (cpufreq_driver->target) { __cpufreq_governor(data, CPUFREQ_GOV_START); __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); -- cgit v0.10.2 From 5302c3fb2e62f4ca5e43e060491ba299f58c5231 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Tue, 30 Jul 2013 04:25:25 +0530 Subject: cpufreq: Perform light-weight init/teardown during suspend/resume Now that we have the infrastructure to perform a light-weight init/tear-down, use that in the cpufreq CPU hotplug notifier when invoked from the suspend/resume path. This also ensures that the file permissions of the cpufreq sysfs files are preserved across suspend/resume, something which commit a66b2e (cpufreq: Preserve sysfs files across suspend/resume) originally intended to do, but had to be reverted due to other problems. Signed-off-by: Srivatsa S. Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e0ace3d..370abb6 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2040,22 +2040,26 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, { unsigned int cpu = (unsigned long)hcpu; struct device *dev; + bool frozen = false; dev = get_cpu_device(cpu); if (dev) { - switch (action) { + + if (action & CPU_TASKS_FROZEN) + frozen = true; + + switch (action & ~CPU_TASKS_FROZEN) { case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - cpufreq_add_dev(dev, NULL); + __cpufreq_add_dev(dev, NULL, frozen); cpufreq_update_policy(cpu); break; + case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: - __cpufreq_remove_dev(dev, NULL, false); + __cpufreq_remove_dev(dev, NULL, frozen); break; + case CPU_DOWN_FAILED: - case CPU_DOWN_FAILED_FROZEN: - cpufreq_add_dev(dev, NULL); + __cpufreq_add_dev(dev, NULL, frozen); break; } } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index bc73be2..cb38413 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -349,11 +349,9 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, switch (action) { case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: cpufreq_stats_free_sysfs(cpu); break; case CPU_DEAD: - case CPU_DEAD_FROZEN: cpufreq_stats_free_table(cpu); break; } -- cgit v0.10.2 From e8fdde1011ea45792e60f14f620b01f78cb0d34d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 31 Jul 2013 14:31:33 +0200 Subject: cpufreq: Remove extra variables from cpufreq_add_dev_symlink() We call cpufreq_cpu_get() in cpufreq_add_dev_symlink() to increase usage refcount of policy, but not to get a policy for the given CPU. So, we don't really need to capture the return value of this routine. We can simply use policy passed as an argument to cpufreq_add_dev_symlink(). Moreover debug print is rewritten to make it more clear. [rjw: Changelog] Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 370abb6..b6154ca 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -813,19 +813,18 @@ static int cpufreq_add_dev_symlink(unsigned int cpu, int ret = 0; for_each_cpu(j, policy->cpus) { - struct cpufreq_policy *managed_policy; struct device *cpu_dev; if (j == cpu) continue; - pr_debug("CPU %u already managed, adding link\n", j); - managed_policy = cpufreq_cpu_get(cpu); + pr_debug("Adding link for CPU: %u\n", j); + cpufreq_cpu_get(cpu); cpu_dev = get_cpu_device(j); ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, "cpufreq"); if (ret) { - cpufreq_cpu_put(managed_policy); + cpufreq_cpu_put(policy); return ret; } } -- cgit v0.10.2 From 308b60e71541518f3fe97171b4daf71adc607f3d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 31 Jul 2013 14:35:14 +0200 Subject: cpufreq: Don't pass CPU to cpufreq_add_dev_{symlink|interface}() Pointer to struct cpufreq_policy is already passed to these routines and we don't need to send policy->cpu to them as well. So, get rid of this extra argument and use policy->cpu everywhere. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b6154ca..576b312 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -806,8 +806,7 @@ void cpufreq_sysfs_remove_file(const struct attribute *attr) EXPORT_SYMBOL(cpufreq_sysfs_remove_file); /* symlink affected CPUs */ -static int cpufreq_add_dev_symlink(unsigned int cpu, - struct cpufreq_policy *policy) +static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy) { unsigned int j; int ret = 0; @@ -815,11 +814,11 @@ static int cpufreq_add_dev_symlink(unsigned int cpu, for_each_cpu(j, policy->cpus) { struct device *cpu_dev; - if (j == cpu) + if (j == policy->cpu) continue; pr_debug("Adding link for CPU: %u\n", j); - cpufreq_cpu_get(cpu); + cpufreq_cpu_get(policy->cpu); cpu_dev = get_cpu_device(j); ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, "cpufreq"); @@ -831,8 +830,7 @@ static int cpufreq_add_dev_symlink(unsigned int cpu, return ret; } -static int cpufreq_add_dev_interface(unsigned int cpu, - struct cpufreq_policy *policy, +static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, struct device *dev) { struct freq_attr **drv_attr; @@ -868,7 +866,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu, goto err_out_kobj_put; } - ret = cpufreq_add_dev_symlink(cpu, policy); + ret = cpufreq_add_dev_symlink(policy); if (ret) goto err_out_kobj_put; @@ -1097,7 +1095,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, write_unlock_irqrestore(&cpufreq_driver_lock, flags); if (!frozen) { - ret = cpufreq_add_dev_interface(cpu, policy, dev); + ret = cpufreq_add_dev_interface(policy, dev); if (ret) goto err_out_unregister; } -- cgit v0.10.2 From 71c3461ef7c67024792d283b88630245a6c169ba Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 4 Aug 2013 01:19:34 +0200 Subject: cpufreq: Do not hold driver module references for additional policy CPUs The cpufreq core is a little inconsistent in the way it uses the driver module refcount. Namely, if __cpufreq_add_dev() is called for a CPU that doesn't share the policy object with any other CPUs, the driver module refcount it grabs to start with will be dropped by it before returning and will be equal to whatever it had been before that function was invoked. However, if the given CPU does share the policy object with other CPUs, either cpufreq_add_policy_cpu() is called to link the new CPU to the existing policy, or cpufreq_add_dev_symlink() is used to link the other CPUs sharing the policy with it to the just created policy object. In that case, because both cpufreq_add_policy_cpu() and cpufreq_add_dev_symlink() call cpufreq_cpu_get() for the given policy (the latter possibly many times) without the balancing cpufreq_cpu_put() (unless there is an error), the driver module refcount will be left by __cpufreq_add_dev() with a nonzero value (different from the initial one). To remove that inconsistency make cpufreq_add_policy_cpu() execute cpufreq_cpu_put() for the given policy before returning, which decrements the driver module refcount so that it will be equal to its initial value after __cpufreq_add_dev() returns. Also remove the cpufreq_cpu_get() call from cpufreq_add_dev_symlink(), since both the policy refcount and the driver module refcount are nonzero when it is called and they don't need to be bumped up by it. Accordingly, drop the cpufreq_cpu_put() from __cpufreq_remove_dev(), since it is only necessary to balance the cpufreq_cpu_get() called by cpufreq_add_policy_cpu() or cpufreq_add_dev_symlink(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Srivatsa S. Bhat Acked-by: Viresh Kumar diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 576b312..c8b2ca0 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -818,14 +818,11 @@ static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy) continue; pr_debug("Adding link for CPU: %u\n", j); - cpufreq_cpu_get(policy->cpu); cpu_dev = get_cpu_device(j); ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, "cpufreq"); - if (ret) { - cpufreq_cpu_put(policy); - return ret; - } + if (ret) + break; } return ret; } @@ -908,7 +905,8 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, unsigned long flags; policy = cpufreq_cpu_get(sibling); - WARN_ON(!policy); + if (WARN_ON_ONCE(!policy)) + return -ENODATA; if (has_target) __cpufreq_governor(policy, CPUFREQ_GOV_STOP); @@ -930,16 +928,10 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, } /* Don't touch sysfs links during light-weight init */ - if (frozen) { - /* Drop the extra refcount that we took above */ - cpufreq_cpu_put(policy); - return 0; - } - - ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); - if (ret) - cpufreq_cpu_put(policy); + if (!frozen) + ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); + cpufreq_cpu_put(policy); return ret; } #endif @@ -1298,12 +1290,6 @@ static int __cpufreq_remove_dev(struct device *dev, if (!frozen) cpufreq_policy_free(data); } else { - - if (!frozen) { - pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); - cpufreq_cpu_put(data); - } - if (cpufreq_driver->target) { __cpufreq_governor(data, CPUFREQ_GOV_START); __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); -- cgit v0.10.2 From 10659ab7b50e963429f1a681882404ca37aa584c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 4 Aug 2013 01:19:41 +0200 Subject: cpufreq: Avoid double kobject_put() for the same kobject in error code path The only case triggering a jump to the err_out_unregister label in __cpufreq_add_dev() is when cpufreq_add_dev_interface() fails. However, if cpufreq_add_dev_interface() fails, it calls kobject_put() for the policy kobject in its error code path and since that causes the kobject's refcount to become 0, the additional kobject_put() for the same kobject under err_out_unregister and the wait_for_completion() following it are pointless, so drop them. Signed-off-by: Rafael J. Wysocki Reviewed-by: Srivatsa S. Bhat Acked-by: Viresh Kumar diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index c8b2ca0..924d3f5 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1109,9 +1109,6 @@ err_out_unregister: } write_unlock_irqrestore(&cpufreq_driver_lock, flags); - kobject_put(&policy->kobj); - wait_for_completion(&policy->kobj_unregister); - err_set_policy_cpu: per_cpu(cpufreq_policy_cpu, cpu) = -1; cpufreq_policy_free(policy); -- cgit v0.10.2 From d8d3b4711297e101bbad826474013edbe342c333 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sun, 4 Aug 2013 01:20:07 +0200 Subject: cpufreq: Pass policy to cpufreq_add_policy_cpu() The caller of cpufreq_add_policy_cpu() already has a pointer to the policy structure and there is no need to look it up again in cpufreq_add_policy_cpu(). Let's pass it directly. Signed-off-by: Viresh Kumar Reviewed-by: Srivatsa S. Bhat Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 924d3f5..1faf320 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -897,21 +897,17 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) } #ifdef CONFIG_HOTPLUG_CPU -static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, - struct device *dev, bool frozen) +static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, + unsigned int cpu, struct device *dev, + bool frozen) { - struct cpufreq_policy *policy; int ret = 0, has_target = !!cpufreq_driver->target; unsigned long flags; - policy = cpufreq_cpu_get(sibling); - if (WARN_ON_ONCE(!policy)) - return -ENODATA; - if (has_target) __cpufreq_governor(policy, CPUFREQ_GOV_STOP); - lock_policy_rwsem_write(sibling); + lock_policy_rwsem_write(policy->cpu); write_lock_irqsave(&cpufreq_driver_lock, flags); @@ -920,7 +916,7 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, per_cpu(cpufreq_cpu_data, cpu) = policy; write_unlock_irqrestore(&cpufreq_driver_lock, flags); - unlock_policy_rwsem_write(sibling); + unlock_policy_rwsem_write(policy->cpu); if (has_target) { __cpufreq_governor(policy, CPUFREQ_GOV_START); @@ -931,7 +927,6 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, if (!frozen) ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); - cpufreq_cpu_put(policy); return ret; } #endif @@ -1014,8 +1009,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - return cpufreq_add_policy_cpu(cpu, sibling, dev, - frozen); + return cpufreq_add_policy_cpu(cp, cpu, dev, frozen); } } read_unlock_irqrestore(&cpufreq_driver_lock, flags); -- cgit v0.10.2 From 5ff0a268037d344f86df690ccb994d8bc015d2d9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:03 +0530 Subject: cpufreq: Clean up header files included in the core This patch addresses the following issues in the header files in the cpufreq core: - Include headers in ascending order, so that we don't add same many times by mistake. - must be included after , so that they override whatever they need to. - Remove unnecessary includes. - Don't include files already included by cpufreq.h or cpufreq_governor.h. [rjw: Changelog] Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e34bd94..8458371 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -17,24 +17,17 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include +#include #include #include -#include -#include -#include #include -#include -#include -#include +#include +#include +#include #include +#include #include - +#include #include /** diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 0ceb2ef..841e256 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -11,19 +11,7 @@ * published by the Free Software Foundation. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include - #include "cpufreq_governor.h" /* Conservative governor macros */ diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 7409dbd..556064e 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -16,15 +16,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include #include #include -#include #include -#include -#include #include "cpufreq_governor.h" diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 0e0dd4c..cf0b7a4 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -18,10 +18,9 @@ #define _CPUFREQ_GOVERNOR_H #include -#include +#include +#include #include -#include -#include /* * The polling frequency depends on the capability of the processor. Default diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index a3c5574..27c732e 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -12,20 +12,10 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include -#include +#include #include #include -#include #include -#include -#include - #include "cpufreq_governor.h" /* On-demand governor macros */ diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index 9fef7d6..cf117de 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -12,10 +12,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include #include #include +#include static int cpufreq_governor_performance(struct cpufreq_policy *policy, unsigned int event) diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 32109a1..e3b874c 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -12,10 +12,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include #include #include +#include static int cpufreq_governor_powersave(struct cpufreq_policy *policy, unsigned int event) diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index cb38413..a7143b0 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -9,17 +9,10 @@ * published by the Free Software Foundation. */ -#include -#include #include -#include #include #include -#include -#include -#include -#include -#include +#include #include static spinlock_t cpufreq_stats_lock; diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index f0d8741..f111454a 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -11,10 +11,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include #include +#include /********************************************************************* * FREQUENCY TABLE HELPERS * diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index e1fd215..97627bb 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -11,16 +11,11 @@ #ifndef _LINUX_CPUFREQ_H #define _LINUX_CPUFREQ_H -#include -#include -#include -#include +#include +#include #include +#include #include -#include -#include -#include -#include #define CPUFREQ_NAME_LEN 16 /* Print length for names. Extra 1 space for accomodating '\n' in prints */ -- cgit v0.10.2 From 74aca95da74836a6807118f6590d8df8232c74a9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:04 +0530 Subject: cpufreq: Re-arrange declarations in cpufreq.h They are pretty much mixed up. Although generic headers are present, definitions/declarations are present outside of them too ... This patch just moves stuff up and down to make it look better and consistent. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 97627bb..0d3b026 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -17,60 +17,30 @@ #include #include -#define CPUFREQ_NAME_LEN 16 -/* Print length for names. Extra 1 space for accomodating '\n' in prints */ -#define CPUFREQ_NAME_PLEN (CPUFREQ_NAME_LEN + 1) - /********************************************************************* - * CPUFREQ NOTIFIER INTERFACE * + * CPUFREQ INTERFACE * *********************************************************************/ - -#define CPUFREQ_TRANSITION_NOTIFIER (0) -#define CPUFREQ_POLICY_NOTIFIER (1) - -#ifdef CONFIG_CPU_FREQ -int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); -int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); -extern void disable_cpufreq(void); -#else /* CONFIG_CPU_FREQ */ -static inline int cpufreq_register_notifier(struct notifier_block *nb, - unsigned int list) -{ - return 0; -} -static inline int cpufreq_unregister_notifier(struct notifier_block *nb, - unsigned int list) -{ - return 0; -} -static inline void disable_cpufreq(void) { } -#endif /* CONFIG_CPU_FREQ */ - -/* if (cpufreq_driver->target) exists, the ->governor decides what frequency - * within the limits is used. If (cpufreq_driver->setpolicy> exists, these - * two generic policies are available: - */ - -#define CPUFREQ_POLICY_POWERSAVE (1) -#define CPUFREQ_POLICY_PERFORMANCE (2) - -/* Frequency values here are CPU kHz so that hardware which doesn't run - * with some frequencies can complain without having to guess what per - * cent / per mille means. +/* + * Frequency values here are CPU kHz + * * Maximum transition latency is in nanoseconds - if it's unknown, * CPUFREQ_ETERNAL shall be used. */ +#define CPUFREQ_ETERNAL (-1) +#define CPUFREQ_NAME_LEN 16 +/* Print length for names. Extra 1 space for accomodating '\n' in prints */ +#define CPUFREQ_NAME_PLEN (CPUFREQ_NAME_LEN + 1) + struct cpufreq_governor; -/* /sys/devices/system/cpu/cpufreq: entry point for global variables */ -extern struct kobject *cpufreq_global_kobject; -int cpufreq_get_global_kobject(void); -void cpufreq_put_global_kobject(void); -int cpufreq_sysfs_create_file(const struct attribute *attr); -void cpufreq_sysfs_remove_file(const struct attribute *attr); +struct cpufreq_freqs { + unsigned int cpu; /* cpu nr */ + unsigned int old; + unsigned int new; + u8 flags; /* flags of cpufreq_driver, see below. */ +}; -#define CPUFREQ_ETERNAL (-1) struct cpufreq_cpuinfo { unsigned int max_freq; unsigned int min_freq; @@ -117,111 +87,95 @@ struct cpufreq_policy { int transition_ongoing; /* Tracks transition status */ }; -#define CPUFREQ_ADJUST (0) -#define CPUFREQ_INCOMPATIBLE (1) -#define CPUFREQ_NOTIFY (2) -#define CPUFREQ_START (3) -#define CPUFREQ_UPDATE_POLICY_CPU (4) - /* Only for ACPI */ #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ #define CPUFREQ_SHARED_TYPE_ALL (2) /* All dependent CPUs should set freq */ #define CPUFREQ_SHARED_TYPE_ANY (3) /* Freq can be set from any dependent CPU*/ +struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu); +void cpufreq_cpu_put(struct cpufreq_policy *data); + static inline bool policy_is_shared(struct cpufreq_policy *policy) { return cpumask_weight(policy->cpus) > 1; } -/******************** cpufreq transition notifiers *******************/ - -#define CPUFREQ_PRECHANGE (0) -#define CPUFREQ_POSTCHANGE (1) -#define CPUFREQ_RESUMECHANGE (8) -#define CPUFREQ_SUSPENDCHANGE (9) +/* /sys/devices/system/cpu/cpufreq: entry point for global variables */ +extern struct kobject *cpufreq_global_kobject; +int cpufreq_get_global_kobject(void); +void cpufreq_put_global_kobject(void); +int cpufreq_sysfs_create_file(const struct attribute *attr); +void cpufreq_sysfs_remove_file(const struct attribute *attr); -struct cpufreq_freqs { - unsigned int cpu; /* cpu nr */ - unsigned int old; - unsigned int new; - u8 flags; /* flags of cpufreq_driver, see below. */ -}; +#ifdef CONFIG_CPU_FREQ +unsigned int cpufreq_get(unsigned int cpu); +unsigned int cpufreq_quick_get(unsigned int cpu); +unsigned int cpufreq_quick_get_max(unsigned int cpu); +void disable_cpufreq(void); -/** - * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch - * safe) - * @old: old value - * @div: divisor - * @mult: multiplier - * - * - * new = old * mult / div - */ -static inline unsigned long cpufreq_scale(unsigned long old, u_int div, - u_int mult) +u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy); +int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); +int cpufreq_update_policy(unsigned int cpu); +bool have_governor_per_policy(void); +struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy); +#else +static inline unsigned int cpufreq_get(unsigned int cpu) { -#if BITS_PER_LONG == 32 - - u64 result = ((u64) old) * ((u64) mult); - do_div(result, div); - return (unsigned long) result; - -#elif BITS_PER_LONG == 64 - - unsigned long result = old * ((u64) mult); - result /= div; - return result; - + return 0; +} +static inline unsigned int cpufreq_quick_get(unsigned int cpu) +{ + return 0; +} +static inline unsigned int cpufreq_quick_get_max(unsigned int cpu) +{ + return 0; +} +static inline void disable_cpufreq(void) { } #endif -}; /********************************************************************* - * CPUFREQ GOVERNORS * + * CPUFREQ DRIVER INTERFACE * *********************************************************************/ -#define CPUFREQ_GOV_START 1 -#define CPUFREQ_GOV_STOP 2 -#define CPUFREQ_GOV_LIMITS 3 -#define CPUFREQ_GOV_POLICY_INIT 4 -#define CPUFREQ_GOV_POLICY_EXIT 5 +#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ +#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ -struct cpufreq_governor { - char name[CPUFREQ_NAME_LEN]; - int initialized; - int (*governor) (struct cpufreq_policy *policy, - unsigned int event); - ssize_t (*show_setspeed) (struct cpufreq_policy *policy, - char *buf); - int (*store_setspeed) (struct cpufreq_policy *policy, - unsigned int freq); - unsigned int max_transition_latency; /* HW must be able to switch to - next freq faster than this value in nano secs or we - will fallback to performance governor */ - struct list_head governor_list; - struct module *owner; +struct freq_attr { + struct attribute attr; + ssize_t (*show)(struct cpufreq_policy *, char *); + ssize_t (*store)(struct cpufreq_policy *, const char *, size_t count); }; -/* - * Pass a target to the cpufreq driver. - */ -extern int cpufreq_driver_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation); -extern int __cpufreq_driver_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation); -int cpufreq_register_governor(struct cpufreq_governor *governor); -void cpufreq_unregister_governor(struct cpufreq_governor *governor); +#define cpufreq_freq_attr_ro(_name) \ +static struct freq_attr _name = \ +__ATTR(_name, 0444, show_##_name, NULL) -/********************************************************************* - * CPUFREQ DRIVER INTERFACE * - *********************************************************************/ +#define cpufreq_freq_attr_ro_perm(_name, _perm) \ +static struct freq_attr _name = \ +__ATTR(_name, _perm, show_##_name, NULL) -#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ -#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ +#define cpufreq_freq_attr_rw(_name) \ +static struct freq_attr _name = \ +__ATTR(_name, 0644, show_##_name, store_##_name) + +struct global_attr { + struct attribute attr; + ssize_t (*show)(struct kobject *kobj, + struct attribute *attr, char *buf); + ssize_t (*store)(struct kobject *a, struct attribute *b, + const char *c, size_t count); +}; + +#define define_one_global_ro(_name) \ +static struct global_attr _name = \ +__ATTR(_name, 0444, show_##_name, NULL) + +#define define_one_global_rw(_name) \ +static struct global_attr _name = \ +__ATTR(_name, 0644, show_##_name, store_##_name) -struct freq_attr; struct cpufreq_driver { struct module *owner; @@ -258,7 +212,6 @@ struct cpufreq_driver { }; /* flags */ - #define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if * all ->init() calls failed */ #define CPUFREQ_CONST_LOOPS 0x02 /* loops_per_jiffy or other kernel @@ -270,8 +223,7 @@ struct cpufreq_driver { int cpufreq_register_driver(struct cpufreq_driver *driver_data); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); -void cpufreq_notify_transition(struct cpufreq_policy *policy, - struct cpufreq_freqs *freqs, unsigned int state); +const char *cpufreq_get_current_driver(void); static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) @@ -289,87 +241,118 @@ static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, return; } -struct freq_attr { - struct attribute attr; - ssize_t (*show)(struct cpufreq_policy *, char *); - ssize_t (*store)(struct cpufreq_policy *, const char *, size_t count); -}; - -#define cpufreq_freq_attr_ro(_name) \ -static struct freq_attr _name = \ -__ATTR(_name, 0444, show_##_name, NULL) - -#define cpufreq_freq_attr_ro_perm(_name, _perm) \ -static struct freq_attr _name = \ -__ATTR(_name, _perm, show_##_name, NULL) - -#define cpufreq_freq_attr_rw(_name) \ -static struct freq_attr _name = \ -__ATTR(_name, 0644, show_##_name, store_##_name) +/********************************************************************* + * CPUFREQ NOTIFIER INTERFACE * + *********************************************************************/ -struct global_attr { - struct attribute attr; - ssize_t (*show)(struct kobject *kobj, - struct attribute *attr, char *buf); - ssize_t (*store)(struct kobject *a, struct attribute *b, - const char *c, size_t count); -}; +#define CPUFREQ_TRANSITION_NOTIFIER (0) +#define CPUFREQ_POLICY_NOTIFIER (1) -#define define_one_global_ro(_name) \ -static struct global_attr _name = \ -__ATTR(_name, 0444, show_##_name, NULL) +/* Transition notifiers */ +#define CPUFREQ_PRECHANGE (0) +#define CPUFREQ_POSTCHANGE (1) +#define CPUFREQ_RESUMECHANGE (8) +#define CPUFREQ_SUSPENDCHANGE (9) -#define define_one_global_rw(_name) \ -static struct global_attr _name = \ -__ATTR(_name, 0644, show_##_name, store_##_name) +/* Policy Notifiers */ +#define CPUFREQ_ADJUST (0) +#define CPUFREQ_INCOMPATIBLE (1) +#define CPUFREQ_NOTIFY (2) +#define CPUFREQ_START (3) +#define CPUFREQ_UPDATE_POLICY_CPU (4) -struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu); -void cpufreq_cpu_put(struct cpufreq_policy *data); -const char *cpufreq_get_current_driver(void); +#ifdef CONFIG_CPU_FREQ +int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); +int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); -/********************************************************************* - * CPUFREQ 2.6. INTERFACE * - *********************************************************************/ -u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy); -int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); -int cpufreq_update_policy(unsigned int cpu); -bool have_governor_per_policy(void); -struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy); +void cpufreq_notify_transition(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, unsigned int state); -#ifdef CONFIG_CPU_FREQ -/* - * query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it - */ -unsigned int cpufreq_get(unsigned int cpu); -#else -static inline unsigned int cpufreq_get(unsigned int cpu) +#else /* CONFIG_CPU_FREQ */ +static inline int cpufreq_register_notifier(struct notifier_block *nb, + unsigned int list) { return 0; } -#endif - -/* - * query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it - */ -#ifdef CONFIG_CPU_FREQ -unsigned int cpufreq_quick_get(unsigned int cpu); -unsigned int cpufreq_quick_get_max(unsigned int cpu); -#else -static inline unsigned int cpufreq_quick_get(unsigned int cpu) +static inline int cpufreq_unregister_notifier(struct notifier_block *nb, + unsigned int list) { return 0; } -static inline unsigned int cpufreq_quick_get_max(unsigned int cpu) +#endif /* !CONFIG_CPU_FREQ */ + +/** + * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch + * safe) + * @old: old value + * @div: divisor + * @mult: multiplier + * + * + * new = old * mult / div + */ +static inline unsigned long cpufreq_scale(unsigned long old, u_int div, + u_int mult) { - return 0; -} +#if BITS_PER_LONG == 32 + u64 result = ((u64) old) * ((u64) mult); + do_div(result, div); + return (unsigned long) result; + +#elif BITS_PER_LONG == 64 + unsigned long result = old * ((u64) mult); + result /= div; + return result; #endif +} /********************************************************************* - * CPUFREQ DEFAULT GOVERNOR * + * CPUFREQ GOVERNORS * *********************************************************************/ /* + * If (cpufreq_driver->target) exists, the ->governor decides what frequency + * within the limits is used. If (cpufreq_driver->setpolicy> exists, these + * two generic policies are available: + */ +#define CPUFREQ_POLICY_POWERSAVE (1) +#define CPUFREQ_POLICY_PERFORMANCE (2) + +/* Governor Events */ +#define CPUFREQ_GOV_START 1 +#define CPUFREQ_GOV_STOP 2 +#define CPUFREQ_GOV_LIMITS 3 +#define CPUFREQ_GOV_POLICY_INIT 4 +#define CPUFREQ_GOV_POLICY_EXIT 5 + +struct cpufreq_governor { + char name[CPUFREQ_NAME_LEN]; + int initialized; + int (*governor) (struct cpufreq_policy *policy, + unsigned int event); + ssize_t (*show_setspeed) (struct cpufreq_policy *policy, + char *buf); + int (*store_setspeed) (struct cpufreq_policy *policy, + unsigned int freq); + unsigned int max_transition_latency; /* HW must be able to switch to + next freq faster than this value in nano secs or we + will fallback to performance governor */ + struct list_head governor_list; + struct module *owner; +}; + +/* Pass a target to the cpufreq driver */ +int cpufreq_driver_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); +int __cpufreq_driver_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); +int cpufreq_register_governor(struct cpufreq_governor *governor); +void cpufreq_unregister_governor(struct cpufreq_governor *governor); + +/* CPUFREQ DEFAULT GOVERNOR */ +/* * Performance governor is fallback governor if any other gov failed to auto * load due latency restrictions */ @@ -417,18 +400,16 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, unsigned int relation, unsigned int *index); -/* the following 3 funtions are for cpufreq core use only */ +void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); +ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); + +/* the following funtion is for cpufreq core use only */ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu); /* the following are really really optional */ extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; - void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, unsigned int cpu); -void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); - void cpufreq_frequency_table_put_attr(unsigned int cpu); -ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); - #endif /* _LINUX_CPUFREQ_H */ -- cgit v0.10.2 From 3a3e9e06d0c11b8efa95933a88c9e67209fa4330 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:05 +0530 Subject: cpufreq: Give consistent names to cpufreq_policy objects They are called policy, cur_policy, new_policy, data, etc. Just call them policy wherever possible. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8458371..1793fe8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -179,7 +179,7 @@ EXPORT_SYMBOL_GPL(get_cpu_idle_time); static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) { - struct cpufreq_policy *data; + struct cpufreq_policy *policy; unsigned long flags; if (cpu >= nr_cpu_ids) @@ -195,16 +195,16 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) goto err_out_unlock; /* get the CPU */ - data = per_cpu(cpufreq_cpu_data, cpu); + policy = per_cpu(cpufreq_cpu_data, cpu); - if (!data) + if (!policy) goto err_out_put_module; - if (!sysfs && !kobject_get(&data->kobj)) + if (!sysfs && !kobject_get(&policy->kobj)) goto err_out_put_module; read_unlock_irqrestore(&cpufreq_driver_lock, flags); - return data; + return policy; err_out_put_module: module_put(cpufreq_driver->owner); @@ -228,25 +228,25 @@ static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu) return __cpufreq_cpu_get(cpu, true); } -static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs) +static void __cpufreq_cpu_put(struct cpufreq_policy *policy, bool sysfs) { if (!sysfs) - kobject_put(&data->kobj); + kobject_put(&policy->kobj); module_put(cpufreq_driver->owner); } -void cpufreq_cpu_put(struct cpufreq_policy *data) +void cpufreq_cpu_put(struct cpufreq_policy *policy) { if (cpufreq_disabled()) return; - __cpufreq_cpu_put(data, false); + __cpufreq_cpu_put(policy, false); } EXPORT_SYMBOL_GPL(cpufreq_cpu_put); -static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data) +static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *policy) { - __cpufreq_cpu_put(data, true); + __cpufreq_cpu_put(policy, true); } /********************************************************************* @@ -453,8 +453,8 @@ show_one(scaling_min_freq, min); show_one(scaling_max_freq, max); show_one(scaling_cur_freq, cur); -static int __cpufreq_set_policy(struct cpufreq_policy *data, - struct cpufreq_policy *policy); +static int __cpufreq_set_policy(struct cpufreq_policy *policy, + struct cpufreq_policy *new_policy); /** * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access @@ -1136,7 +1136,7 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) CPUFREQ_UPDATE_POLICY_CPU, policy); } -static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, +static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, unsigned int old_cpu, bool frozen) { struct device *cpu_dev; @@ -1144,27 +1144,27 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, int ret; /* first sibling now owns the new sysfs dir */ - cpu_dev = get_cpu_device(cpumask_first(data->cpus)); + cpu_dev = get_cpu_device(cpumask_first(policy->cpus)); /* Don't touch sysfs files during light-weight tear-down */ if (frozen) return cpu_dev->id; sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); - ret = kobject_move(&data->kobj, &cpu_dev->kobj); + ret = kobject_move(&policy->kobj, &cpu_dev->kobj); if (ret) { pr_err("%s: Failed to move kobj: %d", __func__, ret); WARN_ON(lock_policy_rwsem_write(old_cpu)); - cpumask_set_cpu(old_cpu, data->cpus); + cpumask_set_cpu(old_cpu, policy->cpus); write_lock_irqsave(&cpufreq_driver_lock, flags); - per_cpu(cpufreq_cpu_data, old_cpu) = data; + per_cpu(cpufreq_cpu_data, old_cpu) = policy; write_unlock_irqrestore(&cpufreq_driver_lock, flags); unlock_policy_rwsem_write(old_cpu); - ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, + ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, "cpufreq"); return -EINVAL; @@ -1186,7 +1186,7 @@ static int __cpufreq_remove_dev(struct device *dev, unsigned int cpu = dev->id, cpus; int new_cpu; unsigned long flags; - struct cpufreq_policy *data; + struct cpufreq_policy *policy; struct kobject *kobj; struct completion *cmp; @@ -1194,44 +1194,44 @@ static int __cpufreq_remove_dev(struct device *dev, write_lock_irqsave(&cpufreq_driver_lock, flags); - data = per_cpu(cpufreq_cpu_data, cpu); + policy = per_cpu(cpufreq_cpu_data, cpu); per_cpu(cpufreq_cpu_data, cpu) = NULL; /* Save the policy somewhere when doing a light-weight tear-down */ if (frozen) - per_cpu(cpufreq_cpu_data_fallback, cpu) = data; + per_cpu(cpufreq_cpu_data_fallback, cpu) = policy; write_unlock_irqrestore(&cpufreq_driver_lock, flags); - if (!data) { + if (!policy) { pr_debug("%s: No cpu_data found\n", __func__); return -EINVAL; } if (cpufreq_driver->target) - __cpufreq_governor(data, CPUFREQ_GOV_STOP); + __cpufreq_governor(policy, CPUFREQ_GOV_STOP); #ifdef CONFIG_HOTPLUG_CPU if (!cpufreq_driver->setpolicy) strncpy(per_cpu(cpufreq_cpu_governor, cpu), - data->governor->name, CPUFREQ_NAME_LEN); + policy->governor->name, CPUFREQ_NAME_LEN); #endif WARN_ON(lock_policy_rwsem_write(cpu)); - cpus = cpumask_weight(data->cpus); + cpus = cpumask_weight(policy->cpus); if (cpus > 1) - cpumask_clear_cpu(cpu, data->cpus); + cpumask_clear_cpu(cpu, policy->cpus); unlock_policy_rwsem_write(cpu); - if (cpu != data->cpu && !frozen) { + if (cpu != policy->cpu && !frozen) { sysfs_remove_link(&dev->kobj, "cpufreq"); } else if (cpus > 1) { - new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu, frozen); + new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen); if (new_cpu >= 0) { WARN_ON(lock_policy_rwsem_write(cpu)); - update_policy_cpu(data, new_cpu); + update_policy_cpu(policy, new_cpu); unlock_policy_rwsem_write(cpu); if (!frozen) { @@ -1244,12 +1244,12 @@ static int __cpufreq_remove_dev(struct device *dev, /* If cpu is last user of policy, free policy */ if (cpus == 1) { if (cpufreq_driver->target) - __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); + __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); if (!frozen) { lock_policy_rwsem_read(cpu); - kobj = &data->kobj; - cmp = &data->kobj_unregister; + kobj = &policy->kobj; + cmp = &policy->kobj_unregister; unlock_policy_rwsem_read(cpu); kobject_put(kobj); @@ -1269,14 +1269,14 @@ static int __cpufreq_remove_dev(struct device *dev, * subsequent light-weight ->init() to succeed. */ if (cpufreq_driver->exit) - cpufreq_driver->exit(data); + cpufreq_driver->exit(policy); if (!frozen) - cpufreq_policy_free(data); + cpufreq_policy_free(policy); } else { if (cpufreq_driver->target) { - __cpufreq_governor(data, CPUFREQ_GOV_START); - __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); + __cpufreq_governor(policy, CPUFREQ_GOV_START); + __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); } } @@ -1450,23 +1450,23 @@ static int cpufreq_bp_suspend(void) int ret = 0; int cpu = smp_processor_id(); - struct cpufreq_policy *cpu_policy; + struct cpufreq_policy *policy; pr_debug("suspending cpu %u\n", cpu); /* If there's no policy for the boot CPU, we have nothing to do. */ - cpu_policy = cpufreq_cpu_get(cpu); - if (!cpu_policy) + policy = cpufreq_cpu_get(cpu); + if (!policy) return 0; if (cpufreq_driver->suspend) { - ret = cpufreq_driver->suspend(cpu_policy); + ret = cpufreq_driver->suspend(policy); if (ret) printk(KERN_ERR "cpufreq: suspend failed in ->suspend " - "step on CPU %u\n", cpu_policy->cpu); + "step on CPU %u\n", policy->cpu); } - cpufreq_cpu_put(cpu_policy); + cpufreq_cpu_put(policy); return ret; } @@ -1488,28 +1488,28 @@ static void cpufreq_bp_resume(void) int ret = 0; int cpu = smp_processor_id(); - struct cpufreq_policy *cpu_policy; + struct cpufreq_policy *policy; pr_debug("resuming cpu %u\n", cpu); /* If there's no policy for the boot CPU, we have nothing to do. */ - cpu_policy = cpufreq_cpu_get(cpu); - if (!cpu_policy) + policy = cpufreq_cpu_get(cpu); + if (!policy) return; if (cpufreq_driver->resume) { - ret = cpufreq_driver->resume(cpu_policy); + ret = cpufreq_driver->resume(policy); if (ret) { printk(KERN_ERR "cpufreq: resume failed in ->resume " - "step on CPU %u\n", cpu_policy->cpu); + "step on CPU %u\n", policy->cpu); goto fail; } } - schedule_work(&cpu_policy->update); + schedule_work(&policy->update); fail: - cpufreq_cpu_put(cpu_policy); + cpufreq_cpu_put(policy); } static struct syscore_ops cpufreq_syscore_ops = { @@ -1829,95 +1829,95 @@ EXPORT_SYMBOL(cpufreq_get_policy); * data : current policy. * policy : policy to be set. */ -static int __cpufreq_set_policy(struct cpufreq_policy *data, - struct cpufreq_policy *policy) +static int __cpufreq_set_policy(struct cpufreq_policy *policy, + struct cpufreq_policy *new_policy) { int ret = 0, failed = 1; - pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, - policy->min, policy->max); + pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu, + new_policy->min, new_policy->max); - memcpy(&policy->cpuinfo, &data->cpuinfo, + memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(struct cpufreq_cpuinfo)); - if (policy->min > data->max || policy->max < data->min) { + if (new_policy->min > policy->max || new_policy->max < policy->min) { ret = -EINVAL; goto error_out; } /* verify the cpu speed can be set within this limit */ - ret = cpufreq_driver->verify(policy); + ret = cpufreq_driver->verify(new_policy); if (ret) goto error_out; /* adjust if necessary - all reasons */ blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_ADJUST, policy); + CPUFREQ_ADJUST, new_policy); /* adjust if necessary - hardware incompatibility*/ blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_INCOMPATIBLE, policy); + CPUFREQ_INCOMPATIBLE, new_policy); /* * verify the cpu speed can be set within this limit, which might be * different to the first one */ - ret = cpufreq_driver->verify(policy); + ret = cpufreq_driver->verify(new_policy); if (ret) goto error_out; /* notification of the new policy */ blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_NOTIFY, policy); + CPUFREQ_NOTIFY, new_policy); - data->min = policy->min; - data->max = policy->max; + policy->min = new_policy->min; + policy->max = new_policy->max; pr_debug("new min and max freqs are %u - %u kHz\n", - data->min, data->max); + policy->min, policy->max); if (cpufreq_driver->setpolicy) { - data->policy = policy->policy; + policy->policy = new_policy->policy; pr_debug("setting range\n"); - ret = cpufreq_driver->setpolicy(policy); + ret = cpufreq_driver->setpolicy(new_policy); } else { - if (policy->governor != data->governor) { + if (new_policy->governor != policy->governor) { /* save old, working values */ - struct cpufreq_governor *old_gov = data->governor; + struct cpufreq_governor *old_gov = policy->governor; pr_debug("governor switch\n"); /* end old governor */ - if (data->governor) { - __cpufreq_governor(data, CPUFREQ_GOV_STOP); - unlock_policy_rwsem_write(policy->cpu); - __cpufreq_governor(data, + if (policy->governor) { + __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + unlock_policy_rwsem_write(new_policy->cpu); + __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); - lock_policy_rwsem_write(policy->cpu); + lock_policy_rwsem_write(new_policy->cpu); } /* start new governor */ - data->governor = policy->governor; - if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) { - if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) { + policy->governor = new_policy->governor; + if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) { + if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) { failed = 0; } else { - unlock_policy_rwsem_write(policy->cpu); - __cpufreq_governor(data, + unlock_policy_rwsem_write(new_policy->cpu); + __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); - lock_policy_rwsem_write(policy->cpu); + lock_policy_rwsem_write(new_policy->cpu); } } if (failed) { /* new governor failed, so re-start old one */ pr_debug("starting governor %s failed\n", - data->governor->name); + policy->governor->name); if (old_gov) { - data->governor = old_gov; - __cpufreq_governor(data, + policy->governor = old_gov; + __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT); - __cpufreq_governor(data, + __cpufreq_governor(policy, CPUFREQ_GOV_START); } ret = -EINVAL; @@ -1926,7 +1926,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, /* might be a policy change, too, so fall through */ } pr_debug("governor: change or update limits\n"); - __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); + __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); } error_out: @@ -1942,11 +1942,11 @@ error_out: */ int cpufreq_update_policy(unsigned int cpu) { - struct cpufreq_policy *data = cpufreq_cpu_get(cpu); - struct cpufreq_policy policy; + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy new_policy; int ret; - if (!data) { + if (!policy) { ret = -ENODEV; goto no_policy; } @@ -1957,34 +1957,34 @@ int cpufreq_update_policy(unsigned int cpu) } pr_debug("updating policy for CPU %u\n", cpu); - memcpy(&policy, data, sizeof(struct cpufreq_policy)); - policy.min = data->user_policy.min; - policy.max = data->user_policy.max; - policy.policy = data->user_policy.policy; - policy.governor = data->user_policy.governor; + memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); + new_policy.min = policy->user_policy.min; + new_policy.max = policy->user_policy.max; + new_policy.policy = policy->user_policy.policy; + new_policy.governor = policy->user_policy.governor; /* * BIOS might change freq behind our back * -> ask driver for current freq and notify governors about a change */ if (cpufreq_driver->get) { - policy.cur = cpufreq_driver->get(cpu); - if (!data->cur) { + new_policy.cur = cpufreq_driver->get(cpu); + if (!policy->cur) { pr_debug("Driver did not initialize current freq"); - data->cur = policy.cur; + policy->cur = new_policy.cur; } else { - if (data->cur != policy.cur && cpufreq_driver->target) - cpufreq_out_of_sync(cpu, data->cur, - policy.cur); + if (policy->cur != new_policy.cur && cpufreq_driver->target) + cpufreq_out_of_sync(cpu, policy->cur, + new_policy.cur); } } - ret = __cpufreq_set_policy(data, &policy); + ret = __cpufreq_set_policy(policy, &new_policy); unlock_policy_rwsem_write(cpu); fail: - cpufreq_cpu_put(data); + cpufreq_cpu_put(policy); no_policy: return ret; } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index cf0b7a4..264e509 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -221,7 +221,7 @@ struct od_ops { void (*powersave_bias_init_cpu)(int cpu); unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy, unsigned int freq_next, unsigned int relation); - void (*freq_increase)(struct cpufreq_policy *p, unsigned int freq); + void (*freq_increase)(struct cpufreq_policy *policy, unsigned int freq); }; struct cs_ops { diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 27c732e..47d4b69b 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -132,18 +132,18 @@ static void ondemand_powersave_bias_init(void) } } -static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) +static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq) { - struct dbs_data *dbs_data = p->governor_data; + struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; if (od_tuners->powersave_bias) - freq = od_ops.powersave_bias_target(p, freq, + freq = od_ops.powersave_bias_target(policy, freq, CPUFREQ_RELATION_H); - else if (p->cur == p->max) + else if (policy->cur == policy->max) return; - __cpufreq_driver_target(p, freq, od_tuners->powersave_bias ? + __cpufreq_driver_target(policy, freq, od_tuners->powersave_bias ? CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index a7143b0..a17b14e 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -193,7 +193,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, { unsigned int i, j, count = 0, ret = 0; struct cpufreq_stats *stat; - struct cpufreq_policy *data; + struct cpufreq_policy *current_policy; unsigned int alloc_size; unsigned int cpu = policy->cpu; if (per_cpu(cpufreq_stats_table, cpu)) @@ -202,13 +202,13 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, if ((stat) == NULL) return -ENOMEM; - data = cpufreq_cpu_get(cpu); - if (data == NULL) { + current_policy = cpufreq_cpu_get(cpu); + if (current_policy == NULL) { ret = -EINVAL; goto error_get_fail; } - ret = sysfs_create_group(&data->kobj, &stats_attr_group); + ret = sysfs_create_group(¤t_policy->kobj, &stats_attr_group); if (ret) goto error_out; @@ -251,10 +251,10 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, stat->last_time = get_jiffies_64(); stat->last_index = freq_table_get_index(stat, policy->cur); spin_unlock(&cpufreq_stats_lock); - cpufreq_cpu_put(data); + cpufreq_cpu_put(current_policy); return 0; error_out: - cpufreq_cpu_put(data); + cpufreq_cpu_put(current_policy); error_get_fail: kfree(stat); per_cpu(cpufreq_stats_table, cpu) = NULL; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 0d3b026..2920892 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -94,7 +94,7 @@ struct cpufreq_policy { #define CPUFREQ_SHARED_TYPE_ANY (3) /* Freq can be set from any dependent CPU*/ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu); -void cpufreq_cpu_put(struct cpufreq_policy *data); +void cpufreq_cpu_put(struct cpufreq_policy *policy); static inline bool policy_is_shared(struct cpufreq_policy *policy) { -- cgit v0.10.2 From d5b73cd870e2b049ef566aec2791dbf5fd26a7ec Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:06 +0530 Subject: cpufreq: Use sizeof(*ptr) convetion for computing sizes Chapter 14 of Documentation/CodingStyle says: The preferred form for passing a size of a struct is the following: p = kmalloc(sizeof(*p), ...); The alternative form where struct name is spelled out hurts readability and introduces an opportunity for a bug when the pointer variable type is changed but the corresponding sizeof that is passed to a memory allocator is not. This wasn't followed consistently in drivers/cpufreq, let's make it more consistent by always following this rule. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index e673670..44758ce 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -709,7 +709,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) return blacklisted; #endif - data = kzalloc(sizeof(struct acpi_cpufreq_data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -799,7 +799,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) goto err_unreg; } - data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * + data->freq_table = kmalloc(sizeof(*data->freq_table) * (perf->state_count+1), GFP_KERNEL); if (!data->freq_table) { result = -ENOMEM; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1793fe8..9e83d91 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -873,7 +873,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) struct cpufreq_policy new_policy; int ret = 0; - memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); + memcpy(&new_policy, policy, sizeof(*policy)); /* assure that the starting sequence is run in __cpufreq_set_policy */ policy->governor = NULL; @@ -1818,7 +1818,7 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) if (!cpu_policy) return -EINVAL; - memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); + memcpy(policy, cpu_policy, sizeof(*policy)); cpufreq_cpu_put(cpu_policy); return 0; @@ -1837,8 +1837,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *policy, pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu, new_policy->min, new_policy->max); - memcpy(&new_policy->cpuinfo, &policy->cpuinfo, - sizeof(struct cpufreq_cpuinfo)); + memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo)); if (new_policy->min > policy->max || new_policy->max < policy->min) { ret = -EINVAL; @@ -1957,7 +1956,7 @@ int cpufreq_update_policy(unsigned int cpu) } pr_debug("updating policy for CPU %u\n", cpu); - memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); + memcpy(&new_policy, policy, sizeof(*policy)); new_policy.min = policy->user_policy.min; new_policy.max = policy->user_policy.max; new_policy.policy = policy->user_policy.policy; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 841e256..c400924 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -317,7 +317,7 @@ static int cs_init(struct dbs_data *dbs_data) { struct cs_dbs_tuners *tuners; - tuners = kzalloc(sizeof(struct cs_dbs_tuners), GFP_KERNEL); + tuners = kzalloc(sizeof(*tuners), GFP_KERNEL); if (!tuners) { pr_err("%s: kzalloc failed\n", __func__); return -ENOMEM; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 47d4b69b..117278a 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -482,7 +482,7 @@ static int od_init(struct dbs_data *dbs_data) u64 idle_time; int cpu; - tuners = kzalloc(sizeof(struct od_dbs_tuners), GFP_KERNEL); + tuners = kzalloc(sizeof(*tuners), GFP_KERNEL); if (!tuners) { pr_err("%s: kzalloc failed\n", __func__); return -ENOMEM; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index a17b14e..04452f0 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -198,7 +198,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, unsigned int cpu = policy->cpu; if (per_cpu(cpufreq_stats_table, cpu)) return -EBUSY; - stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL); + stat = kzalloc(sizeof(*stat), GFP_KERNEL); if ((stat) == NULL) return -ENOMEM; diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index a60efae..de974be 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -54,7 +54,7 @@ static struct acpi_processor_performance *eps_acpi_cpu_perf; /* Minimum necessary to get acpi_processor_get_bios_limit() working */ static int eps_acpi_init(void) { - eps_acpi_cpu_perf = kzalloc(sizeof(struct acpi_processor_performance), + eps_acpi_cpu_perf = kzalloc(sizeof(*eps_acpi_cpu_perf), GFP_KERNEL); if (!eps_acpi_cpu_perf) return -ENOMEM; @@ -366,7 +366,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy) states = 2; /* Allocate private data and frequency table for current cpu */ - centaur = kzalloc(sizeof(struct eps_cpu_data) + centaur = kzalloc(sizeof(*centaur) + (states + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL); if (!centaur) diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 0d32f02..3664751 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -289,7 +289,7 @@ static int __init exynos_cpufreq_init(void) { int ret = -EINVAL; - exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL); + exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL); if (!exynos_info) return -ENOMEM; diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c index 3dfc99b..4f25fb6 100644 --- a/drivers/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -466,7 +466,7 @@ static int __init cpufreq_gx_init(void) pr_debug("geode suspend modulation available.\n"); - params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL); + params = kzalloc(sizeof(*params), GFP_KERNEL); if (params == NULL) return -ENOMEM; diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index 573c14e..08792dd 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -274,7 +274,7 @@ acpi_cpufreq_cpu_init ( pr_debug("acpi_cpufreq_cpu_init\n"); - data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return (-ENOMEM); @@ -304,7 +304,7 @@ acpi_cpufreq_cpu_init ( } /* alloc freq_table */ - data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * + data->freq_table = kmalloc(sizeof(*data->freq_table) * (data->acpi_data.state_count + 1), GFP_KERNEL); if (!data->freq_table) { diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c index 7ba4234..4d7799b 100644 --- a/drivers/cpufreq/pmac64-cpufreq.c +++ b/drivers/cpufreq/pmac64-cpufreq.c @@ -447,9 +447,8 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus) if (!shdr) goto bail_noprops; g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1]; - ssize = (shdr->len * sizeof(u32)) - - sizeof(struct smu_sdbp_header); - g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt); + ssize = (shdr->len * sizeof(u32)) - sizeof(*shdr); + g5_fvt_count = ssize / sizeof(*g5_fvt_table); g5_fvt_cur = 0; /* Sanity checking */ diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 9558708..4687d40 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -177,7 +177,7 @@ static int get_ranges(unsigned char *pst) unsigned int speed; u8 fid, vid; - powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * + powernow_table = kzalloc((sizeof(*powernow_table) * (number_scales + 1)), GFP_KERNEL); if (!powernow_table) return -ENOMEM; @@ -309,8 +309,7 @@ static int powernow_acpi_init(void) goto err0; } - acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance), - GFP_KERNEL); + acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL); if (!acpi_processor_perf) { retval = -ENOMEM; goto err0; @@ -346,7 +345,7 @@ static int powernow_acpi_init(void) goto err2; } - powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * + powernow_table = kzalloc((sizeof(*powernow_table) * (number_scales + 1)), GFP_KERNEL); if (!powernow_table) { retval = -ENOMEM; @@ -497,7 +496,7 @@ static int powernow_decode_bios(int maxfid, int startvid) "relevant to this CPU).\n", psb->numpst); - p += sizeof(struct psb_s); + p += sizeof(*psb); pst = (struct pst_s *) p; @@ -510,12 +509,12 @@ static int powernow_decode_bios(int maxfid, int startvid) (maxfid == pst->maxfid) && (startvid == pst->startvid)) { print_pst_entry(pst, j); - p = (char *)pst + sizeof(struct pst_s); + p = (char *)pst + sizeof(*pst); ret = get_ranges(p); return ret; } else { unsigned int k; - p = (char *)pst + sizeof(struct pst_s); + p = (char *)pst + sizeof(*pst); for (k = 0; k < number_scales; k++) p += 2; } diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index c39d189..3f3c6ca 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -623,7 +623,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, if (check_pst_table(data, pst, maxvid)) return -EINVAL; - powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) + powernow_table = kmalloc((sizeof(*powernow_table) * (data->numps + 1)), GFP_KERNEL); if (!powernow_table) { printk(KERN_ERR PFX "powernow_table memory alloc failure\n"); @@ -793,7 +793,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) } /* fill in data->powernow_table */ - powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) + powernow_table = kmalloc((sizeof(*powernow_table) * (data->acpi_data.state_count + 1)), GFP_KERNEL); if (!powernow_table) { pr_debug("powernow_table memory alloc failure\n"); @@ -1106,7 +1106,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) if (rc) return -ENODEV; - data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) { printk(KERN_ERR PFX "unable to alloc powernow_k8_data"); return -ENOMEM; diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 87781eb..f169ee5 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -522,7 +522,7 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board) /* Copy the board information so that each board can make this * initdata. */ - ours = kzalloc(sizeof(struct s3c_cpufreq_board), GFP_KERNEL); + ours = kzalloc(sizeof(*ours), GFP_KERNEL); if (ours == NULL) { printk(KERN_ERR "%s: no memory\n", __func__); return -ENOMEM; @@ -615,7 +615,7 @@ static int s3c_cpufreq_build_freq(void) size = cpu_cur.info->calc_freqtable(&cpu_cur, NULL, 0); size++; - ftab = kmalloc(sizeof(struct cpufreq_frequency_table) * size, GFP_KERNEL); + ftab = kmalloc(sizeof(*ftab) * size, GFP_KERNEL); if (!ftab) { printk(KERN_ERR "%s: no memory for tables\n", __func__); return -ENOMEM; @@ -691,7 +691,7 @@ int __init s3c_plltab_register(struct cpufreq_frequency_table *plls, struct cpufreq_frequency_table *vals; unsigned int size; - size = sizeof(struct cpufreq_frequency_table) * (plls_no + 1); + size = sizeof(*vals) * (plls_no + 1); vals = kmalloc(size, GFP_KERNEL); if (vals) { diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c index 93061a4..7c43a72 100644 --- a/drivers/cpufreq/sparc-us2e-cpufreq.c +++ b/drivers/cpufreq/sparc-us2e-cpufreq.c @@ -351,12 +351,11 @@ static int __init us2e_freq_init(void) struct cpufreq_driver *driver; ret = -ENOMEM; - driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); + driver = kzalloc(sizeof(*driver), GFP_KERNEL); if (!driver) goto err_out; - us2e_freq_table = kzalloc( - (NR_CPUS * sizeof(struct us2e_freq_percpu_info)), + us2e_freq_table = kzalloc((NR_CPUS * sizeof(*us2e_freq_table)), GFP_KERNEL); if (!us2e_freq_table) goto err_out; diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c index 880ee29..7f500c1 100644 --- a/drivers/cpufreq/sparc-us3-cpufreq.c +++ b/drivers/cpufreq/sparc-us3-cpufreq.c @@ -212,12 +212,11 @@ static int __init us3_freq_init(void) struct cpufreq_driver *driver; ret = -ENOMEM; - driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); + driver = kzalloc(sizeof(*driver), GFP_KERNEL); if (!driver) goto err_out; - us3_freq_table = kzalloc( - (NR_CPUS * sizeof(struct us3_freq_percpu_info)), + us3_freq_table = kzalloc((NR_CPUS * sizeof(*us3_freq_table)), GFP_KERNEL); if (!us3_freq_table) goto err_out; -- cgit v0.10.2 From 3fe444ad7e3a6951fa0c9b552c5afe6f6df0d571 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Aug 2013 01:15:25 +0200 Subject: ACPI: Do not fail acpi_bind_one() if device is already bound correctly Modify acpi_bind_one() so that it doesn't fail if the device represented by its first argument has already been bound to the given ACPI handle (second argument), because that is not a good enough reason for returning an error code. Signed-off-by: Rafael J. Wysocki Reviewed-by: Lan Tianyu Acked-by: Toshi Kani diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 408f6b2..48cc4c9 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -217,7 +217,10 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) /* Sanity check. */ if (pn->dev == dev) { dev_warn(dev, "Already associated with ACPI node\n"); - goto err_free; + if (ACPI_HANDLE(dev) == handle) + retval = 0; + + goto out_free; } if (pn->node_id == node_id) { physnode_list = &pn->node; @@ -255,10 +258,14 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) put_device(dev); return retval; - err_free: + out_free: mutex_unlock(&acpi_dev->physical_node_lock); kfree(physical_node); - goto err; + if (retval) + goto err; + + put_device(dev); + return 0; } EXPORT_SYMBOL_GPL(acpi_bind_one); -- cgit v0.10.2 From bdbdbf91081250657d018fc66d7cd0c07f337070 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Aug 2013 01:19:23 +0200 Subject: ACPI: Reduce acpi_bind_one()/acpi_unbind_one() code duplication Move some duplicated code from acpi_bind_one() and acpi_unbind_one() into a separate function and make that function use snprintf() instead of sprintf() for extra safety. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yasuaki Ishimatsu diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 48cc4c9..92cacb1 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -173,6 +173,15 @@ acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge) } EXPORT_SYMBOL_GPL(acpi_find_child); +static void acpi_physnode_link_name(char *buf, unsigned int node_id) +{ + if (node_id > 0) + snprintf(buf, PHYSICAL_NODE_NAME_SIZE, + PHYSICAL_NODE_STRING "%u", node_id); + else + strcpy(buf, PHYSICAL_NODE_STRING); +} + int acpi_bind_one(struct device *dev, acpi_handle handle) { struct acpi_device *acpi_dev; @@ -238,11 +247,7 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) if (!ACPI_HANDLE(dev)) ACPI_HANDLE_SET(dev, acpi_dev->handle); - if (!physical_node->node_id) - strcpy(physical_node_name, PHYSICAL_NODE_STRING); - else - sprintf(physical_node_name, - "physical_node%d", physical_node->node_id); + acpi_physnode_link_name(physical_node_name, node_id); retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, physical_node_name); retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, @@ -296,12 +301,7 @@ int acpi_unbind_one(struct device *dev) acpi_dev->physical_node_count--; - if (!entry->node_id) - strcpy(physical_node_name, PHYSICAL_NODE_STRING); - else - sprintf(physical_node_name, - "physical_node%d", entry->node_id); - + acpi_physnode_link_name(physical_node_name, entry->node_id); sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name); sysfs_remove_link(&dev->kobj, "firmware_node"); ACPI_HANDLE_SET(dev, NULL); -- cgit v0.10.2 From 4005520648c7d6cf28e74addb52bc4a793eea3eb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Aug 2013 01:19:37 +0200 Subject: ACPI: Create symlinks in acpi_bind_one() under physical_node_lock Put the creation of symlinks in acpi_bind_one() under the physical_node_lock mutex of the given ACPI device object, because that is part of the binding operation logically (those links are already removed under that mutex too). Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yasuaki Ishimatsu diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 92cacb1..914a346 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -242,8 +242,6 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) list_add(&physical_node->node, physnode_list); acpi_dev->physical_node_count++; - mutex_unlock(&acpi_dev->physical_node_lock); - if (!ACPI_HANDLE(dev)) ACPI_HANDLE_SET(dev, acpi_dev->handle); @@ -253,6 +251,8 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, "firmware_node"); + mutex_unlock(&acpi_dev->physical_node_lock); + if (acpi_dev->wakeup.flags.valid) device_set_wakeup_capable(dev, true); -- cgit v0.10.2 From f501b6ec290f59b9c444bc061acf0e422347fb55 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Aug 2013 01:19:52 +0200 Subject: ACPI: acpi_bind_one()/acpi_unbind_one() whitespace cleanups Clean up some inconsistent use of whitespace in acpi_bind_one() and acpi_unbind_one(). Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yasuaki Ishimatsu diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 914a346..69641c0 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -247,9 +247,9 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) acpi_physnode_link_name(physical_node_name, node_id); retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, - physical_node_name); + physical_node_name); retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, - "firmware_node"); + "firmware_node"); mutex_unlock(&acpi_dev->physical_node_lock); @@ -293,12 +293,11 @@ int acpi_unbind_one(struct device *dev) char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; entry = list_entry(node, struct acpi_device_physical_node, - node); + node); if (entry->dev != dev) continue; list_del(node); - acpi_dev->physical_node_count--; acpi_physnode_link_name(physical_node_name, entry->node_id); -- cgit v0.10.2 From 3e3327837c180781960188563b4e4d5c004c2b29 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Aug 2013 01:22:08 +0200 Subject: ACPI: Use list_for_each_entry() in acpi_unbind_one() Since acpi_unbind_one() walks physical_node_list under the ACPI device object's physical_node_lock mutex and the walk may be terminated as soon as the matching entry has been found, it is not necessary to use list_for_each_safe() for that walk, so use list_for_each_entry() instead and make the code slightly more straightforward. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yasuaki Ishimatsu diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 69641c0..570628e 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -279,7 +279,6 @@ int acpi_unbind_one(struct device *dev) struct acpi_device_physical_node *entry; struct acpi_device *acpi_dev; acpi_status status; - struct list_head *node, *next; if (!ACPI_HANDLE(dev)) return 0; @@ -289,25 +288,24 @@ int acpi_unbind_one(struct device *dev) goto err; mutex_lock(&acpi_dev->physical_node_lock); - list_for_each_safe(node, next, &acpi_dev->physical_node_list) { - char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; - - entry = list_entry(node, struct acpi_device_physical_node, - node); - if (entry->dev != dev) - continue; - - list_del(node); - acpi_dev->physical_node_count--; - - acpi_physnode_link_name(physical_node_name, entry->node_id); - sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name); - sysfs_remove_link(&dev->kobj, "firmware_node"); - ACPI_HANDLE_SET(dev, NULL); - /* acpi_bind_one increase refcnt by one */ - put_device(dev); - kfree(entry); - } + + list_for_each_entry(entry, &acpi_dev->physical_node_list, node) + if (entry->dev == dev) { + char physnode_name[PHYSICAL_NODE_NAME_SIZE]; + + list_del(&entry->node); + acpi_dev->physical_node_count--; + + acpi_physnode_link_name(physnode_name, entry->node_id); + sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name); + sysfs_remove_link(&dev->kobj, "firmware_node"); + ACPI_HANDLE_SET(dev, NULL); + /* acpi_bind_one() increase refcnt by one. */ + put_device(dev); + kfree(entry); + break; + } + mutex_unlock(&acpi_dev->physical_node_lock); return 0; -- cgit v0.10.2 From 38e88839eff8a3d2e8d3bcc2ad833fe51cca0496 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Aug 2013 01:22:51 +0200 Subject: ACPI: Clean up error code path in acpi_unbind_one() The error code path in acpi_unbind_one() is unnecessarily complicated (in particular, the err label is not really necessary) and the error message printed by it is inaccurate (there's nothing called 'acpi_handle' in that function), so clean up those things. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yasuaki Ishimatsu diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 570628e..dcba319 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -284,8 +284,10 @@ int acpi_unbind_one(struct device *dev) return 0; status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev); - if (ACPI_FAILURE(status)) - goto err; + if (ACPI_FAILURE(status)) { + dev_err(dev, "Oops, ACPI handle corrupt in %s()\n", __func__); + return -EINVAL; + } mutex_lock(&acpi_dev->physical_node_lock); @@ -307,12 +309,7 @@ int acpi_unbind_one(struct device *dev) } mutex_unlock(&acpi_dev->physical_node_lock); - return 0; - -err: - dev_err(dev, "Oops, 'acpi_handle' corrupt\n"); - return -EINVAL; } EXPORT_SYMBOL_GPL(acpi_unbind_one); -- cgit v0.10.2 From 6cef74970186797c45b3add1e73a14aa71d338d1 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 7 Aug 2013 17:16:55 +0530 Subject: ACPI / EC: Fix incorrect placement of __initdata __initdata should be placed between the variable name and equal sign for the variable to be placed in the intended section. Signed-off-by: Sachin Kamat Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 80403c1..3444803 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -948,7 +948,7 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id) return 0; } -static struct dmi_system_id __initdata ec_dmi_table[] = { +static struct dmi_system_id ec_dmi_table[] __initdata = { { ec_skip_dsdt_scan, "Compal JFL92", { DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), -- cgit v0.10.2 From 8ef9fc78911ef64df98feba8ad12e406e8fa479b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 7 Aug 2013 17:16:56 +0530 Subject: ACPI / processor: Fix incorrect placement of __initdata __initdata should be placed between the variable name and equal sign for the variable to be placed in the intended section. Signed-off-by: Sachin Kamat Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 164d495..210079c 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -28,7 +28,7 @@ static int __init set_no_mwait(const struct dmi_system_id *id) return 0; } -static struct dmi_system_id __initdata processor_idle_dmi_table[] = { +static struct dmi_system_id processor_idle_dmi_table[] __initdata = { { set_no_mwait, "Extensa 5220", { DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), -- cgit v0.10.2 From 3e4376ffcec8e51091bd8ea54da8323e7b912971 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 7 Aug 2013 17:16:57 +0530 Subject: ACPI / Sleep: Fix incorrect placement of __initdata __initdata should be placed between the variable name and equal sign for the variable to be placed in the intended section. Signed-off-by: Sachin Kamat Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 187ab61..72554fd 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -141,7 +141,7 @@ static int __init init_nvs_nosave(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id __initdata acpisleep_dmi_table[] = { +static struct dmi_system_id acpisleep_dmi_table[] __initdata = { { .callback = init_old_suspend_ordering, .ident = "Abit KN9 (nForce4 variant)", -- cgit v0.10.2 From 38f7c5a11e8ec0f770d8850ca8442528a959f9f3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Aug 2013 15:29:22 +0800 Subject: ACPICA: Export acpi_tb_validate_rsdp(). This patch exports acpi_tb_validate_rsdp(), so that code duplication in some ACPICA utilities can be reduced. This patch also includes lint changes. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 917315e..c54f42c 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -49,6 +49,8 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count); /* * tbxfroot - Root pointer utilities */ +acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); + u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length); /* diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index e76ed0f..948c95e 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -48,9 +48,6 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxfroot") -/* Local prototypes */ -static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); - /******************************************************************************* * * FUNCTION: acpi_tb_validate_rsdp @@ -62,8 +59,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); * DESCRIPTION: Validate the RSDP (ptr) * ******************************************************************************/ - -static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) +acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) { /* @@ -72,7 +68,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) * Note: Sometimes there exists more than one RSDP in memory; the valid * RSDP has a valid checksum, all others have an invalid checksum. */ - if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, + if (ACPI_STRNCMP((char *)rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1) != 0) { /* Nope, BAD Signature */ -- cgit v0.10.2 From b268cee867ed193379762fdf94005c5bb79317a8 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Aug 2013 15:29:27 +0800 Subject: ACPICA: Emit all unresolved method externals in a text block Put all of the unresolved external method declarations in a single block, since they are important and may cause the resulting disassembled ASL file to not compile. This patch only affects ACPICA utilities and is necessary to avoid adding source code divergences between Linux and ACPICA upstream. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index b0e3d15..0ed0066 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -1033,6 +1033,7 @@ struct acpi_external_list { u8 type; u8 flags; u8 resolved; + u8 emitted; }; /* Values for Flags field above */ -- cgit v0.10.2 From 63660e05ec719613b518547b40a1c501c10f0bc4 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Aug 2013 15:29:32 +0800 Subject: ACPICA: DeRefOf operator: Update to fully resolve FieldUnit and BufferField refs. Previously, references to these objects were resolved only to the actual FieldUnit or BufferField object. The correct behavior is to resolve these references to an actual value. The problem is that DerefOf did not resolve these objects to actual values. An "Integer" object is simple, return the value. But a field in an operation region will require a read operation. For a BufferField, the appropriate data must be extracted from the parent buffer. NOTE: It appears that this issues is present in Windows7 but not Windows8. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 814b4a3..3482df4 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -990,11 +990,40 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) acpi_namespace_node *) return_desc); - } + if (!return_desc) { + break; + } + + /* + * June 2013: + * buffer_fields/field_units require additional resolution + */ + switch (return_desc->common.type) { + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + status = + acpi_ex_read_data_from_field + (walk_state, return_desc, + &temp_desc); + if (ACPI_FAILURE(status)) { + goto cleanup; + } - /* Add another reference to the object! */ + return_desc = temp_desc; + break; - acpi_ut_add_reference(return_desc); + default: + + /* Add another reference to the object */ + + acpi_ut_add_reference + (return_desc); + break; + } + } break; default: -- cgit v0.10.2 From 3342c753bdeb29ec29d721c7ce38d283cc969174 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 8 Aug 2013 16:19:10 +0200 Subject: ACPI: Drop unnecessary label from acpi_bind_one() The out_free label in acpi_bind_one() is only jumped to from one place, so in fact it is not necessary, because the code below it can be moved to that place directly. Move that code and drop the label. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index dcba319..f3ead0c 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -225,11 +225,15 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) list_for_each_entry(pn, &acpi_dev->physical_node_list, node) { /* Sanity check. */ if (pn->dev == dev) { + mutex_unlock(&acpi_dev->physical_node_lock); + dev_warn(dev, "Already associated with ACPI node\n"); - if (ACPI_HANDLE(dev) == handle) - retval = 0; + kfree(physical_node); + if (ACPI_HANDLE(dev) != handle) + goto err; - goto out_free; + put_device(dev); + return 0; } if (pn->node_id == node_id) { physnode_list = &pn->node; @@ -262,15 +266,6 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) ACPI_HANDLE_SET(dev, NULL); put_device(dev); return retval; - - out_free: - mutex_unlock(&acpi_dev->physical_node_lock); - kfree(physical_node); - if (retval) - goto err; - - put_device(dev); - return 0; } EXPORT_SYMBOL_GPL(acpi_bind_one); -- cgit v0.10.2 From 464c114717ae221202ebdbd9aa216035b4626f18 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 8 Aug 2013 16:19:19 +0200 Subject: ACPI: Print diagnostic messages if device links cannot be created Although the device links created by acpi_bind_one() are not essential from the kernel functionality point of view, user space may be confused when they are missing, so print diagnostic messages to the kernel log if they can't be created. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index f3ead0c..9467229 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -252,8 +252,15 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) acpi_physnode_link_name(physical_node_name, node_id); retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, physical_node_name); + if (retval) + dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n", + physical_node_name, retval); + retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, "firmware_node"); + if (retval) + dev_err(dev, "Failed to create link firmware_node (%d)\n", + retval); mutex_unlock(&acpi_dev->physical_node_lock); -- cgit v0.10.2 From c88a1f8b96e7384627b918dfabbfc0c615a4a914 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 6 Aug 2013 22:53:08 +0530 Subject: cpufreq: Store cpufreq policies in a list Policies available in the cpufreq framework are now linked together. They are accessible via cpufreq_policy_list defined in the cpufreq core. [rjw: Fix from Yinghai Lu folded in] Signed-off-by: Lukasz Majewski Signed-off-by: Myungjoo Ham Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9e83d91..75c5bd4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -40,6 +40,7 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); static DEFINE_RWLOCK(cpufreq_driver_lock); static DEFINE_MUTEX(cpufreq_governor_lock); +static LIST_HEAD(cpufreq_policy_list); #ifdef CONFIG_HOTPLUG_CPU /* This one keeps track of the previously set governor of a removed CPU */ @@ -952,6 +953,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void) if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) goto err_free_cpumask; + INIT_LIST_HEAD(&policy->policy_list); return policy; err_free_cpumask: @@ -964,6 +966,12 @@ err_free_policy: static void cpufreq_policy_free(struct cpufreq_policy *policy) { + unsigned long flags; + + write_lock_irqsave(&cpufreq_driver_lock, flags); + list_del(&policy->policy_list); + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + free_cpumask_var(policy->related_cpus); free_cpumask_var(policy->cpus); kfree(policy); @@ -1077,6 +1085,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, ret = cpufreq_add_dev_interface(policy, dev); if (ret) goto err_out_unregister; + + write_lock_irqsave(&cpufreq_driver_lock, flags); + list_add(&policy->policy_list, &cpufreq_policy_list); + write_unlock_irqrestore(&cpufreq_driver_lock, flags); } cpufreq_init_policy(policy); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 2920892..431a05d 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -82,6 +82,7 @@ struct cpufreq_policy { struct cpufreq_real_policy user_policy; + struct list_head policy_list; struct kobject kobj; struct completion kobj_unregister; int transition_ongoing; /* Tracks transition status */ -- cgit v0.10.2 From eb608521f1e25a8c14295b6d9a3853c3cd8c6cf8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:09 +0530 Subject: cpufreq: Use cpufreq_policy_list for iterating over policies To iterate over all policies we currently iterate over all CPUs and then get the policy for each of them. Let's use the newly created cpufreq_policy_list for this purpose. [rjw: Changelog] Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 75c5bd4..37af929 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -985,8 +985,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, struct cpufreq_policy *policy; unsigned long flags; #ifdef CONFIG_HOTPLUG_CPU + struct cpufreq_policy *tpolicy; struct cpufreq_governor *gov; - int sibling; #endif if (cpu_is_offline(cpu)) @@ -1006,11 +1006,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, #ifdef CONFIG_HOTPLUG_CPU /* Check if this cpu was hot-unplugged earlier and has siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_online_cpu(sibling) { - struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); - if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { + list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { + if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - return cpufreq_add_policy_cpu(cp, cpu, dev, frozen); + return cpufreq_add_policy_cpu(tpolicy, cpu, dev, + frozen); } } read_unlock_irqrestore(&cpufreq_driver_lock, flags); -- cgit v0.10.2 From fe492f3f0332e23cc6ca4913e5a2ed78e1888902 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:10 +0530 Subject: cpufreq: Fix broken usage of governor->owner's refcount The cpufreq governor owner refcount usage is broken. We should only increment that refcount when a CPUFREQ_GOV_POLICY_INIT event has come and it should only be decremented if CPUFREQ_GOV_POLICY_EXIT has come. Currently, there can be situations where the governor is in use, but we have allowed it to be unloaded which may result in undefined behavior. Let's fix it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 37af929..f149e14 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1709,8 +1709,9 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, } } - if (!try_module_get(policy->governor->owner)) - return -EINVAL; + if (event == CPUFREQ_GOV_POLICY_INIT) + if (!try_module_get(policy->governor->owner)) + return -EINVAL; pr_debug("__cpufreq_governor for CPU %u, event %u\n", policy->cpu, event); @@ -1719,6 +1720,8 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) || (policy->governor_enabled && (event == CPUFREQ_GOV_START))) { mutex_unlock(&cpufreq_governor_lock); + if (event == CPUFREQ_GOV_POLICY_INIT) + module_put(policy->governor->owner); return -EBUSY; } @@ -1746,11 +1749,8 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, mutex_unlock(&cpufreq_governor_lock); } - /* we keep one module reference alive for - each CPU governed by this CPU */ - if ((event != CPUFREQ_GOV_START) || ret) - module_put(policy->governor->owner); - if ((event == CPUFREQ_GOV_STOP) && !ret) + if (((event == CPUFREQ_GOV_POLICY_INIT) && ret) || + ((event == CPUFREQ_GOV_POLICY_EXIT) && !ret)) module_put(policy->governor->owner); return ret; -- cgit v0.10.2 From 6eed9404ab3c4baea54ce4c7e862e69df1d39f38 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:11 +0530 Subject: cpufreq: Use rwsem for protecting critical sections Critical sections of the cpufreq core are protected with the help of the driver module owner's refcount, which isn't the correct approach, because it causes rmmod to return an error when some routine has updated that refcount. Let's use rwsem for this purpose instead. Only cpufreq_unregister_driver() will use write sem and everybody else will use read sem. [rjw: Subject & changelog] Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f149e14..c9bbfee 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -91,6 +91,12 @@ static void unlock_policy_rwsem_##mode(int cpu) \ unlock_policy_rwsem(read, cpu); unlock_policy_rwsem(write, cpu); +/* + * rwsem to guarantee that cpufreq driver module doesn't unload during critical + * sections + */ +static DECLARE_RWSEM(cpufreq_rwsem); + /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); @@ -178,78 +184,46 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy) } EXPORT_SYMBOL_GPL(get_cpu_idle_time); -static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) +struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) { - struct cpufreq_policy *policy; + struct cpufreq_policy *policy = NULL; unsigned long flags; - if (cpu >= nr_cpu_ids) - goto err_out; + if (cpufreq_disabled() || (cpu >= nr_cpu_ids)) + return NULL; + + if (!down_read_trylock(&cpufreq_rwsem)) + return NULL; /* get the cpufreq driver */ read_lock_irqsave(&cpufreq_driver_lock, flags); - if (!cpufreq_driver) - goto err_out_unlock; - - if (!try_module_get(cpufreq_driver->owner)) - goto err_out_unlock; + if (cpufreq_driver) { + /* get the CPU */ + policy = per_cpu(cpufreq_cpu_data, cpu); + if (policy) + kobject_get(&policy->kobj); + } - /* get the CPU */ - policy = per_cpu(cpufreq_cpu_data, cpu); + read_unlock_irqrestore(&cpufreq_driver_lock, flags); if (!policy) - goto err_out_put_module; - - if (!sysfs && !kobject_get(&policy->kobj)) - goto err_out_put_module; + up_read(&cpufreq_rwsem); - read_unlock_irqrestore(&cpufreq_driver_lock, flags); return policy; - -err_out_put_module: - module_put(cpufreq_driver->owner); -err_out_unlock: - read_unlock_irqrestore(&cpufreq_driver_lock, flags); -err_out: - return NULL; -} - -struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) -{ - if (cpufreq_disabled()) - return NULL; - - return __cpufreq_cpu_get(cpu, false); } EXPORT_SYMBOL_GPL(cpufreq_cpu_get); -static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu) -{ - return __cpufreq_cpu_get(cpu, true); -} - -static void __cpufreq_cpu_put(struct cpufreq_policy *policy, bool sysfs) -{ - if (!sysfs) - kobject_put(&policy->kobj); - module_put(cpufreq_driver->owner); -} - void cpufreq_cpu_put(struct cpufreq_policy *policy) { if (cpufreq_disabled()) return; - __cpufreq_cpu_put(policy, false); + kobject_put(&policy->kobj); + up_read(&cpufreq_rwsem); } EXPORT_SYMBOL_GPL(cpufreq_cpu_put); -static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *policy) -{ - __cpufreq_cpu_put(policy, true); -} - /********************************************************************* * EXTERNALLY AFFECTING FREQUENCY CHANGES * *********************************************************************/ @@ -694,12 +668,12 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) struct cpufreq_policy *policy = to_policy(kobj); struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; - policy = cpufreq_cpu_get_sysfs(policy->cpu); - if (!policy) - goto no_policy; + + if (!down_read_trylock(&cpufreq_rwsem)) + goto exit; if (lock_policy_rwsem_read(policy->cpu) < 0) - goto fail; + goto up_read; if (fattr->show) ret = fattr->show(policy, buf); @@ -707,9 +681,10 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) ret = -EIO; unlock_policy_rwsem_read(policy->cpu); -fail: - cpufreq_cpu_put_sysfs(policy); -no_policy: + +up_read: + up_read(&cpufreq_rwsem); +exit: return ret; } @@ -719,12 +694,12 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, struct cpufreq_policy *policy = to_policy(kobj); struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; - policy = cpufreq_cpu_get_sysfs(policy->cpu); - if (!policy) - goto no_policy; + + if (!down_read_trylock(&cpufreq_rwsem)) + goto exit; if (lock_policy_rwsem_write(policy->cpu) < 0) - goto fail; + goto up_read; if (fattr->store) ret = fattr->store(policy, buf, count); @@ -732,9 +707,10 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, ret = -EIO; unlock_policy_rwsem_write(policy->cpu); -fail: - cpufreq_cpu_put_sysfs(policy); -no_policy: + +up_read: + up_read(&cpufreq_rwsem); +exit: return ret; } @@ -1003,25 +979,24 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, return 0; } + if (!down_read_trylock(&cpufreq_rwsem)) + return 0; + #ifdef CONFIG_HOTPLUG_CPU /* Check if this cpu was hot-unplugged earlier and has siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags); list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - return cpufreq_add_policy_cpu(tpolicy, cpu, dev, - frozen); + ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen); + up_read(&cpufreq_rwsem); + return ret; } } read_unlock_irqrestore(&cpufreq_driver_lock, flags); #endif #endif - if (!try_module_get(cpufreq_driver->owner)) { - ret = -EINVAL; - goto module_out; - } - if (frozen) /* Restore the saved policy when doing light-weight init */ policy = cpufreq_policy_restore(cpu); @@ -1094,7 +1069,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, cpufreq_init_policy(policy); kobject_uevent(&policy->kobj, KOBJ_ADD); - module_put(cpufreq_driver->owner); + up_read(&cpufreq_rwsem); + pr_debug("initialization complete\n"); return 0; @@ -1112,8 +1088,8 @@ err_set_policy_cpu: per_cpu(cpufreq_policy_cpu, cpu) = -1; cpufreq_policy_free(policy); nomem_out: - module_put(cpufreq_driver->owner); -module_out: + up_read(&cpufreq_rwsem); + return ret; } @@ -1425,10 +1401,9 @@ static unsigned int __cpufreq_get(unsigned int cpu) unsigned int cpufreq_get(unsigned int cpu) { unsigned int ret_freq = 0; - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - if (!policy) - goto out; + if (!down_read_trylock(&cpufreq_rwsem)) + return 0; if (unlikely(lock_policy_rwsem_read(cpu))) goto out_policy; @@ -1438,8 +1413,8 @@ unsigned int cpufreq_get(unsigned int cpu) unlock_policy_rwsem_read(cpu); out_policy: - cpufreq_cpu_put(policy); -out: + up_read(&cpufreq_rwsem); + return ret_freq; } EXPORT_SYMBOL(cpufreq_get); @@ -2132,9 +2107,13 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) subsys_interface_unregister(&cpufreq_interface); unregister_hotcpu_notifier(&cpufreq_cpu_notifier); + down_write(&cpufreq_rwsem); write_lock_irqsave(&cpufreq_driver_lock, flags); + cpufreq_driver = NULL; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + up_write(&cpufreq_rwsem); return 0; } -- cgit v0.10.2 From adc97d6a735dbb1e94cb4f1bf0b55f258b349941 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:12 +0530 Subject: cpufreq: Drop the owner field from struct cpufreq_driver We don't need to set .owner = THIS_MODULE any more in cpufreq drivers as this field isn't used any more by the cpufreq core. This patch removes it and updates all dependent drivers accordingly. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index 19fa98e..40282e6 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -50,8 +50,6 @@ What shall this struct cpufreq_driver contain? cpufreq_driver.name - The name of this driver. -cpufreq_driver.owner - THIS_MODULE; - cpufreq_driver.init - A pointer to the per-CPU initialization function. diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 44758ce..9b5d1b1 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -936,7 +936,6 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .exit = acpi_cpufreq_cpu_exit, .resume = acpi_cpufreq_resume, .name = "acpi-cpufreq", - .owner = THIS_MODULE, .attr = acpi_cpufreq_attr, }; diff --git a/drivers/cpufreq/at32ap-cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c index 6544887..e0c38d9 100644 --- a/drivers/cpufreq/at32ap-cpufreq.c +++ b/drivers/cpufreq/at32ap-cpufreq.c @@ -108,7 +108,6 @@ static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy) static struct cpufreq_driver at32_driver = { .name = "at32ap", - .owner = THIS_MODULE, .init = at32_cpufreq_driver_init, .verify = at32_verify_speed, .target = at32_set_target, diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c index 9cdbbd2..ef05978 100644 --- a/drivers/cpufreq/blackfin-cpufreq.c +++ b/drivers/cpufreq/blackfin-cpufreq.c @@ -225,7 +225,6 @@ static struct cpufreq_driver bfin_driver = { .get = bfin_getfreq_khz, .init = __bfin_cpu_init, .name = "bfin cpufreq", - .owner = THIS_MODULE, .attr = bfin_freq_attr, }; diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c index af1542d..b83d45f6 100644 --- a/drivers/cpufreq/cpufreq-nforce2.c +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -379,7 +379,6 @@ static struct cpufreq_driver nforce2_driver = { .get = nforce2_get, .init = nforce2_cpu_init, .exit = nforce2_cpu_exit, - .owner = THIS_MODULE, }; #ifdef MODULE diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c index ee142c4..cb8276d 100644 --- a/drivers/cpufreq/cris-artpec3-cpufreq.c +++ b/drivers/cpufreq/cris-artpec3-cpufreq.c @@ -111,7 +111,6 @@ static struct cpufreq_driver cris_freq_driver = { .init = cris_freq_cpu_init, .exit = cris_freq_cpu_exit, .name = "cris_freq", - .owner = THIS_MODULE, .attr = cris_freq_attr, }; diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c index 1295223..72328f7 100644 --- a/drivers/cpufreq/cris-etraxfs-cpufreq.c +++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c @@ -108,7 +108,6 @@ static struct cpufreq_driver cris_freq_driver = { .init = cris_freq_cpu_init, .exit = cris_freq_cpu_exit, .name = "cris_freq", - .owner = THIS_MODULE, .attr = cris_freq_attr, }; diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index de974be..09f64cc 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -436,7 +436,6 @@ static struct cpufreq_driver eps_driver = { .exit = eps_cpu_exit, .get = eps_get, .name = "e_powersaver", - .owner = THIS_MODULE, .attr = eps_attr, }; diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c index 658d860..823a400 100644 --- a/drivers/cpufreq/elanfreq.c +++ b/drivers/cpufreq/elanfreq.c @@ -274,7 +274,6 @@ static struct cpufreq_driver elanfreq_driver = { .init = elanfreq_cpu_init, .exit = elanfreq_cpu_exit, .name = "elanfreq", - .owner = THIS_MODULE, .attr = elanfreq_attr, }; diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c index 4f25fb6..ef5fee7 100644 --- a/drivers/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -446,7 +446,6 @@ static struct cpufreq_driver gx_suspmod_driver = { .target = cpufreq_gx_target, .init = cpufreq_gx_cpu_init, .name = "gx-suspmod", - .owner = THIS_MODULE, }; static int __init cpufreq_gx_init(void) diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index 08792dd..3e14f03 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -409,7 +409,6 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .init = acpi_cpufreq_cpu_init, .exit = acpi_cpufreq_cpu_exit, .name = "acpi-cpufreq", - .owner = THIS_MODULE, .attr = acpi_cpufreq_attr, }; diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 7cde885..6efd96c 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -665,7 +665,6 @@ static struct cpufreq_driver intel_pstate_driver = { .init = intel_pstate_cpu_init, .exit = intel_pstate_cpu_exit, .name = "intel_pstate", - .owner = THIS_MODULE, }; static int __initdata no_load; diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index c233ea6..45e4d7f 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c @@ -158,7 +158,6 @@ static struct cpufreq_driver kirkwood_cpufreq_driver = { .init = kirkwood_cpufreq_cpu_init, .exit = kirkwood_cpufreq_cpu_exit, .name = "kirkwood-cpufreq", - .owner = THIS_MODULE, .attr = kirkwood_cpufreq_attr, }; diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 8c49261..4ada1cc 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -948,7 +948,6 @@ static struct cpufreq_driver longhaul_driver = { .init = longhaul_cpu_init, .exit = longhaul_cpu_exit, .name = "longhaul", - .owner = THIS_MODULE, .attr = longhaul_attr, }; diff --git a/drivers/cpufreq/longrun.c b/drivers/cpufreq/longrun.c index 0fe041d..5aa0316 100644 --- a/drivers/cpufreq/longrun.c +++ b/drivers/cpufreq/longrun.c @@ -286,7 +286,6 @@ static struct cpufreq_driver longrun_driver = { .get = longrun_get, .init = longrun_cpu_init, .name = "longrun", - .owner = THIS_MODULE, }; static const struct x86_cpu_id longrun_ids[] = { diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index bb838b9..e65de91 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -157,7 +157,6 @@ static struct freq_attr *loongson2_table_attr[] = { }; static struct cpufreq_driver loongson2_cpufreq_driver = { - .owner = THIS_MODULE, .name = "loongson2", .init = loongson2_cpufreq_cpu_init, .verify = loongson2_cpufreq_verify, diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c index cdd6291..41c601f 100644 --- a/drivers/cpufreq/maple-cpufreq.c +++ b/drivers/cpufreq/maple-cpufreq.c @@ -190,7 +190,6 @@ static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy) static struct cpufreq_driver maple_cpufreq_driver = { .name = "maple", - .owner = THIS_MODULE, .flags = CPUFREQ_CONST_LOOPS, .init = maple_cpufreq_cpu_init, .verify = maple_cpufreq_verify, diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c index 9ee7817..2f0a2a6 100644 --- a/drivers/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c @@ -279,7 +279,6 @@ static struct cpufreq_driver p4clockmod_driver = { .exit = cpufreq_p4_cpu_exit, .get = cpufreq_p4_get, .name = "p4-clockmod", - .owner = THIS_MODULE, .attr = p4clockmod_attr, }; diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c index b704da4..534e43a 100644 --- a/drivers/cpufreq/pasemi-cpufreq.c +++ b/drivers/cpufreq/pasemi-cpufreq.c @@ -297,7 +297,6 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy, static struct cpufreq_driver pas_cpufreq_driver = { .name = "pas-cpufreq", - .owner = THIS_MODULE, .flags = CPUFREQ_CONST_LOOPS, .init = pas_cpufreq_cpu_init, .exit = pas_cpufreq_cpu_exit, diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 1581fcc..d81c4e5 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -587,7 +587,6 @@ static struct cpufreq_driver pcc_cpufreq_driver = { .init = pcc_cpufreq_cpu_init, .exit = pcc_cpufreq_cpu_exit, .name = "pcc-cpufreq", - .owner = THIS_MODULE, }; static int __init pcc_cpufreq_init(void) diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c index 3104fad..38cdc63 100644 --- a/drivers/cpufreq/pmac32-cpufreq.c +++ b/drivers/cpufreq/pmac32-cpufreq.c @@ -477,7 +477,6 @@ static struct cpufreq_driver pmac_cpufreq_driver = { .flags = CPUFREQ_PM_NO_WARN, .attr = pmac_cpu_freqs_attr, .name = "powermac", - .owner = THIS_MODULE, }; diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c index 4d7799b..b6850d9 100644 --- a/drivers/cpufreq/pmac64-cpufreq.c +++ b/drivers/cpufreq/pmac64-cpufreq.c @@ -371,7 +371,6 @@ static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy) static struct cpufreq_driver g5_cpufreq_driver = { .name = "powermac", - .owner = THIS_MODULE, .flags = CPUFREQ_CONST_LOOPS, .init = g5_cpufreq_cpu_init, .verify = g5_cpufreq_verify, diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index ea8e103..85f1c8c 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -207,7 +207,6 @@ static struct cpufreq_driver powernow_k6_driver = { .exit = powernow_k6_cpu_exit, .get = powernow_k6_get, .name = "powernow-k6", - .owner = THIS_MODULE, .attr = powernow_k6_attr, }; diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 4687d40..14ce480 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -716,7 +716,6 @@ static struct cpufreq_driver powernow_driver = { .init = powernow_cpu_init, .exit = powernow_cpu_exit, .name = "powernow-k7", - .owner = THIS_MODULE, .attr = powernow_table_attr, }; diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 3f3c6ca..2344a9e 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1240,7 +1240,6 @@ static struct cpufreq_driver cpufreq_amd64_driver = { .exit = powernowk8_cpu_exit, .get = powernowk8_get, .name = "powernow-k8", - .owner = THIS_MODULE, .attr = powernow_k8_attr, }; diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c index 3cae452..60e81d5 100644 --- a/drivers/cpufreq/ppc-corenet-cpufreq.c +++ b/drivers/cpufreq/ppc-corenet-cpufreq.c @@ -300,7 +300,6 @@ static struct freq_attr *corenet_cpufreq_attr[] = { static struct cpufreq_driver ppc_corenet_cpufreq_driver = { .name = "ppc_cpufreq", - .owner = THIS_MODULE, .flags = CPUFREQ_CONST_LOOPS, .init = corenet_cpufreq_cpu_init, .exit = __exit_p(corenet_cpufreq_cpu_exit), diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c index 5936f8d..2e448f0 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq.c @@ -181,7 +181,6 @@ static struct cpufreq_driver cbe_cpufreq_driver = { .init = cbe_cpufreq_cpu_init, .exit = cbe_cpufreq_cpu_exit, .name = "cbe-cpufreq", - .owner = THIS_MODULE, .flags = CPUFREQ_CONST_LOOPS, }; diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index ce5b9fc..22dcb81 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -524,7 +524,6 @@ static struct freq_attr *s3c2416_cpufreq_attr[] = { }; static struct cpufreq_driver s3c2416_cpufreq_driver = { - .owner = THIS_MODULE, .flags = 0, .verify = s3c2416_cpufreq_verify_speed, .target = s3c2416_cpufreq_set_target, diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 13bb4ba..8a72b0c 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -263,7 +263,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) } static struct cpufreq_driver s3c64xx_cpufreq_driver = { - .owner = THIS_MODULE, .flags = 0, .verify = s3c64xx_cpufreq_verify_speed, .target = s3c64xx_cpufreq_set_target, diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c index 77a2109..d6f6c6f 100644 --- a/drivers/cpufreq/sc520_freq.c +++ b/drivers/cpufreq/sc520_freq.c @@ -147,7 +147,6 @@ static struct cpufreq_driver sc520_freq_driver = { .init = sc520_freq_cpu_init, .exit = sc520_freq_cpu_exit, .name = "sc520_freq", - .owner = THIS_MODULE, .attr = sc520_freq_attr, }; diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index 73adb64..ffc6d24 100644 --- a/drivers/cpufreq/sh-cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -160,7 +160,6 @@ static struct freq_attr *sh_freq_attr[] = { }; static struct cpufreq_driver sh_cpufreq_driver = { - .owner = THIS_MODULE, .name = "sh", .get = sh_cpufreq_get, .target = sh_cpufreq_target, diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c index 7c43a72..cf5bc2c 100644 --- a/drivers/cpufreq/sparc-us2e-cpufreq.c +++ b/drivers/cpufreq/sparc-us2e-cpufreq.c @@ -365,7 +365,6 @@ static int __init us2e_freq_init(void) driver->target = us2e_freq_target; driver->get = us2e_freq_get; driver->exit = us2e_freq_cpu_exit; - driver->owner = THIS_MODULE, strcpy(driver->name, "UltraSPARC-IIe"); cpufreq_us2e_driver = driver; diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c index 7f500c1..ac76b48 100644 --- a/drivers/cpufreq/sparc-us3-cpufreq.c +++ b/drivers/cpufreq/sparc-us3-cpufreq.c @@ -226,7 +226,6 @@ static int __init us3_freq_init(void) driver->target = us3_freq_target; driver->get = us3_freq_get; driver->exit = us3_freq_cpu_exit; - driver->owner = THIS_MODULE, strcpy(driver->name, "UltraSPARC-III"); cpufreq_us3_driver = driver; diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index 0915e71..f897d51 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -575,7 +575,6 @@ static struct cpufreq_driver centrino_driver = { .target = centrino_target, .get = get_cur_freq, .attr = centrino_attr, - .owner = THIS_MODULE, }; /* diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c index e2e5aa9..5355abb 100644 --- a/drivers/cpufreq/speedstep-ich.c +++ b/drivers/cpufreq/speedstep-ich.c @@ -378,7 +378,6 @@ static struct cpufreq_driver speedstep_driver = { .init = speedstep_cpu_init, .exit = speedstep_cpu_exit, .get = speedstep_get, - .owner = THIS_MODULE, .attr = speedstep_attr, }; diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c index f5a6b70..abfba4f 100644 --- a/drivers/cpufreq/speedstep-smi.c +++ b/drivers/cpufreq/speedstep-smi.c @@ -375,7 +375,6 @@ static struct cpufreq_driver speedstep_driver = { .exit = speedstep_cpu_exit, .get = speedstep_get, .resume = speedstep_resume, - .owner = THIS_MODULE, .attr = speedstep_attr, }; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 431a05d..d568f39 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -179,7 +179,6 @@ __ATTR(_name, 0644, show_##_name, store_##_name) struct cpufreq_driver { - struct module *owner; char name[CPUFREQ_NAME_LEN]; u8 flags; /* -- cgit v0.10.2 From 3de9bdeb28638e164d1f0eb38dd68e3f5d2ac95c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Aug 2013 22:53:13 +0530 Subject: cpufreq: improve error checking on return values of __cpufreq_governor() The __cpufreq_governor() function can fail in rare cases especially if there are bugs in cpufreq drivers. Thus we must stop processing as soon as this routine fails, otherwise it may result in undefined behavior. This patch adds error checking code whenever this routine is called from any place. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index c9bbfee..37a6874 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -874,8 +874,13 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, int ret = 0, has_target = !!cpufreq_driver->target; unsigned long flags; - if (has_target) - __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + if (has_target) { + ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + if (ret) { + pr_err("%s: Failed to stop governor\n", __func__); + return ret; + } + } lock_policy_rwsem_write(policy->cpu); @@ -889,8 +894,11 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unlock_policy_rwsem_write(policy->cpu); if (has_target) { - __cpufreq_governor(policy, CPUFREQ_GOV_START); - __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); + if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) || + (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) { + pr_err("%s: Failed to start governor\n", __func__); + return ret; + } } /* Don't touch sysfs links during light-weight init */ @@ -1172,7 +1180,7 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif, bool frozen) { unsigned int cpu = dev->id, cpus; - int new_cpu; + int new_cpu, ret; unsigned long flags; struct cpufreq_policy *policy; struct kobject *kobj; @@ -1196,8 +1204,13 @@ static int __cpufreq_remove_dev(struct device *dev, return -EINVAL; } - if (cpufreq_driver->target) - __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + if (cpufreq_driver->target) { + ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + if (ret) { + pr_err("%s: Failed to stop governor\n", __func__); + return ret; + } + } #ifdef CONFIG_HOTPLUG_CPU if (!cpufreq_driver->setpolicy) @@ -1231,8 +1244,15 @@ static int __cpufreq_remove_dev(struct device *dev, /* If cpu is last user of policy, free policy */ if (cpus == 1) { - if (cpufreq_driver->target) - __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); + if (cpufreq_driver->target) { + ret = __cpufreq_governor(policy, + CPUFREQ_GOV_POLICY_EXIT); + if (ret) { + pr_err("%s: Failed to exit governor\n", + __func__); + return ret; + } + } if (!frozen) { lock_policy_rwsem_read(cpu); @@ -1263,8 +1283,12 @@ static int __cpufreq_remove_dev(struct device *dev, cpufreq_policy_free(policy); } else { if (cpufreq_driver->target) { - __cpufreq_governor(policy, CPUFREQ_GOV_START); - __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); + if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) || + (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) { + pr_err("%s: Failed to start governor\n", + __func__); + return ret; + } } } @@ -1912,7 +1936,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *policy, /* might be a policy change, too, so fall through */ } pr_debug("governor: change or update limits\n"); - __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); } error_out: -- cgit v0.10.2 From c721d15a5cc1dade16f068123070c570378c5cc0 Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Wed, 7 Aug 2013 16:46:11 +0530 Subject: cpufreq: exynos5440: Fix to skip when new frequency same as current This patch fixes the issue of un-necessary setting the clock controller when the new target frequency is same as the current one. This case usually occurs with governors like ondemand which passes the target frequency as the percentage of average frequency. This check is present in most of the cpufreq drivers. Cc: Viresh Kumar Cc: Rafael J. Wysocki Cc: Kukjin Kim Signed-off-by: Amit Daniel Kachhap Signed-off-by: Viresh Kumar diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index 0c74018..d514c15 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -238,6 +238,9 @@ static int exynos_target(struct cpufreq_policy *policy, freqs.old = dvfs_info->cur_frequency; freqs.new = freq_table[index].frequency; + if (freqs.old == freqs.new) + goto out; + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); /* Set the target frequency in all C0_3_PSTATE register */ -- cgit v0.10.2 From 45e12086263a53f16b489fc7f4f8f6348a688661 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 9 Aug 2013 14:04:55 +0200 Subject: cpufreq: fix EXYNOS drivers selection * remove superfluous pr_debug() call from exynos_cpufreq_init() (init errors are always logged anyway) * add dummy per-SoC type init functions to exynos-cpufreq.h * make per-SoC type cpufreq config options selectable * make CONFIG_ARM_EXYNOS_CPUFREQ config option invisible to user and automatically enable it when needed This patch fixes following issues: * EXYNOS per-SoC type cpufreq support (i.e. exynos4210-cpufreq.c) being always built if given SoC support was enabled (i.e. CPU_EXYNOS4210), even if common EXYNOS cpufreq support was disabled * inability to select cpufreq for each SoC type separately (it could be only enabled/disabled for all SoCs for which support was enabled) * EXYNOS5440 cpufreq support was always enabled when EXYNOS5440 support was enabled and couldn't be disabled Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Reviewed-by: Tomasz Figa Signed-off-by: Viresh Kumar diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index de4d5d9..0fa204b 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -17,37 +17,47 @@ config ARM_DT_BL_CPUFREQ big.LITTLE platform. This gets frequency tables from DT. config ARM_EXYNOS_CPUFREQ - bool "SAMSUNG EXYNOS SoCs" - depends on ARCH_EXYNOS + bool select CPU_FREQ_TABLE - default y - help - This adds the CPUFreq driver common part for Samsung - EXYNOS SoCs. - - If in doubt, say N. config ARM_EXYNOS4210_CPUFREQ - def_bool CPU_EXYNOS4210 + bool "SAMSUNG EXYNOS4210" + depends on CPU_EXYNOS4210 + default y + select ARM_EXYNOS_CPUFREQ help This adds the CPUFreq driver for Samsung EXYNOS4210 SoC (S5PV310 or S5PC210). + If in doubt, say N. + config ARM_EXYNOS4X12_CPUFREQ - def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412) + bool "SAMSUNG EXYNOS4x12" + depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412) + default y + select ARM_EXYNOS_CPUFREQ help This adds the CPUFreq driver for Samsung EXYNOS4X12 SoC (EXYNOS4212 or EXYNOS4412). + If in doubt, say N. + config ARM_EXYNOS5250_CPUFREQ - def_bool SOC_EXYNOS5250 + bool "SAMSUNG EXYNOS5250" + depends on SOC_EXYNOS5250 + default y + select ARM_EXYNOS_CPUFREQ help This adds the CPUFreq driver for Samsung EXYNOS5250 SoC. + If in doubt, say N. + config ARM_EXYNOS5440_CPUFREQ - def_bool SOC_EXYNOS5440 + bool "SAMSUNG EXYNOS5440" + depends on SOC_EXYNOS5440 depends on HAVE_CLK && PM_OPP && OF + default y select CPU_FREQ_TABLE help This adds the CPUFreq driver for Samsung EXYNOS5440 @@ -55,6 +65,8 @@ config ARM_EXYNOS5440_CPUFREQ different than previous exynos controllers so not using the common exynos framework. + If in doubt, say N. + config ARM_HIGHBANK_CPUFREQ tristate "Calxeda Highbank-based" depends on ARCH_HIGHBANK diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 0d32f02..51cb116 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -332,7 +332,6 @@ err_cpufreq: regulator_put(arm_regulator); err_vdd_arm: kfree(exynos_info); - pr_debug("%s: failed initialization\n", __func__); return -EINVAL; } late_initcall(exynos_cpufreq_init); diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h index 92b852e..7f25cee 100644 --- a/drivers/cpufreq/exynos-cpufreq.h +++ b/drivers/cpufreq/exynos-cpufreq.h @@ -43,6 +43,27 @@ struct exynos_dvfs_info { bool (*need_apll_change)(unsigned int, unsigned int); }; +#ifdef CONFIG_ARM_EXYNOS4210_CPUFREQ extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *); +#else +static inline int exynos4210_cpufreq_init(struct exynos_dvfs_info *info) +{ + return -EOPNOTSUPP; +} +#endif +#ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *); +#else +static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info) +{ + return -EOPNOTSUPP; +} +#endif +#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *); +#else +static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) +{ + return -EOPNOTSUPP; +} +#endif -- cgit v0.10.2 From c78e43601b8f6d06bd92753e5f4ae51e4d6a1284 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 26 Jul 2013 00:14:04 +0200 Subject: SH: cpuidle: Add missing parameter for cpuidle_register() arch/sh/kernel/cpu/shmobile/cpuidle.c: In function 'sh_mobile_setup_cpuidle': arch/sh/kernel/cpu/shmobile/cpuidle.c:102:2: error: too few arguments to function 'cpuidle_register' include/linux/cpuidle.h:129:12: note: declared here arch/sh/kernel/cpu/shmobile/cpuidle.c:94:6: warning: unused variable 'ret' [-Wunused-variable] Add the missing parameter, and remove the unused variable. Both introduced by commit b181a3b03f866776211f22390c185c4da1dc45ff ("SH: cpuidle: use init/exit common routine"). Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index d306225..e3abfd4 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -91,13 +91,11 @@ static struct cpuidle_driver cpuidle_driver = { int __init sh_mobile_setup_cpuidle(void) { - int ret; - if (sh_mobile_sleep_supported & SUSP_SH_SF) cpuidle_driver.states[1].disabled = false; if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) cpuidle_driver.states[2].disabled = false; - return cpuidle_register(&cpuidle_driver); + return cpuidle_register(&cpuidle_driver, NULL); } -- cgit v0.10.2 From 3e0c190dbf51f587ac78b3b1bcd85648a7dbe166 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 9 Aug 2013 16:09:15 +0900 Subject: cpuidle: calxeda: Add missing __iomem annotation Added missing __iomem annotation in order to fix the following sparse warnings: drivers/cpuidle/cpuidle-calxeda.c:44:24: warning: incorrect type in argument 1 (different address spaces) drivers/cpuidle/cpuidle-calxeda.c:44:24: expected void [noderef] * drivers/cpuidle/cpuidle-calxeda.c:44:24: got void *extern [addressable] [toplevel] scu_base_addr drivers/cpuidle/cpuidle-calxeda.c:56:24: warning: incorrect type in argument 1 (different address spaces) drivers/cpuidle/cpuidle-calxeda.c:56:24: expected void [noderef] * drivers/cpuidle/cpuidle-calxeda.c:56:24: got void *extern [addressable] [toplevel] scu_base_addr Signed-off-by: Jingoo Han Signed-off-by: Daniel Lezcano diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index 0e6e408..3460584 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c @@ -35,7 +35,7 @@ #include extern void highbank_set_cpu_jump(int cpu, void *jump_addr); -extern void *scu_base_addr; +extern void __iomem *scu_base_addr; static noinline void calxeda_idle_restore(void) { -- cgit v0.10.2 From 75d6137da195a1e059e1c814cb95635e168f85c0 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 9 Aug 2013 16:11:34 +0900 Subject: cpuidle: kirkwood: Make kirkwood_cpuidle_remove function static This local symbol is used only in this file. Fix the following sparse warnings: drivers/cpuidle/cpuidle-kirkwood.c:73:5: warning: symbol 'kirkwood_cpuidle_remove' was not declared. Should it be static ? Signed-off-by: Jingoo Han Acked-by: Jason Cooper Signed-off-by: Daniel Lezcano diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 521b0a7..3ca3a2e 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -70,7 +70,7 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev) return cpuidle_register(&kirkwood_idle_driver, NULL); } -int kirkwood_cpuidle_remove(struct platform_device *pdev) +static int kirkwood_cpuidle_remove(struct platform_device *pdev) { cpuidle_unregister(&kirkwood_idle_driver); return 0; -- cgit v0.10.2 From 22e7551eb6fd58352930306039a98313c011e615 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 13 Aug 2013 12:11:22 +0200 Subject: ACPI / processor: Remove acpi_processor_get_limit_info() acpi_processor_get_limit_info() is only called in the __acpi_processor_start() and what it does actually is just to check pr->flags.throttling and set limit. The pr pointer has been checked in the __acpi_processor_start() before acpi_processor_get_limit_info() being called. It doesn't make sense still to keep it as a function. So move code to __acpi_processor_start() and remove acpi_processor_get_limit_info(). Signed-off-by: Lan Tianyu Acked-by: Zhang Rui Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 870eaf5..f0a4d0c 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -179,7 +179,9 @@ static int __acpi_processor_start(struct acpi_device *device) acpi_processor_load_module(pr); #endif acpi_processor_get_throttling_info(pr); - acpi_processor_get_limit_info(pr); + + if (pr->flags.throttling) + pr->flags.limit = 1; if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr); diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index e8e6527..d1d2e7f 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -186,18 +186,6 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) #endif -int acpi_processor_get_limit_info(struct acpi_processor *pr) -{ - - if (!pr) - return -EINVAL; - - if (pr->flags.throttling) - pr->flags.limit = 1; - - return 0; -} - /* thermal coolign device callbacks */ static int acpi_processor_max_state(struct acpi_processor *pr) { -- cgit v0.10.2 From b9d10be7a8e88fdcb12540387c219cdde87b0795 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Mon, 12 Aug 2013 09:45:53 -0600 Subject: ACPI / processor: Acquire writer lock to update CPU maps CPU system maps are protected with reader/writer locks. The reader lock, get_online_cpus(), assures that the maps are not updated while holding the lock. The writer lock, cpu_hotplug_begin(), is used to udpate the cpu maps along with cpu_maps_update_begin(). However, the ACPI processor handler updates the cpu maps without holding the the writer lock. acpi_map_lsapic() is called from acpi_processor_hotadd_init() to update cpu_possible_mask and cpu_present_mask. acpi_unmap_lsapic() is called from acpi_processor_remove() to update cpu_possible_mask. Currently, they are either unprotected or protected with the reader lock, which is not correct. For example, the get_online_cpus() below is supposed to assure that cpu_possible_mask is not changed while the code is iterating with for_each_possible_cpu(). get_online_cpus(); for_each_possible_cpu(cpu) { : } put_online_cpus(); However, this lock has no protection with CPU hotplug since the ACPI processor handler does not use the writer lock when it updates cpu_possible_mask. The reader lock does not serialize within the readers. This patch protects them with the writer lock with cpu_hotplug_begin() along with cpu_maps_update_begin(), which must be held before calling cpu_hotplug_begin(). It also protects arch_register_cpu() / arch_unregister_cpu(), which creates / deletes a sysfs cpu device interface. For this purpose it changes cpu_hotplug_begin() and cpu_hotplug_done() to global and exports them in cpu.h. Signed-off-by: Toshi Kani Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 5a74a9c..f29e06e 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -178,14 +178,17 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr) if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) return -ENODEV; + cpu_maps_update_begin(); + cpu_hotplug_begin(); + ret = acpi_map_lsapic(pr->handle, &pr->id); if (ret) - return ret; + goto out; ret = arch_register_cpu(pr->id); if (ret) { acpi_unmap_lsapic(pr->id); - return ret; + goto out; } /* @@ -195,7 +198,11 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr) */ pr_info("CPU%d has been hot-added\n", pr->id); pr->flags.need_hotplug_init = 1; - return 0; + +out: + cpu_hotplug_done(); + cpu_maps_update_done(); + return ret; } #else static inline int acpi_processor_hotadd_init(struct acpi_processor *pr) @@ -452,11 +459,15 @@ static void acpi_processor_remove(struct acpi_device *device) per_cpu(processor_device_array, pr->id) = NULL; per_cpu(processors, pr->id) = NULL; + cpu_maps_update_begin(); + cpu_hotplug_begin(); + /* Remove the CPU. */ - get_online_cpus(); arch_unregister_cpu(pr->id); acpi_unmap_lsapic(pr->id); - put_online_cpus(); + + cpu_hotplug_done(); + cpu_maps_update_done(); try_offline_node(cpu_to_node(pr->id)); diff --git a/include/linux/cpu.h b/include/linux/cpu.h index ab0eade..956c0a1 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -172,6 +172,8 @@ extern struct bus_type cpu_subsys; #ifdef CONFIG_HOTPLUG_CPU /* Stop CPUs going up and down. */ +extern void cpu_hotplug_begin(void); +extern void cpu_hotplug_done(void); extern void get_online_cpus(void); extern void put_online_cpus(void); extern void cpu_hotplug_disable(void); @@ -197,6 +199,8 @@ static inline void cpu_hotplug_driver_unlock(void) #else /* CONFIG_HOTPLUG_CPU */ +static inline void cpu_hotplug_begin(void) {} +static inline void cpu_hotplug_done(void) {} #define get_online_cpus() do { } while (0) #define put_online_cpus() do { } while (0) #define cpu_hotplug_disable() do { } while (0) diff --git a/kernel/cpu.c b/kernel/cpu.c index b2b227b..d7f07a2 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -113,7 +113,7 @@ EXPORT_SYMBOL_GPL(put_online_cpus); * get_online_cpus() not an api which is called all that often. * */ -static void cpu_hotplug_begin(void) +void cpu_hotplug_begin(void) { cpu_hotplug.active_writer = current; @@ -127,7 +127,7 @@ static void cpu_hotplug_begin(void) } } -static void cpu_hotplug_done(void) +void cpu_hotplug_done(void) { cpu_hotplug.active_writer = NULL; mutex_unlock(&cpu_hotplug.lock); @@ -154,10 +154,7 @@ void cpu_hotplug_enable(void) cpu_maps_update_done(); } -#else /* #if CONFIG_HOTPLUG_CPU */ -static void cpu_hotplug_begin(void) {} -static void cpu_hotplug_done(void) {} -#endif /* #else #if CONFIG_HOTPLUG_CPU */ +#endif /* CONFIG_HOTPLUG_CPU */ /* Need to know about CPUs going up/down? */ int __ref register_cpu_notifier(struct notifier_block *nb) -- cgit v0.10.2 From 027951e5650eefffa4d9fffad561468ea77ededa Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 13 Aug 2013 18:31:13 +0800 Subject: ACPI / dock: Fix __init attribute location in find_dock_and_bay() __init belongs after the return type on functions, not before it. Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 8265607..c90112c 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -1055,7 +1055,7 @@ err_unregister: * * This is called by acpi_walk_namespace to look for dock stations and bays. */ -static __init acpi_status +static acpi_status __init find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) { if (is_dock(handle) || is_ejectable_bay(handle)) -- cgit v0.10.2 From 40e318563c3748fd5c6712d163e5d663af8b22ae Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 13 Aug 2013 18:31:14 +0800 Subject: ACPI / numa: Fix __init attribute location in slit_valid() __init belongs after the return type on functions, not before it. Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 33e609f..2e82e5d 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -159,7 +159,7 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header) * distance than the others. * Do some quick checks here and only use the SLIT if it passes. */ -static __init int slit_valid(struct acpi_table_slit *slit) +static int __init slit_valid(struct acpi_table_slit *slit) { int i, j; int d = slit->locality_count; -- cgit v0.10.2 From e73d3136355f511d3e1c2ef21acf02b19bd2b650 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 13 Aug 2013 18:31:15 +0800 Subject: ACPI / osl: Fix osi_setup_entries[] __initdata attribute location __initdata should come after the variable name being declared and nowhere else, in this way the variable will be placed in the intended section. Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 605718f..eb95978 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1352,8 +1352,8 @@ struct osi_setup_entry { bool enable; }; -static struct osi_setup_entry __initdata - osi_setup_entries[OSI_STRING_ENTRIES_MAX] = { +static struct osi_setup_entry + osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = { {"Module Device", true}, {"Processor Device", true}, {"3.0 _SCP Extensions", true}, -- cgit v0.10.2 From bf0dd264b1207b090858e7847919af5f2e367d7c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Aug 2013 15:29:38 +0800 Subject: ACPICA: Fix possible fault for methods that optionally have no return value. Currently applies to the _WAK method only. If the method has no return value and slack mode is not enabled, the return value validation code can fault. Also improves the error message when an expected return value is missing (for any predefined name/method). The problem fixed here cannot happen on Linux unless acpi=strict is added to the kernel command line. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 24b71a0..098e766 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -151,6 +151,15 @@ acpi_ns_check_return_value(struct acpi_namespace_node *node, } /* + * + * 4) If there is no return value and it is optional, just return + * AE_OK (_WAK). + */ + if (!(*return_object_ptr)) { + goto exit; + } + + /* * For returned Package objects, check the type of all sub-objects. * Note: Package may have been newly created by call above. */ @@ -268,7 +277,12 @@ acpi_ns_check_object_type(struct acpi_evaluate_info *info, acpi_ut_get_expected_return_types(type_buffer, expected_btypes); - if (package_index == ACPI_NOT_PACKAGE_ELEMENT) { + if (!return_object) { + ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, + info->node_flags, + "Expected return object of type %s", + type_buffer)); + } else if (package_index == ACPI_NOT_PACKAGE_ELEMENT) { ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags, "Return type mismatch - found %s, expected %s", -- cgit v0.10.2 From 2641f540800b47a1b9e9d8ce9d682fc15df088e2 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 8 Aug 2013 15:29:46 +0800 Subject: ACPICA: Fix divergences of the commit - ACPICA: Expose OSI version. The original commit 242b2287cd7f27521c8b54a4101d569e53e7a0ca "ACPICA: expose OSI version" triggers build errors in ACPICA when it is back ported. The patch removes the divergences between Linux and upstream ACPICA resulting from that. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index b8d3811..90e846f 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -138,6 +138,12 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE); */ u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_ssdt_table_load, FALSE); +/* + * We keep track of the latest version of Windows that has been requested by + * the BIOS. + */ +u8 ACPI_INIT_GLOBAL(acpi_gbl_osi_data, 0); + /* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ struct acpi_table_fadt acpi_gbl_FADT; @@ -285,7 +291,6 @@ ACPI_EXTERN u8 acpi_gbl_debugger_configuration; ACPI_EXTERN u8 acpi_gbl_step_to_next_call; ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; ACPI_EXTERN u8 acpi_gbl_events_initialized; -ACPI_EXTERN u8 acpi_gbl_osi_data; ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces; ACPI_EXTERN struct acpi_address_range *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX]; diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index f736448..d6f26bf 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -336,7 +336,6 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_trace_dbg_layer = 0; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT; - acpi_gbl_osi_data = 0; acpi_gbl_osi_mutex = NULL; acpi_gbl_reg_methods_executed = FALSE; diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index eae55fb..b748aef 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1137,7 +1137,19 @@ struct acpi_memory_list { #endif }; -/* Definitions for _OSI support */ +/* Definitions of _OSI support */ + +#define ACPI_VENDOR_STRINGS 0x01 +#define ACPI_FEATURE_STRINGS 0x02 +#define ACPI_ENABLE_INTERFACES 0x00 +#define ACPI_DISABLE_INTERFACES 0x04 + +#define ACPI_DISABLE_ALL_VENDOR_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS) +#define ACPI_DISABLE_ALL_FEATURE_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_FEATURE_STRINGS) +#define ACPI_DISABLE_ALL_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) +#define ACPI_ENABLE_ALL_VENDOR_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS) +#define ACPI_ENABLE_ALL_FEATURE_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_FEATURE_STRINGS) +#define ACPI_ENABLE_ALL_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) #define ACPI_OSI_WIN_2000 0x01 #define ACPI_OSI_WIN_XP 0x02 @@ -1152,18 +1164,4 @@ struct acpi_memory_list { #define ACPI_OSI_WIN_7 0x0B #define ACPI_OSI_WIN_8 0x0C -/* _OSI update actions */ - -#define ACPI_VENDOR_STRINGS 0x01 -#define ACPI_FEATURE_STRINGS 0x02 -#define ACPI_ENABLE_INTERFACES 0x00 -#define ACPI_DISABLE_INTERFACES 0x04 - -#define ACPI_DISABLE_ALL_VENDOR_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS) -#define ACPI_DISABLE_ALL_FEATURE_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_FEATURE_STRINGS) -#define ACPI_DISABLE_ALL_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) -#define ACPI_ENABLE_ALL_VENDOR_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS) -#define ACPI_ENABLE_ALL_FEATURE_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_FEATURE_STRINGS) -#define ACPI_ENABLE_ALL_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) - #endif /* __ACTYPES_H__ */ -- cgit v0.10.2 From 1d82980c99ef2a91459ea39627d8114befb2c895 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Aug 2013 15:29:51 +0800 Subject: ACPICA: Make ACPI Power Management Timer (PM Timer) optional. PM Timer is now optional. This support is already in Windows8 and "SHOULD" come out in ACPI 5.0A (if all goes well). The change doesn't affect Linux directly, because it does not rely on the presence of the PM timer. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 0c1a8bb..2d7d22e 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -100,8 +100,13 @@ acpi_status acpi_get_timer(u32 * ticks) return_ACPI_STATUS(AE_BAD_PARAMETER); } - status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block); + /* ACPI 5.0A: PM Timer is optional */ + + if (!acpi_gbl_FADT.xpm_timer_block.address) { + return_ACPI_STATUS(AE_SUPPORT); + } + status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block); return_ACPI_STATUS(status); } @@ -148,6 +153,12 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) return_ACPI_STATUS(AE_BAD_PARAMETER); } + /* ACPI 5.0A: PM Timer is optional */ + + if (!acpi_gbl_FADT.xpm_timer_block.address) { + return_ACPI_STATUS(AE_SUPPORT); + } + /* * Compute Tick Delta: * Handle (max one) timer rollovers on 24-bit versus 32-bit timers. diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 33b00d2..9d99f21 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -117,7 +117,7 @@ static struct acpi_fadt_info fadt_info_table[] = { ACPI_FADT_OFFSET(pm_timer_block), ACPI_FADT_OFFSET(pm_timer_length), ACPI_PM_TIMER_WIDTH, - ACPI_FADT_REQUIRED}, + ACPI_FADT_SEPARATE_LENGTH}, /* ACPI 5.0A: Timer is optional */ {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block), @@ -574,7 +574,7 @@ static void acpi_tb_validate_fadt(void) if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { /* - * Field is required (Pm1a_event, Pm1a_control, pm_timer). + * Field is required (Pm1a_event, Pm1a_control). * Both the address and length must be non-zero. */ if (!address64->address || !length) { -- cgit v0.10.2 From a50abf4842dd7d603a2ad6dcc7f1467fd2a66f03 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Aug 2013 15:29:58 +0800 Subject: ACPICA: Return error if DerefOf resolves to a null package element. Disallow the dereference of a reference (via index) to an uninitialized package element. Provides compatibility with other ACPI implementations. ACPICA BZ 1003. References: https://bugs.acpica.org/show_bug.cgi?id=431 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 3482df4..2cdd41d 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -962,10 +962,17 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) */ return_desc = *(operand[0]->reference.where); - if (return_desc) { - acpi_ut_add_reference - (return_desc); + if (!return_desc) { + /* + * Element is NULL, do not allow the dereference. + * This provides compatibility with other ACPI + * implementations. + */ + return_ACPI_STATUS + (AE_AML_UNINITIALIZED_ELEMENT); } + + acpi_ut_add_reference(return_desc); break; default: -- cgit v0.10.2 From 4ef17507834d19ba4fc24c4c1c61e8f68df356a6 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Aug 2013 15:30:05 +0800 Subject: ACPICA: Update names for walk_namespace callbacks to clarify usage. Use of "preorder" and "postorder" was incorrect. The callbacks are simply invoked during tree ascent and descent during the depth-first walk. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index b83dc32..40b04bd 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -104,8 +104,8 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_object, u32 max_depth, u32 flags, - acpi_walk_callback pre_order_visit, - acpi_walk_callback post_order_visit, + acpi_walk_callback descending_callback, + acpi_walk_callback ascending_callback, void *context, void **return_value); struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index e70911a..e81f15e 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -156,9 +156,9 @@ struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, * max_depth - Depth to which search is to reach * flags - Whether to unlock the NS before invoking * the callback routine - * pre_order_visit - Called during tree pre-order visit + * descending_callback - Called during tree descent * when an object of "Type" is found - * post_order_visit - Called during tree post-order visit + * ascending_callback - Called during tree ascent * when an object of "Type" is found * context - Passed to user function(s) above * return_value - from the user_function if terminated @@ -185,8 +185,8 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_node, u32 max_depth, u32 flags, - acpi_walk_callback pre_order_visit, - acpi_walk_callback post_order_visit, + acpi_walk_callback descending_callback, + acpi_walk_callback ascending_callback, void *context, void **return_value) { acpi_status status; @@ -255,22 +255,22 @@ acpi_ns_walk_namespace(acpi_object_type type, } /* - * Invoke the user function, either pre-order or post-order + * Invoke the user function, either descending, ascending, * or both. */ if (!node_previously_visited) { - if (pre_order_visit) { + if (descending_callback) { status = - pre_order_visit(child_node, level, - context, - return_value); + descending_callback(child_node, + level, context, + return_value); } } else { - if (post_order_visit) { + if (ascending_callback) { status = - post_order_visit(child_node, level, - context, - return_value); + ascending_callback(child_node, + level, context, + return_value); } } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index f553cfd..b38b4b0 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -533,9 +533,9 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info) * PARAMETERS: type - acpi_object_type to search for * start_object - Handle in namespace where search begins * max_depth - Depth to which search is to reach - * pre_order_visit - Called during tree pre-order visit + * descending_callback - Called during tree descent * when an object of "Type" is found - * post_order_visit - Called during tree post-order visit + * ascending_callback - Called during tree ascent * when an object of "Type" is found * context - Passed to user function(s) above * return_value - Location where return value of @@ -563,8 +563,8 @@ acpi_status acpi_walk_namespace(acpi_object_type type, acpi_handle start_object, u32 max_depth, - acpi_walk_callback pre_order_visit, - acpi_walk_callback post_order_visit, + acpi_walk_callback descending_callback, + acpi_walk_callback ascending_callback, void *context, void **return_value) { acpi_status status; @@ -574,7 +574,7 @@ acpi_walk_namespace(acpi_object_type type, /* Parameter validation */ if ((type > ACPI_TYPE_LOCAL_MAX) || - (!max_depth) || (!pre_order_visit && !post_order_visit)) { + (!max_depth) || (!descending_callback && !ascending_callback)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -606,9 +606,9 @@ acpi_walk_namespace(acpi_object_type type, } status = acpi_ns_walk_namespace(type, start_object, max_depth, - ACPI_NS_WALK_UNLOCK, pre_order_visit, - post_order_visit, context, - return_value); + ACPI_NS_WALK_UNLOCK, + descending_callback, ascending_callback, + context, return_value); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 0dd03f2..e53f16a 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -212,8 +212,8 @@ acpi_status acpi_walk_namespace(acpi_object_type type, acpi_handle start_object, u32 max_depth, - acpi_walk_callback pre_order_visit, - acpi_walk_callback post_order_visit, + acpi_walk_callback descending_callback, + acpi_walk_callback ascending_callback, void *context, void **return_value); acpi_status -- cgit v0.10.2 From 36b99b22877bd25162239f1b00477ee6ae2d01ee Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Aug 2013 15:30:11 +0800 Subject: ACPICA: Update version to 20130725. Version 20130725. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index e53f16a..85bfdbe 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20130626 +#define ACPI_CA_VERSION 0x20130725 #include #include -- cgit v0.10.2 From 81455e72211e41972cca1d4686bc07b2e93b81e1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 14 Aug 2013 11:11:12 +0200 Subject: cpuidle-kirkwood.c: simplify use of devm_ioremap_resource() Remove unneeded error handling on the result of a call to platform_get_resource when the value is passed to devm_ioremap_resource(). A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression pdev,res,n,e,e1; expression ret != 0; identifier l; @@ - res = platform_get_resource(pdev, IORESOURCE_MEM, n); ... when != res - if (res == NULL) { ... \(goto l;\|return ret;\) } ... when != res + res = platform_get_resource(pdev, IORESOURCE_MEM, n); e = devm_ioremap_resource(e1, res); // Signed-off-by: Julia Lawall Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 3ca3a2e..41ba843 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -60,9 +60,6 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev) struct resource *res; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) - return -EINVAL; - ddr_operation_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ddr_operation_base)) return PTR_ERR(ddr_operation_base); -- cgit v0.10.2 From 59027d356666a2c1d576baacb98de9fb30e4c48e Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 13 Aug 2013 10:05:53 +0800 Subject: acpi-cpufreq: Use cpufreq_freq_attr_rw to define the cpb attribute Standardise the defintion of the cpb (Core Performance Boost) attribute in the acpi-cpufreq driver via the cpufreq_freq_attr_rw macro. [rjw: Subject and changelog] Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 9b5d1b1..a1260b4 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -197,7 +197,7 @@ static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf) return sprintf(buf, "%u\n", boost_enabled); } -static struct freq_attr cpb = __ATTR(cpb, 0644, show_cpb, store_cpb); +cpufreq_freq_attr_rw(cpb); #endif static int check_est_cpu(unsigned int cpuid) -- cgit v0.10.2 From 4a511de96d692f2dfa126c10dda4e41636c0ef27 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 13 Aug 2013 14:58:24 +0200 Subject: cpufreq: cpufreq-cpu0: NULL is a valid regulator Since NULL could in theory be a valid regulator we ought to check for IS_ERR() rather than for NULL. In practice this is unlikely to be an issue but it's better for neatness. Signed-off-by: Mark Brown Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index ad1fde2..09cd3a7 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -69,7 +69,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - if (cpu_reg) { + if (!IS_ERR(cpu_reg)) { rcu_read_lock(); opp = opp_find_freq_ceil(cpu_dev, &freq_Hz); if (IS_ERR(opp)) { @@ -90,7 +90,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, freqs.new / 1000, volt ? volt / 1000 : -1); /* scaling up? scale voltage before frequency */ - if (cpu_reg && freqs.new > freqs.old) { + if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) { ret = regulator_set_voltage_tol(cpu_reg, volt, tol); if (ret) { pr_err("failed to scale voltage up: %d\n", ret); @@ -102,14 +102,14 @@ static int cpu0_set_target(struct cpufreq_policy *policy, ret = clk_set_rate(cpu_clk, freq_exact); if (ret) { pr_err("failed to set clock rate: %d\n", ret); - if (cpu_reg) + if (!IS_ERR(cpu_reg)) regulator_set_voltage_tol(cpu_reg, volt_old, tol); freqs.new = freqs.old; goto post_notify; } /* scaling down? scale voltage after frequency */ - if (cpu_reg && freqs.new < freqs.old) { + if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) { ret = regulator_set_voltage_tol(cpu_reg, volt, tol); if (ret) { pr_err("failed to scale voltage down: %d\n", ret); @@ -210,7 +210,6 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) } pr_warn("failed to get cpu0 regulator: %ld\n", PTR_ERR(cpu_reg)); - cpu_reg = NULL; } cpu_clk = devm_clk_get(cpu_dev, NULL); -- cgit v0.10.2 From 8ee3f8e038d4261f70940364415c0680f4014eb6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 13 Aug 2013 15:02:25 +0200 Subject: pxa3xx-cpufreq.c: Avoid using ARRAY_AND_SIZE(e) as a function argument Replace ARRAY_AND_SIZE(e) in function argument position to avoid hiding the arity of the called function. The semantic match that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression e,f; @@ f(..., - ARRAY_AND_SIZE(e) + e,ARRAY_SIZE(e) ,...) // Signed-off-by: Julia Lawall Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c index 9c92ef0..d26306f 100644 --- a/drivers/cpufreq/pxa3xx-cpufreq.c +++ b/drivers/cpufreq/pxa3xx-cpufreq.c @@ -213,10 +213,12 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy) policy->cur = policy->min = policy->max; if (cpu_is_pxa300() || cpu_is_pxa310()) - ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa300_freqs)); + ret = setup_freqs_table(policy, pxa300_freqs, + ARRAY_SIZE(pxa300_freqs)); if (cpu_is_pxa320()) - ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa320_freqs)); + ret = setup_freqs_table(policy, pxa320_freqs, + ARRAY_SIZE(pxa320_freqs)); if (ret) { pr_err("failed to setup frequency table\n"); -- cgit v0.10.2 From af97385ad4054fc2f2e1eddfe3d9f4a12e36e051 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 13 Aug 2013 18:20:08 +0800 Subject: cpufreq / gx: Fix gx_detect_chipset() __init attribute location __init belongs after the return type on functions, not before it. Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c index ef5fee7..70442c7 100644 --- a/drivers/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -183,7 +183,7 @@ static void gx_write_byte(int reg, int value) * gx_detect_chipset: * **/ -static __init struct pci_dev *gx_detect_chipset(void) +static struct pci_dev * __init gx_detect_chipset(void) { struct pci_dev *gx_pci = NULL; -- cgit v0.10.2 From 295dbde1c6d5a07979d2f0ba7aff4c170656314a Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 13 Aug 2013 18:20:09 +0800 Subject: cpufreq / pxa2xx: Fix pxa_cpufreq_init_voltages() __init attribute location __init belongs after the return type on functions, not before it. Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c index fb3981a..8749eaf 100644 --- a/drivers/cpufreq/pxa2xx-cpufreq.c +++ b/drivers/cpufreq/pxa2xx-cpufreq.c @@ -191,7 +191,7 @@ static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq) return ret; } -static __init void pxa_cpufreq_init_voltages(void) +static void __init pxa_cpufreq_init_voltages(void) { vcc_core = regulator_get(NULL, "vcc_core"); if (IS_ERR(vcc_core)) { @@ -207,7 +207,7 @@ static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq) return 0; } -static __init void pxa_cpufreq_init_voltages(void) { } +static void __init pxa_cpufreq_init_voltages(void) { } #endif static void find_freq_tables(struct cpufreq_frequency_table **freq_table, -- cgit v0.10.2 From 21b4c415e43717b3dbc17ebef66ee2054f8f2e21 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 13 Aug 2013 18:20:10 +0800 Subject: cpufreq / s3c24xx: Fix s3c_cpufreq_initclks() __init attribute location __init belongs after the return type on functions, not before it. Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index f169ee5..b0f343f 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -392,7 +392,7 @@ static int s3c_cpufreq_init(struct cpufreq_policy *policy) return 0; } -static __init int s3c_cpufreq_initclks(void) +static int __init s3c_cpufreq_initclks(void) { _clk_mpll = s3c_cpufreq_clk_get(NULL, "mpll"); _clk_xtal = s3c_cpufreq_clk_get(NULL, "xtal"); -- cgit v0.10.2 From 0e25246fb3d7455dc3405435da70156370e285ec Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 9 Aug 2013 16:14:51 +0900 Subject: cpufreq: unicore2: Staticize local symbol This local symbol is used only in this file. Fix the following sparse warnings: drivers/cpufreq/unicore2-cpufreq.c:27:5: warning: symbol 'ucv2_verify_speed' was not declared. Should it be static? Signed-off-by: Jingoo Han Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c index 12fc904..b225f04 100644 --- a/drivers/cpufreq/unicore2-cpufreq.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -24,7 +24,7 @@ static struct cpufreq_driver ucv2_driver; /* make sure that only the "userspace" governor is run * -- anything else wouldn't make sense on this platform, anyway. */ -int ucv2_verify_speed(struct cpufreq_policy *policy) +static int ucv2_verify_speed(struct cpufreq_policy *policy) { if (policy->cpu) return -EINVAL; -- cgit v0.10.2 From 8a6036b92620a4ea0a1285d5c134ac9610ff4b32 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 14 Aug 2013 21:00:37 +0800 Subject: ACPI / thermal: Remove the unused lock of struct acpi_thermal The acpi_thermal->lock now just is initialized when a thermal zone device is added and destroyed when the thermal zone is removed. It is never used in any other places, so remove it. Signed-off-by: Lan Tianyu Acked-by: Zhang Rui Acked-by: Durgadoss R Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 547a906..dc1ba6c 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -190,7 +190,6 @@ struct acpi_thermal { struct thermal_zone_device *thermal_zone; int tz_enabled; int kelvin_offset; - struct mutex lock; }; /* -------------------------------------------------------------------------- @@ -1098,8 +1097,6 @@ static int acpi_thermal_add(struct acpi_device *device) strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); device->driver_data = tz; - mutex_init(&tz->lock); - result = acpi_thermal_get_info(tz); if (result) @@ -1132,7 +1129,6 @@ static int acpi_thermal_remove(struct acpi_device *device) tz = acpi_driver_data(device); acpi_thermal_unregister_thermal_zone(tz); - mutex_destroy(&tz->lock); kfree(tz); return 0; } -- cgit v0.10.2 From b22131c254a9a3cfe0184b234ab8bd737b4c8ba2 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 14 Aug 2013 21:00:38 +0800 Subject: ACPI / thermal: Remove unused macros in the driver/acpi/thermal.c The ACPI_THERMAL_FILE* macros are not used now, so remove them. Signed-off-by: Lan Tianyu Acked-by: Zhang Rui Acked-by: Durgadoss R Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index dc1ba6c..eccd22d 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -50,11 +50,6 @@ #define ACPI_THERMAL_CLASS "thermal_zone" #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" -#define ACPI_THERMAL_FILE_STATE "state" -#define ACPI_THERMAL_FILE_TEMPERATURE "temperature" -#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points" -#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode" -#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency" #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80 #define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81 #define ACPI_THERMAL_NOTIFY_DEVICES 0x82 -- cgit v0.10.2 From 70f2903b506100396dbdb301ae1ead74842a6894 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 14 Aug 2013 21:00:39 +0800 Subject: ACPI / thermal: Use THERMAL_TRIPS_NONE macro to replace number It's unreadable to pass "-1" as trip parameter directly to thermal_zone_bind_cooling_device(). Use THERMAL_TRIPS_NONE instead. Signed-off-by: Lan Tianyu Acked-by: Zhang Rui Acked-by: Durgadoss R Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index eccd22d..ccf9527 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -843,12 +843,13 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, if (ACPI_SUCCESS(status) && (dev == device)) { if (bind) result = thermal_zone_bind_cooling_device - (thermal, -1, cdev, - THERMAL_NO_LIMIT, + (thermal, THERMAL_TRIPS_NONE, + cdev, THERMAL_NO_LIMIT, THERMAL_NO_LIMIT); else result = thermal_zone_unbind_cooling_device - (thermal, -1, cdev); + (thermal, THERMAL_TRIPS_NONE, + cdev); if (result) goto failed; } -- cgit v0.10.2 From d7b2c3d8fb6f53a370696572ef3578a7f8723147 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Wed, 14 Aug 2013 17:37:06 +0800 Subject: ACPI / x86: Print Hot-Pluggable Field in SRAT. The Hot-Pluggable field in SRAT suggests if the memory could be hotplugged while the system is running. Print it as well when parsing SRAT will help users to know which memory is hotpluggable. Signed-off-by: Tang Chen Reviewed-by: Wanpeng Li Reviewed-by: Zhang Yanfei Acked-by: Tejun Heo Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index cdd0da9..266ca91 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c @@ -146,6 +146,7 @@ int __init acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { u64 start, end; + u32 hotpluggable; int node, pxm; if (srat_disabled()) @@ -154,7 +155,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) goto out_err_bad_srat; if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) goto out_err; - if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) + hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE; + if (hotpluggable && !save_add_info()) goto out_err; start = ma->base_address; @@ -174,9 +176,10 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) node_set(node, numa_nodes_parsed); - printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n", - node, pxm, - (unsigned long long) start, (unsigned long long) end - 1); + pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s\n", + node, pxm, + (unsigned long long) start, (unsigned long long) end - 1, + hotpluggable ? " hotplug" : ""); return 0; out_err_bad_srat: -- cgit v0.10.2 From 598bae70c2a8e35c8d39b610cca2b32afcf047af Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Wed, 14 Aug 2013 17:37:07 +0800 Subject: earlycpio.c: Fix the confusing comment of find_cpio_data(). The comments of find_cpio_data() says: * @offset: When a matching file is found, this is the offset to the * beginning of the cpio. ...... But according to the code, dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4); nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4); .... *offset = (long)nptr - (long)data; /* data is the cpio file */ @offset is the offset of the next file, not the matching file itself. This is confused and may cause unnecessary waste of time to debug. So fix it. As Tejun Heo suggested, rename @offset to @nextoff which is more clear to users. And also adjust the new comments. Signed-off-by: Tang Chen Reviewed-by: Zhang Yanfei Reviewed-by: Tejun Heo Signed-off-by: Rafael J. Wysocki diff --git a/lib/earlycpio.c b/lib/earlycpio.c index 7aa7ce2..3eb3e47 100644 --- a/lib/earlycpio.c +++ b/lib/earlycpio.c @@ -49,22 +49,23 @@ enum cpio_fields { /** * cpio_data find_cpio_data - Search for files in an uncompressed cpio - * @path: The directory to search for, including a slash at the end - * @data: Pointer to the the cpio archive or a header inside - * @len: Remaining length of the cpio based on data pointer - * @offset: When a matching file is found, this is the offset to the - * beginning of the cpio. It can be used to iterate through - * the cpio to find all files inside of a directory path + * @path: The directory to search for, including a slash at the end + * @data: Pointer to the the cpio archive or a header inside + * @len: Remaining length of the cpio based on data pointer + * @nextoff: When a matching file is found, this is the offset from the + * beginning of the cpio to the beginning of the next file, not the + * matching file itself. It can be used to iterate through the cpio + * to find all files inside of a directory path. * - * @return: struct cpio_data containing the address, length and - * filename (with the directory path cut off) of the found file. - * If you search for a filename and not for files in a directory, - * pass the absolute path of the filename in the cpio and make sure - * the match returned an empty filename string. + * @return: struct cpio_data containing the address, length and + * filename (with the directory path cut off) of the found file. + * If you search for a filename and not for files in a directory, + * pass the absolute path of the filename in the cpio and make sure + * the match returned an empty filename string. */ struct cpio_data find_cpio_data(const char *path, void *data, - size_t len, long *offset) + size_t len, long *nextoff) { const size_t cpio_header_len = 8*C_NFIELDS - 2; struct cpio_data cd = { NULL, 0, "" }; @@ -124,7 +125,7 @@ struct cpio_data find_cpio_data(const char *path, void *data, if ((ch[C_MODE] & 0170000) == 0100000 && ch[C_NAMESIZE] >= mypathsize && !memcmp(p, path, mypathsize)) { - *offset = (long)nptr - (long)data; + *nextoff = (long)nptr - (long)data; if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { pr_warn( "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", -- cgit v0.10.2 From 7702ae0dd9b40930931914866999a2ac9734d3eb Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Wed, 14 Aug 2013 17:37:08 +0800 Subject: ACPI / osl: Kill macro INVALID_TABLE(). The macro INVALID_TABLE() is defined like this: #define INVALID_TABLE(x, path, name) \ { pr_err("ACPI OVERRIDE: " x " [%s%s]\n", path, name); continue; } And it is used like this: for (...) { ... if (...) INVALID_TABLE() ... } The "continue" in the macro makes the code hard to understand. And also, this macro is only used several times in a single file. As suggested by Joe Perches , we can remote it and use pr_err directly. So after this patch, this macro is removed, and pr_err() is used like this: for (...) { ... if (...) { pr_err("ACPI OVERRIDE: ......"); continue; } ... } Signed-off-by: Tang Chen Suggested-by: Joe Perches Acked-by: Tejun Heo Acked-by: Toshi Kani Reviewed-by: Zhang Yanfei Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index eb95978..6bc0827 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -564,10 +564,6 @@ static const char * const table_sigs[] = { ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL }; -/* Non-fatal errors: Affected tables/files are ignored */ -#define INVALID_TABLE(x, path, name) \ - { pr_err("ACPI OVERRIDE: " x " [%s%s]\n", path, name); continue; } - #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) /* Must not increase 10 or needs code modification below */ @@ -594,9 +590,11 @@ void __init acpi_initrd_override(void *data, size_t size) data += offset; size -= offset; - if (file.size < sizeof(struct acpi_table_header)) - INVALID_TABLE("Table smaller than ACPI header", - cpio_path, file.name); + if (file.size < sizeof(struct acpi_table_header)) { + pr_err("ACPI OVERRIDE: Table smaller than ACPI header [%s%s]\n", + cpio_path, file.name); + continue; + } table = file.data; @@ -604,15 +602,21 @@ void __init acpi_initrd_override(void *data, size_t size) if (!memcmp(table->signature, table_sigs[sig], 4)) break; - if (!table_sigs[sig]) - INVALID_TABLE("Unknown signature", - cpio_path, file.name); - if (file.size != table->length) - INVALID_TABLE("File length does not match table length", - cpio_path, file.name); - if (acpi_table_checksum(file.data, table->length)) - INVALID_TABLE("Bad table checksum", - cpio_path, file.name); + if (!table_sigs[sig]) { + pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n", + cpio_path, file.name); + continue; + } + if (file.size != table->length) { + pr_err("ACPI OVERRIDE: File length does not match table length [%s%s]\n", + cpio_path, file.name); + continue; + } + if (acpi_table_checksum(file.data, table->length)) { + pr_err("ACPI OVERRIDE: Bad table checksum [%s%s]\n", + cpio_path, file.name); + continue; + } pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n", table->signature, cpio_path, file.name, table->length); -- cgit v0.10.2 From 1aaac07112f04068d7e2fc47bb435cfd4f9d5468 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 17 Aug 2013 22:16:33 +0200 Subject: ACPI / hotplug / PCI: Fix NULL pointer dereference in cleanup_bridge() After commit bbd34fc (ACPI / hotplug / PCI: Register all devices under the given bridge) register_slot() is called for all PCI devices under a given bridge that have corresponding objects in the ACPI namespace, but it calls acpiphp_register_hotplug_slot() only for devices satisfying specific criteria. Still, cleanup_bridge() calls acpiphp_unregister_hotplug_slot() for all objects created by register_slot(), although it should only call it for the ones that acpiphp_register_hotplug_slot() has been called for (successfully). This causes a NULL pointer to be dereferenced by the acpiphp_unregister_hotplug_slot() executed by cleanup_bridge() if the object it is called for has not been passed to acpiphp_register_hotplug_slot(). To fix this problem, check if the 'slot' field of the object passed to acpiphp_unregister_hotplug_slot() in cleanup_bridge() is not NULL, which only is the case if acpiphp_register_hotplug_slot() has been executed for that object. In addition to that, make register_slot() reset the 'slot' field to NULL if acpiphp_register_hotplug_slot() has failed for the given object to prevent stale pointers from being used by acpiphp_unregister_hotplug_slot(). Reported-and-tested-by: Yinghai Lu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 05e463d..8054ddc 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -340,6 +340,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, retval = acpiphp_register_hotplug_slot(slot, sun); if (retval) { + slot->slot = NULL; bridge->nr_slots--; if (retval == -EBUSY) warn("Slot %llu already registered by another " @@ -429,7 +430,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) err("failed to remove notify handler\n"); } } - acpiphp_unregister_hotplug_slot(slot); + if (slot->slot) + acpiphp_unregister_hotplug_slot(slot); } mutex_lock(&bridge_mutex); -- cgit v0.10.2 From 878f6e074e9a7784a6e351512eace4ccb3542eef Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 18 Aug 2013 15:35:59 +0200 Subject: Revert "cpufreq: Use cpufreq_policy_list for iterating over policies" Revert commit eb60852 (cpufreq: Use cpufreq_policy_list for iterating over policies), because it breaks system suspend/resume on multiple machines. It either causes resume to block indefinitely or causes the BUG_ON() in lock_policy_rwsem_##mode() to trigger on sysfs accesses to cpufreq attributes. Conflicts: drivers/cpufreq/cpufreq.c diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 37a6874..c0ef84d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -969,8 +969,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, struct cpufreq_policy *policy; unsigned long flags; #ifdef CONFIG_HOTPLUG_CPU - struct cpufreq_policy *tpolicy; struct cpufreq_governor *gov; + int sibling; #endif if (cpu_is_offline(cpu)) @@ -993,10 +993,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, #ifdef CONFIG_HOTPLUG_CPU /* Check if this cpu was hot-unplugged earlier and has siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags); - list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { - if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { + for_each_online_cpu(sibling) { + struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); + if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen); + ret = cpufreq_add_policy_cpu(cp, cpu, dev, frozen); up_read(&cpufreq_rwsem); return ret; } -- cgit v0.10.2 From edab2fbc21b9eb37007ad8bffe1159d536bbb451 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 20 Aug 2013 12:08:22 +0530 Subject: cpufreq: Fix white space in __cpufreq_remove_dev() Align closing brace '}' of an if block. [rjw: Subject and changelog] Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index c0ef84d..fedc842 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1253,7 +1253,7 @@ static int __cpufreq_remove_dev(struct device *dev, __func__); return ret; } - } + } if (!frozen) { lock_policy_rwsem_read(cpu); -- cgit v0.10.2 From 9515f4d69b92feafe37581047a1bb41e41602faa Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 20 Aug 2013 12:08:23 +0530 Subject: cpufreq: remove policy from cpufreq_policy_list during suspend cpufreq_policy_list is a list of active policies. We do remove policies from this list when all CPUs belonging to that policy are removed. But during system suspend we don't really free a policy struct as it will be used again during resume, so we didn't remove it from cpufreq_policy_list as well.. However, this is incorrect. We are saying this policy isn't valid anymore and must not be referenced (though we haven't freed it), but it can still be used by code that iterates over cpufreq_policy_list. Remove policy from this list during system suspend as well. Of course, we must add it back whenever the first CPU belonging to that policy shows up. [rjw: Changelog] Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index fedc842..0302121 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -950,12 +950,6 @@ err_free_policy: static void cpufreq_policy_free(struct cpufreq_policy *policy) { - unsigned long flags; - - write_lock_irqsave(&cpufreq_driver_lock, flags); - list_del(&policy->policy_list); - write_unlock_irqrestore(&cpufreq_driver_lock, flags); - free_cpumask_var(policy->related_cpus); free_cpumask_var(policy->cpus); kfree(policy); @@ -1069,12 +1063,12 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, ret = cpufreq_add_dev_interface(policy, dev); if (ret) goto err_out_unregister; - - write_lock_irqsave(&cpufreq_driver_lock, flags); - list_add(&policy->policy_list, &cpufreq_policy_list); - write_unlock_irqrestore(&cpufreq_driver_lock, flags); } + write_lock_irqsave(&cpufreq_driver_lock, flags); + list_add(&policy->policy_list, &cpufreq_policy_list); + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + cpufreq_init_policy(policy); kobject_uevent(&policy->kobj, KOBJ_ADD); @@ -1280,6 +1274,11 @@ static int __cpufreq_remove_dev(struct device *dev, if (cpufreq_driver->exit) cpufreq_driver->exit(policy); + /* Remove policy from list of active policies */ + write_lock_irqsave(&cpufreq_driver_lock, flags); + list_del(&policy->policy_list); + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + if (!frozen) cpufreq_policy_free(policy); } else { -- cgit v0.10.2 From 9e9fd801676a946b759a8669baa24ba327c8c903 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 20 Aug 2013 12:08:24 +0530 Subject: cpufreq: remove unnecessary check in __cpufreq_governor() We don't need to check if event is CPUFREQ_GOV_POLICY_INIT and put governor module as we are sure event can only be START/STOP here. Remove the useless check. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0302121..b03a851 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1719,8 +1719,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) || (policy->governor_enabled && (event == CPUFREQ_GOV_START))) { mutex_unlock(&cpufreq_governor_lock); - if (event == CPUFREQ_GOV_POLICY_INIT) - module_put(policy->governor->owner); return -EBUSY; } -- cgit v0.10.2 From 474deff744c4012f07cfa994947d7c6260c9ab89 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 20 Aug 2013 12:08:25 +0530 Subject: cpufreq: remove cpufreq_policy_cpu per-cpu variable cpufreq_policy_cpu per-cpu variables are used for storing the ID of the CPU that manages the given CPU's policy. However, we also store a policy pointer for each cpu in cpufreq_cpu_data, so the cpufreq_policy_cpu information is simply redundant. It is better to use cpufreq_cpu_data to retrieve a policy and get policy->cpu from there, so make that happen everywhere and drop the cpufreq_policy_cpu per-cpu variables which aren't necessary any more. [rjw: Changelog] Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b03a851..0586bd2 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -64,15 +64,14 @@ static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); * - Lock should not be held across * __cpufreq_governor(data, CPUFREQ_GOV_STOP); */ -static DEFINE_PER_CPU(int, cpufreq_policy_cpu); static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem); #define lock_policy_rwsem(mode, cpu) \ static int lock_policy_rwsem_##mode(int cpu) \ { \ - int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ - BUG_ON(policy_cpu == -1); \ - down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ + struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); \ + BUG_ON(!policy); \ + down_##mode(&per_cpu(cpu_policy_rwsem, policy->cpu)); \ \ return 0; \ } @@ -83,9 +82,9 @@ lock_policy_rwsem(write, cpu); #define unlock_policy_rwsem(mode, cpu) \ static void unlock_policy_rwsem_##mode(int cpu) \ { \ - int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ - BUG_ON(policy_cpu == -1); \ - up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ + struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); \ + BUG_ON(!policy); \ + up_##mode(&per_cpu(cpu_policy_rwsem, policy->cpu)); \ } unlock_policy_rwsem(read, cpu); @@ -887,7 +886,6 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, write_lock_irqsave(&cpufreq_driver_lock, flags); cpumask_set_cpu(cpu, policy->cpus); - per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu; per_cpu(cpufreq_cpu_data, cpu) = policy; write_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -1013,9 +1011,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, policy->governor = CPUFREQ_DEFAULT_GOVERNOR; cpumask_copy(policy->cpus, cpumask_of(cpu)); - /* Initially set CPU itself as the policy_cpu */ - per_cpu(cpufreq_policy_cpu, cpu) = cpu; - init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); @@ -1053,10 +1048,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, #endif write_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu(j, policy->cpus) { + for_each_cpu(j, policy->cpus) per_cpu(cpufreq_cpu_data, j) = policy; - per_cpu(cpufreq_policy_cpu, j) = policy->cpu; - } write_unlock_irqrestore(&cpufreq_driver_lock, flags); if (!frozen) { @@ -1080,15 +1073,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, err_out_unregister: write_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu(j, policy->cpus) { + for_each_cpu(j, policy->cpus) per_cpu(cpufreq_cpu_data, j) = NULL; - if (j != cpu) - per_cpu(cpufreq_policy_cpu, j) = -1; - } write_unlock_irqrestore(&cpufreq_driver_lock, flags); err_set_policy_cpu: - per_cpu(cpufreq_policy_cpu, cpu) = -1; cpufreq_policy_free(policy); nomem_out: up_read(&cpufreq_rwsem); @@ -1112,14 +1101,9 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) { - int j; - policy->last_cpu = policy->cpu; policy->cpu = cpu; - for_each_cpu(j, policy->cpus) - per_cpu(cpufreq_policy_cpu, j) = cpu; - #ifdef CONFIG_CPU_FREQ_TABLE cpufreq_frequency_table_update_policy_cpu(policy); #endif @@ -1131,7 +1115,6 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, unsigned int old_cpu, bool frozen) { struct device *cpu_dev; - unsigned long flags; int ret; /* first sibling now owns the new sysfs dir */ @@ -1148,11 +1131,6 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, WARN_ON(lock_policy_rwsem_write(old_cpu)); cpumask_set_cpu(old_cpu, policy->cpus); - - write_lock_irqsave(&cpufreq_driver_lock, flags); - per_cpu(cpufreq_cpu_data, old_cpu) = policy; - write_unlock_irqrestore(&cpufreq_driver_lock, flags); - unlock_policy_rwsem_write(old_cpu); ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, @@ -1186,7 +1164,6 @@ static int __cpufreq_remove_dev(struct device *dev, write_lock_irqsave(&cpufreq_driver_lock, flags); policy = per_cpu(cpufreq_cpu_data, cpu); - per_cpu(cpufreq_cpu_data, cpu) = NULL; /* Save the policy somewhere when doing a light-weight tear-down */ if (frozen) @@ -1292,7 +1269,7 @@ static int __cpufreq_remove_dev(struct device *dev, } } - per_cpu(cpufreq_policy_cpu, cpu) = -1; + per_cpu(cpufreq_cpu_data, cpu) = NULL; return 0; } @@ -2148,10 +2125,8 @@ static int __init cpufreq_core_init(void) if (cpufreq_disabled()) return -ENODEV; - for_each_possible_cpu(cpu) { - per_cpu(cpufreq_policy_cpu, cpu) = -1; + for_each_possible_cpu(cpu) init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); - } cpufreq_global_kobject = kobject_create(); BUG_ON(!cpufreq_global_kobject); -- cgit v0.10.2 From 1b27429446f0c37353179544e844dc2086fa2353 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 20 Aug 2013 12:08:26 +0530 Subject: cpufreq: Use cpufreq_policy_list for iterating over policies To iterate over all policies we currently iterate over all online CPUs and then get the policy for each of them which is suboptimal. Use the newly created cpufreq_policy_list for this purpose instead. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0586bd2..81ceea6 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -961,8 +961,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, struct cpufreq_policy *policy; unsigned long flags; #ifdef CONFIG_HOTPLUG_CPU + struct cpufreq_policy *tpolicy; struct cpufreq_governor *gov; - int sibling; #endif if (cpu_is_offline(cpu)) @@ -985,11 +985,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, #ifdef CONFIG_HOTPLUG_CPU /* Check if this cpu was hot-unplugged earlier and has siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_online_cpu(sibling) { - struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); - if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { + list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { + if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - ret = cpufreq_add_policy_cpu(cp, cpu, dev, frozen); + ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen); up_read(&cpufreq_rwsem); return ret; } -- cgit v0.10.2 From ad07277e82dedabacc52c82746633680a3187d25 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 20 Aug 2013 01:42:32 +0200 Subject: ACPI / PM: Hold acpi_scan_lock over system PM transitions Bad things happen if ACPI hotplug events are handled during system PM transitions, especially if devices are removed as a result. To prevent those bad things from happening, acquire acpi_scan_lock when a PM transition is started and release it when that transition is complete or has been aborted. This fixes resume lockup on my test-bed Acer Aspire S5 that happens when Thunderbolt devices are disconnected from the machine while suspended. Also fixes the analogous problem for Mika Westerberg on an Intel DZ77RE-75K board. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg Acked-by: Toshi Kani diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 81b0f03..1dec53d 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -420,10 +420,21 @@ static void acpi_pm_finish(void) } /** - * acpi_pm_end - Finish up suspend sequence. + * acpi_pm_start - Start system PM transition. + */ +static void acpi_pm_start(u32 acpi_state) +{ + acpi_target_sleep_state = acpi_state; + acpi_sleep_tts_switch(acpi_target_sleep_state); + acpi_scan_lock_acquire(); +} + +/** + * acpi_pm_end - Finish up system PM transition. */ static void acpi_pm_end(void) { + acpi_scan_lock_release(); /* * This is necessary in case acpi_pm_finish() is not called during a * failing transition to a sleep state. @@ -451,21 +462,19 @@ static u32 acpi_suspend_states[] = { static int acpi_suspend_begin(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; - int error = 0; + int error; error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc(); if (error) return error; - if (sleep_states[acpi_state]) { - acpi_target_sleep_state = acpi_state; - acpi_sleep_tts_switch(acpi_target_sleep_state); - } else { - printk(KERN_ERR "ACPI does not support this state: %d\n", - pm_state); - error = -ENOSYS; + if (!sleep_states[acpi_state]) { + pr_err("ACPI does not support sleep state S%u\n", acpi_state); + return -ENOSYS; } - return error; + + acpi_pm_start(acpi_state); + return 0; } /** @@ -631,10 +640,8 @@ static int acpi_hibernation_begin(void) int error; error = nvs_nosave ? 0 : suspend_nvs_alloc(); - if (!error) { - acpi_target_sleep_state = ACPI_STATE_S4; - acpi_sleep_tts_switch(acpi_target_sleep_state); - } + if (!error) + acpi_pm_start(ACPI_STATE_S4); return error; } @@ -713,8 +720,10 @@ static int acpi_hibernation_begin_old(void) if (!error) { if (!nvs_nosave) error = suspend_nvs_alloc(); - if (!error) + if (!error) { acpi_target_sleep_state = ACPI_STATE_S4; + acpi_scan_lock_acquire(); + } } return error; } -- cgit v0.10.2 From 5025d628c8659fbf939f929107bf76db81dcdfff Mon Sep 17 00:00:00 2001 From: Li Zhong Date: Wed, 21 Aug 2013 01:31:08 +0200 Subject: cpufreq: fix bad unlock balance on !CONFIG_SMP This patch tries to fix lockdep complaint attached below. It seems that we should always read acquire the cpufreq_rwsem, whether CONFIG_SMP is enabled or not. And CONFIG_HOTPLUG_CPU depends on CONFIG_SMP, so it seems we don't need CONFIG_SMP for the code enabled by CONFIG_HOTPLUG_CPU. [ 0.504191] ===================================== [ 0.504627] [ BUG: bad unlock balance detected! ] [ 0.504627] 3.11.0-rc6-next-20130819 #1 Not tainted [ 0.504627] ------------------------------------- [ 0.504627] swapper/1 is trying to release lock (cpufreq_rwsem) at: [ 0.504627] [] cpufreq_add_dev+0x13a/0x3e0 [ 0.504627] but there are no more locks to release! [ 0.504627] [ 0.504627] other info that might help us debug this: [ 0.504627] 1 lock held by swapper/1: [ 0.504627] #0: (subsys mutex#4){+.+.+.}, at: [] subsys_interface_register+0x4f/0xe0 [ 0.504627] [ 0.504627] stack backtrace: [ 0.504627] CPU: 0 PID: 1 Comm: swapper Not tainted 3.11.0-rc6-next-20130819 #1 [ 0.504627] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 [ 0.504627] ffffffff813d927a ffff88007f847c98 ffffffff814c062b ffff88007f847cc8 [ 0.504627] ffffffff81098bce ffff88007f847cf8 ffffffff81aadc30 ffffffff813d927a [ 0.504627] 00000000ffffffff ffff88007f847d68 ffffffff8109d0be 0000000000000006 [ 0.504627] Call Trace: [ 0.504627] [] ? cpufreq_add_dev+0x13a/0x3e0 [ 0.504627] [] dump_stack+0x19/0x1b [ 0.504627] [] print_unlock_imbalance_bug+0xfe/0x110 [ 0.504627] [] ? cpufreq_add_dev+0x13a/0x3e0 [ 0.504627] [] lock_release_non_nested+0x1ee/0x310 [ 0.504627] [] ? mark_held_locks+0xae/0x120 [ 0.504627] [] ? kfree+0xcb/0x1d0 [ 0.504627] [] ? cpufreq_policy_free+0x4a/0x60 [ 0.504627] [] ? cpufreq_add_dev+0x13a/0x3e0 [ 0.504627] [] lock_release+0xc4/0x250 [ 0.504627] [] up_read+0x23/0x40 [ 0.504627] [] cpufreq_add_dev+0x13a/0x3e0 [ 0.504627] [] subsys_interface_register+0x99/0xe0 [ 0.504627] [] ? cpufreq_gov_dbs_init+0x12/0x12 [ 0.504627] [] cpufreq_register_driver+0x9d/0x1d0 [ 0.504627] [] ? cpufreq_gov_dbs_init+0x12/0x12 [ 0.504627] [] acpi_cpufreq_init+0xfe/0x1f8 [ 0.504627] [] do_one_initcall+0xda/0x180 [ 0.504627] [] kernel_init_freeable+0x12c/0x1bb [ 0.504627] [] ? do_early_param+0x8c/0x8c [ 0.504627] [] ? rest_init+0x140/0x140 [ 0.504627] [] kernel_init+0xe/0xf0 [ 0.504627] [] ret_from_fork+0x7a/0xb0 [ 0.504627] [] ? rest_init+0x140/0x140 Signed-off-by: Li Zhong Acked-and-tested-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 81ceea6..5c75e31 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -978,6 +978,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, cpufreq_cpu_put(policy); return 0; } +#endif if (!down_read_trylock(&cpufreq_rwsem)) return 0; @@ -995,7 +996,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, } read_unlock_irqrestore(&cpufreq_driver_lock, flags); #endif -#endif if (frozen) /* Restore the saved policy when doing light-weight init */ -- cgit v0.10.2 From 06baa2ae85295f37c30b3f7c254578cd2abb5e4b Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Thu, 15 Aug 2013 10:07:43 +0100 Subject: microblaze: remove undefined of_get_cpu_node declaration This patch removes the declaration of the function 'of_get_cpu_node' which is not defined for microblaze. This is in preparation to move it's definition from PPC to DT common code. Michal Simek says: "it was just there because Microblaze was based on powerpc code" Acked-by: Michal Simek Signed-off-by: Sudeep KarkadaNagesha diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 20c5e8e..9977816 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -50,9 +50,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, extern void kdump_move_device_tree(void); -/* CPU OF node matching */ -struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ -- cgit v0.10.2 From 007fb9aedc7544f67ffbdce95283b1c6c58999c3 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Thu, 15 Aug 2013 10:19:51 +0100 Subject: openrisc: remove undefined of_get_cpu_node declaration This patch removes the declaration of the function 'of_get_cpu_node' which is not defined for openrisc. This is in preparation to move it's definition from PPC to DT common code. Again it could be there as it was originally copied from powerpc. Acked-by: Jonas Bonn Signed-off-by: Sudeep KarkadaNagesha diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm/prom.h index bbb34e5..eb59bfe 100644 --- a/arch/openrisc/include/asm/prom.h +++ b/arch/openrisc/include/asm/prom.h @@ -44,9 +44,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, extern void kdump_move_device_tree(void); -/* CPU OF node matching */ -struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); - /* Get the MAC address */ extern const void *of_get_mac_address(struct device_node *np); -- cgit v0.10.2 From 819d596568d82ffb85b0b5989a1567810fe66098 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Thu, 15 Aug 2013 13:34:18 +0100 Subject: powerpc: refactor of_get_cpu_node to support other architectures Currently different drivers requiring to access cpu device node are parsing the device tree themselves. Since the ordering in the DT need not match the logical cpu ordering, the parsing logic needs to consider that. However, this has resulted in lots of code duplication and in some cases even incorrect logic. It's better to consolidate them by adding support for getting cpu device node for a given logical cpu index in DT core library. However logical to physical index mapping can be architecture specific. PowerPC has it's own implementation to get the cpu node for a given logical index. This patch refactors the current implementation of of_get_cpu_node. This in preparation to move the implementation to DT core library. It separates out the logical to physical mapping so that a default matching of the physical id to the logical cpu index can be added when moved to common code. Architecture specific code can override it. Cc: Rob Herring Cc: Grant Likely Acked-by: Benjamin Herrenschmidt Signed-off-by: Sudeep KarkadaNagesha diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index eb23ac9..f7b8c0b 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -865,45 +865,63 @@ static int __init prom_reconfig_setup(void) __initcall(prom_reconfig_setup); #endif +bool arch_match_cpu_phys_id(int cpu, u64 phys_id) +{ + return (int)phys_id == get_hard_smp_processor_id(cpu); +} + +static bool __of_find_n_match_cpu_property(struct device_node *cpun, + const char *prop_name, int cpu, unsigned int *thread) +{ + const __be32 *cell; + int ac, prop_len, tid; + u64 hwid; + + ac = of_n_addr_cells(cpun); + cell = of_get_property(cpun, prop_name, &prop_len); + if (!cell) + return false; + prop_len /= sizeof(*cell); + for (tid = 0; tid < prop_len; tid++) { + hwid = of_read_number(cell, ac); + if (arch_match_cpu_phys_id(cpu, hwid)) { + if (thread) + *thread = tid; + return true; + } + cell += ac; + } + return false; +} + /* Find the device node for a given logical cpu number, also returns the cpu * local thread number (index in ibm,interrupt-server#s) if relevant and * asked for (non NULL) */ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) { - int hardid; - struct device_node *np; + struct device_node *cpun, *cpus; - hardid = get_hard_smp_processor_id(cpu); + cpus = of_find_node_by_path("/cpus"); + if (!cpus) { + pr_warn("Missing cpus node, bailing out\n"); + return NULL; + } - for_each_node_by_type(np, "cpu") { - const u32 *intserv; - unsigned int plen, t; + for_each_child_of_node(cpus, cpun) { + if (of_node_cmp(cpun->type, "cpu")) + continue; - /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist - * fallback to "reg" property and assume no threads + /* Check for non-standard "ibm,ppc-interrupt-server#s" property + * for thread ids on PowerPC. If it doesn't exist fallback to + * standard "reg" property. */ - intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", - &plen); - if (intserv == NULL) { - const u32 *reg = of_get_property(np, "reg", NULL); - if (reg == NULL) - continue; - if (*reg == hardid) { - if (thread) - *thread = 0; - return np; - } - } else { - plen /= sizeof(u32); - for (t = 0; t < plen; t++) { - if (hardid == intserv[t]) { - if (thread) - *thread = t; - return np; - } - } - } + if (__of_find_n_match_cpu_property(cpun, + "ibm,ppc-interrupt-server#s", cpu, thread)) + return cpun; + + if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) + return cpun; } return NULL; } -- cgit v0.10.2 From 183912d352a242a276a7877852f107459a13aff9 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Thu, 15 Aug 2013 14:01:40 +0100 Subject: of: move of_get_cpu_node implementation to DT core library This patch moves the generalized implementation of of_get_cpu_node from PowerPC to DT core library, thereby adding support for retrieving cpu node for a given logical cpu index on any architecture. The CPU subsystem can now use this function to assign of_node in the cpu device while registering CPUs. It is recommended to use these helper function only in pre-SMP/early initialisation stages to retrieve CPU device node pointers in logical ordering. Once the cpu devices are registered, it can be retrieved easily from cpu device of_node which avoids unnecessary parsing and matching. Cc: Benjamin Herrenschmidt Cc: Grant Likely Acked-by: Rob Herring Signed-off-by: Sudeep KarkadaNagesha diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index bc2da15..ac204e0 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -43,9 +43,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, extern void kdump_move_device_tree(void); -/* CPU OF node matching */ -struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); - /* cache lookup */ struct device_node *of_find_next_cache_node(struct device_node *np); diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f7b8c0b..1c14cd4 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -870,63 +870,6 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id) return (int)phys_id == get_hard_smp_processor_id(cpu); } -static bool __of_find_n_match_cpu_property(struct device_node *cpun, - const char *prop_name, int cpu, unsigned int *thread) -{ - const __be32 *cell; - int ac, prop_len, tid; - u64 hwid; - - ac = of_n_addr_cells(cpun); - cell = of_get_property(cpun, prop_name, &prop_len); - if (!cell) - return false; - prop_len /= sizeof(*cell); - for (tid = 0; tid < prop_len; tid++) { - hwid = of_read_number(cell, ac); - if (arch_match_cpu_phys_id(cpu, hwid)) { - if (thread) - *thread = tid; - return true; - } - cell += ac; - } - return false; -} - -/* Find the device node for a given logical cpu number, also returns the cpu - * local thread number (index in ibm,interrupt-server#s) if relevant and - * asked for (non NULL) - */ -struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) -{ - struct device_node *cpun, *cpus; - - cpus = of_find_node_by_path("/cpus"); - if (!cpus) { - pr_warn("Missing cpus node, bailing out\n"); - return NULL; - } - - for_each_child_of_node(cpus, cpun) { - if (of_node_cmp(cpun->type, "cpu")) - continue; - - /* Check for non-standard "ibm,ppc-interrupt-server#s" property - * for thread ids on PowerPC. If it doesn't exist fallback to - * standard "reg" property. - */ - if (__of_find_n_match_cpu_property(cpun, - "ibm,ppc-interrupt-server#s", cpu, thread)) - return cpun; - - if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) - return cpun; - } - return NULL; -} -EXPORT_SYMBOL(of_get_cpu_node); - #if defined(CONFIG_DEBUG_FS) && defined(DEBUG) static struct debugfs_blob_wrapper flat_dt_blob; diff --git a/drivers/of/base.c b/drivers/of/base.c index 5c54279..605afa9 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -18,6 +18,7 @@ * 2 of the License, or (at your option) any later version. */ #include +#include #include #include #include @@ -230,6 +231,100 @@ const void *of_get_property(const struct device_node *np, const char *name, } EXPORT_SYMBOL(of_get_property); +/* + * arch_match_cpu_phys_id - Match the given logical CPU and physical id + * + * @cpu: logical cpu index of a core/thread + * @phys_id: physical identifier of a core/thread + * + * CPU logical to physical index mapping is architecture specific. + * However this __weak function provides a default match of physical + * id to logical cpu index. phys_id provided here is usually values read + * from the device tree which must match the hardware internal registers. + * + * Returns true if the physical identifier and the logical cpu index + * correspond to the same core/thread, false otherwise. + */ +bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id) +{ + return (u32)phys_id == cpu; +} + +/** + * Checks if the given "prop_name" property holds the physical id of the + * core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not + * NULL, local thread number within the core is returned in it. + */ +static bool __of_find_n_match_cpu_property(struct device_node *cpun, + const char *prop_name, int cpu, unsigned int *thread) +{ + const __be32 *cell; + int ac, prop_len, tid; + u64 hwid; + + ac = of_n_addr_cells(cpun); + cell = of_get_property(cpun, prop_name, &prop_len); + if (!cell) + return false; + prop_len /= sizeof(*cell); + for (tid = 0; tid < prop_len; tid++) { + hwid = of_read_number(cell, ac); + if (arch_match_cpu_phys_id(cpu, hwid)) { + if (thread) + *thread = tid; + return true; + } + cell += ac; + } + return false; +} + +/** + * of_get_cpu_node - Get device node associated with the given logical CPU + * + * @cpu: CPU number(logical index) for which device node is required + * @thread: if not NULL, local thread number within the physical core is + * returned + * + * The main purpose of this function is to retrieve the device node for the + * given logical CPU index. It should be used to initialize the of_node in + * cpu device. Once of_node in cpu device is populated, all the further + * references can use that instead. + * + * CPU logical to physical index mapping is architecture specific and is built + * before booting secondary cores. This function uses arch_match_cpu_phys_id + * which can be overridden by architecture specific implementation. + * + * Returns a node pointer for the logical cpu if found, else NULL. + */ +struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) +{ + struct device_node *cpun, *cpus; + + cpus = of_find_node_by_path("/cpus"); + if (!cpus) { + pr_warn("Missing cpus node, bailing out\n"); + return NULL; + } + + for_each_child_of_node(cpus, cpun) { + if (of_node_cmp(cpun->type, "cpu")) + continue; + /* Check for non-standard "ibm,ppc-interrupt-server#s" property + * for thread ids on PowerPC. If it doesn't exist fallback to + * standard "reg" property. + */ + if (IS_ENABLED(CONFIG_PPC) && + __of_find_n_match_cpu_property(cpun, + "ibm,ppc-interrupt-server#s", cpu, thread)) + return cpun; + if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) + return cpun; + } + return NULL; +} +EXPORT_SYMBOL(of_get_cpu_node); + /** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */ diff --git a/include/linux/cpu.h b/include/linux/cpu.h index ab0eade..3dfed2b 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -28,6 +28,7 @@ struct cpu { extern int register_cpu(struct cpu *cpu, int num); extern struct device *get_cpu_device(unsigned cpu); extern bool cpu_is_hotpluggable(unsigned cpu); +extern bool arch_match_cpu_phys_id(int cpu, u64 phys_id); extern int cpu_add_dev_attr(struct device_attribute *attr); extern void cpu_remove_dev_attr(struct device_attribute *attr); diff --git a/include/linux/of.h b/include/linux/of.h index 1fd08ca..c0bb2f1 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -266,6 +266,7 @@ extern int of_device_is_available(const struct device_node *device); extern const void *of_get_property(const struct device_node *node, const char *name, int *lenp); +extern struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); #define for_each_property_of_node(dn, pp) \ for (pp = dn->properties; pp != NULL; pp = pp->next) @@ -459,6 +460,12 @@ static inline const void *of_get_property(const struct device_node *node, return NULL; } +static inline struct device_node *of_get_cpu_node(int cpu, + unsigned int *thread) +{ + return NULL; +} + static inline int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value) { -- cgit v0.10.2 From 973e02c1e89768d13be259bf77f88b5cfd16bade Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 13:11:29 +0100 Subject: ARM: DT/kernel: define ARM specific arch_match_cpu_phys_id OF/DT core library now provides architecture specific hook to match the logical cpu index with the corresponding physical identifier. Most of the cpu DT node parsing and initialisation is contained in devtree.c. So it's better to define ARM specific arch_match_cpu_phys_id there. This mainly helps to avoid replication of the code doing CPU node parsing and physical(MPIDR) to logical mapping. Cc: Russell King Cc: Lorenzo Pieralisi Acked-by: Rob Herring Acked-by: Nicolas Pitre Signed-off-by: Sudeep KarkadaNagesha diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index 5859c8b..2ee8a17 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -169,6 +169,11 @@ void __init arm_dt_init_cpu_maps(void) } } +bool arch_match_cpu_phys_id(int cpu, u64 phys_id) +{ + return (phys_id & MPIDR_HWID_BITMASK) == cpu_logical_map(cpu); +} + /** * setup_machine_fdt - Machine setup when an dtb was passed to the kernel * @dt_phys: physical address of dt blob -- cgit v0.10.2 From f86e4718f24b83be0c42894d2b97accc993d65d3 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 12:58:45 +0100 Subject: driver/core: cpu: initialize of_node in cpu's device struture CPUs are also registered as devices but the of_node in these cpu devices are not initialized. Currently different drivers requiring to access cpu device node are parsing the nodes themselves and initialising the of_node in cpu device. The of_node in all the cpu devices needs to be initialized properly and at one place. The best place to update this is CPU subsystem driver when registering the cpu devices. The OF/DT core library now provides of_get_cpu_node to retrieve a cpu device node for a given logical index by abstracting the architecture specific details. This patch uses of_get_cpu_node to assign of_node when registering the cpu devices. Acked-by: Greg Kroah-Hartman Acked-by: Rob Herring Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 4c358bc..4cf0717 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "base.h" @@ -289,6 +290,7 @@ int register_cpu(struct cpu *cpu, int num) cpu->dev.release = cpu_device_release; cpu->dev.offline_disabled = !cpu->hotpluggable; cpu->dev.offline = !cpu_online(num); + cpu->dev.of_node = of_get_cpu_node(num, NULL); #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE cpu->dev.bus->uevent = arch_cpu_uevent; #endif -- cgit v0.10.2 From bd00860e960e52658cebfd65eeb4748ed6ff039f Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Thu, 18 Jul 2013 11:22:04 +0100 Subject: of/device: add helper to get cpu device node from logical cpu index Multiple drivers need to get the cpu device node from the cpu logical index and then access the of_node. This patch adds helper function to fetch the device node directly. Acked-by: Rob Herring Signed-off-by: Sudeep KarkadaNagesha diff --git a/include/linux/of_device.h b/include/linux/of_device.h index 9d27475..82ce324 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -1,6 +1,7 @@ #ifndef _LINUX_OF_DEVICE_H #define _LINUX_OF_DEVICE_H +#include #include #include /* temporary until merge */ @@ -43,6 +44,15 @@ static inline void of_device_node_put(struct device *dev) of_node_put(dev->of_node); } +static inline struct device_node *of_cpu_device_node_get(int cpu) +{ + struct device *cpu_dev; + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) + return NULL; + return of_node_get(cpu_dev->of_node); +} + #else /* CONFIG_OF */ static inline int of_driver_match_device(struct device *dev, @@ -67,6 +77,11 @@ static inline const struct of_device_id *of_match_device( { return NULL; } + +static inline struct device_node *of_cpu_device_node_get(int cpu) +{ + return NULL; +} #endif /* CONFIG_OF */ #endif /* _LINUX_OF_DEVICE_H */ -- cgit v0.10.2 From 816a8de0017f16c32e747abc5367bf379515b20a Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 14:20:00 +0100 Subject: ARM: topology: remove hwid/MPIDR dependency from cpu_capacity Currently the topology code computes cpu capacity and stores it in the list along with hwid(which is MPIDR) as it parses the CPU nodes in the device tree. This is required as it needs to be mapped to the logical CPU later. Since the CPU device nodes can be retrieved in the logical ordering using DT/OF helpers, its possible to store cpu_capacity also in logical ordering and avoid storing hwid for each entry. This patch removes hwid by making use of of_get_cpu_node. Cc: Russell King Cc: Lorenzo Pieralisi Acked-by: Rob Herring Acked-by: Nicolas Pitre Signed-off-by: Sudeep KarkadaNagesha diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index c5a5954..85a8737 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -74,12 +74,8 @@ struct cpu_efficiency table_efficiency[] = { {NULL, }, }; -struct cpu_capacity { - unsigned long hwid; - unsigned long capacity; -}; - -struct cpu_capacity *cpu_capacity; +unsigned long *__cpu_capacity; +#define cpu_capacity(cpu) __cpu_capacity[cpu] unsigned long middle_capacity = 1; @@ -100,15 +96,19 @@ static void __init parse_dt_topology(void) unsigned long capacity = 0; int alloc_size, cpu = 0; - alloc_size = nr_cpu_ids * sizeof(struct cpu_capacity); - cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT); + alloc_size = nr_cpu_ids * sizeof(*__cpu_capacity); + __cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT); - while ((cn = of_find_node_by_type(cn, "cpu"))) { - const u32 *rate, *reg; + for_each_possible_cpu(cpu) { + const u32 *rate; int len; - if (cpu >= num_possible_cpus()) - break; + /* too early to use cpu->of_node */ + cn = of_get_cpu_node(cpu, NULL); + if (!cn) { + pr_err("missing device node for CPU %d\n", cpu); + continue; + } for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++) if (of_device_is_compatible(cn, cpu_eff->compatible)) @@ -124,12 +124,6 @@ static void __init parse_dt_topology(void) continue; } - reg = of_get_property(cn, "reg", &len); - if (!reg || len != 4) { - pr_err("%s missing reg property\n", cn->full_name); - continue; - } - capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency; /* Save min capacity of the system */ @@ -140,13 +134,9 @@ static void __init parse_dt_topology(void) if (capacity > max_capacity) max_capacity = capacity; - cpu_capacity[cpu].capacity = capacity; - cpu_capacity[cpu++].hwid = be32_to_cpup(reg); + cpu_capacity(cpu) = capacity; } - if (cpu < num_possible_cpus()) - cpu_capacity[cpu].hwid = (unsigned long)(-1); - /* If min and max capacities are equals, we bypass the update of the * cpu_scale because all CPUs have the same capacity. Otherwise, we * compute a middle_capacity factor that will ensure that the capacity @@ -154,9 +144,7 @@ static void __init parse_dt_topology(void) * SCHED_POWER_SCALE, which is the default value, but with the * constraint explained near table_efficiency[]. */ - if (min_capacity == max_capacity) - cpu_capacity[0].hwid = (unsigned long)(-1); - else if (4*max_capacity < (3*(max_capacity + min_capacity))) + if (4*max_capacity < (3*(max_capacity + min_capacity))) middle_capacity = (min_capacity + max_capacity) >> (SCHED_POWER_SHIFT+1); else @@ -170,23 +158,12 @@ static void __init parse_dt_topology(void) * boot. The update of all CPUs is in O(n^2) for heteregeneous system but the * function returns directly for SMP system. */ -void update_cpu_power(unsigned int cpu, unsigned long hwid) +void update_cpu_power(unsigned int cpu) { - unsigned int idx = 0; - - /* look for the cpu's hwid in the cpu capacity table */ - for (idx = 0; idx < num_possible_cpus(); idx++) { - if (cpu_capacity[idx].hwid == hwid) - break; - - if (cpu_capacity[idx].hwid == -1) - return; - } - - if (idx == num_possible_cpus()) + if (!cpu_capacity(cpu)) return; - set_power_scale(cpu, cpu_capacity[idx].capacity / middle_capacity); + set_power_scale(cpu, cpu_capacity(cpu) / middle_capacity); printk(KERN_INFO "CPU%u: update cpu_power %lu\n", cpu, arch_scale_freq_power(NULL, cpu)); @@ -194,7 +171,7 @@ void update_cpu_power(unsigned int cpu, unsigned long hwid) #else static inline void parse_dt_topology(void) {} -static inline void update_cpu_power(unsigned int cpuid, unsigned int mpidr) {} +static inline void update_cpu_power(unsigned int cpuid) {} #endif /* @@ -281,7 +258,7 @@ void store_cpu_topology(unsigned int cpuid) update_siblings_masks(cpuid); - update_cpu_power(cpuid, mpidr & MPIDR_HWID_BITMASK); + update_cpu_power(cpuid); printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n", cpuid, cpu_topology[cpuid].thread_id, -- cgit v0.10.2 From f6cec7cd0777fa18723fce9d398fa7e53b6ef00c Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Wed, 3 Jul 2013 16:01:42 +0100 Subject: ARM: mvebu: remove device tree parsing for cpu nodes Currently set_secondary_cpus_clock assume the CPU logical ordering and the MPDIR in DT are same, which is incorrect. Since the CPU device nodes can be retrieved in the logical ordering using the DT helper, we can remove the devices tree parsing. This patch removes DT parsing by making use of of_get_cpu_node. Cc: Andrew Lunn Cc: Jason Cooper Acked-by: Gregory Clement Signed-off-by: Sudeep KarkadaNagesha diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index ce81d30..594b63d 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -29,45 +29,40 @@ #include "pmsu.h" #include "coherency.h" +static struct clk *__init get_cpu_clk(int cpu) +{ + struct clk *cpu_clk; + struct device_node *np = of_get_cpu_node(cpu, NULL); + + if (WARN(!np, "missing cpu node\n")) + return NULL; + cpu_clk = of_clk_get(np, 0); + if (WARN_ON(IS_ERR(cpu_clk))) + return NULL; + return cpu_clk; +} + void __init set_secondary_cpus_clock(void) { - int thiscpu; + int thiscpu, cpu; unsigned long rate; - struct clk *cpu_clk = NULL; - struct device_node *np = NULL; + struct clk *cpu_clk; thiscpu = smp_processor_id(); - for_each_node_by_type(np, "cpu") { - int err; - int cpu; - - err = of_property_read_u32(np, "reg", &cpu); - if (WARN_ON(err)) - return; - - if (cpu == thiscpu) { - cpu_clk = of_clk_get(np, 0); - break; - } - } - if (WARN_ON(IS_ERR(cpu_clk))) + cpu_clk = get_cpu_clk(thiscpu); + if (!cpu_clk) return; clk_prepare_enable(cpu_clk); rate = clk_get_rate(cpu_clk); /* set all the other CPU clk to the same rate than the boot CPU */ - for_each_node_by_type(np, "cpu") { - int err; - int cpu; - - err = of_property_read_u32(np, "reg", &cpu); - if (WARN_ON(err)) + for_each_possible_cpu(cpu) { + if (cpu == thiscpu) + continue; + cpu_clk = get_cpu_clk(cpu); + if (!cpu_clk) return; - - if (cpu != thiscpu) { - cpu_clk = of_clk_get(np, 0); - clk_set_rate(cpu_clk, rate); - } + clk_set_rate(cpu_clk, rate); } } -- cgit v0.10.2 From 78b4d6e0fd2695da3019c86133444578d1ceeed3 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 14:51:48 +0100 Subject: drivers/bus: arm-cci: avoid parsing DT for cpu device nodes Since the CPU device nodes can be retrieved using arch_of_get_cpu_node, we can use it to avoid parsing the cpus node searching the cpu nodes and mapping to logical index. This patch removes parsing DT for cpu nodes by using of_get_cpu_node. Cc: Lorenzo Pieralisi Acked-by: Nicolas Pitre Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 7332889..2009266 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -122,17 +122,8 @@ EXPORT_SYMBOL_GPL(cci_ace_get_port); static void __init cci_ace_init_ports(void) { - int port, ac, cpu; - u64 hwid; - const u32 *cell; - struct device_node *cpun, *cpus; - - cpus = of_find_node_by_path("/cpus"); - if (WARN(!cpus, "Missing cpus node, bailing out\n")) - return; - - if (WARN_ON(of_property_read_u32(cpus, "#address-cells", &ac))) - ac = of_n_addr_cells(cpus); + int port, cpu; + struct device_node *cpun; /* * Port index look-up speeds up the function disabling ports by CPU, @@ -141,18 +132,13 @@ static void __init cci_ace_init_ports(void) * The stashed index array is initialized for all possible CPUs * at probe time. */ - for_each_child_of_node(cpus, cpun) { - if (of_node_cmp(cpun->type, "cpu")) - continue; - cell = of_get_property(cpun, "reg", NULL); - if (WARN(!cell, "%s: missing reg property\n", cpun->full_name)) - continue; - - hwid = of_read_number(cell, ac); - cpu = get_logical_index(hwid & MPIDR_HWID_BITMASK); + for_each_possible_cpu(cpu) { + /* too early to use cpu->of_node */ + cpun = of_get_cpu_node(cpu, NULL); - if (cpu < 0 || !cpu_possible(cpu)) + if (WARN(!cpun, "Missing cpu device node\n")) continue; + port = __cci_ace_get_port(cpun, ACE_PORT); if (port < 0) continue; -- cgit v0.10.2 From cdc58d602d2e657602a90c190cbf745886c95977 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 14:58:48 +0100 Subject: cpufreq: imx6q-cpufreq: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes all DT parsing and uses cpu->of_node instead. Acked-by: Shawn Guo Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 7be13f8..a02f275 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -254,13 +254,12 @@ static void __init imx6q_opp_init(struct device *cpu_dev) { struct device_node *np; - np = of_find_node_by_path("/cpus/cpu@0"); + np = of_node_get(cpu_dev->of_node); if (!np) { pr_warn("failed to find cpu0 node\n"); return; } - cpu_dev->of_node = np; if (of_init_opp_table(cpu_dev)) { pr_warn("failed to init OPP table\n"); goto put_node; diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index e37cdae..b16632b 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -221,14 +221,12 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) cpu_dev = &pdev->dev; - np = of_find_node_by_path("/cpus/cpu@0"); + np = of_node_get(cpu_dev->of_node); if (!np) { dev_err(cpu_dev, "failed to find cpu0 node\n"); return -ENOENT; } - cpu_dev->of_node = np; - arm_clk = devm_clk_get(cpu_dev, "arm"); pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys"); pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw"); -- cgit v0.10.2 From f837a9b5ab05c52a07108c6f09ca66f2e0aee757 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 15:04:19 +0100 Subject: cpufreq: cpufreq-cpu0: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes all DT parsing and uses cpu->of_node instead. Acked-by: Shawn Guo Acked-by: Rob Herring Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index ad1fde2..5b05c26 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -174,29 +174,17 @@ static struct cpufreq_driver cpu0_cpufreq_driver = { static int cpu0_cpufreq_probe(struct platform_device *pdev) { - struct device_node *np, *parent; + struct device_node *np; int ret; - parent = of_find_node_by_path("/cpus"); - if (!parent) { - pr_err("failed to find OF /cpus\n"); - return -ENOENT; - } - - for_each_child_of_node(parent, np) { - if (of_get_property(np, "operating-points", NULL)) - break; - } + cpu_dev = &pdev->dev; + np = of_node_get(cpu_dev->of_node); if (!np) { pr_err("failed to find cpu0 node\n"); - ret = -ENOENT; - goto out_put_parent; + return -ENOENT; } - cpu_dev = &pdev->dev; - cpu_dev->of_node = np; - cpu_reg = devm_regulator_get(cpu_dev, "cpu0"); if (IS_ERR(cpu_reg)) { /* @@ -269,15 +257,12 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) } of_node_put(np); - of_node_put(parent); return 0; out_free_table: opp_free_cpufreq_table(cpu_dev, &freq_table); out_put_node: of_node_put(np); -out_put_parent: - of_node_put(parent); return ret; } -- cgit v0.10.2 From 5de6e94a298576c2774ba43c0c3b0a0410cd100e Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 15:07:28 +0100 Subject: cpufreq: highbank-cpufreq: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes all DT parsing and uses cpu->of_node instead. Cc: Mark Langsdorf Acked-by: Rob Herring Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c index b61b5a3..794123f 100644 --- a/drivers/cpufreq/highbank-cpufreq.c +++ b/drivers/cpufreq/highbank-cpufreq.c @@ -69,23 +69,17 @@ static int hb_cpufreq_driver_init(void) if (!of_machine_is_compatible("calxeda,highbank")) return -ENODEV; - for_each_child_of_node(of_find_node_by_path("/cpus"), np) - if (of_get_property(np, "operating-points", NULL)) - break; - - if (!np) { - pr_err("failed to find highbank cpufreq node\n"); - return -ENOENT; - } - cpu_dev = get_cpu_device(0); if (!cpu_dev) { pr_err("failed to get highbank cpufreq device\n"); - ret = -ENODEV; - goto out_put_node; + return -ENODEV; } - cpu_dev->of_node = np; + np = of_node_get(cpu_dev->of_node); + if (!np) { + pr_err("failed to find highbank cpufreq node\n"); + return -ENOENT; + } cpu_clk = clk_get(cpu_dev, NULL); if (IS_ERR(cpu_clk)) { -- cgit v0.10.2 From c0e469487d2327e644e8d86e091c0d4e4351a1a1 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 15:09:15 +0100 Subject: cpufreq: spear-cpufreq: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes all DT parsing and uses cpu->of_node instead. Cc: Deepak Sikri Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c index c3efa7f..19e364fa 100644 --- a/drivers/cpufreq/spear-cpufreq.c +++ b/drivers/cpufreq/spear-cpufreq.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -223,7 +223,7 @@ static int spear_cpufreq_driver_init(void) const __be32 *val; int cnt, i, ret; - np = of_find_node_by_path("/cpus/cpu@0"); + np = of_cpu_device_node_get(0); if (!np) { pr_err("No cpu node found"); return -ENODEV; -- cgit v0.10.2 From e768f350c8c3d4253011282db771f35af37ee59a Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 15:09:51 +0100 Subject: cpufreq: kirkwood-cpufreq: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes all DT parsing and uses cpu->of_node instead. Cc: Jason Cooper Acked-by: Andrew Lunn Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index c233ea6..25ac2cb 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -175,9 +175,11 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev) if (IS_ERR(priv.base)) return PTR_ERR(priv.base); - np = of_find_node_by_path("/cpus/cpu@0"); - if (!np) + np = of_cpu_device_node_get(0); + if (!np) { + dev_err(&pdev->dev, "failed to get cpu device node\n"); return -ENODEV; + } priv.cpu_clk = of_clk_get_by_name(np, "cpu_clk"); if (IS_ERR(priv.cpu_clk)) { -- cgit v0.10.2 From da0eb143dbbaf26b6f084bee81d56fc64efb5390 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Mon, 17 Jun 2013 15:51:44 +0100 Subject: cpufreq: arm_big_little: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes all DT parsing and uses cpu->of_node instead. Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c index fd9e3ea..480c0bd 100644 --- a/drivers/cpufreq/arm_big_little_dt.c +++ b/drivers/cpufreq/arm_big_little_dt.c @@ -19,12 +19,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include #include #include #include #include -#include +#include #include #include #include @@ -34,27 +33,13 @@ /* get cpu node with valid operating-points */ static struct device_node *get_cpu_node_with_valid_op(int cpu) { - struct device_node *np = NULL, *parent; - int count = 0; + struct device_node *np = of_cpu_device_node_get(cpu); - parent = of_find_node_by_path("/cpus"); - if (!parent) { - pr_err("failed to find OF /cpus\n"); - return NULL; + if (!of_get_property(np, "operating-points", NULL)) { + of_node_put(np); + np = NULL; } - for_each_child_of_node(parent, np) { - if (count++ != cpu) - continue; - if (!of_get_property(np, "operating-points", NULL)) { - of_node_put(np); - np = NULL; - } - - break; - } - - of_node_put(parent); return np; } @@ -63,11 +48,12 @@ static int dt_init_opp_table(struct device *cpu_dev) struct device_node *np; int ret; - np = get_cpu_node_with_valid_op(cpu_dev->id); - if (!np) - return -ENODATA; + np = of_node_get(cpu_dev->of_node); + if (!np) { + pr_err("failed to find cpu%d node\n", cpu_dev->id); + return -ENOENT; + } - cpu_dev->of_node = np; ret = of_init_opp_table(cpu_dev); of_node_put(np); @@ -79,9 +65,11 @@ static int dt_get_transition_latency(struct device *cpu_dev) struct device_node *np; u32 transition_latency = CPUFREQ_ETERNAL; - np = get_cpu_node_with_valid_op(cpu_dev->id); - if (!np) + np = of_node_get(cpu_dev->of_node); + if (!np) { + pr_info("Failed to find cpu node. Use CPUFREQ_ETERNAL transition latency\n"); return CPUFREQ_ETERNAL; + } of_property_read_u32(np, "clock-latency", &transition_latency); of_node_put(np); -- cgit v0.10.2 From 2421d4c34d492efd8b116ce62ae5612b5b9864b2 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Wed, 17 Jul 2013 12:39:29 +0100 Subject: cpufreq: maple-cpufreq: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes all DT parsing and uses cpu->of_node instead. Cc: Dmitry Eremin-Solenikov Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c index cdd6291..f071dc4 100644 --- a/drivers/cpufreq/maple-cpufreq.c +++ b/drivers/cpufreq/maple-cpufreq.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #define DBG(fmt...) pr_debug(fmt) @@ -201,7 +201,6 @@ static struct cpufreq_driver maple_cpufreq_driver = { static int __init maple_cpufreq_init(void) { - struct device_node *cpus; struct device_node *cpunode; unsigned int psize; unsigned long max_freq; @@ -217,24 +216,11 @@ static int __init maple_cpufreq_init(void) !of_machine_is_compatible("Momentum,Apache")) return 0; - cpus = of_find_node_by_path("/cpus"); - if (cpus == NULL) { - DBG("No /cpus node !\n"); - return -ENODEV; - } - /* Get first CPU node */ - for (cpunode = NULL; - (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) { - const u32 *reg = of_get_property(cpunode, "reg", NULL); - if (reg == NULL || (*reg) != 0) - continue; - if (!strcmp(cpunode->type, "cpu")) - break; - } + cpunode = of_cpu_device_node_get(0); if (cpunode == NULL) { printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n"); - goto bail_cpus; + goto bail_noprops; } /* Check 970FX for now */ @@ -290,14 +276,11 @@ static int __init maple_cpufreq_init(void) rc = cpufreq_register_driver(&maple_cpufreq_driver); of_node_put(cpunode); - of_node_put(cpus); return rc; bail_noprops: of_node_put(cpunode); -bail_cpus: - of_node_put(cpus); return rc; } -- cgit v0.10.2 From 760287ab90a3ca93a2f87f7e7137e06e89a26b01 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Wed, 17 Jul 2013 13:42:56 +0100 Subject: cpufreq: pmac64-cpufreq: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes all DT parsing and uses cpu->of_node instead. Cc: Benjamin Herrenschmidt Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c index 7ba4234..97b719f 100644 --- a/drivers/cpufreq/pmac64-cpufreq.c +++ b/drivers/cpufreq/pmac64-cpufreq.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -383,9 +384,8 @@ static struct cpufreq_driver g5_cpufreq_driver = { #ifdef CONFIG_PMAC_SMU -static int __init g5_neo2_cpufreq_init(struct device_node *cpus) +static int __init g5_neo2_cpufreq_init(struct device_node *cpunode) { - struct device_node *cpunode; unsigned int psize, ssize; unsigned long max_freq; char *freq_method, *volt_method; @@ -405,20 +405,6 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus) else return -ENODEV; - /* Get first CPU node */ - for (cpunode = NULL; - (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) { - const u32 *reg = of_get_property(cpunode, "reg", NULL); - if (reg == NULL || (*reg) != 0) - continue; - if (!strcmp(cpunode->type, "cpu")) - break; - } - if (cpunode == NULL) { - printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n"); - return -ENODEV; - } - /* Check 970FX for now */ valp = of_get_property(cpunode, "cpu-version", NULL); if (!valp) { @@ -537,9 +523,9 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus) #endif /* CONFIG_PMAC_SMU */ -static int __init g5_pm72_cpufreq_init(struct device_node *cpus) +static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) { - struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL; + struct device_node *cpuid = NULL, *hwclock = NULL; const u8 *eeprom = NULL; const u32 *valp; u64 max_freq, min_freq, ih, il; @@ -548,17 +534,6 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus) DBG("cpufreq: Initializing for PowerMac7,2, PowerMac7,3 and" " RackMac3,1...\n"); - /* Get first CPU node */ - for (cpunode = NULL; - (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) { - if (!strcmp(cpunode->type, "cpu")) - break; - } - if (cpunode == NULL) { - printk(KERN_ERR "cpufreq: Can't find any CPU node\n"); - return -ENODEV; - } - /* Lookup the cpuid eeprom node */ cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0"); if (cpuid != NULL) @@ -718,25 +693,25 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus) static int __init g5_cpufreq_init(void) { - struct device_node *cpus; + struct device_node *cpunode; int rc = 0; - cpus = of_find_node_by_path("/cpus"); - if (cpus == NULL) { - DBG("No /cpus node !\n"); + /* Get first CPU node */ + cpunode = of_cpu_device_node_get(0); + if (cpunode == NULL) { + pr_err("cpufreq: Can't find any CPU node\n"); return -ENODEV; } if (of_machine_is_compatible("PowerMac7,2") || of_machine_is_compatible("PowerMac7,3") || of_machine_is_compatible("RackMac3,1")) - rc = g5_pm72_cpufreq_init(cpus); + rc = g5_pm72_cpufreq_init(cpunode); #ifdef CONFIG_PMAC_SMU else - rc = g5_neo2_cpufreq_init(cpus); + rc = g5_neo2_cpufreq_init(cpunode); #endif /* CONFIG_PMAC_SMU */ - of_node_put(cpus); return rc; } -- cgit v0.10.2 From 1037b2752345cc5666e90b711a913ab2ae6c5920 Mon Sep 17 00:00:00 2001 From: Sudeep KarkadaNagesha Date: Wed, 17 Jul 2013 13:52:17 +0100 Subject: cpufreq: pmac32-cpufreq: remove device tree parsing for cpu nodes Now that the cpu device registration initialises the of_node(if available) appropriately for all the cpus, parsing here is redundant. This patch removes DT parsing and uses cpu->of_node instead. Cc: Benjamin Herrenschmidt Acked-by: Viresh Kumar Signed-off-by: Sudeep KarkadaNagesha diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c index 3104fad..56bfb6f 100644 --- a/drivers/cpufreq/pmac32-cpufreq.c +++ b/drivers/cpufreq/pmac32-cpufreq.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -649,8 +650,8 @@ static int __init pmac_cpufreq_setup(void) if (strstr(cmd_line, "nocpufreq")) return 0; - /* Assume only one CPU */ - cpunode = of_find_node_by_type(NULL, "cpu"); + /* Get first CPU node */ + cpunode = of_cpu_device_node_get(0); if (!cpunode) goto out; -- cgit v0.10.2 From 330647a9501fe8f93a8ae9361417e51ee0bebd7e Mon Sep 17 00:00:00 2001 From: Tuukka Tikkanen Date: Wed, 14 Aug 2013 19:02:34 +0300 Subject: cpuidle: Ignore interval prediction result when timer is shorter This patch prevents cpuidle menu governor from using repeating interval prediction result if the idle period predicted is longer than the one allowed by shortest running timer. Signed-off-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index cbbb73b..3516973 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -238,10 +238,13 @@ again: * * The typical interval is obtained when standard deviation is small * or standard deviation is small compared to the average interval. + * + * Use this result only if there is no timer to wake us up sooner. */ if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) || stddev <= 20) { - data->predicted_us = avg; + if (data->expected_us > avg) + data->predicted_us = avg; return; } else if ((divisor * 4) > INTERVALS * 3) { -- cgit v0.10.2 From 017099e25fb7e482a249d36a654556d32f601f71 Mon Sep 17 00:00:00 2001 From: Tuukka Tikkanen Date: Wed, 14 Aug 2013 19:02:35 +0300 Subject: cpuidle: Rearrange code and comments in get_typical_interval() This patch rearranges a if-return-elsif-goto-fi-return sequence into if-return-fi-if-return-fi-goto sequence. The functionality remains the same. Also, a lengthy comment that did not describe the functionality in the order it occurs is split into half and top half is moved closer to actual implementation it describes. Signed-off-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 3516973..f1fadbe 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -228,14 +228,6 @@ again: do_div(stddev, divisor); stddev = int_sqrt(stddev); /* - * If we have outliers to the upside in our distribution, discard - * those by setting the threshold to exclude these outliers, then - * calculate the average and standard deviation again. Once we get - * down to the bottom 3/4 of our samples, stop excluding samples. - * - * This can deal with workloads that have long pauses interspersed - * with sporadic activity with a bunch of short pauses. - * * The typical interval is obtained when standard deviation is small * or standard deviation is small compared to the average interval. * @@ -246,12 +238,22 @@ again: if (data->expected_us > avg) data->predicted_us = avg; return; - - } else if ((divisor * 4) > INTERVALS * 3) { - /* Exclude the max interval */ - thresh = max - 1; - goto again; } + + /* + * If we have outliers to the upside in our distribution, discard + * those by setting the threshold to exclude these outliers, then + * calculate the average and standard deviation again. Once we get + * down to the bottom 3/4 of our samples, stop excluding samples. + * + * This can deal with workloads that have long pauses interspersed + * with sporadic activity with a bunch of short pauses. + */ + if ((divisor * 4) <= INTERVALS * 3) + return; + + thresh = max - 1; + goto again; } /** -- cgit v0.10.2 From 0d6a7ffa4cc67cc70bf1f4e24fbb0747632845a2 Mon Sep 17 00:00:00 2001 From: Tuukka Tikkanen Date: Wed, 14 Aug 2013 19:02:36 +0300 Subject: cpuidle: Check called function parameter in get_typical_interval() get_typical_interval() uses int_sqrt() in calculation of standard deviation. The formal parameter of int_sqrt() is unsigned long, which may on some platforms be smaller than the 64 bit unsigned integer used as the actual parameter. The overflow can occur frequently when actual idle period lengths are in hundreds of milliseconds. This patch adds a check for such overflow and rejects the candidate average when an overflow would occur. Signed-off-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index f1fadbe..af7b3f6 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -226,18 +226,26 @@ again: } } do_div(stddev, divisor); - stddev = int_sqrt(stddev); /* * The typical interval is obtained when standard deviation is small * or standard deviation is small compared to the average interval. * + * int_sqrt() formal parameter type is unsigned long. When the + * greatest difference to an outlier exceeds ~65 ms * sqrt(divisor) + * the resulting squared standard deviation exceeds the input domain + * of int_sqrt on platforms where unsigned long is 32 bits in size. + * In such case reject the candidate average. + * * Use this result only if there is no timer to wake us up sooner. */ - if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) + if (likely(stddev <= ULONG_MAX)) { + stddev = int_sqrt(stddev); + if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) || stddev <= 20) { - if (data->expected_us > avg) - data->predicted_us = avg; - return; + if (data->expected_us > avg) + data->predicted_us = avg; + return; + } } /* -- cgit v0.10.2 From 4cd46bca8ca8ad20cadf74fd9b76364c46ed0f31 Mon Sep 17 00:00:00 2001 From: Tuukka Tikkanen Date: Wed, 14 Aug 2013 19:02:37 +0300 Subject: cpuidle: CodingStyle: Break up multiple assignments on single line The function get_typical_interval() initializes a number of variables that are immediately after declarations assigned constant values. In addition, there are multiple assignments on a single line, which is explicitly forbidden by Documentation/CodingStyle. This patch removes redundant initial values for the variables and breaks up the multiple assignment line. Signed-off-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index af7b3f6..94a3037 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -199,14 +199,17 @@ static u64 div_round64(u64 dividend, u32 divisor) */ static void get_typical_interval(struct menu_device *data) { - int i = 0, divisor = 0; - uint64_t max = 0, avg = 0, stddev = 0; + int i, divisor; + uint64_t max, avg, stddev; int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */ again: /* first calculate average and standard deviation of the past */ - max = avg = divisor = stddev = 0; + max = 0; + avg = 0; + divisor = 0; + stddev = 0; for (i = 0; i < INTERVALS; i++) { int64_t value = data->intervals[i]; if (value <= thresh) { -- cgit v0.10.2 From 939e33b7fcd4980f21ff4c9558eb27fe81d16cdb Mon Sep 17 00:00:00 2001 From: Tuukka Tikkanen Date: Wed, 14 Aug 2013 19:02:38 +0300 Subject: cpuidle: Fix menu_device->intervals type Struct menu_device member intervals is declared as u32, but the value stored is (unsigned) int. The type is changed to match the value being stored. Signed-off-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 94a3037..ee88838 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -118,7 +118,7 @@ struct menu_device { unsigned int exit_us; unsigned int bucket; u64 correction_factor[BUCKETS]; - u32 intervals[INTERVALS]; + unsigned int intervals[INTERVALS]; int interval_ptr; }; -- cgit v0.10.2 From 0e96d5adcfef22f86e4463909728d63f88944749 Mon Sep 17 00:00:00 2001 From: Tuukka Tikkanen Date: Wed, 14 Aug 2013 19:02:39 +0300 Subject: cpuidle: Fix variable domains in get_typical_interval() The menu governor uses a static function get_typical_interval() to try to detect a repeating pattern of wakeups. The previous interval durations are stored as an array of unsigned ints, but the arithmetic in the function is performed exclusively as 64 bit values, even when the value stored in a variable is known not to exceed unsigned int, which may be smaller and more efficient on some platforms. This patch changes the types of varibles used to store some intermediates, the maximum and and the cutoff threshold to unsigned ints. Average and standard deviation are still treated as 64 bit values, even when the values are known to be within the domain of unsigned int, to avoid casts to ensure correct integer promotion for arithmetic operations. Signed-off-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index ee88838..a56081c 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -200,18 +200,19 @@ static u64 div_round64(u64 dividend, u32 divisor) static void get_typical_interval(struct menu_device *data) { int i, divisor; - uint64_t max, avg, stddev; - int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */ + unsigned int max, thresh; + uint64_t avg, stddev; + + thresh = UINT_MAX; /* Discard outliers above this value */ again: - /* first calculate average and standard deviation of the past */ + /* First calculate the average of past intervals */ max = 0; avg = 0; divisor = 0; - stddev = 0; for (i = 0; i < INTERVALS; i++) { - int64_t value = data->intervals[i]; + unsigned int value = data->intervals[i]; if (value <= thresh) { avg += value; divisor++; @@ -221,8 +222,10 @@ again: } do_div(avg, divisor); + /* Then try to determine standard deviation */ + stddev = 0; for (i = 0; i < INTERVALS; i++) { - int64_t value = data->intervals[i]; + unsigned int value = data->intervals[i]; if (value <= thresh) { int64_t diff = value - avg; stddev += diff * diff; -- cgit v0.10.2 From decd51bbcd7fd949840da4cc634f6b70baa1b512 Mon Sep 17 00:00:00 2001 From: Tuukka Tikkanen Date: Wed, 14 Aug 2013 19:02:40 +0300 Subject: cpuidle: Add a comment warning about possible overflow The menu governor has a number of tunable constants that may be changed in the source. If certain combination of values are chosen, an overflow is possible when the correction_factor is being recalculated. This patch adds a warning regarding this possibility and describes the change needed for fixing the issue. The change should not be permanently enabled, as it will hurt performance when it is not needed. Signed-off-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index a56081c..a8b31b0 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -21,6 +21,15 @@ #include #include +/* + * Please note when changing the tuning values: + * If (MAX_INTERESTING-1) * RESOLUTION > UINT_MAX, the result of + * a scaling operation multiplication may overflow on 32 bit platforms. + * In that case, #define RESOLUTION as ULL to get 64 bit result: + * #define RESOLUTION 1024ULL + * + * The default values do not overflow. + */ #define BUCKETS 12 #define INTERVALS 8 #define RESOLUTION 1024 -- cgit v0.10.2 From 51f245b895e3fe4cbac0b2633e54a1830864a83f Mon Sep 17 00:00:00 2001 From: Tuukka Tikkanen Date: Wed, 14 Aug 2013 19:02:41 +0300 Subject: cpuidle: Change struct menu_device field types Field predicted_us value can never exceed expected_us value, but it has a potentially larger type. As there is no need for additional 32 bits of zeroes on 32 bit plaforms, change the type of predicted_us to match the type of expected_us. Field correction_factor is used to store a value that cannot exceed the product of RESOLUTION and DECAY (default 1024*8 = 8192). The constants cannot in practice be incremented to such values, that they'd overflow unsigned int even on 32 bit systems, so the type is changed to avoid unnecessary 64 bit arithmetic on 32 bit systems. One multiplication of (now) 32 bit values needs an added cast to avoid truncation of the result and has been added. In order to avoid another multiplication from 32 bit domain to 64 bit domain, the new correction_factor calculation has been changed from new = old * (DECAY-1) / DECAY to new = old - old / DECAY, which with infinite precision would yeild exactly the same result, but now changes the direction of rounding. The impact is not significant as the maximum accumulated difference cannot exceed the value of DECAY, which is relatively small compared to product of RESOLUTION and DECAY (8 / 8192). Signed-off-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index a8b31b0..cf7f2f0 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -123,10 +123,10 @@ struct menu_device { int needs_update; unsigned int expected_us; - u64 predicted_us; + unsigned int predicted_us; unsigned int exit_us; unsigned int bucket; - u64 correction_factor[BUCKETS]; + unsigned int correction_factor[BUCKETS]; unsigned int intervals[INTERVALS]; int interval_ptr; }; @@ -321,8 +321,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (data->correction_factor[data->bucket] == 0) data->correction_factor[data->bucket] = RESOLUTION * DECAY; - /* Make sure to round up for half microseconds */ - data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], + /* + * Force the result of multiplication to be 64 bits even if both + * operands are 32 bits. + * Make sure to round up for half microseconds. + */ + data->predicted_us = div_round64((uint64_t)data->expected_us * + data->correction_factor[data->bucket], RESOLUTION * DECAY); get_typical_interval(data); @@ -388,7 +393,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) unsigned int last_idle_us = cpuidle_get_last_residency(dev); struct cpuidle_state *target = &drv->states[last_idx]; unsigned int measured_us; - u64 new_factor; + unsigned int new_factor; /* * Ugh, this idle state doesn't support residency measurements, so we @@ -409,10 +414,9 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) measured_us -= data->exit_us; - /* update our correction ratio */ - - new_factor = data->correction_factor[data->bucket] - * (DECAY - 1) / DECAY; + /* Update our correction ratio */ + new_factor = data->correction_factor[data->bucket]; + new_factor -= new_factor / DECAY; if (data->expected_us > 0 && measured_us < MAX_INTERESTING) new_factor += RESOLUTION * measured_us / data->expected_us; @@ -425,9 +429,11 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) /* * We don't want 0 as factor; we always want at least - * a tiny bit of estimated time. + * a tiny bit of estimated time. Fortunately, due to rounding, + * new_factor will stay nonzero regardless of measured_us values + * and the compiler can eliminate this test as long as DECAY > 1. */ - if (new_factor == 0) + if (DECAY == 1 && unlikely(new_factor == 0)) new_factor = 1; data->correction_factor[data->bucket] = new_factor; -- cgit v0.10.2 From b192b910f3832793082c1a18262c4da0efe121ae Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Fri, 23 Aug 2013 09:43:58 +0800 Subject: cpufreq: tegra: fix the wrong clock name The "cpu" and "pclk_p_cclk" was a virtual clock name that was used in the legacy Tegra clock framework. It was not used after converting to CCF. Fix it as the correct clock name that we are using. Tested-by: Stephen Warren Signed-off-by: Joseph Lo Signed-off-by: Viresh Kumar diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c index cd66b85..a7b876f 100644 --- a/drivers/cpufreq/tegra-cpufreq.c +++ b/drivers/cpufreq/tegra-cpufreq.c @@ -255,7 +255,7 @@ static struct cpufreq_driver tegra_cpufreq_driver = { static int __init tegra_cpufreq_init(void) { - cpu_clk = clk_get_sys(NULL, "cpu"); + cpu_clk = clk_get_sys(NULL, "cclk"); if (IS_ERR(cpu_clk)) return PTR_ERR(cpu_clk); @@ -263,7 +263,7 @@ static int __init tegra_cpufreq_init(void) if (IS_ERR(pll_x_clk)) return PTR_ERR(pll_x_clk); - pll_p_clk = clk_get_sys(NULL, "pll_p_cclk"); + pll_p_clk = clk_get_sys(NULL, "pll_p"); if (IS_ERR(pll_p_clk)) return PTR_ERR(pll_p_clk); -- cgit v0.10.2 From 94fb9823a7c478bf88b99b8da4fc3e540608ece5 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sun, 25 Aug 2013 12:37:33 -0500 Subject: ACPI: blacklist win8 OSI for buggy laptops Since v3.7 the acpi backlight driver doesn't work correctly in several machines because ACPI code has different code for Windows 8, and the rest. The commit ea45ea7 (in v3.11-rc2) tried to fix this problem by using the intel backlight driver, however it introduced several other issues in different machines. This patch fixes both regressions by blacklisting the win8 OSI, so we are back to v3.6 behavior, and it should remain that way until the intel backlight driver is fixed. Since v3.7, users have been forced to fix the initial regression by modifying the boot arguments (acpi_osi="!Windows 2012"). Once the Intel backlight driver works correctly for all machines, this blacklist can be removed and that driver can be used instead. References: https://bugzilla.kernel.org/show_bug.cgi?id=60682 Reported-by: Danny Baumann Reported-by: Philipp Richter Signed-off-by: Felipe Contreras Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index a404127..9515f18 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -281,6 +281,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "UX31A"), }, }, + { + .callback = dmi_disable_osi_win8, + .ident = "Dell Inspiron 15R SE", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad Edge E530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "3259A2G"), + }, + }, /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. -- cgit v0.10.2 From fae19b84724ff93c1ac59ce1eecc1411f8269d9e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 26 Aug 2013 13:48:36 +0200 Subject: cpufreq: imx6q: Fix clock enable balance For changing the cpu frequency the i.MX6q has to be switched to some intermediate clock during the PLL reprogramming. The driver tries to be clever to keep the enable count correct but gets it wrong. If the cpufreq is increased it calls clk_disable_unprepare twice on pll2_pfd2_396m. This puts all other devices which get their clock from pll2_pfd2_396m into a nonworking state. Fix this by removing the clk enabling/disabling altogether since the clk core will do this automatically during a reparent. Signed-off-by: Sascha Hauer Signed-off-by: Viresh Kumar diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index e37cdae..2971d12 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -117,28 +117,11 @@ static int imx6q_set_target(struct cpufreq_policy *policy, * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it * - Disable pll2_pfd2_396m_clk */ - clk_prepare_enable(pll2_pfd2_396m_clk); clk_set_parent(step_clk, pll2_pfd2_396m_clk); clk_set_parent(pll1_sw_clk, step_clk); if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { clk_set_rate(pll1_sys_clk, freqs.new * 1000); - /* - * If we are leaving 396 MHz set-point, we need to enable - * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep - * their use count correct. - */ - if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) { - clk_prepare_enable(pll1_sys_clk); - clk_disable_unprepare(pll2_pfd2_396m_clk); - } clk_set_parent(pll1_sw_clk, pll1_sys_clk); - clk_disable_unprepare(pll2_pfd2_396m_clk); - } else { - /* - * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient - * to provide the frequency. - */ - clk_disable_unprepare(pll1_sys_clk); } /* Ensure the arm clock divider is what we expect */ -- cgit v0.10.2 From 668e02004462487df8ec6c65c665ddb8af78dc12 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 27 Aug 2013 16:29:31 +0800 Subject: ACPI / thermal: Add check of "_TZD" availability and evaluating result Some machines don't provide _TZD, so check the availability of it before carrying out futher operations. If _TZD is present, also check the result of its evaluation. [rjw: Changelog] Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index ccf9527..0055c83 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -485,14 +485,14 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) break; } - if (flag & ACPI_TRIPS_DEVICES) { - memset(&devices, 0, sizeof(struct acpi_handle_list)); + if ((flag & ACPI_TRIPS_DEVICES) + && acpi_has_method(tz->device->handle, "_TZD")) { + memset(&devices, 0, sizeof(devices)); status = acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &devices); - if (memcmp(&tz->devices, &devices, - sizeof(struct acpi_handle_list))) { - memcpy(&tz->devices, &devices, - sizeof(struct acpi_handle_list)); + if (ACPI_SUCCESS(status) + && memcmp(&tz->devices, &devices, sizeof(devices))) { + tz->devices = devices; ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); } } -- cgit v0.10.2 From 524f42fab787a9510be826ce3d736b56d454ac6d Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Mon, 26 Aug 2013 10:19:18 +0800 Subject: ACPI / EC: Add ASUSTEK L4R to quirk list in order to validate ECDT The ECDT of ASUSTEK L4R doesn't provide correct command and data I/O ports. The DSDT provides the correct information instead. For this reason, add this machine to quirk list for ECDT validation and use the EC information from the DSDT. [rjw: Changelog] References: https://bugzilla.kernel.org/show_bug.cgi?id=60765 Reported-and-tested-by: Daniele Esposti Signed-off-by: Lan Tianyu Cc: All Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 3444803..81b1331 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -987,6 +987,10 @@ static struct dmi_system_id ec_dmi_table[] __initdata = { ec_skip_dsdt_scan, "HP Folio 13", { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13"),}, NULL}, + { + ec_validate_ecdt, "ASUS hardware", { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL}, {}, }; -- cgit v0.10.2 From 3617f2ca6d0eba48114308532945a7f1577816a4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 27 Aug 2013 11:47:29 -0700 Subject: cpufreq: Fix timer/workqueue corruption due to double queueing When a CPU is hot removed we'll cancel all the delayed work items via gov_cancel_work(). Normally this will just cancels a delayed timer on each CPU that the policy is managing and the work won't run, but if the work is already running the workqueue code will wait for the work to finish before continuing to prevent the work items from re-queuing themselves like they normally do. This scheme will work most of the time, except for the case where the work function determines that it should adjust the delay for all other CPUs that the policy is managing. If this scenario occurs, the canceling CPU will cancel its own work but queue up the other CPUs works to run. For example: CPU0 CPU1 ---- ---- cpu_down() ... __cpufreq_remove_dev() cpufreq_governor_dbs() case CPUFREQ_GOV_STOP: gov_cancel_work(dbs_data, policy); cpu0 work is canceled timer is canceled cpu1 work is canceled od_dbs_timer() gov_queue_work(*, *, true); cpu0 work queued cpu1 work queued cpu2 work queued ... cpu1 work is canceled cpu2 work is canceled ... At the end of the GOV_STOP case cpu0 still has a work queued to run although the code is expecting all of the works to be canceled. __cpufreq_remove_dev() will then proceed to re-initialize all the other CPUs works except for the CPU that is going down. The CPUFREQ_GOV_START case in cpufreq_governor_dbs() will trample over the queued work and debugobjects will spit out a warning: WARNING: at lib/debugobjects.c:260 debug_print_object+0x94/0xbc() ODEBUG: init active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x10 Modules linked in: CPU: 0 PID: 1491 Comm: sh Tainted: G W 3.10.0 #19 [] (unwind_backtrace+0x0/0x11c) from [] (show_stack+0x10/0x14) [] (show_stack+0x10/0x14) from [] (warn_slowpath_common+0x4c/0x6c) [] (warn_slowpath_common+0x4c/0x6c) from [] (warn_slowpath_fmt+0x2c/0x3c) [] (warn_slowpath_fmt+0x2c/0x3c) from [] (debug_print_object+0x94/0xbc) [] (debug_print_object+0x94/0xbc) from [] (__debug_object_init+0x2d0/0x340) [] (__debug_object_init+0x2d0/0x340) from [] (init_timer_key+0x14/0xb0) [] (init_timer_key+0x14/0xb0) from [] (cpufreq_governor_dbs+0x3e8/0x5f8) [] (cpufreq_governor_dbs+0x3e8/0x5f8) from [] (__cpufreq_governor+0xdc/0x1a4) [] (__cpufreq_governor+0xdc/0x1a4) from [] (__cpufreq_remove_dev.isra.10+0x3b4/0x434) [] (__cpufreq_remove_dev.isra.10+0x3b4/0x434) from [] (cpufreq_cpu_callback+0x60/0x80) [] (cpufreq_cpu_callback+0x60/0x80) from [] (notifier_call_chain+0x38/0x68) [] (notifier_call_chain+0x38/0x68) from [] (__cpu_notify+0x28/0x40) [] (__cpu_notify+0x28/0x40) from [] (_cpu_down+0x7c/0x2c0) [] (_cpu_down+0x7c/0x2c0) from [] (cpu_down+0x24/0x40) [] (cpu_down+0x24/0x40) from [] (store_online+0x2c/0x74) [] (store_online+0x2c/0x74) from [] (dev_attr_store+0x18/0x24) [] (dev_attr_store+0x18/0x24) from [] (sysfs_write_file+0x100/0x148) [] (sysfs_write_file+0x100/0x148) from [] (vfs_write+0xcc/0x174) [] (vfs_write+0xcc/0x174) from [] (SyS_write+0x38/0x64) [] (SyS_write+0x38/0x64) from [] (ret_fast_syscall+0x0/0x30) Signed-off-by: Stephen Boyd Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 8742736..bce2cd2 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -119,6 +119,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, { int i; + if (!policy->governor_enabled) + return; + if (!all_cpus) { __gov_queue_work(smp_processor_id(), dbs_data, delay); } else { -- cgit v0.10.2 From 934dac1ea072bd8adff8d6a6abba561731e093cf Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Mon, 26 Aug 2013 21:37:28 +0300 Subject: cpufreq: governors: Remove duplicate check of target freq in supported range Function __cpufreq_driver_target() checks if target_freq is within policy->min and policy->max range. generic_powersave_bias_target() also checks if target_freq is valid via a cpufreq_frequency_table_target() call. So, drop the unnecessary duplicate check in *_check_cpu(). Signed-off-by: Stratos Karafotis Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 7f67a75..f62d822 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -67,8 +67,6 @@ static void cs_check_cpu(int cpu, unsigned int load) return; dbs_info->requested_freq += get_freq_target(cs_tuners, policy); - if (dbs_info->requested_freq > policy->max) - dbs_info->requested_freq = policy->max; __cpufreq_driver_target(policy, dbs_info->requested_freq, CPUFREQ_RELATION_H); @@ -89,8 +87,6 @@ static void cs_check_cpu(int cpu, unsigned int load) return; dbs_info->requested_freq -= get_freq_target(cs_tuners, policy); - if (dbs_info->requested_freq < policy->min) - dbs_info->requested_freq = policy->min; __cpufreq_driver_target(policy, dbs_info->requested_freq, CPUFREQ_RELATION_L); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 87f3305..32f26f6 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -177,9 +177,6 @@ static void od_check_cpu(int cpu, unsigned int load) /* No longer fully busy, reset rate_mult */ dbs_info->rate_mult = 1; - if (freq_next < policy->min) - freq_next = policy->min; - if (!od_tuners->powersave_bias) { __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); -- cgit v0.10.2 From c4afc410942f9f0675a5431adbdb03cf5908d1df Mon Sep 17 00:00:00 2001 From: Stratos Karafotis Date: Mon, 26 Aug 2013 21:42:21 +0300 Subject: cpufreq: governor: Fix typos in comments - 'Governer' should be 'Governor'. - 'S' is used for Siemens (electrical conductance) in SI units, so use small 's' for seconds. Signed-off-by: Stratos Karafotis Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index bce2cd2..0e5929b 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -233,7 +233,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, policy->governor_data = dbs_data; - /* policy latency is in nS. Convert it to uS first */ + /* policy latency is in ns. Convert it to us first */ latency = policy->cpuinfo.transition_latency / 1000; if (latency == 0) latency = 1; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index a02d78b..88cd39f 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -25,11 +25,11 @@ /* * The polling frequency depends on the capability of the processor. Default * polling frequency is 1000 times the transition latency of the processor. The - * governor will work on any processor with transition latency <= 10mS, using + * governor will work on any processor with transition latency <= 10ms, using * appropriate sampling rate. * - * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) - * this governor will not work. All times here are in uS. + * For CPUs with transition latency > 10ms (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. All times here are in us (micro seconds). */ #define MIN_SAMPLING_RATE_RATIO (2) #define LATENCY_MULTIPLIER (1000) @@ -162,7 +162,7 @@ struct cs_cpu_dbs_info_s { unsigned int enable:1; }; -/* Per policy Governers sysfs tunables */ +/* Per policy Governors sysfs tunables */ struct od_dbs_tuners { unsigned int ignore_nice_load; unsigned int sampling_rate; @@ -181,7 +181,7 @@ struct cs_dbs_tuners { unsigned int freq_step; }; -/* Common Governer data across policies */ +/* Common Governor data across policies */ struct dbs_data; struct common_dbs_data { /* Common across governors */ @@ -205,7 +205,7 @@ struct common_dbs_data { void *gov_ops; }; -/* Governer Per policy data */ +/* Governor Per policy data */ struct dbs_data { struct common_dbs_data *cdata; unsigned int min_sampling_rate; -- cgit v0.10.2 From 5e33bc4165f3edd558d9633002465a95230effc1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 28 Aug 2013 21:41:01 +0200 Subject: driver core / ACPI: Avoid device hot remove locking issues device_hotplug_lock is held around the acpi_bus_trim() call in acpi_scan_hot_remove() which generally removes devices (it removes ACPI device objects at least, but it may also remove "physical" device objects through .detach() callbacks of ACPI scan handlers). Thus, potentially, device sysfs attributes are removed under that lock and to remove those attributes it is necessary to hold the s_active references of their directory entries for writing. On the other hand, the execution of a .show() or .store() callback from a sysfs attribute is carried out with that attribute's s_active reference held for reading. Consequently, if any device sysfs attribute that may be removed from within acpi_scan_hot_remove() through acpi_bus_trim() has a .store() or .show() callback which acquires device_hotplug_lock, the execution of that callback may deadlock with the removal of the attribute. [Unfortunately, the "online" device attribute of CPUs and memory blocks is one of them.] To avoid such deadlocks, make all of the sysfs attribute callbacks that need to lock device hotplug, for example store_online(), use a special function, lock_device_hotplug_sysfs(), to lock device hotplug and return the result of that function immediately if it is not zero. This will cause the s_active reference of the directory entry in question to be released and the syscall to be restarted if device_hotplug_lock cannot be acquired. [show_online() actually doesn't need to lock device hotplug, but it is useful to serialize it with respect to device_offline() and device_online() for the same device (in case user space attempts to run them concurrently) which can be done with the help of device_lock().] Reported-by: Yasuaki Ishimatsu Reported-and-tested-by: Gu Zheng Suggested-by: Tejun Heo Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Toshi Kani diff --git a/drivers/base/core.c b/drivers/base/core.c index 8856d74..ac419a1 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -49,6 +49,28 @@ static struct kobject *dev_kobj; struct kobject *sysfs_dev_char_kobj; struct kobject *sysfs_dev_block_kobj; +static DEFINE_MUTEX(device_hotplug_lock); + +void lock_device_hotplug(void) +{ + mutex_lock(&device_hotplug_lock); +} + +void unlock_device_hotplug(void) +{ + mutex_unlock(&device_hotplug_lock); +} + +int lock_device_hotplug_sysfs(void) +{ + if (mutex_trylock(&device_hotplug_lock)) + return 0; + + /* Avoid busy looping (5 ms of sleep should do). */ + msleep(5); + return restart_syscall(); +} + #ifdef CONFIG_BLOCK static inline int device_is_not_partition(struct device *dev) { @@ -408,9 +430,9 @@ static ssize_t show_online(struct device *dev, struct device_attribute *attr, { bool val; - lock_device_hotplug(); + device_lock(dev); val = !dev->offline; - unlock_device_hotplug(); + device_unlock(dev); return sprintf(buf, "%u\n", val); } @@ -424,7 +446,10 @@ static ssize_t store_online(struct device *dev, struct device_attribute *attr, if (ret < 0) return ret; - lock_device_hotplug(); + ret = lock_device_hotplug_sysfs(); + if (ret) + return ret; + ret = val ? device_online(dev) : device_offline(dev); unlock_device_hotplug(); return ret < 0 ? ret : count; @@ -1479,18 +1504,6 @@ EXPORT_SYMBOL_GPL(put_device); EXPORT_SYMBOL_GPL(device_create_file); EXPORT_SYMBOL_GPL(device_remove_file); -static DEFINE_MUTEX(device_hotplug_lock); - -void lock_device_hotplug(void) -{ - mutex_lock(&device_hotplug_lock); -} - -void unlock_device_hotplug(void) -{ - mutex_unlock(&device_hotplug_lock); -} - static int device_check_offline(struct device *dev, void *not_used) { int ret; diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 2b7813e..6f4c99f 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -351,7 +351,9 @@ store_mem_state(struct device *dev, mem = container_of(dev, struct memory_block, dev); - lock_device_hotplug(); + ret = lock_device_hotplug_sysfs(); + if (ret) + return ret; if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) { offline = false; diff --git a/include/linux/device.h b/include/linux/device.h index 22b546a..545a042 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -895,6 +895,7 @@ static inline bool device_supports_offline(struct device *dev) extern void lock_device_hotplug(void); extern void unlock_device_hotplug(void); +extern int lock_device_hotplug_sysfs(void); extern int device_offline(struct device *dev); extern int device_online(struct device *dev); /* -- cgit v0.10.2 From f943db40c29f3c82a56956e9ca36f21d6d855db9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 28 Aug 2013 21:41:07 +0200 Subject: ACPI / hotplug: Remove containers synchronously The current protocol for handling hot remove of containers is very fragile and causes acpi_eject_store() to acquire acpi_scan_lock which may deadlock with the removal of the device that it is called for (the reason is that device sysfs attributes cannot be removed while their callbacks are being executed and ACPI device objects are removed under acpi_scan_lock). The problem is related to the fact that containers are handled by acpi_bus_device_eject() in a special way, which is to emit an offline uevent instead of just removing the container. Then, user space is expected to handle that uevent and use the container's "eject" attribute to actually remove it. That is fragile, because user space may fail to complete the ejection (for example, by not using the container's "eject" attribute at all) leaving the BIOS kind of in a limbo. Moreover, if the eject event is not signaled for a container itself, but for its parent device object (or generally, for an ancestor above it in the ACPI namespace), the container will be removed straight away without doing that whole dance. For this reason, modify acpi_bus_device_eject() to remove containers synchronously like any other objects (user space will get its uevent anyway in case it does some other things in response to it) and remove the eject_pending ACPI device flag that is not used any more. This way acpi_eject_store() doesn't have a reason to acquire acpi_scan_lock any more and one possible deadlock scenario goes away (plus the code is simplified a bit). Reported-and-tested-by: Gu Zheng Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Toshi Kani diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 8a46c92..e2f6d9d 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -307,6 +307,7 @@ static void acpi_bus_device_eject(void *context) struct acpi_device *device = NULL; struct acpi_scan_handler *handler; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + int error; mutex_lock(&acpi_scan_lock); @@ -321,17 +322,13 @@ static void acpi_bus_device_eject(void *context) } acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); - if (handler->hotplug.mode == AHM_CONTAINER) { - device->flags.eject_pending = true; + if (handler->hotplug.mode == AHM_CONTAINER) kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); - } else { - int error; - get_device(&device->dev); - error = acpi_scan_hot_remove(device); - if (error) - goto err_out; - } + get_device(&device->dev); + error = acpi_scan_hot_remove(device); + if (error) + goto err_out; out: mutex_unlock(&acpi_scan_lock); @@ -516,7 +513,6 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, struct acpi_eject_event *ej_event; acpi_object_type not_used; acpi_status status; - u32 ost_source; int ret; if (!count || buf[0] != '1') @@ -530,43 +526,28 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) return -ENODEV; - mutex_lock(&acpi_scan_lock); - - if (acpi_device->flags.eject_pending) { - /* ACPI eject notification event. */ - ost_source = ACPI_NOTIFY_EJECT_REQUEST; - acpi_device->flags.eject_pending = 0; - } else { - /* Eject initiated by user space. */ - ost_source = ACPI_OST_EC_OSPM_EJECT; - } ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); if (!ej_event) { ret = -ENOMEM; goto err_out; } - acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source, + acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); ej_event->device = acpi_device; - ej_event->event = ost_source; + ej_event->event = ACPI_OST_EC_OSPM_EJECT; get_device(&acpi_device->dev); status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event); - if (ACPI_FAILURE(status)) { - put_device(&acpi_device->dev); - kfree(ej_event); - ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; - goto err_out; - } - ret = count; + if (ACPI_SUCCESS(status)) + return count; - out: - mutex_unlock(&acpi_scan_lock); - return ret; + put_device(&acpi_device->dev); + kfree(ej_event); + ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; err_out: - acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source, + acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); - goto out; + return ret; } static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 94383a7..6ff9510 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -157,9 +157,8 @@ struct acpi_device_flags { u32 removable:1; u32 ejectable:1; u32 power_manageable:1; - u32 eject_pending:1; u32 match_driver:1; - u32 reserved:26; + u32 reserved:27; }; /* File System */ -- cgit v0.10.2 From 59e998561103a93f294c8d3138dd659af772a5da Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 23 Aug 2013 12:45:10 -0700 Subject: cpuidle: coupled: disable interrupts after entering safe state Calling cpuidle_enter_state is expected to return with interrupts enabled, but interrupts must be disabled before starting the ready loop synchronization stage. Call local_irq_disable after each call to cpuidle_enter_state for the safe state. Tested-by: Stephen Warren Signed-off-by: Colin Cross Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index 2a297f8..db92bcb 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -460,6 +460,7 @@ int cpuidle_enter_state_coupled(struct cpuidle_device *dev, } entered_state = cpuidle_enter_state(dev, drv, dev->safe_state_index); + local_irq_disable(); } /* Read barrier ensures online_count is read after prevent is cleared */ @@ -485,6 +486,7 @@ retry: entered_state = cpuidle_enter_state(dev, drv, dev->safe_state_index); + local_irq_disable(); } if (cpuidle_coupled_clear_pokes(dev->cpu)) { -- cgit v0.10.2 From f983827bcb9d2c34c4d8935861a1e9128aec2baf Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 28 Aug 2013 18:41:47 -0700 Subject: cpuidle: coupled: abort idle if pokes are pending Joseph Lo reported a lockup on Tegra20 caused by a race condition in coupled cpuidle. When two or more cpus enter idle at the same time, the first cpus to arrive may go to the ready loop without processing pending pokes from the last cpu to arrive. This patch adds a check for pending pokes once all cpus have been synchronized in the ready loop and resets the coupled state and retries if any cpus failed to handle their pending poke. Retrying on all cpus may trigger the same issue again, so this patch also adds a check to ensure that each cpu has received at least one poke between when it enters the waiting loop and when it moves on to the ready loop. Reported-and-tested-by: Joseph Lo Tested-by: Stephen Warren Signed-off-by: Colin Cross Cc: 3.6+ # 3.6+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index db92bcb..5d39627 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -106,6 +106,7 @@ struct cpuidle_coupled { cpumask_t coupled_cpus; int requested_state[NR_CPUS]; atomic_t ready_waiting_counts; + atomic_t abort_barrier; int online_count; int refcnt; int prevent; @@ -122,12 +123,19 @@ static DEFINE_MUTEX(cpuidle_coupled_lock); static DEFINE_PER_CPU(struct call_single_data, cpuidle_coupled_poke_cb); /* - * The cpuidle_coupled_poked_mask mask is used to avoid calling + * The cpuidle_coupled_poke_pending mask is used to avoid calling * __smp_call_function_single with the per cpu call_single_data struct already * in use. This prevents a deadlock where two cpus are waiting for each others * call_single_data struct to be available */ -static cpumask_t cpuidle_coupled_poked_mask; +static cpumask_t cpuidle_coupled_poke_pending; + +/* + * The cpuidle_coupled_poked mask is used to ensure that each cpu has been poked + * once to minimize entering the ready loop with a poke pending, which would + * require aborting and retrying. + */ +static cpumask_t cpuidle_coupled_poked; /** * cpuidle_coupled_parallel_barrier - synchronize all online coupled cpus @@ -291,10 +299,11 @@ static inline int cpuidle_coupled_get_state(struct cpuidle_device *dev, return state; } -static void cpuidle_coupled_poked(void *info) +static void cpuidle_coupled_handle_poke(void *info) { int cpu = (unsigned long)info; - cpumask_clear_cpu(cpu, &cpuidle_coupled_poked_mask); + cpumask_set_cpu(cpu, &cpuidle_coupled_poked); + cpumask_clear_cpu(cpu, &cpuidle_coupled_poke_pending); } /** @@ -313,7 +322,7 @@ static void cpuidle_coupled_poke(int cpu) { struct call_single_data *csd = &per_cpu(cpuidle_coupled_poke_cb, cpu); - if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poked_mask)) + if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poke_pending)) __smp_call_function_single(cpu, csd, 0); } @@ -340,30 +349,19 @@ static void cpuidle_coupled_poke_others(int this_cpu, * @coupled: the struct coupled that contains the current cpu * @next_state: the index in drv->states of the requested state for this cpu * - * Updates the requested idle state for the specified cpuidle device, - * poking all coupled cpus out of idle if necessary to let them see the new - * state. + * Updates the requested idle state for the specified cpuidle device. + * Returns the number of waiting cpus. */ -static void cpuidle_coupled_set_waiting(int cpu, +static int cpuidle_coupled_set_waiting(int cpu, struct cpuidle_coupled *coupled, int next_state) { - int w; - coupled->requested_state[cpu] = next_state; /* - * If this is the last cpu to enter the waiting state, poke - * all the other cpus out of their waiting state so they can - * enter a deeper state. This can race with one of the cpus - * exiting the waiting state due to an interrupt and - * decrementing waiting_count, see comment below. - * * The atomic_inc_return provides a write barrier to order the write * to requested_state with the later write that increments ready_count. */ - w = atomic_inc_return(&coupled->ready_waiting_counts) & WAITING_MASK; - if (w == coupled->online_count) - cpuidle_coupled_poke_others(cpu, coupled); + return atomic_inc_return(&coupled->ready_waiting_counts) & WAITING_MASK; } /** @@ -418,13 +416,24 @@ static void cpuidle_coupled_set_done(int cpu, struct cpuidle_coupled *coupled) static int cpuidle_coupled_clear_pokes(int cpu) { local_irq_enable(); - while (cpumask_test_cpu(cpu, &cpuidle_coupled_poked_mask)) + while (cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending)) cpu_relax(); local_irq_disable(); return need_resched() ? -EINTR : 0; } +static bool cpuidle_coupled_any_pokes_pending(struct cpuidle_coupled *coupled) +{ + cpumask_t cpus; + int ret; + + cpumask_and(&cpus, cpu_online_mask, &coupled->coupled_cpus); + ret = cpumask_and(&cpus, &cpuidle_coupled_poke_pending, &cpus); + + return ret; +} + /** * cpuidle_enter_state_coupled - attempt to enter a state with coupled cpus * @dev: struct cpuidle_device for the current cpu @@ -449,6 +458,7 @@ int cpuidle_enter_state_coupled(struct cpuidle_device *dev, { int entered_state = -1; struct cpuidle_coupled *coupled = dev->coupled; + int w; if (!coupled) return -EINVAL; @@ -466,14 +476,33 @@ int cpuidle_enter_state_coupled(struct cpuidle_device *dev, /* Read barrier ensures online_count is read after prevent is cleared */ smp_rmb(); - cpuidle_coupled_set_waiting(dev->cpu, coupled, next_state); +reset: + cpumask_clear_cpu(dev->cpu, &cpuidle_coupled_poked); + + w = cpuidle_coupled_set_waiting(dev->cpu, coupled, next_state); + /* + * If this is the last cpu to enter the waiting state, poke + * all the other cpus out of their waiting state so they can + * enter a deeper state. This can race with one of the cpus + * exiting the waiting state due to an interrupt and + * decrementing waiting_count, see comment below. + */ + if (w == coupled->online_count) { + cpumask_set_cpu(dev->cpu, &cpuidle_coupled_poked); + cpuidle_coupled_poke_others(dev->cpu, coupled); + } retry: /* * Wait for all coupled cpus to be idle, using the deepest state - * allowed for a single cpu. + * allowed for a single cpu. If this was not the poking cpu, wait + * for at least one poke before leaving to avoid a race where + * two cpus could arrive at the waiting loop at the same time, + * but the first of the two to arrive could skip the loop without + * processing the pokes from the last to arrive. */ - while (!cpuidle_coupled_cpus_waiting(coupled)) { + while (!cpuidle_coupled_cpus_waiting(coupled) || + !cpumask_test_cpu(dev->cpu, &cpuidle_coupled_poked)) { if (cpuidle_coupled_clear_pokes(dev->cpu)) { cpuidle_coupled_set_not_waiting(dev->cpu, coupled); goto out; @@ -495,6 +524,12 @@ retry: } /* + * Make sure final poke status for this cpu is visible before setting + * cpu as ready. + */ + smp_wmb(); + + /* * All coupled cpus are probably idle. There is a small chance that * one of the other cpus just became active. Increment the ready count, * and spin until all coupled cpus have incremented the counter. Once a @@ -513,6 +548,28 @@ retry: cpu_relax(); } + /* + * Make sure read of all cpus ready is done before reading pending pokes + */ + smp_rmb(); + + /* + * There is a small chance that a cpu left and reentered idle after this + * cpu saw that all cpus were waiting. The cpu that reentered idle will + * have sent this cpu a poke, which will still be pending after the + * ready loop. The pending interrupt may be lost by the interrupt + * controller when entering the deep idle state. It's not possible to + * clear a pending interrupt without turning interrupts on and handling + * it, and it's too late to turn on interrupts here, so reset the + * coupled idle state of all cpus and retry. + */ + if (cpuidle_coupled_any_pokes_pending(coupled)) { + cpuidle_coupled_set_done(dev->cpu, coupled); + /* Wait for all cpus to see the pending pokes */ + cpuidle_coupled_parallel_barrier(dev, &coupled->abort_barrier); + goto reset; + } + /* all cpus have acked the coupled state */ next_state = cpuidle_coupled_get_state(dev, coupled); @@ -598,7 +655,7 @@ have_coupled: coupled->refcnt++; csd = &per_cpu(cpuidle_coupled_poke_cb, dev->cpu); - csd->func = cpuidle_coupled_poked; + csd->func = cpuidle_coupled_handle_poke; csd->info = (void *)(unsigned long)dev->cpu; return 0; -- cgit v0.10.2 From 9e19b73c30a5fa42a53583a1f7817dd857126156 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 23 Aug 2013 12:45:12 -0700 Subject: cpuidle: coupled: fix race condition between pokes and safe state The coupled cpuidle waiting loop clears pending pokes before entering the safe state. If a poke arrives just before the pokes are cleared, but after the while loop condition checks, the poke will be lost and the cpu will stay in the safe state until another interrupt arrives. This may cause the cpu that sent the poke to spin in the ready loop with interrupts off until another cpu receives an interrupt, and if no other cpus have interrupts routed to them it can spin forever. Change the return value of cpuidle_coupled_clear_pokes to return if a poke was cleared, and move the need_resched() checks into the callers. In the waiting loop, if a poke was cleared restart the loop to repeat the while condition checks. Reported-by: Neil Zhang Signed-off-by: Colin Cross Cc: 3.6+ # 3.6+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index 5d39627..f8a8636 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -408,19 +408,22 @@ static void cpuidle_coupled_set_done(int cpu, struct cpuidle_coupled *coupled) * been processed and the poke bit has been cleared. * * Other interrupts may also be processed while interrupts are enabled, so - * need_resched() must be tested after turning interrupts off again to make sure + * need_resched() must be tested after this function returns to make sure * the interrupt didn't schedule work that should take the cpu out of idle. * - * Returns 0 if need_resched was false, -EINTR if need_resched was true. + * Returns 0 if no poke was pending, 1 if a poke was cleared. */ static int cpuidle_coupled_clear_pokes(int cpu) { + if (!cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending)) + return 0; + local_irq_enable(); while (cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending)) cpu_relax(); local_irq_disable(); - return need_resched() ? -EINTR : 0; + return 1; } static bool cpuidle_coupled_any_pokes_pending(struct cpuidle_coupled *coupled) @@ -464,7 +467,8 @@ int cpuidle_enter_state_coupled(struct cpuidle_device *dev, return -EINVAL; while (coupled->prevent) { - if (cpuidle_coupled_clear_pokes(dev->cpu)) { + cpuidle_coupled_clear_pokes(dev->cpu); + if (need_resched()) { local_irq_enable(); return entered_state; } @@ -503,7 +507,10 @@ retry: */ while (!cpuidle_coupled_cpus_waiting(coupled) || !cpumask_test_cpu(dev->cpu, &cpuidle_coupled_poked)) { - if (cpuidle_coupled_clear_pokes(dev->cpu)) { + if (cpuidle_coupled_clear_pokes(dev->cpu)) + continue; + + if (need_resched()) { cpuidle_coupled_set_not_waiting(dev->cpu, coupled); goto out; } @@ -518,7 +525,8 @@ retry: local_irq_disable(); } - if (cpuidle_coupled_clear_pokes(dev->cpu)) { + cpuidle_coupled_clear_pokes(dev->cpu); + if (need_resched()) { cpuidle_coupled_set_not_waiting(dev->cpu, coupled); goto out; } -- cgit v0.10.2 From 6932078376e2c1fd49b6c4aa41cc5e162ee83d8a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 28 Aug 2013 14:24:45 -0700 Subject: cpufreq: Don't use smp_processor_id() in preemptible context Workqueues are preemptible even if works are queued on them with queue_work_on(). Let's use raw_smp_processor_id() here to silence the warning. BUG: using smp_processor_id() in preemptible [00000000] code: kworker/3:2/674 caller is gov_queue_work+0x28/0xb0 CPU: 0 PID: 674 Comm: kworker/3:2 Tainted: G W 3.10.0 #30 Workqueue: events od_dbs_timer [] (unwind_backtrace+0x0/0x11c) from [] (show_stack+0x10/0x14) [] (show_stack+0x10/0x14) from [] (debug_smp_processor_id+0xbc/0xf0) [] (debug_smp_processor_id+0xbc/0xf0) from [] (gov_queue_work+0x28/0xb0) [] (gov_queue_work+0x28/0xb0) from [] (od_dbs_timer+0x108/0x134) [] (od_dbs_timer+0x108/0x134) from [] (process_one_work+0x25c/0x444) [] (process_one_work+0x25c/0x444) from [] (worker_thread+0x200/0x344) [] (worker_thread+0x200/0x344) from [] (kthread+0xa0/0xb0) [] (kthread+0xa0/0xb0) from [] (ret_from_fork+0x14/0x3c) Signed-off-by: Stephen Boyd Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 0e5929b..0806c31 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -123,7 +123,14 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, return; if (!all_cpus) { - __gov_queue_work(smp_processor_id(), dbs_data, delay); + /* + * Use raw_smp_processor_id() to avoid preemptible warnings. + * We know that this is only called with all_cpus == false from + * works that have been queued with *_work_on() functions and + * those works are canceled during CPU_DOWN_PREPARE so they + * can't possibly run on any other CPU. + */ + __gov_queue_work(raw_smp_processor_id(), dbs_data, delay); } else { for_each_cpu(i, policy->cpus) __gov_queue_work(i, dbs_data, delay); -- cgit v0.10.2