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