~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/csky/kernel/perf_event.c

Version: ~ [ linux-5.1-rc2 ] ~ [ linux-5.0.4 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.31 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.108 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.165 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.177 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.137 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.63 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
  3 
  4 #include <linux/errno.h>
  5 #include <linux/interrupt.h>
  6 #include <linux/module.h>
  7 #include <linux/of.h>
  8 #include <linux/perf_event.h>
  9 #include <linux/platform_device.h>
 10 
 11 #define CSKY_PMU_MAX_EVENTS 32
 12 
 13 #define HPCR            "<0, 0x0>"      /* PMU Control reg */
 14 #define HPCNTENR        "<0, 0x4>"      /* Count Enable reg */
 15 
 16 static uint64_t (*hw_raw_read_mapping[CSKY_PMU_MAX_EVENTS])(void);
 17 static void (*hw_raw_write_mapping[CSKY_PMU_MAX_EVENTS])(uint64_t val);
 18 
 19 struct csky_pmu_t {
 20         struct pmu      pmu;
 21         uint32_t        hpcr;
 22 } csky_pmu;
 23 
 24 #define cprgr(reg)                              \
 25 ({                                              \
 26         unsigned int tmp;                       \
 27         asm volatile("cprgr %0, "reg"\n"        \
 28                      : "=r"(tmp)                \
 29                      :                          \
 30                      : "memory");               \
 31         tmp;                                    \
 32 })
 33 
 34 #define cpwgr(reg, val)         \
 35 ({                              \
 36         asm volatile(           \
 37         "cpwgr %0, "reg"\n"     \
 38         :                       \
 39         : "r"(val)              \
 40         : "memory");            \
 41 })
 42 
 43 #define cprcr(reg)                              \
 44 ({                                              \
 45         unsigned int tmp;                       \
 46         asm volatile("cprcr %0, "reg"\n"        \
 47                      : "=r"(tmp)                \
 48                      :                          \
 49                      : "memory");               \
 50         tmp;                                    \
 51 })
 52 
 53 #define cpwcr(reg, val)         \
 54 ({                              \
 55         asm volatile(           \
 56         "cpwcr %0, "reg"\n"     \
 57         :                       \
 58         : "r"(val)              \
 59         : "memory");            \
 60 })
 61 
 62 /* cycle counter */
 63 static uint64_t csky_pmu_read_cc(void)
 64 {
 65         uint32_t lo, hi, tmp;
 66         uint64_t result;
 67 
 68         do {
 69                 tmp = cprgr("<0, 0x3>");
 70                 lo  = cprgr("<0, 0x2>");
 71                 hi  = cprgr("<0, 0x3>");
 72         } while (hi != tmp);
 73 
 74         result = (uint64_t) (hi) << 32;
 75         result |= lo;
 76 
 77         return result;
 78 }
 79 
 80 static void csky_pmu_write_cc(uint64_t val)
 81 {
 82         cpwgr("<0, 0x2>", (uint32_t)  val);
 83         cpwgr("<0, 0x3>", (uint32_t) (val >> 32));
 84 }
 85 
 86 /* instruction counter */
 87 static uint64_t csky_pmu_read_ic(void)
 88 {
 89         uint32_t lo, hi, tmp;
 90         uint64_t result;
 91 
 92         do {
 93                 tmp = cprgr("<0, 0x5>");
 94                 lo  = cprgr("<0, 0x4>");
 95                 hi  = cprgr("<0, 0x5>");
 96         } while (hi != tmp);
 97 
 98         result = (uint64_t) (hi) << 32;
 99         result |= lo;
100 
101         return result;
102 }
103 
104 static void csky_pmu_write_ic(uint64_t val)
105 {
106         cpwgr("<0, 0x4>", (uint32_t)  val);
107         cpwgr("<0, 0x5>", (uint32_t) (val >> 32));
108 }
109 
110 /* l1 icache access counter */
111 static uint64_t csky_pmu_read_icac(void)
112 {
113         uint32_t lo, hi, tmp;
114         uint64_t result;
115 
116         do {
117                 tmp = cprgr("<0, 0x7>");
118                 lo  = cprgr("<0, 0x6>");
119                 hi  = cprgr("<0, 0x7>");
120         } while (hi != tmp);
121 
122         result = (uint64_t) (hi) << 32;
123         result |= lo;
124 
125         return result;
126 }
127 
128 static void csky_pmu_write_icac(uint64_t val)
129 {
130         cpwgr("<0, 0x6>", (uint32_t)  val);
131         cpwgr("<0, 0x7>", (uint32_t) (val >> 32));
132 }
133 
134 /* l1 icache miss counter */
135 static uint64_t csky_pmu_read_icmc(void)
136 {
137         uint32_t lo, hi, tmp;
138         uint64_t result;
139 
140         do {
141                 tmp = cprgr("<0, 0x9>");
142                 lo  = cprgr("<0, 0x8>");
143                 hi  = cprgr("<0, 0x9>");
144         } while (hi != tmp);
145 
146         result = (uint64_t) (hi) << 32;
147         result |= lo;
148 
149         return result;
150 }
151 
152 static void csky_pmu_write_icmc(uint64_t val)
153 {
154         cpwgr("<0, 0x8>", (uint32_t)  val);
155         cpwgr("<0, 0x9>", (uint32_t) (val >> 32));
156 }
157 
158 /* l1 dcache access counter */
159 static uint64_t csky_pmu_read_dcac(void)
160 {
161         uint32_t lo, hi, tmp;
162         uint64_t result;
163 
164         do {
165                 tmp = cprgr("<0, 0xb>");
166                 lo  = cprgr("<0, 0xa>");
167                 hi  = cprgr("<0, 0xb>");
168         } while (hi != tmp);
169 
170         result = (uint64_t) (hi) << 32;
171         result |= lo;
172 
173         return result;
174 }
175 
176 static void csky_pmu_write_dcac(uint64_t val)
177 {
178         cpwgr("<0, 0xa>", (uint32_t)  val);
179         cpwgr("<0, 0xb>", (uint32_t) (val >> 32));
180 }
181 
182 /* l1 dcache miss counter */
183 static uint64_t csky_pmu_read_dcmc(void)
184 {
185         uint32_t lo, hi, tmp;
186         uint64_t result;
187 
188         do {
189                 tmp = cprgr("<0, 0xd>");
190                 lo  = cprgr("<0, 0xc>");
191                 hi  = cprgr("<0, 0xd>");
192         } while (hi != tmp);
193 
194         result = (uint64_t) (hi) << 32;
195         result |= lo;
196 
197         return result;
198 }
199 
200 static void csky_pmu_write_dcmc(uint64_t val)
201 {
202         cpwgr("<0, 0xc>", (uint32_t)  val);
203         cpwgr("<0, 0xd>", (uint32_t) (val >> 32));
204 }
205 
206 /* l2 cache access counter */
207 static uint64_t csky_pmu_read_l2ac(void)
208 {
209         uint32_t lo, hi, tmp;
210         uint64_t result;
211 
212         do {
213                 tmp = cprgr("<0, 0xf>");
214                 lo  = cprgr("<0, 0xe>");
215                 hi  = cprgr("<0, 0xf>");
216         } while (hi != tmp);
217 
218         result = (uint64_t) (hi) << 32;
219         result |= lo;
220 
221         return result;
222 }
223 
224 static void csky_pmu_write_l2ac(uint64_t val)
225 {
226         cpwgr("<0, 0xe>", (uint32_t)  val);
227         cpwgr("<0, 0xf>", (uint32_t) (val >> 32));
228 }
229 
230 /* l2 cache miss counter */
231 static uint64_t csky_pmu_read_l2mc(void)
232 {
233         uint32_t lo, hi, tmp;
234         uint64_t result;
235 
236         do {
237                 tmp = cprgr("<0, 0x11>");
238                 lo  = cprgr("<0, 0x10>");
239                 hi  = cprgr("<0, 0x11>");
240         } while (hi != tmp);
241 
242         result = (uint64_t) (hi) << 32;
243         result |= lo;
244 
245         return result;
246 }
247 
248 static void csky_pmu_write_l2mc(uint64_t val)
249 {
250         cpwgr("<0, 0x10>", (uint32_t)  val);
251         cpwgr("<0, 0x11>", (uint32_t) (val >> 32));
252 }
253 
254 /* I-UTLB miss counter */
255 static uint64_t csky_pmu_read_iutlbmc(void)
256 {
257         uint32_t lo, hi, tmp;
258         uint64_t result;
259 
260         do {
261                 tmp = cprgr("<0, 0x15>");
262                 lo  = cprgr("<0, 0x14>");
263                 hi  = cprgr("<0, 0x15>");
264         } while (hi != tmp);
265 
266         result = (uint64_t) (hi) << 32;
267         result |= lo;
268 
269         return result;
270 }
271 
272 static void csky_pmu_write_iutlbmc(uint64_t val)
273 {
274         cpwgr("<0, 0x14>", (uint32_t)  val);
275         cpwgr("<0, 0x15>", (uint32_t) (val >> 32));
276 }
277 
278 /* D-UTLB miss counter */
279 static uint64_t csky_pmu_read_dutlbmc(void)
280 {
281         uint32_t lo, hi, tmp;
282         uint64_t result;
283 
284         do {
285                 tmp = cprgr("<0, 0x17>");
286                 lo  = cprgr("<0, 0x16>");
287                 hi  = cprgr("<0, 0x17>");
288         } while (hi != tmp);
289 
290         result = (uint64_t) (hi) << 32;
291         result |= lo;
292 
293         return result;
294 }
295 
296 static void csky_pmu_write_dutlbmc(uint64_t val)
297 {
298         cpwgr("<0, 0x16>", (uint32_t)  val);
299         cpwgr("<0, 0x17>", (uint32_t) (val >> 32));
300 }
301 
302 /* JTLB miss counter */
303 static uint64_t csky_pmu_read_jtlbmc(void)
304 {
305         uint32_t lo, hi, tmp;
306         uint64_t result;
307 
308         do {
309                 tmp = cprgr("<0, 0x19>");
310                 lo  = cprgr("<0, 0x18>");
311                 hi  = cprgr("<0, 0x19>");
312         } while (hi != tmp);
313 
314         result = (uint64_t) (hi) << 32;
315         result |= lo;
316 
317         return result;
318 }
319 
320 static void csky_pmu_write_jtlbmc(uint64_t val)
321 {
322         cpwgr("<0, 0x18>", (uint32_t)  val);
323         cpwgr("<0, 0x19>", (uint32_t) (val >> 32));
324 }
325 
326 /* software counter */
327 static uint64_t csky_pmu_read_softc(void)
328 {
329         uint32_t lo, hi, tmp;
330         uint64_t result;
331 
332         do {
333                 tmp = cprgr("<0, 0x1b>");
334                 lo  = cprgr("<0, 0x1a>");
335                 hi  = cprgr("<0, 0x1b>");
336         } while (hi != tmp);
337 
338         result = (uint64_t) (hi) << 32;
339         result |= lo;
340 
341         return result;
342 }
343 
344 static void csky_pmu_write_softc(uint64_t val)
345 {
346         cpwgr("<0, 0x1a>", (uint32_t)  val);
347         cpwgr("<0, 0x1b>", (uint32_t) (val >> 32));
348 }
349 
350 /* conditional branch mispredict counter */
351 static uint64_t csky_pmu_read_cbmc(void)
352 {
353         uint32_t lo, hi, tmp;
354         uint64_t result;
355 
356         do {
357                 tmp = cprgr("<0, 0x1d>");
358                 lo  = cprgr("<0, 0x1c>");
359                 hi  = cprgr("<0, 0x1d>");
360         } while (hi != tmp);
361 
362         result = (uint64_t) (hi) << 32;
363         result |= lo;
364 
365         return result;
366 }
367 
368 static void csky_pmu_write_cbmc(uint64_t val)
369 {
370         cpwgr("<0, 0x1c>", (uint32_t)  val);
371         cpwgr("<0, 0x1d>", (uint32_t) (val >> 32));
372 }
373 
374 /* conditional branch instruction counter */
375 static uint64_t csky_pmu_read_cbic(void)
376 {
377         uint32_t lo, hi, tmp;
378         uint64_t result;
379 
380         do {
381                 tmp = cprgr("<0, 0x1f>");
382                 lo  = cprgr("<0, 0x1e>");
383                 hi  = cprgr("<0, 0x1f>");
384         } while (hi != tmp);
385 
386         result = (uint64_t) (hi) << 32;
387         result |= lo;
388 
389         return result;
390 }
391 
392 static void csky_pmu_write_cbic(uint64_t val)
393 {
394         cpwgr("<0, 0x1e>", (uint32_t)  val);
395         cpwgr("<0, 0x1f>", (uint32_t) (val >> 32));
396 }
397 
398 /* indirect branch mispredict counter */
399 static uint64_t csky_pmu_read_ibmc(void)
400 {
401         uint32_t lo, hi, tmp;
402         uint64_t result;
403 
404         do {
405                 tmp = cprgr("<0, 0x21>");
406                 lo  = cprgr("<0, 0x20>");
407                 hi  = cprgr("<0, 0x21>");
408         } while (hi != tmp);
409 
410         result = (uint64_t) (hi) << 32;
411         result |= lo;
412 
413         return result;
414 }
415 
416 static void csky_pmu_write_ibmc(uint64_t val)
417 {
418         cpwgr("<0, 0x20>", (uint32_t)  val);
419         cpwgr("<0, 0x21>", (uint32_t) (val >> 32));
420 }
421 
422 /* indirect branch instruction counter */
423 static uint64_t csky_pmu_read_ibic(void)
424 {
425         uint32_t lo, hi, tmp;
426         uint64_t result;
427 
428         do {
429                 tmp = cprgr("<0, 0x23>");
430                 lo  = cprgr("<0, 0x22>");
431                 hi  = cprgr("<0, 0x23>");
432         } while (hi != tmp);
433 
434         result = (uint64_t) (hi) << 32;
435         result |= lo;
436 
437         return result;
438 }
439 
440 static void csky_pmu_write_ibic(uint64_t val)
441 {
442         cpwgr("<0, 0x22>", (uint32_t)  val);
443         cpwgr("<0, 0x23>", (uint32_t) (val >> 32));
444 }
445 
446 /* LSU spec fail counter */
447 static uint64_t csky_pmu_read_lsfc(void)
448 {
449         uint32_t lo, hi, tmp;
450         uint64_t result;
451 
452         do {
453                 tmp = cprgr("<0, 0x25>");
454                 lo  = cprgr("<0, 0x24>");
455                 hi  = cprgr("<0, 0x25>");
456         } while (hi != tmp);
457 
458         result = (uint64_t) (hi) << 32;
459         result |= lo;
460 
461         return result;
462 }
463 
464 static void csky_pmu_write_lsfc(uint64_t val)
465 {
466         cpwgr("<0, 0x24>", (uint32_t)  val);
467         cpwgr("<0, 0x25>", (uint32_t) (val >> 32));
468 }
469 
470 /* store instruction counter */
471 static uint64_t csky_pmu_read_sic(void)
472 {
473         uint32_t lo, hi, tmp;
474         uint64_t result;
475 
476         do {
477                 tmp = cprgr("<0, 0x27>");
478                 lo  = cprgr("<0, 0x26>");
479                 hi  = cprgr("<0, 0x27>");
480         } while (hi != tmp);
481 
482         result = (uint64_t) (hi) << 32;
483         result |= lo;
484 
485         return result;
486 }
487 
488 static void csky_pmu_write_sic(uint64_t val)
489 {
490         cpwgr("<0, 0x26>", (uint32_t)  val);
491         cpwgr("<0, 0x27>", (uint32_t) (val >> 32));
492 }
493 
494 /* dcache read access counter */
495 static uint64_t csky_pmu_read_dcrac(void)
496 {
497         uint32_t lo, hi, tmp;
498         uint64_t result;
499 
500         do {
501                 tmp = cprgr("<0, 0x29>");
502                 lo  = cprgr("<0, 0x28>");
503                 hi  = cprgr("<0, 0x29>");
504         } while (hi != tmp);
505 
506         result = (uint64_t) (hi) << 32;
507         result |= lo;
508 
509         return result;
510 }
511 
512 static void csky_pmu_write_dcrac(uint64_t val)
513 {
514         cpwgr("<0, 0x28>", (uint32_t)  val);
515         cpwgr("<0, 0x29>", (uint32_t) (val >> 32));
516 }
517 
518 /* dcache read miss counter */
519 static uint64_t csky_pmu_read_dcrmc(void)
520 {
521         uint32_t lo, hi, tmp;
522         uint64_t result;
523 
524         do {
525                 tmp = cprgr("<0, 0x2b>");
526                 lo  = cprgr("<0, 0x2a>");
527                 hi  = cprgr("<0, 0x2b>");
528         } while (hi != tmp);
529 
530         result = (uint64_t) (hi) << 32;
531         result |= lo;
532 
533         return result;
534 }
535 
536 static void csky_pmu_write_dcrmc(uint64_t val)
537 {
538         cpwgr("<0, 0x2a>", (uint32_t)  val);
539         cpwgr("<0, 0x2b>", (uint32_t) (val >> 32));
540 }
541 
542 /* dcache write access counter */
543 static uint64_t csky_pmu_read_dcwac(void)
544 {
545         uint32_t lo, hi, tmp;
546         uint64_t result;
547 
548         do {
549                 tmp = cprgr("<0, 0x2d>");
550                 lo  = cprgr("<0, 0x2c>");
551                 hi  = cprgr("<0, 0x2d>");
552         } while (hi != tmp);
553 
554         result = (uint64_t) (hi) << 32;
555         result |= lo;
556 
557         return result;
558 }
559 
560 static void csky_pmu_write_dcwac(uint64_t val)
561 {
562         cpwgr("<0, 0x2c>", (uint32_t)  val);
563         cpwgr("<0, 0x2d>", (uint32_t) (val >> 32));
564 }
565 
566 /* dcache write miss counter */
567 static uint64_t csky_pmu_read_dcwmc(void)
568 {
569         uint32_t lo, hi, tmp;
570         uint64_t result;
571 
572         do {
573                 tmp = cprgr("<0, 0x2f>");
574                 lo  = cprgr("<0, 0x2e>");
575                 hi  = cprgr("<0, 0x2f>");
576         } while (hi != tmp);
577 
578         result = (uint64_t) (hi) << 32;
579         result |= lo;
580 
581         return result;
582 }
583 
584 static void csky_pmu_write_dcwmc(uint64_t val)
585 {
586         cpwgr("<0, 0x2e>", (uint32_t)  val);
587         cpwgr("<0, 0x2f>", (uint32_t) (val >> 32));
588 }
589 
590 /* l2cache read access counter */
591 static uint64_t csky_pmu_read_l2rac(void)
592 {
593         uint32_t lo, hi, tmp;
594         uint64_t result;
595 
596         do {
597                 tmp = cprgr("<0, 0x31>");
598                 lo  = cprgr("<0, 0x30>");
599                 hi  = cprgr("<0, 0x31>");
600         } while (hi != tmp);
601 
602         result = (uint64_t) (hi) << 32;
603         result |= lo;
604 
605         return result;
606 }
607 
608 static void csky_pmu_write_l2rac(uint64_t val)
609 {
610         cpwgr("<0, 0x30>", (uint32_t)  val);
611         cpwgr("<0, 0x31>", (uint32_t) (val >> 32));
612 }
613 
614 /* l2cache read miss counter */
615 static uint64_t csky_pmu_read_l2rmc(void)
616 {
617         uint32_t lo, hi, tmp;
618         uint64_t result;
619 
620         do {
621                 tmp = cprgr("<0, 0x33>");
622                 lo  = cprgr("<0, 0x32>");
623                 hi  = cprgr("<0, 0x33>");
624         } while (hi != tmp);
625 
626         result = (uint64_t) (hi) << 32;
627         result |= lo;
628 
629         return result;
630 }
631 
632 static void csky_pmu_write_l2rmc(uint64_t val)
633 {
634         cpwgr("<0, 0x32>", (uint32_t)  val);
635         cpwgr("<0, 0x33>", (uint32_t) (val >> 32));
636 }
637 
638 /* l2cache write access counter */
639 static uint64_t csky_pmu_read_l2wac(void)
640 {
641         uint32_t lo, hi, tmp;
642         uint64_t result;
643 
644         do {
645                 tmp = cprgr("<0, 0x35>");
646                 lo  = cprgr("<0, 0x34>");
647                 hi  = cprgr("<0, 0x35>");
648         } while (hi != tmp);
649 
650         result = (uint64_t) (hi) << 32;
651         result |= lo;
652 
653         return result;
654 }
655 
656 static void csky_pmu_write_l2wac(uint64_t val)
657 {
658         cpwgr("<0, 0x34>", (uint32_t)  val);
659         cpwgr("<0, 0x35>", (uint32_t) (val >> 32));
660 }
661 
662 /* l2cache write miss counter */
663 static uint64_t csky_pmu_read_l2wmc(void)
664 {
665         uint32_t lo, hi, tmp;
666         uint64_t result;
667 
668         do {
669                 tmp = cprgr("<0, 0x37>");
670                 lo  = cprgr("<0, 0x36>");
671                 hi  = cprgr("<0, 0x37>");
672         } while (hi != tmp);
673 
674         result = (uint64_t) (hi) << 32;
675         result |= lo;
676 
677         return result;
678 }
679 
680 static void csky_pmu_write_l2wmc(uint64_t val)
681 {
682         cpwgr("<0, 0x36>", (uint32_t)  val);
683         cpwgr("<0, 0x37>", (uint32_t) (val >> 32));
684 }
685 
686 #define HW_OP_UNSUPPORTED       0xffff
687 static const int csky_pmu_hw_map[PERF_COUNT_HW_MAX] = {
688         [PERF_COUNT_HW_CPU_CYCLES]              = 0x1,
689         [PERF_COUNT_HW_INSTRUCTIONS]            = 0x2,
690         [PERF_COUNT_HW_CACHE_REFERENCES]        = HW_OP_UNSUPPORTED,
691         [PERF_COUNT_HW_CACHE_MISSES]            = HW_OP_UNSUPPORTED,
692         [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0xf,
693         [PERF_COUNT_HW_BRANCH_MISSES]           = 0xe,
694         [PERF_COUNT_HW_BUS_CYCLES]              = HW_OP_UNSUPPORTED,
695         [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED,
696         [PERF_COUNT_HW_STALLED_CYCLES_BACKEND]  = HW_OP_UNSUPPORTED,
697         [PERF_COUNT_HW_REF_CPU_CYCLES]          = HW_OP_UNSUPPORTED,
698 };
699 
700 #define C(_x)                   PERF_COUNT_HW_CACHE_##_x
701 #define CACHE_OP_UNSUPPORTED    0xffff
702 static const int csky_pmu_cache_map[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
703         [C(L1D)] = {
704                 [C(OP_READ)] = {
705                         [C(RESULT_ACCESS)]      = 0x14,
706                         [C(RESULT_MISS)]        = 0x15,
707                 },
708                 [C(OP_WRITE)] = {
709                         [C(RESULT_ACCESS)]      = 0x16,
710                         [C(RESULT_MISS)]        = 0x17,
711                 },
712                 [C(OP_PREFETCH)] = {
713                         [C(RESULT_ACCESS)]      = 0x5,
714                         [C(RESULT_MISS)]        = 0x6,
715                 },
716         },
717         [C(L1I)] = {
718                 [C(OP_READ)] = {
719                         [C(RESULT_ACCESS)]      = 0x3,
720                         [C(RESULT_MISS)]        = 0x4,
721                 },
722                 [C(OP_WRITE)] = {
723                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
724                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
725                 },
726                 [C(OP_PREFETCH)] = {
727                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
728                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
729                 },
730         },
731         [C(LL)] = {
732                 [C(OP_READ)] = {
733                         [C(RESULT_ACCESS)]      = 0x18,
734                         [C(RESULT_MISS)]        = 0x19,
735                 },
736                 [C(OP_WRITE)] = {
737                         [C(RESULT_ACCESS)]      = 0x1a,
738                         [C(RESULT_MISS)]        = 0x1b,
739                 },
740                 [C(OP_PREFETCH)] = {
741                         [C(RESULT_ACCESS)]      = 0x7,
742                         [C(RESULT_MISS)]        = 0x8,
743                 },
744         },
745         [C(DTLB)] = {
746                 [C(OP_READ)] = {
747                         [C(RESULT_ACCESS)]      = 0x5,
748                         [C(RESULT_MISS)]        = 0xb,
749                 },
750                 [C(OP_WRITE)] = {
751                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
752                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
753                 },
754                 [C(OP_PREFETCH)] = {
755                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
756                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
757                 },
758         },
759         [C(ITLB)] = {
760                 [C(OP_READ)] = {
761                         [C(RESULT_ACCESS)]      = 0x3,
762                         [C(RESULT_MISS)]        = 0xa,
763                 },
764                 [C(OP_WRITE)] = {
765                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
766                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
767                 },
768                 [C(OP_PREFETCH)] = {
769                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
770                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
771                 },
772         },
773         [C(BPU)] = {
774                 [C(OP_READ)] = {
775                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
776                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
777                 },
778                 [C(OP_WRITE)] = {
779                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
780                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
781                 },
782                 [C(OP_PREFETCH)] = {
783                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
784                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
785                 },
786         },
787         [C(NODE)] = {
788                 [C(OP_READ)] = {
789                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
790                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
791                 },
792                 [C(OP_WRITE)] = {
793                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
794                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
795                 },
796                 [C(OP_PREFETCH)] = {
797                         [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
798                         [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
799                 },
800         },
801 };
802 
803 static void csky_perf_event_update(struct perf_event *event,
804                                    struct hw_perf_event *hwc)
805 {
806         uint64_t prev_raw_count = local64_read(&hwc->prev_count);
807         uint64_t new_raw_count = hw_raw_read_mapping[hwc->idx]();
808         int64_t delta = new_raw_count - prev_raw_count;
809 
810         /*
811          * We aren't afraid of hwc->prev_count changing beneath our feet
812          * because there's no way for us to re-enter this function anytime.
813          */
814         local64_set(&hwc->prev_count, new_raw_count);
815         local64_add(delta, &event->count);
816         local64_sub(delta, &hwc->period_left);
817 }
818 
819 static void csky_pmu_read(struct perf_event *event)
820 {
821         csky_perf_event_update(event, &event->hw);
822 }
823 
824 static int csky_pmu_cache_event(u64 config)
825 {
826         unsigned int cache_type, cache_op, cache_result;
827 
828         cache_type      = (config >>  0) & 0xff;
829         cache_op        = (config >>  8) & 0xff;
830         cache_result    = (config >> 16) & 0xff;
831 
832         if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
833                 return -EINVAL;
834         if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
835                 return -EINVAL;
836         if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
837                 return -EINVAL;
838 
839         return csky_pmu_cache_map[cache_type][cache_op][cache_result];
840 }
841 
842 static int csky_pmu_event_init(struct perf_event *event)
843 {
844         struct hw_perf_event *hwc = &event->hw;
845         int ret;
846 
847         if (event->attr.exclude_user)
848                 csky_pmu.hpcr = BIT(2);
849         else if (event->attr.exclude_kernel)
850                 csky_pmu.hpcr = BIT(3);
851         else
852                 csky_pmu.hpcr = BIT(2) | BIT(3);
853 
854         csky_pmu.hpcr |= BIT(1) | BIT(0);
855 
856         switch (event->attr.type) {
857         case PERF_TYPE_HARDWARE:
858                 if (event->attr.config >= PERF_COUNT_HW_MAX)
859                         return -ENOENT;
860                 ret = csky_pmu_hw_map[event->attr.config];
861                 if (ret == HW_OP_UNSUPPORTED)
862                         return -ENOENT;
863                 hwc->idx = ret;
864                 return 0;
865         case PERF_TYPE_HW_CACHE:
866                 ret = csky_pmu_cache_event(event->attr.config);
867                 if (ret == CACHE_OP_UNSUPPORTED)
868                         return -ENOENT;
869                 hwc->idx = ret;
870                 return 0;
871         case PERF_TYPE_RAW:
872                 if (hw_raw_read_mapping[event->attr.config] == NULL)
873                         return -ENOENT;
874                 hwc->idx = event->attr.config;
875                 return 0;
876         default:
877                 return -ENOENT;
878         }
879 }
880 
881 /* starts all counters */
882 static void csky_pmu_enable(struct pmu *pmu)
883 {
884         cpwcr(HPCR, csky_pmu.hpcr);
885 }
886 
887 /* stops all counters */
888 static void csky_pmu_disable(struct pmu *pmu)
889 {
890         cpwcr(HPCR, BIT(1));
891 }
892 
893 static void csky_pmu_start(struct perf_event *event, int flags)
894 {
895         struct hw_perf_event *hwc = &event->hw;
896         int idx = hwc->idx;
897 
898         if (WARN_ON_ONCE(idx == -1))
899                 return;
900 
901         if (flags & PERF_EF_RELOAD)
902                 WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
903 
904         hwc->state = 0;
905 
906         cpwcr(HPCNTENR, BIT(idx) | cprcr(HPCNTENR));
907 }
908 
909 static void csky_pmu_stop(struct perf_event *event, int flags)
910 {
911         struct hw_perf_event *hwc = &event->hw;
912         int idx = hwc->idx;
913 
914         if (!(event->hw.state & PERF_HES_STOPPED)) {
915                 cpwcr(HPCNTENR, ~BIT(idx) & cprcr(HPCNTENR));
916                 event->hw.state |= PERF_HES_STOPPED;
917         }
918 
919         if ((flags & PERF_EF_UPDATE) &&
920             !(event->hw.state & PERF_HES_UPTODATE)) {
921                 csky_perf_event_update(event, &event->hw);
922                 event->hw.state |= PERF_HES_UPTODATE;
923         }
924 }
925 
926 static void csky_pmu_del(struct perf_event *event, int flags)
927 {
928         csky_pmu_stop(event, PERF_EF_UPDATE);
929 
930         perf_event_update_userpage(event);
931 }
932 
933 /* allocate hardware counter and optionally start counting */
934 static int csky_pmu_add(struct perf_event *event, int flags)
935 {
936         struct hw_perf_event *hwc = &event->hw;
937 
938         local64_set(&hwc->prev_count, 0);
939 
940         if (hw_raw_write_mapping[hwc->idx] != NULL)
941                 hw_raw_write_mapping[hwc->idx](0);
942 
943         hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
944         if (flags & PERF_EF_START)
945                 csky_pmu_start(event, PERF_EF_RELOAD);
946 
947         perf_event_update_userpage(event);
948 
949         return 0;
950 }
951 
952 int __init init_hw_perf_events(void)
953 {
954         csky_pmu.pmu = (struct pmu) {
955                 .pmu_enable     = csky_pmu_enable,
956                 .pmu_disable    = csky_pmu_disable,
957                 .event_init     = csky_pmu_event_init,
958                 .add            = csky_pmu_add,
959                 .del            = csky_pmu_del,
960                 .start          = csky_pmu_start,
961                 .stop           = csky_pmu_stop,
962                 .read           = csky_pmu_read,
963         };
964 
965         memset((void *)hw_raw_read_mapping, 0,
966                 sizeof(hw_raw_read_mapping[CSKY_PMU_MAX_EVENTS]));
967 
968         hw_raw_read_mapping[0x1]  = csky_pmu_read_cc;
969         hw_raw_read_mapping[0x2]  = csky_pmu_read_ic;
970         hw_raw_read_mapping[0x3]  = csky_pmu_read_icac;
971         hw_raw_read_mapping[0x4]  = csky_pmu_read_icmc;
972         hw_raw_read_mapping[0x5]  = csky_pmu_read_dcac;
973         hw_raw_read_mapping[0x6]  = csky_pmu_read_dcmc;
974         hw_raw_read_mapping[0x7]  = csky_pmu_read_l2ac;
975         hw_raw_read_mapping[0x8]  = csky_pmu_read_l2mc;
976         hw_raw_read_mapping[0xa]  = csky_pmu_read_iutlbmc;
977         hw_raw_read_mapping[0xb]  = csky_pmu_read_dutlbmc;
978         hw_raw_read_mapping[0xc]  = csky_pmu_read_jtlbmc;
979         hw_raw_read_mapping[0xd]  = csky_pmu_read_softc;
980         hw_raw_read_mapping[0xe]  = csky_pmu_read_cbmc;
981         hw_raw_read_mapping[0xf]  = csky_pmu_read_cbic;
982         hw_raw_read_mapping[0x10] = csky_pmu_read_ibmc;
983         hw_raw_read_mapping[0x11] = csky_pmu_read_ibic;
984         hw_raw_read_mapping[0x12] = csky_pmu_read_lsfc;
985         hw_raw_read_mapping[0x13] = csky_pmu_read_sic;
986         hw_raw_read_mapping[0x14] = csky_pmu_read_dcrac;
987         hw_raw_read_mapping[0x15] = csky_pmu_read_dcrmc;
988         hw_raw_read_mapping[0x16] = csky_pmu_read_dcwac;
989         hw_raw_read_mapping[0x17] = csky_pmu_read_dcwmc;
990         hw_raw_read_mapping[0x18] = csky_pmu_read_l2rac;
991         hw_raw_read_mapping[0x19] = csky_pmu_read_l2rmc;
992         hw_raw_read_mapping[0x1a] = csky_pmu_read_l2wac;
993         hw_raw_read_mapping[0x1b] = csky_pmu_read_l2wmc;
994 
995         memset((void *)hw_raw_write_mapping, 0,
996                 sizeof(hw_raw_write_mapping[CSKY_PMU_MAX_EVENTS]));
997 
998         hw_raw_write_mapping[0x1]  = csky_pmu_write_cc;
999         hw_raw_write_mapping[0x2]  = csky_pmu_write_ic;
1000         hw_raw_write_mapping[0x3]  = csky_pmu_write_icac;
1001         hw_raw_write_mapping[0x4]  = csky_pmu_write_icmc;
1002         hw_raw_write_mapping[0x5]  = csky_pmu_write_dcac;
1003         hw_raw_write_mapping[0x6]  = csky_pmu_write_dcmc;
1004         hw_raw_write_mapping[0x7]  = csky_pmu_write_l2ac;
1005         hw_raw_write_mapping[0x8]  = csky_pmu_write_l2mc;
1006         hw_raw_write_mapping[0xa]  = csky_pmu_write_iutlbmc;
1007         hw_raw_write_mapping[0xb]  = csky_pmu_write_dutlbmc;
1008         hw_raw_write_mapping[0xc]  = csky_pmu_write_jtlbmc;
1009         hw_raw_write_mapping[0xd]  = csky_pmu_write_softc;
1010         hw_raw_write_mapping[0xe]  = csky_pmu_write_cbmc;
1011         hw_raw_write_mapping[0xf]  = csky_pmu_write_cbic;
1012         hw_raw_write_mapping[0x10] = csky_pmu_write_ibmc;
1013         hw_raw_write_mapping[0x11] = csky_pmu_write_ibic;
1014         hw_raw_write_mapping[0x12] = csky_pmu_write_lsfc;
1015         hw_raw_write_mapping[0x13] = csky_pmu_write_sic;
1016         hw_raw_write_mapping[0x14] = csky_pmu_write_dcrac;
1017         hw_raw_write_mapping[0x15] = csky_pmu_write_dcrmc;
1018         hw_raw_write_mapping[0x16] = csky_pmu_write_dcwac;
1019         hw_raw_write_mapping[0x17] = csky_pmu_write_dcwmc;
1020         hw_raw_write_mapping[0x18] = csky_pmu_write_l2rac;
1021         hw_raw_write_mapping[0x19] = csky_pmu_write_l2rmc;
1022         hw_raw_write_mapping[0x1a] = csky_pmu_write_l2wac;
1023         hw_raw_write_mapping[0x1b] = csky_pmu_write_l2wmc;
1024 
1025         csky_pmu.pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
1026 
1027         cpwcr(HPCR, BIT(31) | BIT(30) | BIT(1));
1028 
1029         return perf_pmu_register(&csky_pmu.pmu, "cpu", PERF_TYPE_RAW);
1030 }
1031 arch_initcall(init_hw_perf_events);
1032 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp