Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

leds: triggers: Allow to switch the trigger to "panic" on a kernel panic

This commit adds a new led_cdev flag LED_PANIC_INDICATOR, which
allows to mark a specific LED to be switched to the "panic"
trigger, on a kernel panic.

This is useful to allow the user to assign a regular trigger
to a given LED, and still blink that LED on a kernel panic.

Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Matthias Brugger <mbrugger@suse.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>

authored by

Ezequiel Garcia and committed by
Jacek Anaszewski
ba93cdce f15c65af

+53 -1
+1 -1
drivers/leds/led-triggers.c
··· 26 26 * Nests outside led_cdev->trigger_lock 27 27 */ 28 28 static DECLARE_RWSEM(triggers_list_lock); 29 - static LIST_HEAD(trigger_list); 29 + LIST_HEAD(trigger_list); 30 30 31 31 /* Used by LED Class */ 32 32
+1
drivers/leds/leds.h
··· 30 30 31 31 extern struct rw_semaphore leds_list_lock; 32 32 extern struct list_head leds_list; 33 + extern struct list_head trigger_list; 33 34 34 35 #endif /* __LEDS_H_INCLUDED */
+3
drivers/leds/trigger/Kconfig
··· 121 121 depends on LEDS_TRIGGERS 122 122 help 123 123 This allows LEDs to be configured to blink on a kernel panic. 124 + Enabling this option will allow to mark certain LEDs as panic indicators, 125 + allowing to blink them on a kernel panic, even if they are set to 126 + a different trigger. 124 127 If unsure, say Y. 125 128 126 129 endif # LEDS_TRIGGERS
+47
drivers/leds/trigger/ledtrig-panic.c
··· 11 11 12 12 #include <linux/kernel.h> 13 13 #include <linux/init.h> 14 + #include <linux/notifier.h> 14 15 #include <linux/leds.h> 16 + #include "../leds.h" 15 17 16 18 static struct led_trigger *trigger; 19 + 20 + /* 21 + * This is called in a special context by the atomic panic 22 + * notifier. This means the trigger can be changed without 23 + * worrying about locking. 24 + */ 25 + static void led_trigger_set_panic(struct led_classdev *led_cdev) 26 + { 27 + struct led_trigger *trig; 28 + 29 + list_for_each_entry(trig, &trigger_list, next_trig) { 30 + if (strcmp("panic", trig->name)) 31 + continue; 32 + if (led_cdev->trigger) 33 + list_del(&led_cdev->trig_list); 34 + list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); 35 + 36 + /* Avoid the delayed blink path */ 37 + led_cdev->blink_delay_on = 0; 38 + led_cdev->blink_delay_off = 0; 39 + 40 + led_cdev->trigger = trig; 41 + if (trig->activate) 42 + trig->activate(led_cdev); 43 + break; 44 + } 45 + } 46 + 47 + static int led_trigger_panic_notifier(struct notifier_block *nb, 48 + unsigned long code, void *unused) 49 + { 50 + struct led_classdev *led_cdev; 51 + 52 + list_for_each_entry(led_cdev, &leds_list, node) 53 + if (led_cdev->flags & LED_PANIC_INDICATOR) 54 + led_trigger_set_panic(led_cdev); 55 + return NOTIFY_DONE; 56 + } 57 + 58 + static struct notifier_block led_trigger_panic_nb = { 59 + .notifier_call = led_trigger_panic_notifier, 60 + }; 17 61 18 62 static long led_panic_blink(int state) 19 63 { ··· 67 23 68 24 static int __init ledtrig_panic_init(void) 69 25 { 26 + atomic_notifier_chain_register(&panic_notifier_list, 27 + &led_trigger_panic_nb); 28 + 70 29 led_trigger_register_simple("panic", &trigger); 71 30 panic_blink = led_panic_blink; 72 31 return 0;
+1
include/linux/leds.h
··· 50 50 #define LED_SYSFS_DISABLE (1 << 22) 51 51 #define LED_DEV_CAP_FLASH (1 << 23) 52 52 #define LED_HW_PLUGGABLE (1 << 24) 53 + #define LED_PANIC_INDICATOR (1 << 25) 53 54 54 55 /* Set LED brightness level 55 56 * Must not sleep. Use brightness_set_blocking for drivers