summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/tegra-profiler/power_clk.c110
-rw-r--r--drivers/misc/tegra-profiler/version.h2
-rw-r--r--include/linux/tegra_profiler.h15
3 files changed, 108 insertions, 19 deletions
diff --git a/drivers/misc/tegra-profiler/power_clk.c b/drivers/misc/tegra-profiler/power_clk.c
index b7b198333fae..cf72b46126ba 100644
--- a/drivers/misc/tegra-profiler/power_clk.c
+++ b/drivers/misc/tegra-profiler/power_clk.c
@@ -32,24 +32,32 @@
#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]);
}
diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h
index 7fdf4c4bfadf..30da60f3f069 100644
--- a/drivers/misc/tegra-profiler/version.h
+++ b/drivers/misc/tegra-profiler/version.h
@@ -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 */
diff --git a/include/linux/tegra_profiler.h b/include/linux/tegra_profiler.h
index 3462998f9872..caf58e63ed70 100644
--- a/include/linux/tegra_profiler.h
+++ b/include/linux/tegra_profiler.h
@@ -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;
};