From a9c6ce57ec2f136d08141e8220a0ffaca216f7b0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 8 Nov 2016 14:38:46 +0100 Subject: led: core: Use atomic bit-field for the blink-flags All the LED_BLINK* flags are accessed read-modify-write from e.g. led_set_brightness and led_blink_set_oneshot while both set_brightness_work and the blink_timer may be running. If these race then the modify step done by one of them may be lost, switch the LED_BLINK* flags to a new atomic work_flags bit-field to avoid this race. Signed-off-by: Hans de Goede Signed-off-by: Jacek Anaszewski --- include/linux/leds.h | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/leds.h b/include/linux/leds.h index ddfcb2df3656..21c598b366f8 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -42,16 +42,20 @@ struct led_classdev { #define LED_UNREGISTERING (1 << 1) /* Upper 16 bits reflect control information */ #define LED_CORE_SUSPENDRESUME (1 << 16) -#define LED_BLINK_SW (1 << 17) -#define LED_BLINK_ONESHOT (1 << 18) -#define LED_BLINK_ONESHOT_STOP (1 << 19) -#define LED_BLINK_INVERT (1 << 20) -#define LED_BLINK_BRIGHTNESS_CHANGE (1 << 21) -#define LED_BLINK_DISABLE (1 << 22) -#define LED_SYSFS_DISABLE (1 << 23) -#define LED_DEV_CAP_FLASH (1 << 24) -#define LED_HW_PLUGGABLE (1 << 25) -#define LED_PANIC_INDICATOR (1 << 26) +#define LED_SYSFS_DISABLE (1 << 17) +#define LED_DEV_CAP_FLASH (1 << 18) +#define LED_HW_PLUGGABLE (1 << 19) +#define LED_PANIC_INDICATOR (1 << 20) + + /* set_brightness_work / blink_timer flags, atomic, private. */ + unsigned long work_flags; + +#define LED_BLINK_SW 0 +#define LED_BLINK_ONESHOT 1 +#define LED_BLINK_ONESHOT_STOP 2 +#define LED_BLINK_INVERT 3 +#define LED_BLINK_BRIGHTNESS_CHANGE 4 +#define LED_BLINK_DISABLE 5 /* Set LED brightness level * Must not sleep. Use brightness_set_blocking for drivers -- cgit v1.2.3 From eb1610b4c273370f491c5e194e5a56e3470d81e8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 23 Oct 2016 21:47:26 +0200 Subject: led: core: Fix blink_brightness setting race All 3 of led_timer_func, led_set_brightness and led_set_software_blink set blink_brightness. If led_timer_func or led_set_software_blink race with led_set_brightness they may end up overwriting the new blink_brightness. The new atomic work_flags does not protect against this as it just protects the flags and not blink_brightness. This commit introduces a new new_blink_brightness value which gets set by led_set_brightness and read by led_timer_func on LED on, fixing this. Dealing with the new brightness at LED on time, makes the new brightness apply sooner, which also fixes a led_set_brightness which happens while a oneshot blink which ends in LED on is running not getting applied. Signed-off-by: Hans de Goede Signed-off-by: Jacek Anaszewski --- include/linux/leds.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/leds.h b/include/linux/leds.h index 21c598b366f8..569cb531094c 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -93,6 +93,7 @@ struct led_classdev { unsigned long blink_delay_on, blink_delay_off; struct timer_list blink_timer; int blink_brightness; + int new_blink_brightness; void (*flash_resume)(struct led_classdev *led_cdev); struct work_struct set_brightness_work; -- cgit v1.2.3