blob: 6417fdd35288ed973e33e283c9c4689d09a1d679 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (C) 2018 MediaTek Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/sched/clock.h>
15#include <linux/fs.h>
16#include <linux/sched.h>
17#include <linux/module.h>
18#include <linux/device.h>
19#include <linux/miscdevice.h>
20#include <linux/kallsyms.h>
21#include <linux/syscore_ops.h>
22#include <linux/dma-mapping.h>
23#include "interface.h"
24#include "sampler.h"
25#include "util.h"
26
27#include "ondiemet.h"
28
29#include "met_drv.h"
30#include "met_tag.h"
31#include "met_kernel_symbol.h"
32#include "met_api_tbl.h"
33#include "version.h"
34
35extern int enable_met_backlight_tag(void);
36extern int output_met_backlight_tag(int level);
37
38static int run = -1;
39static int sample_rate = 1000; /* Default: 1000 Hz */
40static int met_suspend_compensation_mode;
41static int met_suspend_compensation_flag;
42
43/*
44 * met_cpu_pmu_method:
45 * 0: MET pmu driver
46 * 1: perf APIs
47 */
48unsigned int met_cpu_pmu_method = 1;
49
50int met_hrtimer_expire; /* in ns */
51int met_timer_expire; /* in jiffies */
52unsigned int ctrl_flags;
53int met_mode;
54EXPORT_SYMBOL(met_mode);
55
56DEFINE_PER_CPU(char[MET_STRBUF_SIZE], met_strbuf_nmi);
57EXPORT_SYMBOL(met_strbuf_nmi);
58
59DEFINE_PER_CPU(char[MET_STRBUF_SIZE], met_strbuf_irq);
60EXPORT_SYMBOL(met_strbuf_irq);
61
62DEFINE_PER_CPU(char[MET_STRBUF_SIZE], met_strbuf_sirq);
63EXPORT_SYMBOL(met_strbuf_sirq);
64
65DEFINE_PER_CPU(char[MET_STRBUF_SIZE], met_strbuf);
66EXPORT_SYMBOL(met_strbuf);
67
68static void calc_timer_value(int rate)
69{
70 sample_rate = rate;
71
72 if (rate == 0) {
73 met_hrtimer_expire = 0;
74 met_timer_expire = 0;
75 return;
76 }
77
78 met_hrtimer_expire = 1000000000 / rate;
79
80 /* Case 1: hrtimer < 1 OS tick, met_timer_expire = 1 OS tick */
81 if (rate > HZ)
82 met_timer_expire = 1;
83 /* Case 2: hrtimer > 1 OS tick, met_timer_expire is hrtimer + 1 OS tick */
84 else
85 met_timer_expire = (HZ / rate) + 1;
86
87 /* pr_debug("JBK HZ=%d, met_hrtimer_expire=%d ns, met_timer_expire=%d ticks\n", */
88 /* HZ, met_hrtimer_expire, met_timer_expire); */
89}
90
91int met_parse_num(const char *str, unsigned int *value, int len)
92{
93 int ret;
94
95 if (len <= 0)
96 return -1;
97
98 if ((len > 2) &&
99 ((str[0] == '0') &&
100 ((str[1] == 'x') || (str[1] == 'X')))) {
101 ret = kstrtoint(str, 16, value);
102 } else {
103 ret = kstrtoint(str, 10, value);
104 }
105
106 if (ret != 0)
107 return -1;
108
109 return 0;
110}
111
112void met_set_suspend_notify(int flag)
113{
114 if (met_suspend_compensation_mode == 1)
115 met_suspend_compensation_flag = flag;
116 else
117 met_suspend_compensation_flag = 0;
118}
119
120LIST_HEAD(met_list);
121static struct kobject *kobj_misc;
122static struct kobject *kobj_pmu;
123static struct kobject *kobj_bus;
124
125static ssize_t ver_show(struct device *dev, struct device_attribute *attr, char *buf);
126static DEVICE_ATTR(ver, 0444, ver_show, NULL);
127
128static ssize_t plf_show(struct device *dev, struct device_attribute *attr, char *buf);
129static DEVICE_ATTR(plf, 0444, plf_show, NULL);
130
131static ssize_t core_topology_show(struct device *dev, struct device_attribute *attr, char *buf);
132static DEVICE_ATTR(core_topology, 0444, core_topology_show, NULL);
133
134static ssize_t devices_show(struct device *dev, struct device_attribute *attr, char *buf);
135static DEVICE_ATTR(devices, 0444, devices_show, NULL);
136
137static ssize_t ctrl_show(struct device *dev, struct device_attribute *attr, char *buf);
138static ssize_t ctrl_store(struct device *dev, struct device_attribute *attr, const char *buf,
139 size_t count);
140static DEVICE_ATTR(ctrl, 0664, ctrl_show, ctrl_store);
141
142static ssize_t spr_show(struct device *dev, struct device_attribute *attr, char *buf);
143static ssize_t spr_store(struct device *dev, struct device_attribute *attr, const char *buf,
144 size_t count);
145static DEVICE_ATTR(sample_rate, 0664, spr_show, spr_store);
146
147static ssize_t run_show(struct device *dev, struct device_attribute *attr, char *buf);
148static ssize_t run_store(struct device *dev, struct device_attribute *attr, const char *buf,
149 size_t count);
150static DEVICE_ATTR(run, 0664, run_show, run_store);
151
152static ssize_t ksym_show(struct device *dev, struct device_attribute *attr, char *buf);
153static ssize_t ksym_store(struct device *dev, struct device_attribute *attr, const char *buf,
154 size_t count);
155static DEVICE_ATTR(ksym, 0664, ksym_show, ksym_store);
156
157static ssize_t cpu_pmu_method_show(struct device *dev, struct device_attribute *attr, char *buf);
158static ssize_t cpu_pmu_method_store(struct device *dev, struct device_attribute *attr, const char *buf,
159 size_t count);
160static DEVICE_ATTR(cpu_pmu_method, 0664, cpu_pmu_method_show, cpu_pmu_method_store);
161
162#ifdef PR_CPU_NOTIFY
163int met_cpu_notify;
164static ssize_t cpu_notify_show(struct device *dev, struct device_attribute *attr, char *buf);
165static ssize_t cpu_notify_store(struct device *dev, struct device_attribute *attr, const char *buf,
166 size_t count);
167static DEVICE_ATTR(cpu_notify, 0664, cpu_notify_show, cpu_notify_store);
168#endif
169
170#ifdef CONFIG_CPU_FREQ
171static ssize_t dvfs_show(struct device *dev, struct device_attribute *attr, char *buf);
172static ssize_t dvfs_store(struct device *dev, struct device_attribute *attr, const char *buf,
173 size_t count);
174static DEVICE_ATTR(dvfs, 0664, dvfs_show, dvfs_store);
175#endif
176
177static ssize_t suspend_compensation_enable_show(struct device *dev, struct device_attribute *attr, char *buf);
178static ssize_t suspend_compensation_enable_store(struct device *dev, struct device_attribute *attr,
179 const char *buf, size_t count);
180static DEVICE_ATTR(suspend_compensation_enable, 0664, suspend_compensation_enable_show,
181 suspend_compensation_enable_store);
182
183static ssize_t suspend_compensation_flag_show(struct device *dev, struct device_attribute *attr, char *buf);
184static DEVICE_ATTR(suspend_compensation_flag, 0444, suspend_compensation_flag_show, NULL);
185
186static ssize_t ipi_test_store(struct device *dev, struct device_attribute *attr, const char *buf,
187 size_t count);
188static DEVICE_ATTR(ipi_test, 0220, NULL, ipi_test_store);
189
190static const struct file_operations met_file_ops = {
191 .owner = THIS_MODULE
192};
193
194struct miscdevice met_device = {
195 .minor = MISC_DYNAMIC_MINOR,
196 .name = "met",
197 .mode = 0664,
198 .fops = &met_file_ops
199};
200EXPORT_SYMBOL(met_device);
201
202static int met_run(void)
203{
204 sampler_start();
205#ifdef MET_USER_EVENT_SUPPORT
206 bltab.flag &= (~MET_CLASS_ALL);
207#endif
208 ondiemet_start();
209 return 0;
210}
211
212static void met_stop(void)
213{
214#ifdef MET_USER_EVENT_SUPPORT
215 bltab.flag |= MET_CLASS_ALL;
216#endif
217 sampler_stop();
218 /* the met.ko will be use by script "cat ...", release it */
219 if ((ondiemet_module[ONDIEMET_SSPM] == 0) || (sspm_buffer_size == -1))
220 ondiemet_log_manager_stop();
221 ondiemet_stop();
222 ondiemet_extract();
223}
224
225static ssize_t ver_show(struct device *dev, struct device_attribute *attr, char *buf)
226{
227 int i;
228
229 mutex_lock(&dev->mutex);
230 i = snprintf(buf, PAGE_SIZE, "%s\n", MET_BACKEND_VERSION);
231 mutex_unlock(&dev->mutex);
232 return i;
233}
234
235static ssize_t devices_show(struct device *dev, struct device_attribute *attr, char *buf)
236{
237 int len, total_len = 0;
238 struct metdevice *c = NULL;
239
240 mutex_lock(&dev->mutex);
241 list_for_each_entry(c, &met_list, list) {
242 len = 0;
243 if (c->type == MET_TYPE_PMU)
244 len = snprintf(buf, PAGE_SIZE - total_len, "pmu/%s:0\n", c->name);
245 else if (c->type == MET_TYPE_BUS)
246 len = snprintf(buf, PAGE_SIZE - total_len, "bus/%s:0\n", c->name);
247 else if (c->type == MET_TYPE_MISC)
248 len = snprintf(buf, PAGE_SIZE - total_len, "misc/%s:0\n", c->name);
249
250 if (c->ondiemet_mode == 0) {
251 if (c->process_argument)
252 buf[len - 2]++;
253 } else if (c->ondiemet_mode == 1) {
254 if (c->ondiemet_process_argument)
255 buf[len - 2]++;
256 } else if (c->ondiemet_mode == 2) {
257 if (c->process_argument)
258 buf[len - 2]++;
259 if (c->ondiemet_process_argument)
260 buf[len - 2]++;
261 }
262
263 buf += len;
264 total_len += len;
265 }
266
267 mutex_unlock(&dev->mutex);
268 return total_len;
269}
270
271static char met_platform[16] = "none";
272static ssize_t plf_show(struct device *dev, struct device_attribute *attr, char *buf)
273{
274 int i;
275
276 mutex_lock(&dev->mutex);
277 i = snprintf(buf, PAGE_SIZE, "%s\n", met_platform);
278 mutex_unlock(&dev->mutex);
279 return i;
280}
281
282static char met_topology[64] = "none";
283static ssize_t core_topology_show(struct device *dev, struct device_attribute *attr, char *buf)
284{
285 int i;
286
287 mutex_lock(&dev->mutex);
288 i = snprintf(buf, PAGE_SIZE, "%s\n", met_topology);
289 mutex_unlock(&dev->mutex);
290 return i;
291}
292
293static ssize_t ctrl_show(struct device *dev, struct device_attribute *attr, char *buf)
294{
295 return snprintf(buf, PAGE_SIZE, "%d\n", ctrl_flags);
296}
297
298static ssize_t ctrl_store(struct device *dev, struct device_attribute *attr, const char *buf,
299 size_t count)
300{
301 unsigned int value = 0;
302
303 if (met_parse_num(buf, &value, count) < 0)
304 return -EINVAL;
305
306 ctrl_flags = value;
307 return count;
308}
309
310static ssize_t cpu_pmu_method_show(struct device *dev, struct device_attribute *attr, char *buf)
311{
312 return snprintf(buf, PAGE_SIZE, "%d\n", met_cpu_pmu_method);
313}
314
315static ssize_t cpu_pmu_method_store(struct device *dev, struct device_attribute *attr, const char *buf,
316 size_t count)
317{
318 unsigned int value;
319
320 if (met_parse_num(buf, &value, count) < 0)
321 return -EINVAL;
322
323 met_cpu_pmu_method = value;
324 return count;
325}
326
327
328static void _test_trace_ipi_raise(void *info)
329{
330 unsigned int *cpu = (unsigned int *)info;
331 void (*arch_send_call_function_single_ipi_sym)(int cpu) = NULL;
332
333 arch_send_call_function_single_ipi_sym = (void *)symbol_get(met_arch_send_call_function_single_ipi);
334 if (arch_send_call_function_single_ipi_sym)
335 arch_send_call_function_single_ipi_sym(*cpu);
336}
337
338
339static ssize_t ipi_test_store(struct device *dev, struct device_attribute *attr, const char *buf,
340 size_t count)
341{
342 int this_cpu = smp_processor_id();
343 unsigned int cpu = 0;
344 unsigned int value;
345
346 if (met_parse_num(buf, &value, count) < 0)
347 return -EINVAL;
348
349 cpu = value;
350 if (cpu == this_cpu)
351 _test_trace_ipi_raise(&cpu);
352 else
353 met_smp_call_function_single_symbol(cpu, _test_trace_ipi_raise, &cpu, 1);
354
355 return count;
356}
357
358
359#if defined(MET_BOOT_MSG)
360char met_boot_msg_tmp[256];
361char met_boot_msg[PAGE_SIZE];
362int met_boot_msg_idx;
363
364int pr_bootmsg(int str_len, char *str)
365{
366 if (met_boot_msg_idx+str_len+1 > PAGE_SIZE)
367 return -1;
368 memcpy(met_boot_msg+met_boot_msg_idx, str, str_len);
369 met_boot_msg_idx += str_len;
370 return 0;
371}
372
373static ssize_t bootmsg_show(struct device *dev, struct device_attribute *attr, char *buf)
374{
375 int i;
376
377 mutex_lock(&dev->mutex);
378 i = snprintf(buf, PAGE_SIZE, "%s\n", met_boot_msg);
379 mutex_unlock(&dev->mutex);
380 return i;
381}
382
383static DEVICE_ATTR_RO(bootmsg);
384EXPORT_SYMBOL(met_boot_msg_tmp);
385EXPORT_SYMBOL(pr_bootmsg);
386#endif
387
388static ssize_t spr_show(struct device *dev, struct device_attribute *attr, char *buf)
389{
390 int i;
391
392 mutex_lock(&dev->mutex);
393 i = snprintf(buf, PAGE_SIZE, "%d\n", sample_rate);
394 mutex_unlock(&dev->mutex);
395 return i;
396}
397
398static ssize_t spr_store(struct device *dev, struct device_attribute *attr, const char *buf,
399 size_t count)
400{
401 int value;
402 struct metdevice *c = NULL;
403
404 mutex_lock(&dev->mutex);
405
406 if ((run == 1) || (count == 0) || (buf == NULL)) {
407 mutex_unlock(&dev->mutex);
408 return -EINVAL;
409 }
410 if (kstrtoint(buf, 0, &value) != 0) {
411 mutex_unlock(&dev->mutex);
412 return -EINVAL;
413 }
414
415 if ((value < 0) || (value > 10000)) {
416 mutex_unlock(&dev->mutex);
417 return -EINVAL;
418 }
419
420 calc_timer_value(value);
421
422 list_for_each_entry(c, &met_list, list) {
423 if (c->polling_interval > 0)
424 c->polling_count_reload = ((c->polling_interval * sample_rate) - 1) / 1000;
425 else
426 c->polling_count_reload = 0;
427 }
428
429 mutex_unlock(&dev->mutex);
430
431 return count;
432}
433
434static ssize_t run_show(struct device *dev, struct device_attribute *attr, char *buf)
435{
436 int i;
437
438 mutex_lock(&dev->mutex);
439 i = snprintf(buf, PAGE_SIZE, "%d\n", run);
440 mutex_unlock(&dev->mutex);
441 return i;
442}
443
444static ssize_t run_store(struct device *dev, struct device_attribute *attr, const char *buf,
445 size_t count)
446{
447 int value;
448
449 mutex_lock(&dev->mutex);
450
451 if ((count == 0) || (buf == NULL)) {
452 mutex_unlock(&dev->mutex);
453 return -EINVAL;
454 }
455 if (kstrtoint(buf, 0, &value) != 0) {
456 mutex_unlock(&dev->mutex);
457 return -EINVAL;
458 }
459
460 switch (value) {
461 case 1:
462 if (run != 1) {
463 run = 1;
464 met_run();
465 }
466 break;
467 case 0:
468 if (run != 0) {
469 if (run == 1) {
470 met_stop();
471#ifdef MET_USER_EVENT_SUPPORT
472#ifdef CONFIG_MET_MODULE
473// met_save_dump_buffer_real("/data/trace.dump");
474#else
475 met_save_dump_buffer("/data/trace.dump");
476#endif
477#endif
478 run = 0;
479 } else
480 /* run == -1 */
481 run = 0;
482 }
483 break;
484 case -1:
485 if (run != -1) {
486 if (run == 1)
487 met_stop();
488
489 run = -1;
490 }
491 break;
492 default:
493 mutex_unlock(&dev->mutex);
494 return -EINVAL;
495 }
496
497 mutex_unlock(&dev->mutex);
498
499 return count;
500}
501
502static unsigned int met_ksym_addr;
503static char met_func_name[512];
504static ssize_t ksym_show(struct device *dev, struct device_attribute *attr, char *buf)
505{
506 int i;
507 int len = 0;
508 int idx = 0;
509
510 mutex_lock(&dev->mutex);
511 if (met_ksym_addr != 0)
512 len = sprint_symbol_no_offset(met_func_name, met_ksym_addr);
513 if (len != 0) {
514 for (idx = 0; idx < 512; idx++)
515 if (met_func_name[idx] == ' ')
516 met_func_name[idx] = '\0';
517 i = snprintf(buf, PAGE_SIZE, "%s\n", met_func_name);
518 } else
519 i = snprintf(buf, PAGE_SIZE, "ksymlookup fail(%x)\n", met_ksym_addr);
520
521 mutex_unlock(&dev->mutex);
522 return i;
523}
524
525static ssize_t ksym_store(struct device *dev, struct device_attribute *attr, const char *buf,
526 size_t count)
527{
528 mutex_lock(&dev->mutex);
529
530 if ((count == 0) || (buf == NULL)) {
531 mutex_unlock(&dev->mutex);
532 return -EINVAL;
533 }
534 if (kstrtoint(buf, 16, &met_ksym_addr) != 0) {
535 mutex_unlock(&dev->mutex);
536 return -EINVAL;
537 }
538
539 mutex_unlock(&dev->mutex);
540
541 return count;
542}
543
544#if defined(PR_CPU_NOTIFY)
545static ssize_t cpu_notify_show(struct device *dev, struct device_attribute *attr, char *buf)
546{
547 int i;
548
549 i = snprintf(buf, PAGE_SIZE, "%d\n", met_cpu_notify);
550 return i;
551}
552
553static ssize_t cpu_notify_store(struct device *dev, struct device_attribute *attr, const char *buf,
554 size_t count)
555{
556 if ((count == 0) || (buf == NULL))
557 return -EINVAL;
558
559 if (kstrtoint(buf, 0, &met_cpu_notify) != 0)
560 return -EINVAL;
561
562 return count;
563}
564#endif
565
566#ifdef CONFIG_CPU_FREQ
567static ssize_t dvfs_show(struct device *dev, struct device_attribute *attr, char *buf)
568{
569 int i;
570
571 i = snprintf(buf, PAGE_SIZE, "%d\n", 0);
572 return i;
573}
574
575static ssize_t dvfs_store(struct device *dev, struct device_attribute *attr, const char *buf,
576 size_t count)
577{
578 return count;
579}
580#endif
581
582static ssize_t suspend_compensation_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
583{
584 int ret;
585
586 ret = snprintf(buf, PAGE_SIZE, "%d\n", met_suspend_compensation_mode);
587
588 return ret;
589}
590
591static ssize_t suspend_compensation_enable_store(struct device *dev, struct device_attribute *attr,
592 const char *buf, size_t count)
593{
594 int value;
595
596 if ((count == 0) || (buf == NULL))
597 return -EINVAL;
598
599 if (kstrtoint(buf, 0, &value) != 0)
600 return -EINVAL;
601
602 if (value < 0)
603 return -EINVAL;
604
605 met_suspend_compensation_mode = value;
606
607 return count;
608}
609
610static ssize_t suspend_compensation_flag_show(struct device *dev, struct device_attribute *attr, char *buf)
611{
612 int ret;
613
614 ret = snprintf(buf, PAGE_SIZE, "%d\n", met_suspend_compensation_flag);
615
616 return ret;
617}
618
619static ssize_t hash_show(struct device *dev, struct device_attribute *attr, char *buf)
620{
621 return 0;
622}
623
624static ssize_t hash_store(struct device *dev, struct device_attribute *attr, const char *buf,
625 size_t count)
626{
627 return 0;
628}
629
630static DEVICE_ATTR(hash, 0664, hash_show, hash_store);
631
632static ssize_t mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
633{
634 struct metdevice *c = NULL;
635
636 list_for_each_entry(c, &met_list, list) {
637 if (c->kobj == kobj)
638 break;
639 }
640 if (c == NULL)
641 return -ENOENT;
642
643 return snprintf(buf, PAGE_SIZE, "%d\n", c->mode);
644}
645
646static ssize_t mode_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,
647 size_t n)
648{
649 struct metdevice *c = NULL;
650
651 list_for_each_entry(c, &met_list, list) {
652 if (c->kobj == kobj)
653 break;
654 }
655 if (c == NULL)
656 return -ENOENT;
657
658 if (kstrtoint(buf, 0, &(c->mode)) != 0)
659 return -EINVAL;
660
661 return n;
662}
663
664static struct kobj_attribute mode_attr = __ATTR(mode, 0664, mode_show, mode_store);
665
666static ssize_t ondiemet_mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
667{
668 struct metdevice *c = NULL;
669
670 list_for_each_entry(c, &met_list, list) {
671 if (c->kobj == kobj)
672 break;
673 }
674 if (c == NULL)
675 return -ENOENT;
676
677 return snprintf(buf, PAGE_SIZE, "%d\n", c->ondiemet_mode);
678}
679
680static ssize_t ondiemet_mode_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,
681 size_t n)
682{
683 struct metdevice *c = NULL;
684
685 list_for_each_entry(c, &met_list, list) {
686 if (c->kobj == kobj)
687 break;
688 }
689 if (c == NULL)
690 return -ENOENT;
691
692 if (kstrtoint(buf, 0, &(c->ondiemet_mode)) != 0)
693 return -EINVAL;
694
695 return n;
696}
697
698static struct kobj_attribute ondiemet_mode_attr = __ATTR(ondiemet_mode, 0664, ondiemet_mode_show, ondiemet_mode_store);
699
700static ssize_t polling_interval_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
701{
702 int interval = 1;
703 struct metdevice *c = NULL;
704
705 list_for_each_entry(c, &met_list, list) {
706 if (c->kobj == kobj)
707 break;
708 }
709 if (c == NULL)
710 return -ENOENT;
711
712 if (c->polling_interval)
713 interval = c->polling_interval;
714
715 return snprintf(buf, PAGE_SIZE, "%d\n", interval);
716}
717
718static ssize_t polling_interval_store(struct kobject *kobj, struct kobj_attribute *attr,
719 const char *buf, size_t n)
720{
721 struct metdevice *c = NULL;
722
723 list_for_each_entry(c, &met_list, list) {
724 if (c->kobj == kobj)
725 break;
726 }
727 if (c == NULL)
728 return -ENOENT;
729
730 if (kstrtoint(buf, 0, &(c->polling_interval)) != 0)
731 return -EINVAL;
732
733 if (c->polling_interval > 0)
734 c->polling_count_reload = ((c->polling_interval * sample_rate) - 1) / 1000;
735 else
736 c->polling_count_reload = 0;
737
738 return n;
739}
740
741static struct kobj_attribute polling_interval_attr =
742__ATTR(polling_ms, 0664, polling_interval_show, polling_interval_store);
743
744static ssize_t header_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
745{
746 struct metdevice *c = NULL;
747 ssize_t count = 0;
748
749 list_for_each_entry(c, &met_list, list) {
750 if (c->kobj == kobj)
751 break;
752 }
753 if (c == NULL)
754 return -ENOENT;
755
756 if (c->ondiemet_mode == 0) {
757 if ((c->mode) && (c->print_header))
758 return c->print_header(buf, PAGE_SIZE);
759 } else if (c->ondiemet_mode == 1) {
760 if ((c->mode) && (c->ondiemet_print_header))
761 return c->ondiemet_print_header(buf, PAGE_SIZE);
762 } else if (c->ondiemet_mode == 2) {
763 if ((c->mode) && (c->print_header))
764 count = c->print_header(buf, PAGE_SIZE);
765 if (count < PAGE_SIZE) {
766 if ((c->mode) && (c->ondiemet_print_header))
767 count += c->ondiemet_print_header(buf+count, PAGE_SIZE - count);
768 }
769 return count;
770 }
771
772 return 0;
773}
774
775static struct kobj_attribute header_attr = __ATTR(header, 0444, header_show, NULL);
776
777static ssize_t help_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
778{
779 struct metdevice *c = NULL;
780 ssize_t count = 0;
781
782 list_for_each_entry(c, &met_list, list) {
783 if (c->kobj == kobj)
784 break;
785 }
786 if (c == NULL)
787 return -ENOENT;
788
789 if (c->ondiemet_mode == 0) {
790 if (c->print_help)
791 return c->print_help(buf, PAGE_SIZE);
792 } else if (c->ondiemet_mode == 1) {
793 if (c->ondiemet_print_help)
794 return c->ondiemet_print_help(buf, PAGE_SIZE);
795 } else if (c->ondiemet_mode == 2) {
796 if (c->print_help)
797 count = c->print_help(buf, PAGE_SIZE);
798 if (count < PAGE_SIZE) {
799 if (c->ondiemet_print_help)
800 count += c->ondiemet_print_help(buf+count, PAGE_SIZE - count);
801 }
802 return count;
803 }
804
805 return 0;
806}
807
808static struct kobj_attribute help_attr = __ATTR(help, 0444, help_show, NULL);
809
810static int argu_status = -1;
811static ssize_t argu_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,
812 size_t n)
813{
814 int ret = 0;
815 struct metdevice *c = NULL;
816
817 argu_status = -1;
818
819 list_for_each_entry(c, &met_list, list) {
820 if (c->kobj == kobj)
821 break;
822 }
823 if (c == NULL)
824 return -ENOENT;
825
826 if (c->ondiemet_mode == 0) {
827 if (c->process_argument)
828 ret = c->process_argument(buf, (int)n);
829 } else if (c->ondiemet_mode == 1) {
830 if (c->ondiemet_process_argument)
831 ret = c->ondiemet_process_argument(buf, (int)n);
832 } else if (c->ondiemet_mode == 2) {
833 if (c->process_argument)
834 ret = c->process_argument(buf, (int)n);
835 if (c->ondiemet_process_argument)
836 ret = c->ondiemet_process_argument(buf, (int)n);
837 }
838
839 if (ret != 0)
840 return -EINVAL;
841
842 argu_status = 0;
843 return n;
844}
845
846static ssize_t argu_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
847{
848 return snprintf(buf, PAGE_SIZE, "%d\n", argu_status);
849}
850
851static struct kobj_attribute argu_attr = __ATTR(argu, 0664, argu_show, argu_store);
852
853static ssize_t reset_store(struct kobject *kobj,
854 struct kobj_attribute *attr,
855 const char *buf,
856 size_t n)
857{
858 int ret = 0;
859 struct metdevice *c = NULL;
860
861 list_for_each_entry(c, &met_list, list) {
862 if (c->kobj == kobj)
863 break;
864 }
865 if (c == NULL)
866 return -ENOENT;
867
868 if (c->ondiemet_mode == 0) {
869 if (c->reset)
870 ret = c->reset();
871 else
872 c->mode = 0;
873 } else if (c->ondiemet_mode == 1) {
874 if (c->ondiemet_reset)
875 ret = c->ondiemet_reset();
876 } else if (c->ondiemet_mode == 2) {
877 if (c->reset)
878 ret = c->reset();
879 else
880 c->mode = 0;
881 if (c->ondiemet_reset)
882 ret = c->ondiemet_reset();
883 }
884
885 if (ret != 0)
886 return -EINVAL;
887
888 return n;
889}
890
891static struct kobj_attribute reset_attr = __ATTR(reset, 0220, NULL, reset_store);
892
893static ssize_t header_read_again_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
894{
895 struct metdevice *c = NULL;
896
897 list_for_each_entry(c, &met_list, list) {
898 if (c->kobj == kobj)
899 break;
900 }
901 if (c == NULL)
902 return -ENOENT;
903
904 return snprintf(buf, PAGE_SIZE, "%d\n", c->header_read_again);
905}
906
907static struct kobj_attribute header_read_again_attr = __ATTR(header_read_again, 0664, header_read_again_show, NULL);
908
909
910int met_register(struct metdevice *met)
911{
912 int ret, cpu;
913 struct metdevice *c;
914
915 list_for_each_entry(c, &met_list, list) {
916 if (!strcmp(c->name, met->name))
917 return -EEXIST;
918 }
919
920 PR_BOOTMSG("met_register %s ...\n", met->name);
921
922 INIT_LIST_HEAD(&met->list);
923
924 /* Allocate timer count for per CPU */
925 met->polling_count = alloc_percpu(int);
926 if (met->polling_count == NULL)
927 return -EINVAL;
928
929 for_each_possible_cpu(cpu)
930 *(per_cpu_ptr(met->polling_count, cpu)) = 0;
931
932 if (met->polling_interval > 0) {
933 ret = ((met->polling_interval * sample_rate) - 1) / 1000;
934 met->polling_count_reload = ret;
935 } else
936 met->polling_count_reload = 0;
937
938 met->kobj = NULL;
939
940 if (met->type == MET_TYPE_BUS)
941 met->kobj = kobject_create_and_add(met->name, kobj_bus);
942 else if (met->type == MET_TYPE_PMU)
943 met->kobj = kobject_create_and_add(met->name, kobj_pmu);
944 else if (met->type == MET_TYPE_MISC)
945 met->kobj = kobject_create_and_add(met->name, kobj_misc);
946 else {
947 ret = -EINVAL;
948 goto err_out;
949 }
950
951 if (met->kobj == NULL) {
952 ret = -EINVAL;
953 goto err_out;
954 }
955
956 if (met->create_subfs) {
957 ret = met->create_subfs(met->kobj);
958 if (ret)
959 goto err_out;
960 }
961
962 ret = sysfs_create_file(met->kobj, &mode_attr.attr);
963 if (ret)
964 goto err_out;
965
966
967 ret = sysfs_create_file(met->kobj, &ondiemet_mode_attr.attr);
968 if (ret)
969 goto err_out;
970
971 ret = sysfs_create_file(met->kobj, &polling_interval_attr.attr);
972 if (ret)
973 goto err_out;
974
975 ret = sysfs_create_file(met->kobj, &header_read_again_attr.attr);
976 if (ret)
977 goto err_out;
978
979 if (met->print_header || met->ondiemet_print_header) {
980 ret = sysfs_create_file(met->kobj, &header_attr.attr);
981 if (ret)
982 goto err_out;
983 }
984
985 if (met->print_help || met->ondiemet_print_help) {
986 ret = sysfs_create_file(met->kobj, &help_attr.attr);
987 if (ret)
988 goto err_out;
989 }
990
991 if (met->process_argument || met->ondiemet_process_argument) {
992 ret = sysfs_create_file(met->kobj, &argu_attr.attr);
993 if (ret)
994 goto err_out;
995 }
996
997 if (met->reset) {
998 ret = sysfs_create_file(met->kobj, &reset_attr.attr);
999 if (ret)
1000 goto err_out;
1001 }
1002
1003 spin_lock_init(&met->my_lock);
1004
1005 list_add(&met->list, &met_list);
1006 return 0;
1007
1008 err_out:
1009
1010 if (met->polling_count)
1011 free_percpu(met->polling_count);
1012
1013 if (met->kobj) {
1014 kobject_del(met->kobj);
1015 kobject_put(met->kobj);
1016 met->kobj = NULL;
1017 }
1018
1019 return ret;
1020}
1021EXPORT_SYMBOL(met_register);
1022
1023int met_deregister(struct metdevice *met)
1024{
1025 struct metdevice *c = NULL;
1026
1027 list_for_each_entry(c, &met_list, list) {
1028 if (c == met)
1029 break;
1030 }
1031 if (c != met)
1032 return -ENOENT;
1033
1034 if (met->print_header || met->ondiemet_print_header)
1035 sysfs_remove_file(met->kobj, &header_attr.attr);
1036
1037 if (met->print_help || met->ondiemet_print_help)
1038 sysfs_remove_file(met->kobj, &help_attr.attr);
1039
1040 if (met->process_argument || met->ondiemet_process_argument)
1041 sysfs_remove_file(met->kobj, &argu_attr.attr);
1042
1043 sysfs_remove_file(met->kobj, &reset_attr.attr);
1044 sysfs_remove_file(met->kobj, &header_read_again_attr.attr);
1045 sysfs_remove_file(met->kobj, &polling_interval_attr.attr);
1046 sysfs_remove_file(met->kobj, &mode_attr.attr);
1047 sysfs_remove_file(met->kobj, &ondiemet_mode_attr.attr);
1048
1049 if (met->delete_subfs)
1050 met->delete_subfs();
1051
1052 kobject_del(met->kobj);
1053 kobject_put(met->kobj);
1054 met->kobj = NULL;
1055
1056 if (met->polling_count)
1057 free_percpu(met->polling_count);
1058
1059 list_del(&met->list);
1060 return 0;
1061}
1062EXPORT_SYMBOL(met_deregister);
1063
1064int met_set_platform(const char *plf_name, int flag)
1065{
1066 strncpy(met_platform, plf_name, sizeof(met_platform) - 1);
1067#if 0
1068 int ret;
1069
1070 if (flag) {
1071 ret = device_create_file(met_device.this_device, &dev_attr_plf);
1072 if (ret != 0) {
1073 pr_debug("can not create device file: plf\n");
1074 return ret;
1075 }
1076 strncpy(met_platform, plf_name, sizeof(met_platform) - 1);
1077 } else
1078 device_remove_file(met_device.this_device, &dev_attr_plf);
1079
1080#endif
1081 return 0;
1082}
1083EXPORT_SYMBOL(met_set_platform);
1084
1085int met_set_topology(const char *topology_name, int flag)
1086{
1087 strncpy(met_topology, topology_name, sizeof(met_topology) - 1);
1088#if 0
1089 int ret;
1090
1091 if (flag) {
1092 ret = device_create_file(met_device.this_device, &dev_attr_core_topology);
1093 if (ret != 0) {
1094 pr_debug("can not create device file: topology\n");
1095 return ret;
1096 }
1097 strncpy(met_topology, topology_name, sizeof(met_topology) - 1);
1098 } else {
1099 device_remove_file(met_device.this_device, &dev_attr_core_topology);
1100 }
1101#endif
1102 return 0;
1103}
1104EXPORT_SYMBOL(met_set_topology);
1105
1106#include "met_struct.h"
1107
1108void force_sample(void *unused)
1109{
1110 int cpu;
1111 unsigned long long stamp;
1112 struct metdevice *c;
1113 struct met_cpu_struct *met_cpu_ptr;
1114
1115 if ((run != 1) || (sample_rate == 0))
1116 return;
1117
1118 /* to avoid met tag is coming after __met_hrtimer_stop and before run=-1 */
1119 met_cpu_ptr = this_cpu_ptr(&met_cpu);
1120 if (met_cpu_ptr->work_enabled == 0)
1121 return;
1122
1123 cpu = smp_processor_id();
1124
1125 stamp = cpu_clock(cpu);
1126
1127 list_for_each_entry(c, &met_list, list) {
1128 if (c->ondiemet_mode == 0) {
1129 if ((c->mode != 0) && (c->tagged_polling != NULL))
1130 c->tagged_polling(stamp, 0);
1131 } else if (c->ondiemet_mode == 1) {
1132 if ((c->mode != 0) && (c->ondiemet_tagged_polling != NULL))
1133 c->ondiemet_tagged_polling(stamp, 0);
1134 } else if (c->ondiemet_mode == 2) {
1135 if ((c->mode != 0) && (c->tagged_polling != NULL))
1136 c->tagged_polling(stamp, 0);
1137 if ((c->mode != 0) && (c->ondiemet_tagged_polling != NULL))
1138 c->ondiemet_tagged_polling(stamp, 0);
1139 }
1140 }
1141}
1142
1143#define MET_SUSPEND_HAND
1144#ifdef MET_SUSPEND_HAND
1145static struct syscore_ops met_hrtimer_ops = {
1146 .suspend = met_hrtimer_suspend,
1147 .resume = met_hrtimer_resume,
1148};
1149#endif
1150
1151int fs_reg(void)
1152{
1153 int ret = 0;
1154
1155 ctrl_flags = 0;
1156 met_mode = 0;
1157
1158#ifdef MET_SUSPEND_HAND
1159 /* suspend/resume function handle register */
1160 register_syscore_ops(&met_hrtimer_ops);
1161#endif
1162
1163 calc_timer_value(sample_rate);
1164
1165 ret = misc_register(&met_device);
1166 if (ret != 0) {
1167 pr_debug("misc register failed\n");
1168 return ret;
1169 }
1170
1171 /* dma map config */
1172 /* arch_setup_dma_ops(met_device.this_device, 0, 0, NULL, false); */
1173 met_arch_setup_dma_ops_symbol(met_device.this_device);
1174
1175 ret = device_create_file(met_device.this_device, &dev_attr_ksym);
1176 if (ret != 0) {
1177 pr_debug("can not create device file: ksym\n");
1178 return ret;
1179 }
1180
1181 ret = device_create_file(met_device.this_device, &dev_attr_run);
1182 if (ret != 0) {
1183 pr_debug("can not create device file: run\n");
1184 return ret;
1185 }
1186
1187#if defined(PR_CPU_NOTIFY)
1188 ret = device_create_file(met_device.this_device, &dev_attr_cpu_notify);
1189 if (ret != 0) {
1190 pr_debug("can not create device file: cpu_notify\n");
1191 return ret;
1192 }
1193#endif
1194
1195#ifdef CONFIG_CPU_FREQ
1196 ret = device_create_file(met_device.this_device, &dev_attr_dvfs);
1197 if (ret != 0) {
1198 pr_debug("can not create device file: dvfs\n");
1199 return ret;
1200 }
1201#endif
1202
1203 ret = device_create_file(met_device.this_device, &dev_attr_suspend_compensation_enable);
1204 if (ret != 0) {
1205 pr_debug("can not create device file: suspend_compensation_enable\n");
1206 return ret;
1207 }
1208
1209 ret = device_create_file(met_device.this_device, &dev_attr_suspend_compensation_flag);
1210 if (ret != 0) {
1211 pr_debug("can not create device file: suspend_compensation_enable\n");
1212 return ret;
1213 }
1214
1215 ret = device_create_file(met_device.this_device, &dev_attr_ver);
1216 if (ret != 0) {
1217 pr_debug("can not create device file: ver\n");
1218 return ret;
1219 }
1220
1221 ret = device_create_file(met_device.this_device, &dev_attr_devices);
1222 if (ret != 0) {
1223 pr_debug("can not create device file: devices\n");
1224 return ret;
1225 }
1226
1227 ret = device_create_file(met_device.this_device, &dev_attr_ctrl);
1228 if (ret != 0) {
1229 pr_debug("can not create device file: ctrl\n");
1230 return ret;
1231 }
1232
1233 ret = device_create_file(met_device.this_device, &dev_attr_cpu_pmu_method);
1234 if (ret != 0) {
1235 pr_debug("can not create device file: cpu_pmu_method\n");
1236 return ret;
1237 }
1238
1239#if defined(MET_BOOT_MSG)
1240 ret = device_create_file(met_device.this_device, &dev_attr_bootmsg);
1241 if (ret != 0) {
1242 pr_debug("can not create device file: bootmsg\n");
1243 return ret;
1244 }
1245#endif
1246
1247 ret = device_create_file(met_device.this_device, &dev_attr_sample_rate);
1248 if (ret != 0) {
1249 pr_debug("can not create device file: sample_rate\n");
1250 return ret;
1251 }
1252
1253 ret = device_create_file(met_device.this_device, &dev_attr_core_topology);
1254 if (ret != 0) {
1255 pr_debug("can not create device file: topology\n");
1256 return ret;
1257 }
1258
1259 ret = device_create_file(met_device.this_device, &dev_attr_plf);
1260 if (ret != 0) {
1261 pr_debug("can not create device file: plf\n");
1262 return ret;
1263 }
1264
1265 ret = device_create_file(met_device.this_device, &dev_attr_hash);
1266 if (ret != 0) {
1267 pr_debug("can not create device file: hash\n");
1268 return ret;
1269 }
1270
1271 ret = device_create_file(met_device.this_device, &dev_attr_ipi_test);
1272 if (ret != 0) {
1273 pr_debug("can not create device file: ipi_test\n");
1274 return ret;
1275 }
1276
1277 kobj_misc = kobject_create_and_add("misc", &met_device.this_device->kobj);
1278 if (kobj_misc == NULL) {
1279 pr_debug("can not create kobject: kobj_misc\n");
1280 return ret;
1281 }
1282
1283 kobj_pmu = kobject_create_and_add("pmu", &met_device.this_device->kobj);
1284 if (kobj_pmu == NULL) {
1285 pr_debug("can not create kobject: kobj_pmu\n");
1286 return ret;
1287 }
1288
1289 kobj_bus = kobject_create_and_add("bus", &met_device.this_device->kobj);
1290 if (kobj_bus == NULL) {
1291 pr_debug("can not create kobject: kobj_bus\n");
1292 return ret;
1293 }
1294
1295 met_register(&met_cookie);
1296 met_register(&met_cpupmu);
1297#ifdef MET_SUPPORT_CPUPMU_V2
1298 met_register(&met_cpupmu_v2);
1299#endif
1300#ifdef MET_USER_EVENT_SUPPORT
1301 tag_reg((struct file_operations * const) met_device.fops, &met_device.this_device->kobj);
1302#endif
1303
1304 ondiemet_log_manager_init(met_device.this_device);
1305 ondiemet_attr_init(met_device.this_device);
1306
1307 return ret;
1308}
1309
1310void fs_unreg(void)
1311{
1312 if (run == 1)
1313 met_stop();
1314
1315 run = -1;
1316
1317#ifdef MET_USER_EVENT_SUPPORT
1318 tag_unreg();
1319#endif
1320 met_deregister(&met_cpupmu);
1321#ifdef MET_SUPPORT_CPUPMU_V2
1322 met_deregister(&met_cpupmu_v2);
1323#endif
1324
1325 kobject_del(kobj_misc);
1326 kobject_put(kobj_misc);
1327 kobj_misc = NULL;
1328 kobject_del(kobj_pmu);
1329 kobject_put(kobj_pmu);
1330 kobj_pmu = NULL;
1331 kobject_del(kobj_bus);
1332 kobject_put(kobj_bus);
1333 kobj_bus = NULL;
1334
1335 device_remove_file(met_device.this_device, &dev_attr_ksym);
1336
1337 device_remove_file(met_device.this_device, &dev_attr_run);
1338#ifdef PR_CPU_NOTIFY
1339 device_remove_file(met_device.this_device, &dev_attr_cpu_notify);
1340#endif
1341#ifdef CONFIG_CPU_FREQ
1342 device_remove_file(met_device.this_device, &dev_attr_dvfs);
1343#endif
1344 device_remove_file(met_device.this_device, &dev_attr_suspend_compensation_enable);
1345 device_remove_file(met_device.this_device, &dev_attr_suspend_compensation_flag);
1346
1347 device_remove_file(met_device.this_device, &dev_attr_ver);
1348 device_remove_file(met_device.this_device, &dev_attr_devices);
1349 device_remove_file(met_device.this_device, &dev_attr_sample_rate);
1350
1351 device_remove_file(met_device.this_device, &dev_attr_ctrl);
1352 device_remove_file(met_device.this_device, &dev_attr_cpu_pmu_method);
1353
1354 device_remove_file(met_device.this_device, &dev_attr_core_topology);
1355 device_remove_file(met_device.this_device, &dev_attr_plf);
1356 device_remove_file(met_device.this_device, &dev_attr_hash);
1357 device_remove_file(met_device.this_device, &dev_attr_ipi_test);
1358
1359 ondiemet_log_manager_uninit(met_device.this_device);
1360 ondiemet_attr_uninit(met_device.this_device);
1361
1362 misc_deregister(&met_device);
1363#ifdef MET_SUSPEND_HAND
1364 /* suspend/resume function handle register */
1365 unregister_syscore_ops(&met_hrtimer_ops);
1366#endif
1367}
1368
1369unsigned int get_ctrl_flags(void)
1370{
1371 return ctrl_flags;
1372}