Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | #include <linux/kernel.h> |
2 | #include <linux/module.h> | |
3 | #include <linux/errno.h> | |
4 | #include <linux/trace_seq.h> | |
5 | #include <linux/ftrace_event.h> | |
6 | #include <linux/device.h> | |
7 | #include <linux/platform_device.h> | |
8 | #include <linux/vmalloc.h> | |
9 | ||
10 | ||
11 | #include "asm/hardware/cache-l2x0.h" | |
12 | #include "mach/mt_reg_base.h" | |
13 | #include "mach/sync_write.h" | |
14 | #include "mach/mt_emi_bm.h" | |
15 | //#include "mach/mt6573_pll.h" | |
16 | #include "mach/mt_mon.h" | |
17 | // FIX-ME mark for porting | |
18 | #include "mach/mt_dcm.h" | |
19 | //#include <../../kernel/kernel/trace/trace.h> | |
20 | #include <../../../kernel/trace/trace.h> | |
21 | #include <asm/io.h> | |
22 | ||
23 | #define MON_LOG_BUFF_LEN (64 * 1024) | |
24 | #define DEF_BM_RW_TYPE (BM_BOTH_READ_WRITE) | |
25 | ||
26 | static DECLARE_BITMAP(buf_bitmap, MON_LOG_BUFF_LEN); | |
27 | ||
28 | ||
29 | static unsigned int bm_master_evt = BM_MASTER_AP_MCU; | |
30 | static unsigned int bm_rw_type_evt = DEF_BM_RW_TYPE; | |
31 | ||
32 | static MonitorMode register_mode = MODE_FREE; | |
33 | static unsigned long mon_period_evt; | |
34 | static unsigned int mon_manual_evt; | |
35 | ||
36 | struct mt_mon_log *mt_mon_log_buff; //this buffer is allocated for MODE_MANUAL_USER & MODE_MANUAL_KERNEL only | |
37 | unsigned int mt_mon_log_buff_index; | |
38 | unsigned int mt_kernel_ring_buff_index; | |
39 | ||
40 | struct arm_pmu *p_pmu; | |
41 | struct mtk_monitor mtk_mon; | |
42 | ||
43 | //static DEFINE_SPINLOCK(mtk_monitor_lock); | |
44 | ||
45 | /* | |
46 | * mt65xx_mon_init: Initialize the monitor. | |
47 | * Return 0. | |
48 | */ | |
49 | static int mt65xx_mon_init(void) | |
50 | { | |
51 | BM_Init(); | |
52 | ||
53 | #if 0 | |
54 | // disable system DCM | |
55 | if (0 == BM_GetEmiDcm()) //0 means EMI dcm is enabled | |
56 | { | |
57 | printk("[MON] Disable system DCM\n"); | |
58 | dcm_disable(ALL_DCM); | |
59 | BM_SetEmiDcm(0xff); //disable EMI dcm | |
60 | } | |
61 | #endif | |
62 | return 0; | |
63 | } | |
64 | ||
65 | /* | |
66 | * mt65xx_mon_deinit: De-initialize the monitor. | |
67 | * Return 0. | |
68 | */ | |
69 | static int mt65xx_mon_deinit(void) | |
70 | { | |
71 | ||
72 | BM_DeInit(); | |
73 | ||
74 | /* | |
75 | if (mt_mon_log_buff) { | |
76 | vfree(mt_mon_log_buff); | |
77 | ||
78 | mt_mon_log_buff = 0; | |
79 | } | |
80 | */ | |
81 | #if 0 | |
82 | // enable system DCM | |
83 | if (1 == BM_GetEmiDcm()) //1 means EMI dcm is disabled | |
84 | { | |
85 | printk("[MON] Enable system DCM\n"); | |
86 | dcm_enable(ALL_DCM); | |
87 | BM_SetEmiDcm(0x0); //enable EMI dcm | |
88 | } | |
89 | #endif | |
90 | return 0; | |
91 | ||
92 | } | |
93 | ||
94 | /* | |
95 | * mt65xx_mon_enable: Enable hardware monitors. | |
96 | * Return 0. | |
97 | */ | |
98 | static int mt65xx_mon_enable(void) | |
99 | { | |
100 | ||
101 | p_pmu->reset(); | |
102 | ||
103 | // enable & start ARM performance monitors | |
104 | p_pmu->enable(); | |
105 | p_pmu->start(); | |
106 | ||
107 | // stopping EMI monitors will reset all counters | |
108 | BM_Enable(0); | |
109 | ||
110 | // start EMI monitor counting | |
111 | BM_Enable(1); | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | /* | |
117 | * mt65xx_mon_disable: Disable hardware monitors. | |
118 | * Return 0. | |
119 | */ | |
120 | static int mt65xx_mon_disable(void) | |
121 | { | |
122 | ||
123 | // disable ARM performance monitors | |
124 | p_pmu->stop(); | |
125 | ||
126 | BM_Pause(); | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | static inline void set_cpumask(unsigned int cpu, unsigned int index, volatile unsigned long *p) | |
132 | { | |
133 | unsigned long cpumask = 1UL << cpu; | |
134 | unsigned int offset = (index & 3) << 3; // (index % 4) * 8 | |
135 | ||
136 | p += (index >> 2); | |
137 | ||
138 | *p |= (cpumask << offset); | |
139 | } | |
140 | ||
141 | static inline void clear_bitmap(unsigned int bit, volatile unsigned long *p) | |
142 | { | |
143 | /* | |
144 | unsigned long mask = 1UL << (bit & 31); | |
145 | ||
146 | p += bit >> 5; | |
147 | ||
148 | *p &= ~mask; | |
149 | */ | |
150 | } | |
151 | ||
152 | static inline int get_cpumask(unsigned int index, volatile unsigned long *p) | |
153 | { | |
154 | unsigned int res; | |
155 | unsigned long offset = (index & 3) << 3; // (index % 4) * 8 | |
156 | ||
157 | p += (index >> 2); | |
158 | res = *p; | |
159 | res = (res >> offset) & 0x7; | |
160 | ||
161 | return res; | |
162 | } | |
163 | /* | |
164 | * mt65xx_mon_log: Get the current log from hardware monitors. | |
165 | * Return a index to the curret log entry in the log buffer. | |
166 | */ | |
167 | static unsigned int mt65xx_mon_log(void* log_buff) | |
168 | { | |
169 | struct mt_mon_log* mon_buff; | |
170 | struct pmu_data *pmu_data = & p_pmu->perf_data; | |
171 | unsigned int cpu = raw_smp_processor_id(); | |
172 | unsigned int cur = 0; | |
173 | ||
174 | p_pmu->read_counter(); | |
175 | ||
176 | ||
177 | /* In MODE_SCHED_SWITCH, we need to record the current CPU number to get the Context Switch CPU number. | |
178 | * | |
179 | * */ | |
180 | if( register_mode == MODE_MANUAL_USER || register_mode == MODE_MANUAL_KERNEL){ | |
181 | set_cpumask(cpu,cur,buf_bitmap); | |
182 | cur = mt_mon_log_buff_index++; | |
183 | mon_buff = &mt_mon_log_buff[cur]; | |
184 | mt_mon_log_buff_index %= MON_LOG_BUFF_LEN; | |
185 | }else { | |
186 | cur = mt_kernel_ring_buff_index++; | |
187 | mon_buff = (struct mt_mon_log*)log_buff; | |
188 | } | |
189 | ||
190 | if(mon_buff) | |
191 | { | |
192 | for_each_present_cpu(cpu){ | |
193 | mon_buff->cpu_cnt0[cpu] = pmu_data->cnt_val[cpu][0]; | |
194 | mon_buff->cpu_cnt1[cpu] = pmu_data->cnt_val[cpu][1]; | |
195 | mon_buff->cpu_cnt2[cpu] = pmu_data->cnt_val[cpu][2]; | |
196 | mon_buff->cpu_cnt3[cpu] = pmu_data->cnt_val[cpu][3]; | |
197 | mon_buff->cpu_cyc[cpu] = pmu_data->cnt_val[cpu][ARMV7_CYCLE_COUNTER]; | |
198 | } | |
199 | ||
200 | #if 1 | |
201 | mon_buff->BM_BCNT = BM_GetBusCycCount(); | |
202 | mon_buff->BM_TACT = BM_GetTransAllCount(); | |
203 | mon_buff->BM_TSCT = BM_GetTransCount(1); | |
204 | mon_buff->BM_WACT = BM_GetWordAllCount(); | |
205 | mon_buff->BM_WSCT = BM_GetWordCount(1); | |
206 | mon_buff->BM_BACT = BM_GetBandwidthWordCount(); | |
207 | mon_buff->BM_BSCT = BM_GetOverheadWordCount(); | |
208 | mon_buff->BM_TSCT2 = BM_GetTransCount(2); | |
209 | mon_buff->BM_WSCT2 = BM_GetWordCount(2); | |
210 | mon_buff->BM_TSCT3 = BM_GetTransCount(3); | |
211 | mon_buff->BM_WSCT3 = BM_GetWordCount(3); | |
212 | mon_buff->BM_WSCT4 = BM_GetWordCount(4); | |
213 | mon_buff->BM_TTYPE1 = BM_GetLatencyCycle(1); | |
214 | mon_buff->BM_TTYPE2 = BM_GetLatencyCycle(2); | |
215 | mon_buff->BM_TTYPE3 = BM_GetLatencyCycle(3); | |
216 | mon_buff->BM_TTYPE4 = BM_GetLatencyCycle(4); | |
217 | mon_buff->BM_TTYPE5 = BM_GetLatencyCycle(5); | |
218 | ||
219 | mon_buff->BM_TTYPE9 = BM_GetLatencyCycle(9); | |
220 | mon_buff->BM_TTYPE10 = BM_GetLatencyCycle(10); | |
221 | mon_buff->BM_TTYPE11 = BM_GetLatencyCycle(11); | |
222 | mon_buff->BM_TTYPE12 = BM_GetLatencyCycle(12); | |
223 | mon_buff->BM_TTYPE13 = BM_GetLatencyCycle(13); | |
224 | ||
225 | //mon_buff->BM_TPCT1 = BM_GetTransTypeCount(1); //not used now | |
226 | ||
227 | ||
228 | mon_buff->DRAMC_PageHit = DRAMC_GetPageHitCount(DRAMC_ALL); | |
229 | mon_buff->DRAMC_PageMiss = DRAMC_GetPageMissCount(DRAMC_ALL); | |
230 | mon_buff->DRAMC_Interbank = DRAMC_GetInterbankCount(DRAMC_ALL); | |
231 | mon_buff->DRAMC_Idle = DRAMC_GetIdleCount(); | |
232 | #endif | |
233 | } | |
234 | ||
235 | memset(pmu_data->cnt_val[0], 0, sizeof(struct pmu_data)); | |
236 | return cur; | |
237 | } | |
238 | ||
239 | extern unsigned int mt_get_emi_freq(void); | |
240 | ||
241 | enum print_line_t mt65xx_mon_print_entry(struct mt65xx_mon_entry *entry, struct trace_iterator *iter){ | |
242 | struct trace_seq *s = &iter->seq; | |
243 | int cpu = entry->cpu; | |
244 | struct mt_mon_log *log_entry; | |
245 | unsigned int log = 0; | |
246 | MonitorMode mon_mode_evt = get_mt65xx_mon_mode(); | |
247 | ||
248 | ||
249 | if(entry == NULL) | |
250 | return TRACE_TYPE_HANDLED; | |
251 | else{ | |
252 | log_entry = &entry->field; | |
253 | log = entry->log; | |
254 | } | |
255 | ||
256 | if (log == 0) { | |
257 | trace_seq_printf(s, "MON_LOG_BUFF_LEN = %d, ", MON_LOG_BUFF_LEN); | |
258 | trace_seq_printf(s, "EMI_CLOCK = %d, ", mt_get_emi_freq()); | |
259 | } | |
260 | ||
261 | if(mon_mode_evt != MODE_SCHED_SWITCH){ | |
262 | for_each_present_cpu(cpu) | |
263 | { | |
264 | trace_seq_printf( | |
265 | s, | |
266 | " cpu%d_cyc = %d, cpu%d_cnt0 = %d, cpu%d_cnt1 = %d, cpu%d_cnt2 = %d, cpu%d_cnt3 = %d, ", | |
267 | cpu, | |
268 | log_entry->cpu_cyc[cpu], | |
269 | cpu, | |
270 | log_entry->cpu_cnt0[cpu], | |
271 | cpu, | |
272 | log_entry->cpu_cnt1[cpu], | |
273 | cpu, | |
274 | log_entry->cpu_cnt2[cpu], | |
275 | cpu, | |
276 | log_entry->cpu_cnt3[cpu]); | |
277 | } | |
278 | } | |
279 | else /*SCHED_SWITCH - only print self cpu*/ | |
280 | { | |
281 | trace_seq_printf( | |
282 | s, | |
283 | " cpu%d_cyc = %d, cpu%d_cnt0 = %d, cpu%d_cnt1 = %d, cpu%d_cnt2 = %d, cpu%d_cnt3 = %d, ", | |
284 | cpu, | |
285 | log_entry->cpu_cyc[cpu], | |
286 | cpu, | |
287 | log_entry->cpu_cnt0[cpu], | |
288 | cpu, | |
289 | log_entry->cpu_cnt1[cpu], | |
290 | cpu, | |
291 | log_entry->cpu_cnt2[cpu], | |
292 | cpu, | |
293 | log_entry->cpu_cnt3[cpu]); | |
294 | } | |
295 | ||
296 | trace_seq_printf( | |
297 | s, | |
298 | "BM_BCNT = %d, BM_TACT = %d, BM_TSCT = %d, ", | |
299 | log_entry->BM_BCNT, | |
300 | log_entry->BM_TACT, | |
301 | log_entry->BM_TSCT); | |
302 | ||
303 | trace_seq_printf( | |
304 | s, | |
305 | "BM_WACT = %d, BM_WSCT0 = %d, BM_BACT = %d, ", | |
306 | log_entry->BM_WACT, | |
307 | log_entry->BM_WSCT, | |
308 | log_entry->BM_BACT); | |
309 | ||
310 | trace_seq_printf( | |
311 | s, | |
312 | "BM_BSCT = %d, ", | |
313 | log_entry->BM_BSCT); | |
314 | ||
315 | trace_seq_printf( | |
316 | s, | |
317 | "BM_TSCT2 = %d, BM_WSCT2 = %d, ", | |
318 | log_entry->BM_TSCT2, | |
319 | log_entry->BM_WSCT2); | |
320 | ||
321 | trace_seq_printf( | |
322 | s, | |
323 | "BM_TSCT3 = %d, BM_WSCT3 = %d, ", | |
324 | log_entry->BM_TSCT3, | |
325 | log_entry->BM_WSCT3); | |
326 | ||
327 | trace_seq_printf( | |
328 | s, | |
329 | "BM_WSCT4 = %d, BM_TPCT1 = %d, ", | |
330 | log_entry->BM_WSCT4, | |
331 | log_entry->BM_TPCT1); | |
332 | ||
333 | trace_seq_printf( | |
334 | s, | |
335 | "BM_TTYPE01 = %d, BM_TTYPE09 = %d, ", | |
336 | log_entry->BM_TTYPE1, log_entry->BM_TTYPE9); | |
337 | ||
338 | trace_seq_printf( | |
339 | s, | |
340 | "BM_TTYPE02 = %d, BM_TTYPE10 = %d, ", | |
341 | log_entry->BM_TTYPE2, log_entry->BM_TTYPE10); | |
342 | ||
343 | trace_seq_printf( | |
344 | s, | |
345 | "BM_TTYPE03 = %d, BM_TTYPE11 = %d, ", | |
346 | log_entry->BM_TTYPE3, log_entry->BM_TTYPE11); | |
347 | ||
348 | trace_seq_printf( | |
349 | s, | |
350 | "BM_TTYPE04 = %d, BM_TTYPE12 = %d, ", | |
351 | log_entry->BM_TTYPE4, log_entry->BM_TTYPE12); | |
352 | ||
353 | trace_seq_printf( | |
354 | s, | |
355 | "BM_TTYPE05 = %d, BM_TTYPE13 = %d, ", | |
356 | log_entry->BM_TTYPE5, log_entry->BM_TTYPE13); | |
357 | ||
358 | trace_seq_printf( | |
359 | s, | |
360 | "DRAMC_PageHit = %d, DRAMC_PageMiss = %d, DRAMC_Interbank = %d, DRAMC_Idle = %d\n", | |
361 | log_entry->DRAMC_PageHit, | |
362 | log_entry->DRAMC_PageMiss, | |
363 | log_entry->DRAMC_Interbank, | |
364 | log_entry->DRAMC_Idle); | |
365 | ||
366 | return 0; | |
367 | } | |
368 | ||
369 | static void mt65xx_mon_set_pmu(struct pmu_cfg *p_cfg) | |
370 | { | |
371 | memcpy(&p_pmu->perf_cfg, p_cfg, sizeof(struct pmu_cfg)); | |
372 | } | |
373 | ||
374 | static void mt65xx_mon_get_pmu(struct pmu_cfg *p_cfg) | |
375 | { | |
376 | memcpy(p_cfg, &p_pmu->perf_cfg, sizeof(struct pmu_cfg)); | |
377 | } | |
378 | ||
379 | static void mt65xx_mon_set_l2c(struct l2c_cfg *l_cfg) | |
380 | { | |
381 | } | |
382 | ||
383 | static void mt65xx_mon_get_l2c(struct l2c_cfg *l_cfg) | |
384 | { | |
385 | } | |
386 | ||
387 | static void mt65xx_mon_set_bm_rw(int type) | |
388 | { | |
389 | ||
390 | if(type > BM_WRITE_ONLY) { | |
391 | printk("invalid event\n"); | |
392 | } else { | |
393 | BM_SetReadWriteType(type); | |
394 | } | |
395 | ||
396 | } | |
397 | ||
398 | static ssize_t bm_master_evt_show(struct device_driver *driver, char *buf) | |
399 | { | |
400 | return snprintf(buf, PAGE_SIZE, "EMI bus monitor master = %d\n", bm_master_evt); | |
401 | } | |
402 | ||
403 | static ssize_t bm_master_evt_store(struct device_driver *driver, const char *buf, size_t count) | |
404 | { | |
405 | if (!strncmp(buf, "MM", strlen("MM"))) { | |
406 | bm_master_evt = BM_MASTER_MM; | |
407 | }else if (!strncmp(buf, "APMCU", strlen("APMCU"))) { | |
408 | bm_master_evt = BM_MASTER_AP_MCU; | |
409 | }else if (!strncmp(buf, "MDMCU", strlen("MDMCU"))) { | |
410 | bm_master_evt = BM_MASTER_MD_MCU; | |
411 | }else if (!strncmp(buf, "2G_3G_MDDMA", strlen("2G_3G_MDDMA"))) { | |
412 | bm_master_evt = BM_MASTER_2G_3G_MDDMA; | |
413 | }else if (!strncmp(buf, "MD_ALL", strlen("MD_ALL"))) { | |
414 | bm_master_evt = BM_MASTER_MD_MCU | BM_MASTER_2G_3G_MDDMA; | |
415 | }else if (!strncmp(buf, "PERI", strlen("PERI"))) { | |
416 | bm_master_evt = BM_MASTER_PERI; | |
417 | }else if (!strncmp(buf, "ALL", strlen("ALL"))) { | |
418 | bm_master_evt = BM_MASTER_ALL; | |
419 | }else { | |
420 | printk("invalid event\n"); | |
421 | ||
422 | return count; | |
423 | } | |
424 | ||
425 | BM_SetMaster(1, bm_master_evt); | |
426 | ||
427 | return count; | |
428 | } | |
429 | ||
430 | static ssize_t bm_rw_type_evt_show(struct device_driver *driver, char *buf) | |
431 | { | |
432 | return snprintf(buf, PAGE_SIZE, "EMI bus read write type = %d\n", bm_rw_type_evt); | |
433 | } | |
434 | ||
435 | static ssize_t bm_rw_type_evt_store(struct device_driver *driver, const char *buf, size_t count) | |
436 | { | |
437 | if (!strncmp(buf, "RW", strlen("RW"))) { | |
438 | bm_rw_type_evt = BM_BOTH_READ_WRITE; | |
439 | } else if (!strncmp(buf, "RO", strlen("RO"))) { | |
440 | bm_rw_type_evt = BM_READ_ONLY; | |
441 | } else if (!strncmp(buf, "WO", strlen("WO"))) { | |
442 | bm_rw_type_evt = BM_WRITE_ONLY; | |
443 | } else { | |
444 | printk("invalid event\n"); | |
445 | return count; | |
446 | } | |
447 | ||
448 | BM_SetReadWriteType(bm_rw_type_evt); | |
449 | ||
450 | return count; | |
451 | } | |
452 | ||
453 | static ssize_t mon_mode_evt_show(struct device_driver *driver, char *buf) | |
454 | { | |
455 | MonitorMode mon_mode_evt; | |
456 | mon_mode_evt = get_mt65xx_mon_mode(); | |
457 | if(mon_mode_evt == MODE_MANUAL_USER) | |
458 | return snprintf(buf, PAGE_SIZE, "Monitor mode = MANUAL_USER\n"); | |
459 | else if(mon_mode_evt == MODE_SCHED_SWITCH) | |
460 | return snprintf(buf, PAGE_SIZE, "Monitor mode = SCHED_SWITCH\n"); | |
461 | else if(mon_mode_evt == MODE_PERIODIC) | |
462 | return snprintf(buf, PAGE_SIZE, "Monitor mode = PERIODIC\n"); | |
463 | else if(mon_mode_evt == MODE_MANUAL_TRACER) | |
464 | return snprintf(buf, PAGE_SIZE, "Monitor mode = MANUAL_TRACER\n"); | |
465 | else if(mon_mode_evt == MODE_MANUAL_KERNEL) | |
466 | return snprintf(buf, PAGE_SIZE, "Monitor mode = MANUAL_KERNEL\n"); | |
467 | else if(mon_mode_evt == MODE_FREE) | |
468 | return snprintf(buf, PAGE_SIZE, "Monitor mode = FREE\n"); | |
469 | else | |
470 | return snprintf(buf, PAGE_SIZE, "Monitor mode = Unknown\n"); | |
471 | } | |
472 | ||
473 | static ssize_t mon_mode_evt_store(struct device_driver *driver, const char *buf, size_t count) | |
474 | { | |
475 | MonitorMode mon_mode_evt; | |
476 | if (!strncmp(buf, "SCHED_SWITCH", strlen("SCHED_SWITCH"))) { | |
477 | mon_mode_evt = MODE_SCHED_SWITCH; | |
478 | } else if (!strncmp(buf, "PERIODIC", strlen("PERIODIC"))) { | |
479 | mon_mode_evt = MODE_PERIODIC; | |
480 | } else if (!strncmp(buf, "MANUAL_TRACER", strlen("MANUAL_TRACER"))) { | |
481 | mon_mode_evt = MODE_MANUAL_TRACER; | |
482 | } else { | |
483 | printk("invalid event\n"); | |
484 | return count; | |
485 | } | |
486 | ||
487 | set_mt65xx_mon_mode(mon_mode_evt); | |
488 | ||
489 | return count; | |
490 | } | |
491 | ||
492 | static ssize_t mon_period_evt_show(struct device_driver *driver, char *buf) | |
493 | { | |
494 | return snprintf(buf, PAGE_SIZE, "Monitor period = %ld (for periodic mode)\n", get_mt65xx_mon_period()); | |
495 | } | |
496 | ||
497 | static ssize_t mon_period_evt_store(struct device_driver *driver, const char *buf, size_t count) | |
498 | { | |
499 | ||
500 | sscanf(buf, "%ld", &mon_period_evt); | |
501 | set_mt65xx_mon_period(mon_period_evt); | |
502 | ||
503 | return count; | |
504 | } | |
505 | ||
506 | static ssize_t mon_manual_evt_show(struct device_driver *driver, char *buf) | |
507 | { | |
508 | mon_manual_evt = get_mt65xx_mon_manual_start(); | |
509 | if(mon_manual_evt == 1) | |
510 | return snprintf(buf, PAGE_SIZE, "Manual Monitor is Started (for manual mode)\n"); | |
511 | else if(mon_manual_evt == 0) | |
512 | return snprintf(buf, PAGE_SIZE, "Manual Monitor is Stopped (for manual mode)\n"); | |
513 | else | |
514 | return 0; | |
515 | } | |
516 | ||
517 | static ssize_t mon_manual_evt_store(struct device_driver *driver, const char *buf, size_t count) | |
518 | { | |
519 | ||
520 | if (!strncmp(buf, "START", strlen("START"))) { | |
521 | mon_manual_evt = 1; | |
522 | } else if (!strncmp(buf, "STOP", strlen("STOP"))) { | |
523 | mon_manual_evt = 0; | |
524 | } else { | |
525 | printk("invalid event\n"); | |
526 | return count; | |
527 | } | |
528 | ||
529 | set_mt65xx_mon_manual_start(mon_manual_evt); | |
530 | ||
531 | return count; | |
532 | } | |
533 | ||
534 | static ssize_t cpu_pmu_evt_show(struct device_driver *driver, char *buf) | |
535 | { | |
536 | ||
537 | u32 j; | |
538 | int size = 0; | |
539 | ||
540 | if(p_pmu == NULL) { | |
541 | printk("PMU user interface isn't ready now!\n"); | |
542 | return 0; | |
543 | } | |
544 | ||
545 | for(j = 0; j < NUMBER_OF_EVENT; j++) { | |
546 | size += sprintf(buf + size, "Evt%d = 0x%x\t", j, p_pmu->perf_cfg.event_cfg[j]); | |
547 | } | |
548 | size += sprintf(buf + size, "\n"); | |
549 | ||
550 | return (size); | |
551 | } | |
552 | ||
553 | static ssize_t cpu_pmu_evt_store(struct device_driver *driver, const char *buf, size_t count) | |
554 | { | |
555 | ||
556 | char *p = (char *)buf; | |
557 | char *token[8]; | |
558 | char *ptr; | |
559 | int i = 0; | |
560 | ||
561 | if((strlen(buf)+1) > 128) | |
562 | { | |
563 | printk("[PMU] command overflow!"); | |
564 | return -1; | |
565 | } | |
566 | ||
567 | do{ | |
568 | ptr = strsep (&p, " "); | |
569 | token[i] = ptr; | |
570 | i++; | |
571 | }while(ptr != NULL); | |
572 | ||
573 | //because we use i to count num of evt setting, i is NUMBER_OF_EVENT+1 | |
574 | if(i != (NUMBER_OF_EVENT+1)){ | |
575 | printk("[PMU]The number of parameter is wrong!!! Please echo "); | |
576 | for(i = 0; i < NUMBER_OF_EVENT; i++) | |
577 | printk("Evt%d ",i); | |
578 | printk("> cpu_pmu_cfg\n"); | |
579 | return -1; | |
580 | } | |
581 | ||
582 | ||
583 | for(i = 0; i < NUMBER_OF_EVENT; i++) | |
584 | p_pmu->perf_cfg.event_cfg[i] = simple_strtoul(token[i], &token[i], 16); | |
585 | ||
586 | ||
587 | for(i=0; i<NUMBER_OF_EVENT; i++) | |
588 | printk("%x ",p_pmu->perf_cfg.event_cfg[i]); | |
589 | printk("\n"); | |
590 | p_pmu->enable(); | |
591 | ||
592 | return count; | |
593 | ||
594 | } | |
595 | ||
596 | static ssize_t emi_dcm_ctrl_show(struct device_driver *driver, char *buf) | |
597 | { | |
598 | return snprintf(buf, PAGE_SIZE, "EMI DCM is %s\n", BM_GetEmiDcm() ? "OFF" : "ON"); | |
599 | } | |
600 | ||
601 | static ssize_t emi_dcm_ctrl_store(struct device_driver *driver, const char *buf, size_t count) | |
602 | { | |
603 | if (!strncmp(buf, "OFF", strlen("OFF"))) { | |
604 | BM_SetEmiDcm(0xff); | |
605 | } else if (!strncmp(buf, "ON", strlen("ON"))) { | |
606 | BM_SetEmiDcm(0x0); | |
607 | } else { | |
608 | printk("invalid event\n"); | |
609 | } | |
610 | ||
611 | return count; | |
612 | } | |
613 | ||
614 | #if 0 | |
615 | static ssize_t mci_evt_show(struct device_driver *driver, char *buf) | |
616 | { | |
617 | MCI_Event_Read(); | |
618 | return; | |
619 | } | |
620 | ||
621 | ssize_t mci_evt_store(struct device_driver *driver, const char *buf, size_t count) | |
622 | { | |
623 | unsigned int evt0, evt1; | |
624 | if (sscanf(buf, "%x %x", &evt0, &evt1) != 2) | |
625 | return -EINVAL; | |
626 | MCI_Event_Set(evt0, evt1); | |
627 | ||
628 | return count; | |
629 | } | |
630 | #endif | |
631 | ||
632 | DRIVER_ATTR(bm_master_evt, 0644, bm_master_evt_show, bm_master_evt_store); | |
633 | DRIVER_ATTR(bm_rw_type_evt, 0644, bm_rw_type_evt_show, bm_rw_type_evt_store); | |
634 | ||
635 | DRIVER_ATTR(mon_mode_evt, 0644, mon_mode_evt_show, mon_mode_evt_store); | |
636 | DRIVER_ATTR(mon_period_evt, 0644, mon_period_evt_show, mon_period_evt_store); | |
637 | DRIVER_ATTR(mon_manual_evt, 0644, mon_manual_evt_show, mon_manual_evt_store); | |
638 | ||
639 | DRIVER_ATTR(cpu_pmu_cfg, 0644, cpu_pmu_evt_show, cpu_pmu_evt_store); | |
640 | DRIVER_ATTR(emi_dcm_ctrl, 0644, emi_dcm_ctrl_show, emi_dcm_ctrl_store); | |
641 | ||
642 | //DRIVER_ATTR(mci_evt, 0644, mci_evt_show, mci_evt_store); | |
643 | ||
644 | ||
645 | static struct device_driver mt_mon_drv = | |
646 | { | |
647 | .name = "mt_monitor", | |
648 | .bus = &platform_bus_type, | |
649 | .owner = THIS_MODULE, | |
650 | }; | |
651 | ||
652 | ||
653 | struct mtk_monitor mtk_mon = { | |
654 | .init = mt65xx_mon_init, | |
655 | .deinit = mt65xx_mon_deinit, | |
656 | .enable = mt65xx_mon_enable, | |
657 | .disable = mt65xx_mon_disable, | |
658 | .mon_log = mt65xx_mon_log, | |
659 | .set_pmu = mt65xx_mon_set_pmu, | |
660 | .get_pmu = mt65xx_mon_get_pmu, | |
661 | .set_l2c = mt65xx_mon_set_l2c, | |
662 | .get_l2c = mt65xx_mon_get_l2c, | |
663 | .set_bm_rw = mt65xx_mon_set_bm_rw, | |
664 | }; | |
665 | ||
666 | /* | |
667 | * mt_mon_mod_init: module init function | |
668 | */ | |
669 | static int __init mt_mon_mod_init(void) | |
670 | { | |
671 | int ret; | |
672 | ||
673 | /* register driver and create sysfs files */ | |
674 | ret = driver_register(&mt_mon_drv); | |
675 | ||
676 | if (ret) { | |
677 | printk("fail to register mt_mon_drv\n"); | |
678 | return ret; | |
679 | } | |
680 | ret = driver_create_file(&mt_mon_drv, &driver_attr_bm_master_evt); | |
681 | ret |= driver_create_file(&mt_mon_drv, &driver_attr_bm_rw_type_evt); | |
682 | ret |= driver_create_file(&mt_mon_drv, &driver_attr_mon_mode_evt); | |
683 | ret |= driver_create_file(&mt_mon_drv, &driver_attr_mon_period_evt); | |
684 | ret |= driver_create_file(&mt_mon_drv, &driver_attr_mon_manual_evt); | |
685 | ret |= driver_create_file(&mt_mon_drv, &driver_attr_cpu_pmu_cfg); | |
686 | ret |= driver_create_file(&mt_mon_drv, &driver_attr_emi_dcm_ctrl); | |
687 | // ret |= driver_create_file(&mt_mon_drv, &driver_attr_mci_evt); | |
688 | ||
689 | if (ret) { | |
690 | printk("fail to create mt_mon sysfs files\n"); | |
691 | ||
692 | return ret; | |
693 | } | |
694 | ||
695 | /* SPNIDEN[12] must be 1 for using ARM11 performance monitor unit */ | |
696 | // *(volatile unsigned int *)0xF702A000 |= 0x1000; | |
697 | ||
698 | ||
699 | ret = register_pmu(&p_pmu); | |
700 | if(ret != 0 || p_pmu == NULL) { | |
701 | printk("Register PMU Fail\n"); | |
702 | return ret; | |
703 | } | |
704 | ||
705 | ||
706 | /* init EMI bus monitor */ | |
707 | BM_SetReadWriteType(DEF_BM_RW_TYPE); | |
708 | BM_SetMonitorCounter(1, BM_MASTER_MM, BM_TRANS_TYPE_4BEAT | BM_TRANS_TYPE_8Byte | BM_TRANS_TYPE_BURST_WRAP); | |
709 | BM_SetMonitorCounter(2, BM_MASTER_AP_MCU, BM_TRANS_TYPE_4BEAT | BM_TRANS_TYPE_8Byte | BM_TRANS_TYPE_BURST_WRAP); | |
710 | BM_SetMonitorCounter(3, BM_MASTER_MD_MCU | BM_MASTER_2G_3G_MDDMA, BM_TRANS_TYPE_4BEAT | BM_TRANS_TYPE_8Byte | BM_TRANS_TYPE_BURST_WRAP); | |
711 | BM_SetMonitorCounter(4, BM_MASTER_PERI, BM_TRANS_TYPE_4BEAT | BM_TRANS_TYPE_8Byte | BM_TRANS_TYPE_BURST_WRAP); | |
712 | ||
713 | BM_SetLatencyCounter(); | |
714 | ||
715 | /*select MCI monitor event*/ | |
716 | //MCI_Event_Set(0x6, 0x7); /*0x6: Si0 AR input queue full; 0x7: Si0 AW input queue full*/ | |
717 | ||
718 | return 0; | |
719 | } | |
720 | ||
721 | arch_initcall (mt_mon_mod_init); | |
722 | ||
723 | static DEFINE_SPINLOCK(reg_mon_lock); | |
724 | int register_monitor(struct mtk_monitor **p_mon, MonitorMode mode) | |
725 | { | |
726 | int ret = 0; | |
727 | ||
728 | spin_lock(®_mon_lock); | |
729 | ||
730 | mt_kernel_ring_buff_index = 0; | |
731 | mt_mon_log_buff_index = 0; | |
732 | ||
733 | if(register_mode != MODE_FREE) { | |
734 | goto _err; | |
735 | } else { | |
736 | register_mode = mode; | |
737 | *p_mon = &mtk_mon; | |
738 | } | |
739 | ||
740 | if(mode == MODE_MANUAL_USER || mode == MODE_MANUAL_KERNEL) { | |
741 | if (!mt_mon_log_buff) { | |
742 | mt_mon_log_buff = vmalloc(sizeof(struct mt_mon_log) * MON_LOG_BUFF_LEN); | |
743 | if (!mt_mon_log_buff) { | |
744 | printk(KERN_WARNING "fail to allocate the buffer for the monitor log\n"); | |
745 | register_mode = MODE_FREE; | |
746 | goto _err; | |
747 | } | |
748 | mtk_mon.log_buff = mt_mon_log_buff; | |
749 | } | |
750 | } | |
751 | ||
752 | if(mode == MODE_SCHED_SWITCH) | |
753 | p_pmu->multicore = 0; | |
754 | else | |
755 | p_pmu->multicore = 1; | |
756 | ||
757 | spin_unlock(®_mon_lock); | |
758 | ||
759 | return ret; | |
760 | ||
761 | _err: | |
762 | p_mon = NULL; | |
763 | spin_unlock(®_mon_lock); | |
764 | return -1; | |
765 | } | |
766 | EXPORT_SYMBOL(register_monitor); | |
767 | ||
768 | void unregister_monitor(struct mtk_monitor **p_mon) | |
769 | { | |
770 | ||
771 | spin_lock(®_mon_lock); | |
772 | ||
773 | if(mt_mon_log_buff) { | |
774 | vfree(mt_mon_log_buff); | |
775 | mt_mon_log_buff = NULL; | |
776 | } | |
777 | ||
778 | register_mode = MODE_FREE; | |
779 | *p_mon = NULL; | |
780 | ||
781 | mt_kernel_ring_buff_index = 0; | |
782 | mt_mon_log_buff_index = 0; | |
783 | spin_unlock(®_mon_lock); | |
784 | } | |
785 | EXPORT_SYMBOL(unregister_monitor); |