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