blob: a9fc9ffc28114f07f22778d4a2a2c78b932a5df4 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2019 MediaTek Inc.
4 */
5
6#include <linux/sched/clock.h>
7#include <linux/kernel.h>
8#include <linux/cpuhotplug.h>
9#include <linux/cpu.h>
10#include <linux/sched.h>
11#include <linux/notifier.h>
12#include <linux/module.h>
13#include <linux/irq.h>
14#if 0 /* fix me later, no such file on current tree */
15#include <mach/mt_cpuxgpt.h>
16#endif
17#include <asm/arch_timer.h>
18
19#define MET_USER_EVENT_SUPPORT
20#include "interface.h"
21#include "sampler.h"
22#include "met_struct.h"
23#include "util.h"
24#include "switch.h"
25#include "trace.h"
26#include "met_drv.h"
27#include "met_tag.h" /* for tracing_mark_write */
28
29#include "cpu_pmu.h" /* for using kernel perf PMU driver */
30
31#include "met_kernel_symbol.h"
32
33#undef DEBUG_CPU_NOTIFY
34/* #define DEBUG_CPU_NOTIFY */
35#if defined(DEBUG_CPU_NOTIFY)
36#ifdef CONFIG_MET_MODULE
37#define dbg_met_tag_oneshot met_tag_oneshot_real
38#else
39#define dbg_met_tag_oneshot met_tag_oneshot
40#endif /* CONFIG_MET_MODULE */
41#else
42#define dbg_met_tag_oneshot(class_id, name, value) ({ 0; })
43#endif
44
45static int start;
46static unsigned int online_cpu_map;
47static int curr_polling_cpu;
48static int cpu_related_cnt;
49static int cpu_related_polling_hdlr_cnt;
50
51static int preferred_cpu_list[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
52
53static int calc_preferred_polling_cpu(unsigned int cpu_map)
54{
55 int i;
56
57 for (i = 0; i < ARRAY_SIZE(preferred_cpu_list); i++) {
58 if (cpu_map & (1 << preferred_cpu_list[i]))
59 return preferred_cpu_list[i];
60 }
61
62 return -1;
63}
64
65static void wq_sync_buffer(struct work_struct *work)
66{
67 int cpu;
68 struct delayed_work *dw = container_of(work, struct delayed_work, work);
69 struct met_cpu_struct *met_cpu_ptr = container_of(dw, struct met_cpu_struct, dwork);
70
71 cpu = smp_processor_id();
72 if (met_cpu_ptr->cpu != cpu) {
73 /* panic("ERROR"); */
74 return;
75 }
76
77 /* sync_samples(cpu); */
78 /* don't re-add the work if we're shutting down */
79 if (met_cpu_ptr->work_enabled)
80 schedule_delayed_work(dw, DEFAULT_TIMER_EXPIRE);
81}
82
83static enum hrtimer_restart met_hrtimer_notify(struct hrtimer *hrtimer)
84{
85 int cpu;
86 int *count;
87 unsigned long long stamp;
88 struct met_cpu_struct *met_cpu_ptr = container_of(hrtimer, struct met_cpu_struct, hrtimer);
89 struct metdevice *c;
90#if defined(DEBUG_CPU_NOTIFY)
91 char msg[32];
92#endif
93
94 cpu = smp_processor_id();
95#if defined(DEBUG_CPU_NOTIFY)
96 {
97 char msg[32];
98
99 snprintf(msg, sizeof(msg), "met_hrtimer notify_%d", cpu);
100 dbg_met_tag_oneshot(0, msg, 1);
101 }
102#endif
103
104 if (met_cpu_ptr->cpu != cpu) {
105 /* panic("ERROR2"); */
106 dbg_met_tag_oneshot(0, msg, -3);
107 return HRTIMER_NORESTART;
108 }
109
110 list_for_each_entry(c, &met_list, list) {
111 if (c->ondiemet_mode == 0) {
112 if ((c->mode == 0) || (c->timed_polling == NULL))
113 continue;
114 } else if (c->ondiemet_mode == 1) {
115 if ((c->mode == 0) || (c->ondiemet_timed_polling == NULL))
116 continue;
117 } else if (c->ondiemet_mode == 2) {
118 if ((c->mode == 0) || ((c->timed_polling == NULL)
119 && (c->ondiemet_timed_polling == NULL)))
120 continue;
121 }
122
123 count = per_cpu_ptr(c->polling_count, cpu);
124 if ((*count) > 0) {
125 (*count)--;
126 continue;
127 }
128
129 *(count) = c->polling_count_reload;
130
131 stamp = cpu_clock(cpu);
132
133 if (c->cpu_related == 0) {
134 if (cpu == curr_polling_cpu) {
135 if (c->ondiemet_mode == 0) {
136 c->timed_polling(stamp, 0);
137 } else if (c->ondiemet_mode == 1) {
138 c->ondiemet_timed_polling(stamp, 0);
139 } else if (c->ondiemet_mode == 2) {
140 if (c->timed_polling)
141 c->timed_polling(stamp, 0);
142 if (c->ondiemet_timed_polling)
143 c->ondiemet_timed_polling(stamp, 0);
144 }
145 }
146 } else {
147 if (c->ondiemet_mode == 0) {
148 c->timed_polling(stamp, cpu);
149 } else if (c->ondiemet_mode == 1) {
150 c->ondiemet_timed_polling(stamp, cpu);
151 } else if (c->ondiemet_mode == 2) {
152 if (c->timed_polling)
153 c->timed_polling(stamp, 0);
154 if (c->ondiemet_timed_polling)
155 c->ondiemet_timed_polling(stamp, 0);
156 }
157 }
158 }
159
160 if (met_cpu_ptr->hrtimer_online_check) {
161 online_cpu_map |= (1 << cpu);
162 met_cpu_ptr->hrtimer_online_check = 0;
163 dbg_met_tag_oneshot(0, "met_online check done", cpu);
164 if (calc_preferred_polling_cpu(online_cpu_map) == cpu) {
165 curr_polling_cpu = cpu;
166 dbg_met_tag_oneshot(0, "met_curr polling cpu", cpu);
167 }
168 }
169
170 if (met_cpu_ptr->work_enabled) {
171 hrtimer_forward_now(hrtimer, ns_to_ktime(DEFAULT_HRTIMER_EXPIRE));
172 dbg_met_tag_oneshot(0, msg, 0);
173 return HRTIMER_RESTART;
174 }
175 dbg_met_tag_oneshot(0, msg, 0);
176 return HRTIMER_NORESTART;
177}
178
179static void __met_init_cpu_related_device(void *unused)
180{
181 struct metdevice *c;
182
183 list_for_each_entry(c, &met_list, list) {
184 *(this_cpu_ptr(c->polling_count)) = 0;
185 if (c->ondiemet_mode == 0) {
186 if ((c->cpu_related) && (c->mode) && (c->start))
187 c->start();
188 } else if (c->ondiemet_mode == 1) {
189 if (((c->cpu_related)) && (c->mode) && (c->ondiemet_start))
190 c->ondiemet_start();
191 } else if (c->ondiemet_mode == 2) {
192 if ((c->cpu_related) && (c->mode) && (c->start))
193 c->start();
194 if (((c->cpu_related)) && (c->mode) && (c->ondiemet_start))
195 c->ondiemet_start();
196 }
197 }
198}
199
200static void __met_hrtimer_register(void *unused)
201{
202 struct met_cpu_struct *met_cpu_ptr = NULL;
203 struct hrtimer *hrtimer = NULL;
204 /* struct delayed_work *dw; */
205 /*struct metdevice *c;*/
206
207 met_cpu_ptr = this_cpu_ptr(&met_cpu);
208#if defined(DEBUG_CPU_NOTIFY)
209 {
210 char msg[32];
211
212 snprintf(msg, sizeof(msg), "met_hrtimer status_%d", met_cpu_ptr->cpu);
213 dbg_met_tag_oneshot(0, msg, 1);
214 }
215#endif
216 /*
217 * do not open HRtimer when EVENT timer enable
218 */
219 if (!(met_switch.mode & MT_SWITCH_EVENT_TIMER)) {
220
221 hrtimer = &met_cpu_ptr->hrtimer;
222 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
223 hrtimer->function = met_hrtimer_notify;
224
225 if (DEFAULT_HRTIMER_EXPIRE) {
226 met_cpu_ptr->work_enabled = 1;
227 /* schedule_delayed_work_on(smp_processor_id(), dw, DEFAULT_TIMER_EXPIRE); */
228 hrtimer_start(hrtimer, ns_to_ktime(DEFAULT_HRTIMER_EXPIRE),
229 HRTIMER_MODE_REL_PINNED);
230 }
231 }
232}
233
234static void __met_hrtimer_stop(void *unused)
235{
236 struct met_cpu_struct *met_cpu_ptr;
237 struct hrtimer *hrtimer;
238 /* struct delayed_work *dw; */
239 struct metdevice *c;
240
241 met_cpu_ptr = this_cpu_ptr(&met_cpu);
242#if defined(DEBUG_CPU_NOTIFY)
243 {
244 char msg[32];
245
246 snprintf(msg, sizeof(msg), "met_hrtimer status_%d", met_cpu_ptr->cpu);
247 dbg_met_tag_oneshot(0, msg, 0);
248 }
249#endif
250 /*
251 * do not open HRtimer when EVENT timer enable
252 */
253 if (!(met_switch.mode & MT_SWITCH_EVENT_TIMER)) {
254 hrtimer = &met_cpu_ptr->hrtimer;
255 /* dw = &met_cpu_ptr->dwork; */
256
257 met_cpu_ptr->work_enabled = 0;
258 hrtimer_cancel(hrtimer);
259
260 /* cancel_delayed_work_sync(dw); */
261 }
262 list_for_each_entry(c, &met_list, list) {
263 if (c->ondiemet_mode == 0) {
264 if ((c->cpu_related) && (c->mode) && (c->stop))
265 c->stop();
266 } else if (c->ondiemet_mode == 1) {
267 if ((c->cpu_related) && (c->mode) && (c->ondiemet_stop))
268 c->ondiemet_stop();
269 } else if (c->ondiemet_mode == 2) {
270 if ((c->cpu_related) && (c->mode) && (c->stop))
271 c->stop();
272 if ((c->cpu_related) && (c->mode) && (c->ondiemet_stop))
273 c->ondiemet_stop();
274 }
275 *(this_cpu_ptr(c->polling_count)) = 0;
276 }
277}
278
279static int met_pmu_cpu_notify(enum met_action action, unsigned int cpu)
280{
281 struct met_cpu_struct *met_cpu_ptr;
282 struct delayed_work *dw;
283 int preferred_polling_cpu;
284 struct metdevice *c;
285
286 if (start == 0)
287 return NOTIFY_OK;
288
289#if defined(DEBUG_CPU_NOTIFY)
290 {
291 char msg[32];
292
293 snprintf(msg, sizeof(msg), "met_cpu notify_%d", cpu);
294 dbg_met_tag_oneshot(0, msg, action);
295 }
296#elif defined(PR_CPU_NOTIFY)
297 {
298 char msg[32];
299
300 if (met_cpu_notify) {
301 snprintf(msg, sizeof(msg), "met_cpu notify_%d", cpu);
302 dbg_met_tag_oneshot(0, msg, action);
303 }
304 }
305#endif
306
307 if (cpu < 0 || cpu >= NR_CPUS)
308 return NOTIFY_OK;
309
310 switch (action) {
311 case MET_CPU_ONLINE:
312 met_cpu_ptr = &per_cpu(met_cpu, cpu);
313 met_cpu_ptr->hrtimer_online_check = 1;
314 dbg_met_tag_oneshot(0, "met_online check", cpu);
315
316 if (cpu_related_cnt == 0) {
317 /*pr_info("%s, %d: curr_polling_cpu is alive = %d\n",
318 * __func__, __LINE__, online_cpu_map & (1 << curr_polling_cpu));
319 */
320
321 online_cpu_map |= (1 << cpu);
322
323 /* check curr_polling_cpu is alive, if it is down,
324 * start current cpu hrtimer, and change it to be currr_pollling_cpu
325 */
326 if ((online_cpu_map & (1 << curr_polling_cpu)) == 0) {
327 if (met_export_api_symbol->met_smp_call_function_single)
328 met_export_api_symbol->met_smp_call_function_single(cpu,
329 __met_hrtimer_register, NULL, 1);
330 curr_polling_cpu = cpu;
331 }
332 } else {
333 if (cpu_related_polling_hdlr_cnt) {
334 if (met_export_api_symbol->met_smp_call_function_single) {
335 met_export_api_symbol->met_smp_call_function_single(cpu,
336 __met_init_cpu_related_device, NULL, 1);
337 met_export_api_symbol->met_smp_call_function_single(cpu,
338 __met_hrtimer_register, NULL, 1);
339 }
340 } else {
341 /*pr_info("%s, %d: curr_polling_cpu is alive = %d\n",
342 * __func__, __LINE__, online_cpu_map & (1 << curr_polling_cpu));
343 */
344
345 online_cpu_map |= (1 << cpu);
346
347 /* check curr_polling_cpu is alive, if it is down,
348 * start current cpu hrtimer, and change it to be currr_pollling_cpu
349 */
350 if ((online_cpu_map & (1 << curr_polling_cpu)) == 0) {
351 if (met_export_api_symbol->met_smp_call_function_single) {
352 met_export_api_symbol->met_smp_call_function_single(cpu,
353 __met_init_cpu_related_device, NULL, 1);
354 met_export_api_symbol->met_smp_call_function_single(cpu,
355 __met_hrtimer_register, NULL, 1);
356 }
357 curr_polling_cpu = cpu;
358 }
359 }
360 }
361
362#if IS_ENABLED(CONFIG_CPU_FREQ)
363 force_power_log(cpu);
364#endif
365 list_for_each_entry(c, &met_list, list) {
366 if (c->cpu_state_notify)
367 c->cpu_state_notify(cpu, action);
368 }
369 break;
370
371 case MET_CPU_OFFLINE:
372 list_for_each_entry(c, &met_list, list) {
373 if (c->cpu_state_notify)
374 c->cpu_state_notify(cpu, action);
375 }
376
377 online_cpu_map &= ~(1 << cpu);
378 dbg_met_tag_oneshot(0, "met_offline cpu", cpu);
379 if (cpu == curr_polling_cpu) {
380 /* pr_info("%s, %d: curr_polling_cpu %d is down\n",
381 * __func__, __LINE__, curr_polling_cpu);
382 */
383 preferred_polling_cpu = calc_preferred_polling_cpu(online_cpu_map);
384 /* pr_info("%s, %d: preferred_polling_cpu = %d\n",
385 * __func__, __LINE__, preferred_polling_cpu);
386 */
387 if (preferred_polling_cpu != -1) {
388 curr_polling_cpu = preferred_polling_cpu;
389 dbg_met_tag_oneshot(0, "met_curr polling cpu", curr_polling_cpu);
390
391 if (cpu_related_cnt == 0) {
392 /* pr_info("%s, %d: start cpu %d hrtimer start\n",
393 * __func__, __LINE__, curr_polling_cpu);
394 */
395 if (met_export_api_symbol->met_smp_call_function_single)
396 met_export_api_symbol->met_smp_call_function_single(curr_polling_cpu,
397 __met_hrtimer_register, NULL, 1);
398 } else if (cpu_related_polling_hdlr_cnt == 0) {
399 if (met_export_api_symbol->met_smp_call_function_single)
400 met_export_api_symbol->met_smp_call_function_single(curr_polling_cpu,
401 __met_hrtimer_register, NULL, 1);
402 }
403 }
404 }
405 if (met_export_api_symbol->met_smp_call_function_single)
406 met_export_api_symbol->met_smp_call_function_single(cpu,
407 __met_hrtimer_stop, NULL, 1);
408
409 met_cpu_ptr = &per_cpu(met_cpu, cpu);
410 dw = &met_cpu_ptr->dwork;
411 cancel_delayed_work_sync(dw);
412
413 /* sync_samples(cpu); */
414 break;
415 default:
416 list_for_each_entry(c, &met_list, list) {
417 if (c->cpu_state_notify)
418 c->cpu_state_notify(cpu, action);
419 }
420 }
421
422 return NOTIFY_OK;
423}
424
425static int _met_pmu_cpu_notify_online(unsigned int cpu)
426{
427 met_pmu_cpu_notify(MET_CPU_ONLINE, cpu);
428
429 return 0;
430}
431
432static int _met_pmu_cpu_notify_offline(unsigned int cpu)
433{
434 met_pmu_cpu_notify(MET_CPU_OFFLINE, cpu);
435
436 return 0;
437}
438
439int sampler_start(void)
440{
441 int ret, cpu;
442 struct met_cpu_struct *met_cpu_ptr;
443 struct metdevice *c;
444 int preferred_polling_cpu;
445
446 met_set_suspend_notify(0);
447
448#if IS_ENABLED(CONFIG_CPU_FREQ)
449 force_power_log(POWER_LOG_ALL);
450#endif
451
452 for_each_possible_cpu(cpu) {
453 met_cpu_ptr = &per_cpu(met_cpu, cpu);
454 met_cpu_ptr->work_enabled = 0;
455 met_cpu_ptr->hrtimer_online_check = 0;
456 hrtimer_init(&met_cpu_ptr->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
457 met_cpu_ptr->hrtimer.function = met_hrtimer_notify;
458 INIT_DELAYED_WORK(&met_cpu_ptr->dwork, wq_sync_buffer);
459 }
460
461 start = 0;
462 ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
463 "met:online",
464 _met_pmu_cpu_notify_online,
465 _met_pmu_cpu_notify_offline);
466
467 list_for_each_entry(c, &met_list, list) {
468
469 if (try_module_get(c->owner) == 0)
470 continue;
471
472 if ((c->mode) && (c->cpu_related == 1)) {
473 cpu_related_cnt = 1;
474
475 if (c->ondiemet_mode == 0) {
476 if (c->timed_polling)
477 cpu_related_polling_hdlr_cnt = 1;
478 } else if (c->ondiemet_mode == 1) {
479 if (c->ondiemet_timed_polling)
480 cpu_related_polling_hdlr_cnt = 1;
481 } else if (c->ondiemet_mode == 2) {
482 if (c->timed_polling || c->ondiemet_timed_polling)
483 cpu_related_polling_hdlr_cnt = 1;
484 }
485 }
486
487 if (c->ondiemet_mode == 0) {
488 if ((!(c->cpu_related)) && (c->mode) && (c->start))
489 c->start();
490 else if ((c->cpu_related) && (c->mode) && (c->uniq_start))
491 c->uniq_start();
492 } else if (c->ondiemet_mode == 1) {
493 if ((!(c->cpu_related)) && (c->mode) && (c->ondiemet_start))
494 c->ondiemet_start();
495 if ((c->cpu_related) && (c->mode) && (c->uniq_ondiemet_start))
496 c->uniq_ondiemet_start();
497 } else if (c->ondiemet_mode == 2) {
498 if ((!(c->cpu_related)) && (c->mode) && (c->start))
499 c->start();
500 else if ((c->cpu_related) && (c->mode) && (c->uniq_start))
501 c->uniq_start();
502
503 if ((!(c->cpu_related)) && (c->mode) && (c->ondiemet_start))
504 c->ondiemet_start();
505 else if ((c->cpu_related) && (c->mode) && (c->uniq_ondiemet_start))
506 c->uniq_ondiemet_start();
507 }
508 }
509
510 get_online_cpus();
511 online_cpu_map = 0;
512 for_each_online_cpu(cpu) {
513 online_cpu_map |= (1 << cpu);
514 }
515 dbg_met_tag_oneshot(0, "met_online cpu map", online_cpu_map);
516 preferred_polling_cpu = calc_preferred_polling_cpu(online_cpu_map);
517 if (preferred_polling_cpu != -1)
518 curr_polling_cpu = preferred_polling_cpu;
519 dbg_met_tag_oneshot(0, "met_curr polling cpu", curr_polling_cpu);
520 start = 1;
521
522 if (cpu_related_cnt == 0) {
523 if (met_export_api_symbol->met_smp_call_function_single)
524 met_export_api_symbol->met_smp_call_function_single(curr_polling_cpu,
525 __met_hrtimer_register, NULL, 1);
526 }
527 else {
528 //on_each_cpu(__met_hrtimer_start, NULL, 1);
529 for_each_online_cpu(cpu) {
530 if (met_export_api_symbol->met_smp_call_function_single)
531 met_export_api_symbol->met_smp_call_function_single(cpu,
532 __met_init_cpu_related_device, NULL, 1);
533 }
534
535 if (cpu_related_polling_hdlr_cnt) {
536 for_each_online_cpu(cpu) {
537 if (met_export_api_symbol->met_smp_call_function_single)
538 met_export_api_symbol->met_smp_call_function_single(cpu,
539 __met_hrtimer_register, NULL, 1);
540 }
541 } else {
542 if (met_export_api_symbol->met_smp_call_function_single)
543 met_export_api_symbol->met_smp_call_function_single(curr_polling_cpu,
544 __met_hrtimer_register, NULL, 1);
545 }
546 }
547 put_online_cpus();
548
549 return ret;
550}
551
552void sampler_stop(void)
553{
554 int cpu;
555 struct met_cpu_struct *met_cpu_ptr;
556 struct metdevice *c;
557 struct delayed_work *dw;
558
559
560 get_online_cpus();
561 //on_each_cpu(__met_hrtimer_stop, NULL, 1);
562 online_cpu_map = 0;
563 for_each_online_cpu(cpu) {
564 online_cpu_map |= (1 << cpu);
565 }
566
567 for_each_online_cpu(cpu) {
568 if (met_export_api_symbol->met_smp_call_function_single)
569 met_export_api_symbol->met_smp_call_function_single(cpu,
570 __met_hrtimer_stop, NULL, 1);
571 }
572
573 /* for_each_online_cpu(cpu) { */
574 for_each_possible_cpu(cpu) { /* Just for case */
575 met_cpu_ptr = &per_cpu(met_cpu, cpu);
576 dw = &met_cpu_ptr->dwork;
577 cancel_delayed_work_sync(dw);
578 /* sync_samples(cpu); */
579 }
580 start = 0;
581 put_online_cpus();
582
583 cpuhp_remove_state_nocalls(CPUHP_AP_ONLINE_DYN);
584
585 list_for_each_entry(c, &met_list, list) {
586 if (c->ondiemet_mode == 0) {
587 if ((!(c->cpu_related)) && (c->mode) && (c->stop))
588 c->stop();
589 else if ((c->cpu_related) && (c->mode) && (c->uniq_stop))
590 c->uniq_stop();
591 } else if (c->ondiemet_mode == 1) {
592 if ((!(c->cpu_related)) && (c->mode) && (c->ondiemet_stop))
593 c->ondiemet_stop();
594 else if ((c->cpu_related) && (c->mode) && (c->uniq_ondiemet_stop))
595 c->uniq_ondiemet_stop();
596 } else if (c->ondiemet_mode == 2) {
597 if ((!(c->cpu_related)) && (c->mode) && (c->stop))
598 c->stop();
599 else if ((c->cpu_related) && (c->mode) && (c->uniq_stop))
600 c->uniq_stop();
601
602 if ((!(c->cpu_related)) && (c->mode) && (c->ondiemet_stop))
603 c->ondiemet_stop();
604 else if ((c->cpu_related) && (c->mode) && (c->uniq_ondiemet_stop))
605 c->uniq_ondiemet_stop();
606 }
607 module_put(c->owner);
608 }
609
610 cpu_related_cnt = 0;
611 cpu_related_polling_hdlr_cnt = 0;
612}
613
614#if 0 /* cann't use static now */
615enum {
616 MET_SUSPEND = 1,
617 MET_RESUME = 2,
618};
619
620static noinline void tracing_mark_write(int op)
621{
622 switch (op) {
623 case MET_SUSPEND:
624 MET_TRACE("C|0|MET_SUSPEND|1");
625 break;
626 case MET_RESUME:
627 MET_TRACE("C|0|MET_SUSPEND|0");
628 break;
629 }
630}
631#endif
632
633int met_hrtimer_suspend(void)
634{
635 struct metdevice *c;
636
637 met_set_suspend_notify(1);
638 /* tracing_mark_write(MET_SUSPEND); */
639 tracing_mark_write(TYPE_MET_SUSPEND, 0, 0, 0, 0, 0);
640 if (start == 0)
641 return 0;
642
643 list_for_each_entry(c, &met_list, list) {
644 if (c->suspend)
645 c->suspend();
646 }
647
648 /* get current COUNT */
649 MET_TRACE("TS: %llu GPT: %llX", sched_clock(), arch_counter_get_cntvct());
650 return 0;
651}
652
653void met_hrtimer_resume(void)
654{
655 struct metdevice *c;
656
657 /* get current COUNT */
658 MET_TRACE("TS: %llu GPT: %llX", sched_clock(), arch_counter_get_cntvct());
659
660 /* tracing_mark_write(MET_RESUME); */
661 tracing_mark_write(TYPE_MET_RESUME, 0, 0, 0, 0, 0);
662 if (start == 0)
663 return;
664
665 list_for_each_entry(c, &met_list, list) {
666 if (c->resume)
667 c->resume();
668 }
669}
670
671/*
672 * event timer:
673 * register IRQ, sched_switch event to monitor Polling count
674 * count can be printed at any live cpu.
675 */
676void met_event_timer_notify(void)
677{
678 unsigned long long stamp;
679 struct metdevice *c;
680 int cpu = -1;
681
682 if (start == 0)
683 return;
684
685 cpu = smp_processor_id();
686 list_for_each_entry(c, &met_list, list) {
687 stamp = local_clock();
688
689 if (c->prev_stamp == 0)
690 c->prev_stamp = stamp;
691
692 /* Critical Section Start */
693 /* try spinlock to prevent a event print twice between config time interval */
694 if (!spin_trylock(&(c->my_lock)))
695 continue;
696
697 /*
698 * DEFAULT_HRTIMER_EXPIRE (met_hrtimer_expire):
699 * sample_rate == 0 --> always print
700 * sample_rate == 1000 --> print interval larger than 1 ms
701 */
702 if (DEFAULT_HRTIMER_EXPIRE == 0 || (stamp - c->prev_stamp) < DEFAULT_HRTIMER_EXPIRE) {
703 spin_unlock(&(c->my_lock));
704 continue;
705 }
706
707 c->prev_stamp = stamp;
708 spin_unlock(&(c->my_lock));
709 /* Critical Section End */
710
711 if ((c->mode == 0) || (c->timed_polling == NULL))
712 continue;
713
714 stamp = local_clock();
715 c->timed_polling(stamp, cpu);
716 }
717}
718