/*
* drivers/misc/tegra-profiler/hrt.c
*
- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2014, 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,
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/module.h>
-#include <linux/kallsyms.h>
#include <linux/sched.h>
-#include <asm/cputype.h>
#include <linux/hrtimer.h>
#include <linux/slab.h>
#include <linux/cpu.h>
-#include <linux/ratelimit.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/nsproxy.h>
+
+#include <asm/cputype.h>
#include <asm/irq_regs.h>
#include <linux/tegra_profiler.h>
static struct quadd_hrt_ctx hrt;
-static void read_all_sources(struct pt_regs *regs, pid_t pid);
+static void
+read_all_sources(struct pt_regs *regs, struct task_struct *task);
-static void sample_time_prepare(void);
-static void sample_time_finish(void);
-static void sample_time_reset(struct quadd_cpu_context *cpu_ctx);
+struct hrt_event_value {
+ int event_id;
+ u32 value;
+};
static enum hrtimer_restart hrtimer_handler(struct hrtimer *hrtimer)
{
regs = get_irq_regs();
- if (hrt.active == 0)
+ if (!hrt.active)
return HRTIMER_NORESTART;
qm_debug_handler_sample(regs);
- if (regs) {
- sample_time_prepare();
- read_all_sources(regs, -1);
- sample_time_finish();
- }
+ if (regs)
+ read_all_sources(regs, NULL);
hrtimer_forward_now(hrtimer, ns_to_ktime(hrt.sample_period));
qm_debug_timer_forward(regs, hrt.sample_period);
{
u64 period = hrt.sample_period;
- sample_time_reset(cpu_ctx);
-
- hrtimer_start(&cpu_ctx->hrtimer, ns_to_ktime(period),
- HRTIMER_MODE_REL_PINNED);
+ __hrtimer_start_range_ns(&cpu_ctx->hrtimer,
+ ns_to_ktime(period), 0,
+ HRTIMER_MODE_REL_PINNED, 0);
qm_debug_timer_start(NULL, period);
}
static void init_hrtimer(struct quadd_cpu_context *cpu_ctx)
{
- sample_time_reset(cpu_ctx);
-
hrtimer_init(&cpu_ctx->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
cpu_ctx->hrtimer.function = hrtimer_handler;
}
return timespec_to_ns(&ts);
}
-static u64 get_sample_time(void)
-{
-#ifndef QUADD_USE_CORRECT_SAMPLE_TS
- return quadd_get_time();
-#else
- struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
- return cpu_ctx->current_time;
-#endif
-}
-
-static void sample_time_prepare(void)
-{
-#ifdef QUADD_USE_CORRECT_SAMPLE_TS
- struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
-
- if (cpu_ctx->prev_time == ULLONG_MAX)
- cpu_ctx->current_time = quadd_get_time();
- else
- cpu_ctx->current_time = cpu_ctx->prev_time + hrt.sample_period;
-#endif
-}
-
-static void sample_time_finish(void)
-{
-#ifdef QUADD_USE_CORRECT_SAMPLE_TS
- struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
- cpu_ctx->prev_time = cpu_ctx->current_time;
-#endif
-}
-
-static void sample_time_reset(struct quadd_cpu_context *cpu_ctx)
-{
-#ifdef QUADD_USE_CORRECT_SAMPLE_TS
- cpu_ctx->prev_time = ULLONG_MAX;
- cpu_ctx->current_time = ULLONG_MAX;
-#endif
-}
-
static void put_header(void)
{
- int power_rate_period;
+ int nr_events = 0, max_events = QUADD_MAX_COUNTERS;
+ int events[QUADD_MAX_COUNTERS];
struct quadd_record_data record;
struct quadd_header_data *hdr = &record.hdr;
struct quadd_parameters *param = &hrt.quadd_ctx->param;
- struct quadd_comm_data_interface *comm = hrt.quadd_ctx->comm;
+ unsigned int extra = param->reserved[QUADD_PARAM_IDX_EXTRA];
+ struct quadd_iovec vec;
+ struct quadd_ctx *ctx = hrt.quadd_ctx;
+ struct quadd_event_source_interface *pmu = ctx->pmu;
+ struct quadd_event_source_interface *pl310 = ctx->pl310;
- record.magic = QUADD_RECORD_MAGIC;
record.record_type = QUADD_RECORD_TYPE_HEADER;
- record.cpu_mode = QUADD_CPU_MODE_NONE;
+ hdr->magic = QUADD_HEADER_MAGIC;
hdr->version = QUADD_SAMPLES_VERSION;
hdr->backtrace = param->backtrace;
hdr->debug_samples = 0;
#endif
- hdr->period = hrt.sample_period;
- hdr->ma_period = hrt.ma_period;
+ hdr->freq = param->freq;
+ hdr->ma_freq = param->ma_freq;
+ hdr->power_rate_freq = param->power_rate_freq;
+
+ hdr->power_rate = hdr->power_rate_freq > 0 ? 1 : 0;
+ hdr->get_mmap = (extra & QUADD_PARAM_EXTRA_GET_MMAP) ? 1 : 0;
+
+ hdr->reserved = 0;
+ hdr->extra_length = 0;
+
+ if (pmu)
+ nr_events += pmu->get_current_events(events, max_events);
- hdr->power_rate = quadd_power_clk_is_enabled(&power_rate_period);
- hdr->power_rate_period = power_rate_period;
+ if (pl310)
+ nr_events += pl310->get_current_events(events + nr_events,
+ max_events - nr_events);
- comm->put_sample(&record, NULL, 0);
+ hdr->nr_events = nr_events;
+
+ vec.base = events;
+ vec.len = nr_events * sizeof(events[0]);
+
+ quadd_put_sample(&record, &vec, 1);
}
void quadd_put_sample(struct quadd_record_data *data,
- char *extra_data, unsigned int extra_length)
+ struct quadd_iovec *vec, int vec_count)
{
struct quadd_comm_data_interface *comm = hrt.quadd_ctx->comm;
- if (data->record_type == QUADD_RECORD_TYPE_SAMPLE &&
- data->sample.period > 0x7FFFFFFF) {
- struct quadd_sample_data *sample = &data->sample;
- pr_err_once("very big period, sample id: %d\n",
- sample->event_id);
- return;
- }
-
- comm->put_sample(data, extra_data, extra_length);
+ comm->put_sample(data, vec, vec_count);
atomic64_inc(&hrt.counter_samples);
}
-static int get_sample_data(struct event_data *event,
+static int get_sample_data(struct quadd_sample_data *sample,
struct pt_regs *regs,
- struct quadd_sample_data *sample)
+ struct task_struct *task)
{
- u32 period;
- u32 prev_val, val;
-
- prev_val = event->prev_val;
- val = event->val;
+ unsigned int cpu, flags;
+ struct quadd_ctx *quadd_ctx = hrt.quadd_ctx;
- sample->event_id = event->event_id;
+ cpu = quadd_get_processor_id(regs, &flags);
+ sample->cpu = cpu;
- sample->ip = instruction_pointer(regs);
- sample->cpu = quadd_get_processor_id();
- sample->time = get_sample_time();
+ sample->lp_mode =
+ (flags & QUADD_CPUMODE_TEGRA_POWER_CLUSTER_LP) ? 1 : 0;
+ sample->thumb_mode = (flags & QUADD_CPUMODE_THUMB) ? 1 : 0;
+ sample->user_mode = user_mode(regs) ? 1 : 0;
- if (prev_val <= val)
- period = val - prev_val;
+ /* For security reasons, hide IPs from the kernel space. */
+ if (!sample->user_mode && !quadd_ctx->collect_kernel_ips)
+ sample->ip = 0;
else
- period = QUADD_U32_MAX - prev_val + val;
+ sample->ip = instruction_pointer(regs);
- if (event->event_source == QUADD_EVENT_SOURCE_PL310) {
- int nr_current_active = atomic_read(&hrt.nr_active_all_core);
- if (nr_current_active > 1)
- period = period / nr_current_active;
- }
+ sample->time = quadd_get_time();
+ sample->reserved = 0;
+ sample->pid = task->pid;
+ sample->in_interrupt = in_interrupt() ? 1 : 0;
- sample->period = period;
return 0;
}
-static char *get_mmap_data(struct pt_regs *regs,
- struct quadd_mmap_data *sample,
- unsigned int *extra_length)
-{
- struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
- return quadd_get_mmap(cpu_ctx, regs, sample, extra_length);
-}
-
-static void read_source(struct quadd_event_source_interface *source,
- struct pt_regs *regs, pid_t pid)
+static int read_source(struct quadd_event_source_interface *source,
+ struct pt_regs *regs,
+ struct hrt_event_value *events_vals,
+ int max_events)
{
int nr_events, i;
+ u32 prev_val, val, res_val;
struct event_data events[QUADD_MAX_COUNTERS];
- struct quadd_record_data record_data;
- struct quadd_thread_data *t_data;
- char *extra_data = NULL;
- unsigned int extra_length = 0, callchain_nr = 0;
- struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
- struct quadd_callchain *callchain_data = &cpu_ctx->callchain_data;
- struct quadd_ctx *quadd_ctx = hrt.quadd_ctx;
if (!source)
- return;
+ return 0;
- nr_events = source->read(events);
+ max_events = min_t(int, max_events, QUADD_MAX_COUNTERS);
+ nr_events = source->read(events, max_events);
- if (nr_events == 0 || nr_events > QUADD_MAX_COUNTERS) {
- pr_err_once("Error number of counters: %d, source: %p\n",
- nr_events, source);
- return;
- }
+ for (i = 0; i < nr_events; i++) {
+ struct event_data *s = &events[i];
- if (atomic_read(&cpu_ctx->nr_active) == 0)
- return;
+ prev_val = s->prev_val;
+ val = s->val;
- if (user_mode(regs) && hrt.quadd_ctx->param.backtrace) {
- callchain_nr = quadd_get_user_callchain(regs, callchain_data);
- if (callchain_nr > 0) {
- extra_data = (char *)cpu_ctx->callchain_data.callchain;
- extra_length = callchain_nr * sizeof(u32);
- }
- }
+ if (prev_val <= val)
+ res_val = val - prev_val;
+ else
+ res_val = QUADD_U32_MAX - prev_val + val;
- for (i = 0; i < nr_events; i++) {
- if (get_sample_data(&events[i], regs, &record_data.sample))
- return;
-
- record_data.magic = QUADD_RECORD_MAGIC;
- record_data.record_type = QUADD_RECORD_TYPE_SAMPLE;
- record_data.cpu_mode = user_mode(regs) ?
- QUADD_CPU_MODE_USER : QUADD_CPU_MODE_KERNEL;
-
- /* For security reasons, hide IPs from the kernel space. */
- if (record_data.cpu_mode == QUADD_CPU_MODE_KERNEL &&
- !quadd_ctx->collect_kernel_ips)
- record_data.sample.ip = 0;
-
- if (pid > 0) {
- record_data.sample.pid = pid;
- } else {
- t_data = &cpu_ctx->active_thread;
- record_data.sample.pid = t_data->pid;
+ if (s->event_source == QUADD_EVENT_SOURCE_PL310) {
+ int nr_active = atomic_read(&hrt.nr_active_all_core);
+ if (nr_active > 1)
+ res_val /= nr_active;
}
- if (i == 0) {
- record_data.sample.callchain_nr = callchain_nr;
- quadd_put_sample(&record_data, extra_data,
- extra_length);
- } else {
- record_data.sample.callchain_nr = 0;
- quadd_put_sample(&record_data, NULL, 0);
- }
+ events_vals[i].event_id = s->event_id;
+ events_vals[i].value = res_val;
}
+
+ return nr_events;
}
-static void read_all_sources(struct pt_regs *regs, pid_t pid)
+static void
+read_all_sources(struct pt_regs *regs, struct task_struct *task)
{
+ u32 state, extra_data = 0;
+ int i, vec_idx = 0, bt_size = 0;
+ int nr_events = 0, nr_positive_events = 0;
+ struct pt_regs *user_regs;
+ struct quadd_iovec vec[4];
+ struct hrt_event_value events[QUADD_MAX_COUNTERS];
+ u32 events_extra[QUADD_MAX_COUNTERS];
+
struct quadd_record_data record_data;
+ struct quadd_sample_data *s = &record_data.sample;
+
struct quadd_ctx *ctx = hrt.quadd_ctx;
- unsigned int extra_length;
- char *extra_data;
+ struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
+ struct quadd_callchain *cc = &cpu_ctx->cc;
if (!regs)
return;
- extra_data = get_mmap_data(regs, &record_data.mmap, &extra_length);
- if (extra_data && extra_length > 0) {
- record_data.magic = QUADD_RECORD_MAGIC;
- record_data.record_type = QUADD_RECORD_TYPE_MMAP;
- record_data.cpu_mode = QUADD_CPU_MODE_USER;
+ if (atomic_read(&cpu_ctx->nr_active) == 0)
+ return;
- record_data.mmap.filename_length = extra_length;
- record_data.mmap.pid = pid > 0 ? pid : ctx->param.pids[0];
+ if (!task)
+ task = current;
- quadd_put_sample(&record_data, extra_data, extra_length);
- } else {
- record_data.mmap.filename_length = 0;
+ rcu_read_lock();
+ if (!task_nsproxy(task)) {
+ rcu_read_unlock();
+ return;
}
+ rcu_read_unlock();
if (ctx->pmu && ctx->pmu_info.active)
- read_source(ctx->pmu, regs, pid);
+ nr_events += read_source(ctx->pmu, regs,
+ events, QUADD_MAX_COUNTERS);
if (ctx->pl310 && ctx->pl310_info.active)
- read_source(ctx->pl310, regs, pid);
+ nr_events += read_source(ctx->pl310, regs,
+ events + nr_events,
+ QUADD_MAX_COUNTERS - nr_events);
+
+ if (!nr_events)
+ return;
+
+ if (user_mode(regs))
+ user_regs = regs;
+ else
+ user_regs = current_pt_regs();
+
+ if (get_sample_data(s, regs, task))
+ return;
+
+ if (cc->cs_64)
+ extra_data |= QUADD_SED_IP64;
+
+ vec[vec_idx].base = &extra_data;
+ vec[vec_idx].len = sizeof(extra_data);
+ vec_idx++;
+
+ s->reserved = 0;
+ cc->unw_method = QUADD_URC_SUCCESS;
+
+ if (ctx->param.backtrace) {
+ bt_size = quadd_get_user_callchain(user_regs, cc, ctx, task);
+
+ if (!bt_size && !user_mode(regs)) {
+ unsigned long pc = instruction_pointer(user_regs);
+
+ cc->nr = 0;
+#ifdef CONFIG_ARM64
+ cc->cs_64 = compat_user_mode(user_regs) ? 0 : 1;
+#else
+ cc->cs_64 = 0;
+#endif
+ bt_size += quadd_callchain_store(cc, pc);
+ }
+
+ if (bt_size > 0) {
+ int ip_size = cc->cs_64 ? sizeof(u64) : sizeof(u32);
+
+ vec[vec_idx].base = cc->cs_64 ?
+ (void *)cc->ip_64 : (void *)cc->ip_32;
+ vec[vec_idx].len = bt_size * ip_size;
+ vec_idx++;
+ }
+
+ extra_data |= cc->unw_method << QUADD_SED_UNW_METHOD_SHIFT;
+ s->reserved |= cc->unw_rc << QUADD_SAMPLE_URC_SHIFT;
+ }
+ s->callchain_nr = bt_size;
+
+ record_data.record_type = QUADD_RECORD_TYPE_SAMPLE;
+
+ s->events_flags = 0;
+ for (i = 0; i < nr_events; i++) {
+ u32 value = events[i].value;
+ if (value > 0) {
+ s->events_flags |= 1 << i;
+ events_extra[nr_positive_events++] = value;
+ }
+ }
+
+ if (nr_positive_events == 0)
+ return;
+
+ vec[vec_idx].base = events_extra;
+ vec[vec_idx].len = nr_positive_events * sizeof(events_extra[0]);
+ vec_idx++;
+
+ state = task->state;
+ if (state) {
+ s->state = 1;
+ vec[vec_idx].base = &state;
+ vec[vec_idx].len = sizeof(state);
+ vec_idx++;
+ } else {
+ s->state = 0;
+ }
+
+ quadd_put_sample(&record_data, vec, vec_idx);
}
-static inline int is_profile_process(pid_t pid)
+static inline int
+is_profile_process(struct task_struct *task)
{
int i;
- pid_t profile_pid;
+ pid_t pid, profile_pid;
struct quadd_ctx *ctx = hrt.quadd_ctx;
+ if (!task)
+ return 0;
+
+ pid = task->tgid;
+
for (i = 0; i < ctx->param.nr_pids; i++) {
profile_pid = ctx->param.pids[i];
if (profile_pid == pid)
return 0;
}
-static int task_sched_in(struct kprobe *kp, struct pt_regs *regs)
+void __quadd_task_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
- int n, prev_flag, current_flag;
- struct task_struct *prev, *task;
- int prev_nr_active, new_nr_active;
struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
struct quadd_ctx *ctx = hrt.quadd_ctx;
struct event_data events[QUADD_MAX_COUNTERS];
/* static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 2); */
- if (hrt.active == 0)
- return 0;
-
- prev = (struct task_struct *)regs->ARM_r1;
- task = current;
+ if (likely(!hrt.active))
+ return;
/*
if (__ratelimit(&ratelimit_state))
- pr_info("cpu: %d, prev: %u (%u) \t--> curr: %u (%u)\n",
- quadd_get_processor_id(), (unsigned int)prev->pid,
+ pr_info("sch_in, cpu: %d, prev: %u (%u) \t--> curr: %u (%u)\n",
+ smp_processor_id(), (unsigned int)prev->pid,
(unsigned int)prev->tgid, (unsigned int)task->pid,
(unsigned int)task->tgid);
*/
- if (!prev || !prev->real_parent || !prev->group_leader ||
- prev->group_leader->tgid != prev->tgid) {
- pr_err_once("Warning\n");
- return 0;
- }
-
- prev_flag = is_profile_process(prev->tgid);
- current_flag = is_profile_process(task->tgid);
- if (prev_flag || current_flag) {
- prev_nr_active = atomic_read(&cpu_ctx->nr_active);
- qm_debug_task_sched_in(prev->pid, task->pid, prev_nr_active);
+ if (is_profile_process(task)) {
+ add_active_thread(cpu_ctx, task->pid, task->tgid);
+ atomic_inc(&cpu_ctx->nr_active);
- if (prev_flag) {
- n = remove_active_thread(cpu_ctx, prev->pid);
- atomic_sub(n, &cpu_ctx->nr_active);
- }
- if (current_flag) {
- add_active_thread(cpu_ctx, task->pid, task->tgid);
- atomic_inc(&cpu_ctx->nr_active);
- }
+ if (atomic_read(&cpu_ctx->nr_active) == 1) {
+ if (ctx->pmu)
+ ctx->pmu->start();
- new_nr_active = atomic_read(&cpu_ctx->nr_active);
- if (prev_nr_active != new_nr_active) {
- if (prev_nr_active == 0) {
- if (ctx->pmu)
- ctx->pmu->start();
+ if (ctx->pl310)
+ ctx->pl310->read(events, 1);
- if (ctx->pl310)
- ctx->pl310->read(events);
-
- start_hrtimer(cpu_ctx);
- atomic_inc(&hrt.nr_active_all_core);
- } else if (new_nr_active == 0) {
- cancel_hrtimer(cpu_ctx);
- atomic_dec(&hrt.nr_active_all_core);
-
- if (ctx->pmu)
- ctx->pmu->stop();
- }
+ start_hrtimer(cpu_ctx);
+ atomic_inc(&hrt.nr_active_all_core);
}
}
-
- return 0;
}
-static int handler_fault(struct kprobe *kp, struct pt_regs *regs, int trapnr)
+void __quadd_task_sched_out(struct task_struct *prev,
+ struct task_struct *next)
{
- pr_err_once("addr: %p, symbol: %s\n", kp->addr, kp->symbol_name);
- return 0;
-}
+ int n;
+ struct pt_regs *user_regs;
+ struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
+ struct quadd_ctx *ctx = hrt.quadd_ctx;
+ /* static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 2); */
-static int start_instr(void)
-{
- int err;
+ if (likely(!hrt.active))
+ return;
+/*
+ if (__ratelimit(&ratelimit_state))
+ pr_info("sch_out: cpu: %d, prev: %u (%u) \t--> next: %u (%u)\n",
+ smp_processor_id(), (unsigned int)prev->pid,
+ (unsigned int)prev->tgid, (unsigned int)next->pid,
+ (unsigned int)next->tgid);
+*/
+
+ if (is_profile_process(prev)) {
+ user_regs = task_pt_regs(prev);
+ if (user_regs)
+ read_all_sources(user_regs, prev);
- memset(&hrt.kp_in, 0, sizeof(struct kprobe));
+ n = remove_active_thread(cpu_ctx, prev->pid);
+ atomic_sub(n, &cpu_ctx->nr_active);
- hrt.kp_in.pre_handler = task_sched_in;
- hrt.kp_in.fault_handler = handler_fault;
- hrt.kp_in.addr = 0;
- hrt.kp_in.symbol_name = QUADD_HRT_SCHED_IN_FUNC;
+ if (n && atomic_read(&cpu_ctx->nr_active) == 0) {
+ cancel_hrtimer(cpu_ctx);
+ atomic_dec(&hrt.nr_active_all_core);
- err = register_kprobe(&hrt.kp_in);
- if (err) {
- pr_err("register_kprobe error, symbol_name: %s\n",
- hrt.kp_in.symbol_name);
- return err;
+ if (ctx->pmu)
+ ctx->pmu->stop();
+ }
}
- return 0;
}
-static void stop_instr(void)
+void __quadd_event_mmap(struct vm_area_struct *vma)
{
- unregister_kprobe(&hrt.kp_in);
-}
+ struct quadd_parameters *param;
-static int init_instr(void)
-{
- int err;
+ if (likely(!hrt.active))
+ return;
- err = start_instr();
- if (err) {
- pr_err("Init instr failed\n");
- return err;
- }
- stop_instr();
- return 0;
-}
+ if (!is_profile_process(current))
+ return;
-static int deinit_instr(void)
-{
- return 0;
+ param = &hrt.quadd_ctx->param;
+ quadd_process_mmap(vma, param->pids[0]);
}
static void reset_cpu_ctx(void)
t_data->pid = -1;
t_data->tgid = -1;
-
- sample_time_reset(cpu_ctx);
}
}
int err;
u64 period;
long freq;
+ unsigned int extra;
struct quadd_ctx *ctx = hrt.quadd_ctx;
+ struct quadd_parameters *param = &ctx->param;
freq = ctx->param.freq;
freq = max_t(long, QUADD_HRT_MIN_FREQ, freq);
reset_cpu_ctx();
- err = start_instr();
- if (err) {
- pr_err("error: start_instr is failed\n");
- return err;
- }
-
put_header();
+ extra = param->reserved[QUADD_PARAM_IDX_EXTRA];
+
+ if (extra & QUADD_PARAM_EXTRA_GET_MMAP) {
+ err = quadd_get_current_mmap(param->pids[0]);
+ if (err) {
+ pr_err("error: quadd_get_current_mmap\n");
+ return err;
+ }
+ }
+
if (ctx->pl310)
ctx->pl310->start();
quadd_ma_stop(&hrt);
hrt.active = 0;
- stop_instr();
atomic64_set(&hrt.counter_samples, 0);
if (hrt.active)
quadd_hrt_stop();
- deinit_instr();
free_percpu(hrt.cpu_ctx);
}
hrt.cpu_ctx = alloc_percpu(struct quadd_cpu_context);
if (!hrt.cpu_ctx)
- return NULL;
+ return ERR_PTR(-ENOMEM);
for (cpu_id = 0; cpu_id < nr_cpu_ids; cpu_id++) {
cpu_ctx = per_cpu_ptr(hrt.cpu_ctx, cpu_id);
init_hrtimer(cpu_ctx);
}
- if (init_instr())
- return NULL;
-
return &hrt;
}