LCOV - code coverage report
Current view: top level - drivers/leds/trigger - ledtrig-cpu.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 27 40 67.5 %
Date: 2020-09-30 20:25:40 Functions: 3 7 42.9 %
Branches: 12 13 92.3 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * ledtrig-cpu.c - LED trigger based on CPU activity
       4                 :            :  *
       5                 :            :  * This LED trigger will be registered for each possible CPU and named as
       6                 :            :  * cpu0, cpu1, cpu2, cpu3, etc.
       7                 :            :  *
       8                 :            :  * It can be bound to any LED just like other triggers using either a
       9                 :            :  * board file or via sysfs interface.
      10                 :            :  *
      11                 :            :  * An API named ledtrig_cpu is exported for any user, who want to add CPU
      12                 :            :  * activity indication in their code
      13                 :            :  *
      14                 :            :  * Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
      15                 :            :  * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com>
      16                 :            :  */
      17                 :            : 
      18                 :            : #include <linux/kernel.h>
      19                 :            : #include <linux/init.h>
      20                 :            : #include <linux/slab.h>
      21                 :            : #include <linux/percpu.h>
      22                 :            : #include <linux/syscore_ops.h>
      23                 :            : #include <linux/rwsem.h>
      24                 :            : #include <linux/cpu.h>
      25                 :            : #include "../leds.h"
      26                 :            : 
      27                 :            : #define MAX_NAME_LEN    8
      28                 :            : 
      29                 :            : struct led_trigger_cpu {
      30                 :            :         bool is_active;
      31                 :            :         char name[MAX_NAME_LEN];
      32                 :            :         struct led_trigger *_trig;
      33                 :            : };
      34                 :            : 
      35                 :            : static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
      36                 :            : 
      37                 :            : static struct led_trigger *trig_cpu_all;
      38                 :            : static atomic_t num_active_cpus = ATOMIC_INIT(0);
      39                 :            : 
      40                 :            : /**
      41                 :            :  * ledtrig_cpu - emit a CPU event as a trigger
      42                 :            :  * @evt: CPU event to be emitted
      43                 :            :  *
      44                 :            :  * Emit a CPU event on a CPU core, which will trigger a
      45                 :            :  * bound LED to turn on or turn off.
      46                 :            :  */
      47                 :  328212901 : void ledtrig_cpu(enum cpu_led_event ledevt)
      48                 :            : {
      49                 :  656425802 :         struct led_trigger_cpu *trig = this_cpu_ptr(&cpu_trig);
      50                 :  328212901 :         bool is_active = trig->is_active;
      51                 :            : 
      52                 :            :         /* Locate the correct CPU LED */
      53      [ +  +  + ]:  328212901 :         switch (ledevt) {
      54                 :            :         case CPU_LED_IDLE_END:
      55                 :            :         case CPU_LED_START:
      56                 :            :                 /* Will turn the LED on, max brightness */
      57                 :            :                 is_active = true;
      58                 :  164062219 :                 break;
      59                 :            : 
      60                 :            :         case CPU_LED_IDLE_START:
      61                 :            :         case CPU_LED_STOP:
      62                 :            :         case CPU_LED_HALTED:
      63                 :            :                 /* Will turn the LED off */
      64                 :            :                 is_active = false;
      65                 :  164087774 :                 break;
      66                 :            : 
      67                 :            :         default:
      68                 :            :                 /* Will leave the LED as it is */
      69                 :            :                 break;
      70                 :            :         }
      71                 :            : 
      72         [ +  + ]:  328212901 :         if (is_active != trig->is_active) {
      73                 :            :                 unsigned int active_cpus;
      74                 :            :                 unsigned int total_cpus;
      75                 :            : 
      76                 :            :                 /* Update trigger state */
      77                 :  328158873 :                 trig->is_active = is_active;
      78         [ +  + ]:  328158873 :                 atomic_add(is_active ? 1 : -1, &num_active_cpus);
      79                 :            :                 active_cpus = atomic_read(&num_active_cpus);
      80                 :  328196173 :                 total_cpus = num_present_cpus();
      81                 :            : 
      82         [ +  + ]:  328151349 :                 led_trigger_event(trig->_trig,
      83                 :            :                         is_active ? LED_FULL : LED_OFF);
      84                 :            : 
      85                 :            : 
      86                 :  656520582 :                 led_trigger_event(trig_cpu_all,
      87                 :  328260291 :                         DIV_ROUND_UP(LED_FULL * active_cpus, total_cpus));
      88                 :            : 
      89                 :            :         }
      90                 :  328344145 : }
      91                 :            : EXPORT_SYMBOL(ledtrig_cpu);
      92                 :            : 
      93                 :          0 : static int ledtrig_cpu_syscore_suspend(void)
      94                 :            : {
      95                 :          0 :         ledtrig_cpu(CPU_LED_STOP);
      96                 :          0 :         return 0;
      97                 :            : }
      98                 :            : 
      99                 :          0 : static void ledtrig_cpu_syscore_resume(void)
     100                 :            : {
     101                 :          0 :         ledtrig_cpu(CPU_LED_START);
     102                 :          0 : }
     103                 :            : 
     104                 :          0 : static void ledtrig_cpu_syscore_shutdown(void)
     105                 :            : {
     106                 :          0 :         ledtrig_cpu(CPU_LED_HALTED);
     107                 :          0 : }
     108                 :            : 
     109                 :            : static struct syscore_ops ledtrig_cpu_syscore_ops = {
     110                 :            :         .shutdown       = ledtrig_cpu_syscore_shutdown,
     111                 :            :         .suspend        = ledtrig_cpu_syscore_suspend,
     112                 :            :         .resume         = ledtrig_cpu_syscore_resume,
     113                 :            : };
     114                 :            : 
     115                 :        828 : static int ledtrig_online_cpu(unsigned int cpu)
     116                 :            : {
     117                 :        828 :         ledtrig_cpu(CPU_LED_START);
     118                 :        828 :         return 0;
     119                 :            : }
     120                 :            : 
     121                 :          0 : static int ledtrig_prepare_down_cpu(unsigned int cpu)
     122                 :            : {
     123                 :          0 :         ledtrig_cpu(CPU_LED_STOP);
     124                 :          0 :         return 0;
     125                 :            : }
     126                 :            : 
     127                 :        207 : static int __init ledtrig_cpu_init(void)
     128                 :            : {
     129                 :            :         int cpu;
     130                 :            :         int ret;
     131                 :            : 
     132                 :            :         /* Supports up to 9999 cpu cores */
     133                 :            :         BUILD_BUG_ON(CONFIG_NR_CPUS > 9999);
     134                 :            : 
     135                 :            :         /*
     136                 :            :          * Registering a trigger for all CPUs.
     137                 :            :          */
     138                 :        207 :         led_trigger_register_simple("cpu", &trig_cpu_all);
     139                 :            : 
     140                 :            :         /*
     141                 :            :          * Registering CPU led trigger for each CPU core here
     142                 :            :          * ignores CPU hotplug, but after this CPU hotplug works
     143                 :            :          * fine with this trigger.
     144                 :            :          */
     145         [ +  + ]:       1242 :         for_each_possible_cpu(cpu) {
     146                 :        828 :                 struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
     147                 :            : 
     148                 :        828 :                 snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
     149                 :            : 
     150                 :        828 :                 led_trigger_register_simple(trig->name, &trig->_trig);
     151                 :            :         }
     152                 :            : 
     153                 :        207 :         register_syscore_ops(&ledtrig_cpu_syscore_ops);
     154                 :            : 
     155                 :            :         ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "leds/trigger:starting",
     156                 :            :                                 ledtrig_online_cpu, ledtrig_prepare_down_cpu);
     157         [ -  + ]:        207 :         if (ret < 0)
     158                 :          0 :                 pr_err("CPU hotplug notifier for ledtrig-cpu could not be registered: %d\n",
     159                 :            :                        ret);
     160                 :            : 
     161                 :        207 :         pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n");
     162                 :            : 
     163                 :        207 :         return 0;
     164                 :            : }
     165                 :            : device_initcall(ledtrig_cpu_init);

Generated by: LCOV version 1.14