[PATCH 01/17] leds: create a trigger for CPU activity

Eric Miao eric.y.miao at gmail.com
Wed Jul 6 09:16:47 EDT 2011


On Wed, Jul 6, 2011 at 8:34 PM, Bryan Wu <bryan.wu at canonical.com> wrote:
> Attempting to consolidate the ARM LED code, this removes the
> custom RealView LED trigger code to turn LEDs on and off in
> response to CPU activity and replace it with a standard trigger.
>
> (bryan.wu at canonical.com:
> It moves arch/arm/kernel/leds.c syscore stubs into this trigger.
> It also provides ledtrig_cpu trigger event stub in <linux/leds.h>.
> Although it was inspired by ARM work, it can be used in other arch.)
>
> Cc: Richard Purdie <rpurdie at rpsys.net>
> Signed-off-by: Linus Walleij <linus.walleij at linaro.org>
> Signed-off-by: Bryan Wu <bryan.wu at canonical.com>
> ---
>  drivers/leds/Kconfig       |   10 +++
>  drivers/leds/Makefile      |    1 +
>  drivers/leds/ledtrig-cpu.c |  144 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/leds.h       |   15 +++++
>  4 files changed, 170 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/leds/ledtrig-cpu.c
>
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 713d43b..186000a 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -446,6 +446,16 @@ config LEDS_TRIGGER_BACKLIGHT
>
>          If unsure, say N.
>
> +config LEDS_TRIGGER_CPU
> +       bool "LED CPU Trigger"
> +       depends on LEDS_TRIGGERS
> +       help
> +         This allows LEDs to be controlled by active CPUs. This shows
> +         the active CPUs across an array of LEDs so you can see what
> +         CPUs are active on the system at any given moment.
> +
> +         If unsure, say N.
> +
>  config LEDS_TRIGGER_GPIO
>        tristate "LED GPIO Trigger"
>        depends on LEDS_TRIGGERS
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index bbfd2e3..5e70d2e 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -53,4 +53,5 @@ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)   += ledtrig-ide-disk.o
>  obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT)   += ledtrig-heartbeat.o
>  obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT)   += ledtrig-backlight.o
>  obj-$(CONFIG_LEDS_TRIGGER_GPIO)                += ledtrig-gpio.o
> +obj-$(CONFIG_LEDS_TRIGGER_CPU)         += ledtrig-cpu.o
>  obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)  += ledtrig-default-on.o
> diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c
> new file mode 100644
> index 0000000..4d63ada
> --- /dev/null
> +++ b/drivers/leds/ledtrig-cpu.c
> @@ -0,0 +1,144 @@
> +/*
> + * ledtrig-cpu.c - LED trigger based on CPU activity
> + *
> + * Copyright 2011 Linus Walleij <linus.walleij at linaro.org>
> + * Copyright 2011 Bryan Wu <bryan.wu at canonical.com>
> + *
> + * 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 <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/percpu.h>
> +#include <linux/syscore_ops.h>
> +#include "leds.h"
> +
> +struct cpu_trig_data {
> +       struct led_classdev *led;
> +};
> +
> +static DEFINE_PER_CPU(struct cpu_trig_data *, cpu_triggers);
> +
> +void ledtrig_cpu(enum cpu_led_event ledevt)
> +{
> +       struct cpu_trig_data *trigdata = __get_cpu_var(cpu_triggers);
> +
> +       if (!trigdata)
> +               return;
> +
> +       /* Locate the correct CPU LED */
> +
> +       switch (ledevt) {
> +       case CPU_LED_START:
> +       case CPU_LED_IDLE_START:
> +               /* Will turn the LED on, max brightness */
> +               if (trigdata->led)
> +                       led_set_brightness(trigdata->led,
> +                                          trigdata->led->max_brightness);
> +               break;
> +
> +       case CPU_LED_STOP:
> +       case CPU_LED_IDLE_END:
> +       case CPU_LED_HALTED:
> +               /* Will turn the LED off */
> +               if (trigdata->led)
> +                       led_set_brightness(trigdata->led, LED_OFF);
> +               break;
> +
> +       default:
> +               /* Will leave the LED as it is */
> +               break;
> +       }
> +}

I'm a bit worrying about the LED brightness hardcoded here, what if
a platform requires different behavior, e.g. LED_OFF when IDLE_START.

> +EXPORT_SYMBOL(ledtrig_cpu);
> +
> +static void cpu_trig_activate_cpu(void *data)
> +{
> +       struct cpu_trig_data *cpu_data;
> +       struct led_classdev *led = data;
> +       int my_cpu = smp_processor_id();
> +       unsigned long target_cpu = (unsigned long) led->trigger_data;
> +
> +       if (target_cpu != my_cpu)
> +               return;
> +
> +       cpu_data = kzalloc(sizeof(*cpu_data), GFP_KERNEL);
> +       if (!cpu_data)
> +               return;
> +
> +       dev_info(led->dev, "led %s indicate activity on CPU %d\n",
> +                led->name, my_cpu);
> +
> +       cpu_data->led = led;
> +       __get_cpu_var(cpu_triggers) = cpu_data;
> +}
> +
> +static void cpu_trig_activate(struct led_classdev *led)
> +{
> +       on_each_cpu(cpu_trig_activate_cpu, led, 1);
> +}
> +
> +static void cpu_trig_deactivate(struct led_classdev *led)
> +{
> +       struct cpu_trig_data *cpu_data = led->trigger_data;
> +
> +       kfree(cpu_data);
> +}
> +
> +static struct led_trigger cpu_led_trigger = {
> +       .name           = "cpu",
> +       .activate       = cpu_trig_activate,
> +       .deactivate     = cpu_trig_deactivate,
> +};
> +
> +
> +static int cpu_syscore_suspend(void)
> +{
> +       ledtrig_cpu(CPU_LED_STOP);
> +       return 0;
> +}
> +
> +static void cpu_syscore_resume(void)
> +{
> +       ledtrig_cpu(CPU_LED_START);
> +}
> +
> +static void cpu_syscore_shutdown(void)
> +{
> +       ledtrig_cpu(CPU_LED_HALTED);
> +}
> +
> +static struct syscore_ops cpu_syscore_ops = {
> +       .shutdown       = cpu_syscore_shutdown,
> +       .suspend        = cpu_syscore_suspend,
> +       .resume         = cpu_syscore_resume,
> +};

Even this is static, I think naming of ledtrig_cpu_syscore_* will be better
here, causing less confusion. As cpu_syscore_shutdown really gave me a
first impression it's about the action when the CPU shuts down.

> +
> +static int __init cpu_trig_init(void)
> +{
> +       int ret;
> +
> +       ret = led_trigger_register(&cpu_led_trigger);
> +       if (!ret)
> +               register_syscore_ops(&cpu_syscore_ops);
> +
> +       return ret;
> +}
> +module_init(cpu_trig_init);
> +
> +static void __exit cpu_trig_exit(void)
> +{
> +       unregister_syscore_ops(&cpu_syscore_ops);
> +       led_trigger_unregister(&cpu_led_trigger);
> +}
> +module_exit(cpu_trig_exit);

ledtrig_cpu_exit?

> +
> +MODULE_AUTHOR("Linus Walleij <linus.walleij at linaro.org>");
> +MODULE_AUTHOR("Bryan Wu <bryan.wu at canonical.com>");
> +MODULE_DESCRIPTION("CPU LED trigger");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/leds.h b/include/linux/leds.h
> index 5884def..94cdb9a 100644
> --- a/include/linux/leds.h
> +++ b/include/linux/leds.h
> @@ -210,4 +210,19 @@ struct gpio_led_platform_data {
>  struct platform_device *gpio_led_register_device(
>                int id, const struct gpio_led_platform_data *pdata);
>
> +#ifdef CONFIG_LEDS_TRIGGER_CPU
> +enum cpu_led_event {
> +       CPU_LED_IDLE_START,
> +       CPU_LED_IDLE_END,
> +       CPU_LED_START,
> +       CPU_LED_STOP,
> +       CPU_LED_HALTED
> +};

A brief block of comments explaining these events would be
very helpful for passing correct parameters to ledtrig_cpu()

> +
> +/* Use this routine to handle LEDs */
> +extern void ledtrig_cpu(enum cpu_led_event evt);
> +#else
> +#define ledtrig_cpu(evt) do {} while (0)
> +#endif
> +
>  #endif         /* __LINUX_LEDS_H_INCLUDED */
> --
> 1.7.5
>
>



More information about the linux-arm-kernel mailing list