Merge tag 'v3.14.25' into backport/v3.14.24-ltsi-rc1+v3.14.25/snapshot-merge.wip
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / ktap / runtime / lib_timer.c
1 /*
2  * timer.c - timer library support for ktap
3  *
4  * This file is part of ktap by Jovi Zhangwei.
5  *
6  * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
7  *
8  * ktap is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * ktap is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <linux/ctype.h>
23 #include <linux/slab.h>
24 #include <linux/delay.h>
25 #include <linux/sched.h>
26 #include "../include/ktap_types.h"
27 #include "ktap.h"
28 #include "kp_obj.h"
29 #include "kp_vm.h"
30
31 struct hrtimer_ktap {
32         struct hrtimer timer;
33         ktap_state *ks;
34         ktap_closure *cl;
35         u64 ns;
36         struct list_head list;
37 };
38
39 /*
40  * Currently ktap disallow tracing event in timer callback closure,
41  * that will corrupt ktap_state and ktap stack, because timer closure
42  * and event closure use same irq percpu ktap_state and stack.
43  * We can use a different percpu ktap_state and stack for timer purpuse,
44  * but that's don't bring any big value with cost on memory consuming.
45  *
46  * So just simply disable tracing in timer closure,
47  * get_recursion_context()/put_recursion_context() is used for this purpose.
48  */
49 static enum hrtimer_restart hrtimer_ktap_fn(struct hrtimer *timer)
50 {
51         struct hrtimer_ktap *t;
52         ktap_state *ks;
53         int rctx;
54
55         rcu_read_lock_sched_notrace();
56
57         t = container_of(timer, struct hrtimer_ktap, timer);
58         rctx = get_recursion_context(t->ks);
59
60         ks = kp_newthread(t->ks);
61         set_closure(ks->top, t->cl);
62         incr_top(ks);
63         kp_call(ks, ks->top - 1, 0);
64         kp_exitthread(ks);
65
66         hrtimer_add_expires_ns(timer, t->ns);
67
68         put_recursion_context(ks, rctx);
69         rcu_read_unlock_sched_notrace();
70
71         return HRTIMER_RESTART;
72 }
73
74 static void set_tick_timer(ktap_state *ks, u64 period, ktap_closure *cl)
75 {
76         struct hrtimer_ktap *t;
77
78         t = kp_malloc(ks, sizeof(*t));
79         t->ks = ks;
80         t->cl = cl;
81         t->ns = period;
82
83         INIT_LIST_HEAD(&t->list);
84         list_add(&t->list, &(G(ks)->timers));
85
86         hrtimer_init(&t->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
87         t->timer.function = hrtimer_ktap_fn;
88         hrtimer_start(&t->timer, ns_to_ktime(period), HRTIMER_MODE_REL);
89 }
90
91 static void set_profile_timer(ktap_state *ks, u64 period, ktap_closure *cl)
92 {
93         struct perf_event_attr attr;
94
95         memset(&attr, 0, sizeof(attr));
96         attr.type = PERF_TYPE_SOFTWARE;
97         attr.config = PERF_COUNT_SW_CPU_CLOCK;
98         attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
99                            PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD;
100         attr.sample_period = period;
101         attr.size = sizeof(attr);
102         attr.disabled = 0;
103
104         kp_perf_event_register(ks, &attr, NULL, NULL, cl);
105 }
106
107 static int do_tick_profile(ktap_state *ks, int is_tick)
108 {
109         const char *str, *tmp;
110         char interval_str[32] = {0};
111         char suffix[10] = {0};
112         int n, i = 0;
113         int factor;
114
115         kp_arg_check(ks, 1, KTAP_TSTRING);
116         kp_arg_check(ks, 2, KTAP_TFUNCTION);
117
118         str = svalue(kp_arg(ks, 1));
119         tmp = str;
120         while (isdigit(*tmp))
121                 tmp++;
122
123         strncpy(interval_str, str, tmp - str);
124         if (kstrtoint(interval_str, 10, &n))
125                 goto error;
126
127         strncpy(suffix, tmp, 9);
128         while (suffix[i] != ' ' && suffix[i] != '\0')
129                 i++;
130
131         suffix[i] = '\0';
132
133         if (!strcmp(suffix, "s") || !strcmp(suffix, "sec"))
134                 factor = NSEC_PER_SEC;
135         else if (!strcmp(suffix, "ms") || !strcmp(suffix, "msec"))
136                 factor = NSEC_PER_MSEC;
137         else if (!strcmp(suffix, "us") || !strcmp(suffix, "usec"))
138                 factor = NSEC_PER_USEC;
139         else
140                 goto error;
141
142         if (is_tick)
143                 set_tick_timer(ks, (u64)factor * n, clvalue(kp_arg(ks, 2)));
144         else
145                 set_profile_timer(ks, (u64)factor * n, clvalue(kp_arg(ks, 2)));
146
147         return 0;
148
149  error:
150         kp_error(ks, "cannot parse timer interval: %s\n", str);
151         return -1;
152 }
153
154 /*
155  * tick-n probes fire on only one CPU per interval.
156  * valid time suffixes: sec/s, msec/ms, usec/us
157  */
158 static int ktap_lib_tick(ktap_state *ks)
159 {
160         return do_tick_profile(ks, 1);
161 }
162
163 /*
164  * A profile-n probe fires every fixed interval on every CPU
165  * valid time suffixes: sec/s, msec/ms, usec/us
166  */
167 static int ktap_lib_profile(ktap_state *ks)
168 {
169         return do_tick_profile(ks, 0);
170 }
171
172 void kp_exit_timers(ktap_state *ks)
173 {
174         struct hrtimer_ktap *t, *tmp;
175         struct list_head *timers_list = &(G(ks)->timers);
176
177         list_for_each_entry_safe(t, tmp, timers_list, list) {
178                 hrtimer_cancel(&t->timer);
179                 kp_free(ks, t);
180         }
181 }
182
183 static const ktap_Reg timerlib_funcs[] = {
184         {"profile",     ktap_lib_profile},
185         {"tick",        ktap_lib_tick},
186         {NULL}
187 };
188
189 void kp_init_timerlib(ktap_state *ks)
190 {
191         kp_register_lib(ks, "timer", timerlib_funcs);
192 }
193