misc: tegra-profiler: add cpu notifier
Igor Nabirushkin [Wed, 29 Apr 2015 06:44:01 +0000 (10:44 +0400)]
Detect when the CPU goes online/offline.

Bug 1634024

Change-Id: I989a9aefbc32a70070b37fe42ce5dcf75b18263b
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/729497
(cherry picked from commit a2eec5a5ea12fb50e073b322ca9d948818179968)
Reviewed-on: http://git-master/r/748094
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Andrey Trachenko <atrachenko@nvidia.com>
Reviewed-by: Winnie Hsu <whsu@nvidia.com>

drivers/misc/tegra-profiler/power_clk.c
drivers/misc/tegra-profiler/version.h
include/linux/tegra_profiler.h

index b7b1983..cf72b46 100644 (file)
 #include "comm.h"
 #include "debug.h"
 
-#define POWER_CLK_MAX_VALUES   32
-
-typedef int (*notifier_call_ft)(struct notifier_block *,
-                               unsigned long, void *);
+#define PCLK_MAX_VALUES        32
 
 struct power_clk_data {
        unsigned long value;
        unsigned long prev;
 };
 
+#define PCLK_NB_GPU    0
+#define PCLK_NB_EMC    0
+
+enum {
+       PCLK_NB_CPU_FREQ,
+       PCLK_NB_CPU_HOTPLUG,
+       PCLK_NB_CPU_MAX,
+};
+
+#define PCLK_NB_MAX    PCLK_NB_CPU_MAX
+
 struct power_clk_source {
        int type;
 
        struct clk *clkp;
-       struct notifier_block nb;
+       struct notifier_block nb[PCLK_NB_MAX];
 
        int nr;
-       struct power_clk_data data[POWER_CLK_MAX_VALUES];
+       struct power_clk_data data[PCLK_MAX_VALUES];
 
        atomic_t active;
        struct mutex lock;
@@ -127,6 +135,22 @@ static void make_sample(void)
        quadd_put_sample(&record, &vec, 1);
 }
 
+static void
+make_sample_hotplug(int cpu, int is_online)
+{
+       struct quadd_record_data record;
+       struct quadd_hotplug_data *s = &record.hotplug;
+
+       record.record_type = QUADD_RECORD_TYPE_HOTPLUG;
+
+       s->cpu = cpu;
+       s->is_online = is_online ? 1 : 0;
+       s->time = quadd_get_time();
+       s->reserved = 0;
+
+       quadd_put_sample(&record, NULL, 0);
+}
+
 static inline int
 is_data_changed(struct power_clk_source *s)
 {
@@ -326,6 +350,48 @@ cpufreq_notifier_call(struct notifier_block *nb,
        return 0;
 }
 
+static int
+cpu_hotplug_notifier_call(struct notifier_block *nb,
+                         unsigned long action, void *hcpu)
+{
+       int cpu;
+       struct power_clk_source *s = &power_ctx.cpu;
+
+       if (!atomic_read(&s->active))
+               return NOTIFY_DONE;
+
+       cpu = (long)hcpu;
+
+       pr_debug("cpu: %d, action: %lu\n", cpu, action);
+
+       if (cpu >= s->nr) {
+               pr_err_once("error: cpu id: %d\n", cpu);
+               return NOTIFY_DONE;
+       }
+
+       switch (action) {
+       case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
+               make_sample_hotplug(cpu, 1);
+               break;
+
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               mutex_lock(&s->lock);
+               if (atomic_read(&s->active))
+                       s->data[cpu].value = 0;
+               mutex_unlock(&s->lock);
+
+               make_sample_hotplug(cpu, 0);
+               break;
+
+       default:
+               return NOTIFY_DONE;
+       }
+
+       return NOTIFY_OK;
+}
+
 static void reset_data(struct power_clk_source *s)
 {
        int i;
@@ -339,13 +405,11 @@ static void reset_data(struct power_clk_source *s)
 }
 
 static void init_source(struct power_clk_source *s,
-                       notifier_call_ft notifier,
                        int nr_values,
                        int type)
 {
        s->type = type;
-       s->nb.notifier_call = notifier;
-       s->nr = min_t(int, nr_values, POWER_CLK_MAX_VALUES);
+       s->nr = min_t(int, nr_values, PCLK_MAX_VALUES);
        atomic_set(&s->active, 0);
        mutex_init(&s->lock);
 
@@ -508,23 +572,37 @@ void quadd_power_clk_stop(void)
 
 int quadd_power_clk_init(struct quadd_ctx *quadd_ctx)
 {
-       init_source(&power_ctx.cpu, cpufreq_notifier_call, nr_cpu_ids,
-                   QUADD_POWER_CLK_CPU);
+       struct power_clk_source *s;
 
-       init_source(&power_ctx.gpu, gpu_notifier_call, 1, QUADD_POWER_CLK_GPU);
-       init_source(&power_ctx.emc, emc_notifier_call, 1, QUADD_POWER_CLK_EMC);
+       s = &power_ctx.gpu;
+       s->nb[PCLK_NB_GPU].notifier_call = gpu_notifier_call;
+       init_source(s, 1, QUADD_POWER_CLK_GPU);
 
-       cpufreq_register_notifier(&power_ctx.cpu.nb,
-                                 CPUFREQ_TRANSITION_NOTIFIER);
+       s = &power_ctx.emc;
+       s->nb[PCLK_NB_EMC].notifier_call = emc_notifier_call;
+       init_source(s, 1, QUADD_POWER_CLK_EMC);
+
+       s = &power_ctx.cpu;
+       s->nb[PCLK_NB_CPU_FREQ].notifier_call = cpufreq_notifier_call;
+       s->nb[PCLK_NB_CPU_HOTPLUG].notifier_call = cpu_hotplug_notifier_call;
+       init_source(s, nr_cpu_ids, QUADD_POWER_CLK_CPU);
 
        power_ctx.quadd_ctx = quadd_ctx;
 
+       cpufreq_register_notifier(&s->nb[PCLK_NB_CPU_FREQ],
+                                 CPUFREQ_TRANSITION_NOTIFIER);
+       register_cpu_notifier(&s->nb[PCLK_NB_CPU_HOTPLUG]);
+
        return 0;
 }
 
 void quadd_power_clk_deinit(void)
 {
+       struct power_clk_source *s = &power_ctx.cpu;
+
        quadd_power_clk_stop();
-       cpufreq_unregister_notifier(&power_ctx.cpu.nb,
+
+       cpufreq_unregister_notifier(&s->nb[PCLK_NB_CPU_FREQ],
                                    CPUFREQ_TRANSITION_NOTIFIER);
+       unregister_cpu_notifier(&s->nb[PCLK_NB_CPU_HOTPLUG]);
 }
index 7fdf4c4..30da60f 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __QUADD_VERSION_H
 #define __QUADD_VERSION_H
 
-#define QUADD_MODULE_VERSION           "1.102"
+#define QUADD_MODULE_VERSION           "1.103"
 #define QUADD_MODULE_BRANCH            "Dev"
 
 #endif /* __QUADD_VERSION_H */
index 3462998..caf58e6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * include/linux/tegra_profiler.h
  *
- * Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -19,7 +19,7 @@
 
 #include <linux/ioctl.h>
 
-#define QUADD_SAMPLES_VERSION  33
+#define QUADD_SAMPLES_VERSION  34
 #define QUADD_IO_VERSION       18
 
 #define QUADD_IO_VERSION_DYNAMIC_RB            5
@@ -52,6 +52,7 @@
 #define QUADD_SAMPLE_VERSION_STACK_OFFSET      31
 #define QUADD_SAMPLE_VERSION_SCHED_TASK_STATE  32
 #define QUADD_SAMPLE_VERSION_URCS              33
+#define QUADD_SAMPLE_VERSION_HOTPLUG           34
 
 #define QUADD_MMAP_HEADER_VERSION              1
 
@@ -152,6 +153,7 @@ enum quadd_record_type {
        QUADD_RECORD_TYPE_POWER_RATE,
        QUADD_RECORD_TYPE_ADDITIONAL_SAMPLE,
        QUADD_RECORD_TYPE_SCHED,
+       QUADD_RECORD_TYPE_HOTPLUG,
 };
 
 enum quadd_event_source {
@@ -258,6 +260,14 @@ struct quadd_power_rate_data {
        u32 emc;
 };
 
+struct quadd_hotplug_data {
+       u64 time;
+       u32 cpu;
+
+       u32 is_online:1,
+           reserved:31;
+};
+
 struct quadd_additional_sample {
        u8 type;
 
@@ -353,6 +363,7 @@ struct quadd_record_data {
                struct quadd_debug_data         debug;
                struct quadd_header_data        hdr;
                struct quadd_power_rate_data    power_rate;
+               struct quadd_hotplug_data       hotplug;
                struct quadd_sched_data         sched;
                struct quadd_additional_sample  additional_sample;
        };