The patch titled hp_accel: do not call ACPI from invalid context has been added to the -mm tree. Its filename is hp_accel-do-not-call-acpi-from-invalid-context.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/SubmitChecklist when testing your code *** See http://userweb.kernel.org/~akpm/stuff/added-to-mm.txt to find out what to do about this The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/ ------------------------------------------------------ Subject: hp_accel: do not call ACPI from invalid context From: Pavel Machek <pavel@xxxxxxx> The LED on HP notebooks is connected through ACPI. That unfortunately means that it needs to be delayed by using schedule_work() to avoid calling the ACPI interpreter from an invalid context. Signed-off-by: Pavel Machek <pavel@xxxxxxx> Cc: Éric Piel <eric.piel@xxxxxxxxxxxxxxxx> Cc: Len Brown <lenb@xxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- drivers/hwmon/hp_accel.c | 71 +++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 19 deletions(-) diff -puN drivers/hwmon/hp_accel.c~hp_accel-do-not-call-acpi-from-invalid-context drivers/hwmon/hp_accel.c --- a/drivers/hwmon/hp_accel.c~hp_accel-do-not-call-acpi-from-invalid-context +++ a/drivers/hwmon/hp_accel.c @@ -3,7 +3,7 @@ * * Copyright (C) 2007-2008 Yan Burman * Copyright (C) 2008 Eric Piel - * Copyright (C) 2008 Pavel Machek + * Copyright (C) 2008-2009 Pavel Machek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,6 +44,36 @@ #define DRIVER_NAME "lis3lv02d" #define ACPI_MDPS_CLASS "accelerometer" +/* Delayed LEDs infrastructure ------------------------------------ */ + +/* Special LED class that can defer work */ +struct delayed_led_classdev { + struct led_classdev led_classdev; + struct work_struct work; + enum led_brightness new_brightness; + + unsigned int led; /* For driver */ + void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value); +}; + +static inline void delayed_set_status_worker(struct work_struct *work) +{ + struct delayed_led_classdev *data = + container_of(work, struct delayed_led_classdev, work); + + data->set_brightness(data, data->new_brightness); +} + +static inline void delayed_sysfs_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct delayed_led_classdev *data = container_of(led_cdev, + struct delayed_led_classdev, led_classdev); + data->new_brightness = brightness; + schedule_work(&data->work); +} + +/* HP-specific accelerometer driver ------------------------------------ */ /* For automatic insertion of the module */ static struct acpi_device_id lis3lv02d_device_ids[] = { @@ -155,28 +185,27 @@ static struct dmi_system_id lis3lv02d_dm */ }; -static acpi_status hpled_acpi_write(acpi_handle handle, int reg) +static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) { + acpi_handle handle = adev.device->handle; unsigned long long ret; /* Not used when writing */ union acpi_object in_obj[1]; struct acpi_object_list args = { 1, in_obj }; in_obj[0].type = ACPI_TYPE_INTEGER; - in_obj[0].integer.value = reg; + in_obj[0].integer.value = !!value; - return acpi_evaluate_integer(handle, "ALED", &args, &ret); + acpi_evaluate_integer(handle, "ALED", &args, &ret); } -static void hpled_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - hpled_acpi_write(adev.device->handle, !!value); -} - -static struct led_classdev hpled_led = { - .name = "hp:red:hddprotection", - .default_trigger = "none", - .brightness_set = hpled_set, +static struct delayed_led_classdev hpled_led = { + .led_classdev = { + .name = "hp::hddprotect", + .default_trigger = "none", + .brightness_set = delayed_sysfs_set, + .flags = LED_CORE_SUSPENDRESUME, + }, + .set_brightness = hpled_set, }; static int lis3lv02d_add(struct acpi_device *device) @@ -208,13 +237,17 @@ static int lis3lv02d_add(struct acpi_dev adev.ac = lis3lv02d_axis_normal; } - ret = led_classdev_register(NULL, &hpled_led); + INIT_WORK(&hpled_led.work, delayed_set_status_worker); + ret = led_classdev_register(NULL, &hpled_led.led_classdev); if (ret) return ret; ret = lis3lv02d_init_device(&adev); if (ret) { - led_classdev_unregister(&hpled_led); + while (work_pending(&hpled_led.work)) + schedule(); + + led_classdev_unregister(&hpled_led.led_classdev); return ret; } @@ -229,7 +262,9 @@ static int lis3lv02d_remove(struct acpi_ lis3lv02d_joystick_disable(); lis3lv02d_poweroff(device->handle); - led_classdev_unregister(&hpled_led); + while (work_pending(&hpled_led.work)) + schedule(); + led_classdev_unregister(&hpled_led.led_classdev); return lis3lv02d_remove_fs(); } @@ -240,7 +275,6 @@ static int lis3lv02d_suspend(struct acpi { /* make sure the device is off when we suspend */ lis3lv02d_poweroff(device->handle); - led_classdev_suspend(&hpled_led); return 0; } @@ -253,7 +287,6 @@ static int lis3lv02d_resume(struct acpi_ else lis3lv02d_poweroff(device->handle); mutex_unlock(&adev.lock); - led_classdev_resume(&hpled_led); return 0; } #else _ Patches currently in -mm which might be from pavel@xxxxxxx are lis3lv02d-merge-with-leds-hp-disk.patch maintainers-add-entry-for-freezer.patch hp_accel-do-not-call-acpi-from-invalid-context.patch linux-next.patch thinkpad-acpi-split-delayed-leds-stuff-clean-up-code.patch thinkpad-acpi-split-delayed-leds-stuff-clean-up-code-checkpatch-fixes.patch nbd-trivial-cleanups.patch -- To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html