perf_event_xscale.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*
  2. * ARMv5 [xscale] Performance counter handling code.
  3. *
  4. * Copyright (C) 2010, ARM Ltd., Will Deacon <will.deacon@arm.com>
  5. *
  6. * Based on the previous xscale OProfile code.
  7. *
  8. * There are two variants of the xscale PMU that we support:
  9. * - xscale1pmu: 2 event counters and a cycle counter
  10. * - xscale2pmu: 4 event counters and a cycle counter
  11. * The two variants share event definitions, but have different
  12. * PMU structures.
  13. */
  14. #ifdef CONFIG_CPU_XSCALE
  15. enum xscale_perf_types {
  16. XSCALE_PERFCTR_ICACHE_MISS = 0x00,
  17. XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01,
  18. XSCALE_PERFCTR_DATA_STALL = 0x02,
  19. XSCALE_PERFCTR_ITLB_MISS = 0x03,
  20. XSCALE_PERFCTR_DTLB_MISS = 0x04,
  21. XSCALE_PERFCTR_BRANCH = 0x05,
  22. XSCALE_PERFCTR_BRANCH_MISS = 0x06,
  23. XSCALE_PERFCTR_INSTRUCTION = 0x07,
  24. XSCALE_PERFCTR_DCACHE_FULL_STALL = 0x08,
  25. XSCALE_PERFCTR_DCACHE_FULL_STALL_CONTIG = 0x09,
  26. XSCALE_PERFCTR_DCACHE_ACCESS = 0x0A,
  27. XSCALE_PERFCTR_DCACHE_MISS = 0x0B,
  28. XSCALE_PERFCTR_DCACHE_WRITE_BACK = 0x0C,
  29. XSCALE_PERFCTR_PC_CHANGED = 0x0D,
  30. XSCALE_PERFCTR_BCU_REQUEST = 0x10,
  31. XSCALE_PERFCTR_BCU_FULL = 0x11,
  32. XSCALE_PERFCTR_BCU_DRAIN = 0x12,
  33. XSCALE_PERFCTR_BCU_ECC_NO_ELOG = 0x14,
  34. XSCALE_PERFCTR_BCU_1_BIT_ERR = 0x15,
  35. XSCALE_PERFCTR_RMW = 0x16,
  36. /* XSCALE_PERFCTR_CCNT is not hardware defined */
  37. XSCALE_PERFCTR_CCNT = 0xFE,
  38. XSCALE_PERFCTR_UNUSED = 0xFF,
  39. };
  40. enum xscale_counters {
  41. XSCALE_CYCLE_COUNTER = 1,
  42. XSCALE_COUNTER0,
  43. XSCALE_COUNTER1,
  44. XSCALE_COUNTER2,
  45. XSCALE_COUNTER3,
  46. };
  47. static const unsigned xscale_perf_map[PERF_COUNT_HW_MAX] = {
  48. [PERF_COUNT_HW_CPU_CYCLES] = XSCALE_PERFCTR_CCNT,
  49. [PERF_COUNT_HW_INSTRUCTIONS] = XSCALE_PERFCTR_INSTRUCTION,
  50. [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
  51. [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
  52. [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = XSCALE_PERFCTR_BRANCH,
  53. [PERF_COUNT_HW_BRANCH_MISSES] = XSCALE_PERFCTR_BRANCH_MISS,
  54. [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,
  55. };
  56. static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
  57. [PERF_COUNT_HW_CACHE_OP_MAX]
  58. [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
  59. [C(L1D)] = {
  60. [C(OP_READ)] = {
  61. [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS,
  62. [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS,
  63. },
  64. [C(OP_WRITE)] = {
  65. [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS,
  66. [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS,
  67. },
  68. [C(OP_PREFETCH)] = {
  69. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  70. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  71. },
  72. },
  73. [C(L1I)] = {
  74. [C(OP_READ)] = {
  75. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  76. [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,
  77. },
  78. [C(OP_WRITE)] = {
  79. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  80. [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,
  81. },
  82. [C(OP_PREFETCH)] = {
  83. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  84. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  85. },
  86. },
  87. [C(LL)] = {
  88. [C(OP_READ)] = {
  89. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  90. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  91. },
  92. [C(OP_WRITE)] = {
  93. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  94. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  95. },
  96. [C(OP_PREFETCH)] = {
  97. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  98. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  99. },
  100. },
  101. [C(DTLB)] = {
  102. [C(OP_READ)] = {
  103. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  104. [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS,
  105. },
  106. [C(OP_WRITE)] = {
  107. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  108. [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS,
  109. },
  110. [C(OP_PREFETCH)] = {
  111. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  112. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  113. },
  114. },
  115. [C(ITLB)] = {
  116. [C(OP_READ)] = {
  117. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  118. [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS,
  119. },
  120. [C(OP_WRITE)] = {
  121. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  122. [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS,
  123. },
  124. [C(OP_PREFETCH)] = {
  125. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  126. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  127. },
  128. },
  129. [C(BPU)] = {
  130. [C(OP_READ)] = {
  131. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  132. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  133. },
  134. [C(OP_WRITE)] = {
  135. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  136. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  137. },
  138. [C(OP_PREFETCH)] = {
  139. [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
  140. [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
  141. },
  142. },
  143. };
  144. #define XSCALE_PMU_ENABLE 0x001
  145. #define XSCALE_PMN_RESET 0x002
  146. #define XSCALE_CCNT_RESET 0x004
  147. #define XSCALE_PMU_RESET (CCNT_RESET | PMN_RESET)
  148. #define XSCALE_PMU_CNT64 0x008
  149. #define XSCALE1_OVERFLOWED_MASK 0x700
  150. #define XSCALE1_CCOUNT_OVERFLOW 0x400
  151. #define XSCALE1_COUNT0_OVERFLOW 0x100
  152. #define XSCALE1_COUNT1_OVERFLOW 0x200
  153. #define XSCALE1_CCOUNT_INT_EN 0x040
  154. #define XSCALE1_COUNT0_INT_EN 0x010
  155. #define XSCALE1_COUNT1_INT_EN 0x020
  156. #define XSCALE1_COUNT0_EVT_SHFT 12
  157. #define XSCALE1_COUNT0_EVT_MASK (0xff << XSCALE1_COUNT0_EVT_SHFT)
  158. #define XSCALE1_COUNT1_EVT_SHFT 20
  159. #define XSCALE1_COUNT1_EVT_MASK (0xff << XSCALE1_COUNT1_EVT_SHFT)
  160. static inline u32
  161. xscale1pmu_read_pmnc(void)
  162. {
  163. u32 val;
  164. asm volatile("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));
  165. return val;
  166. }
  167. static inline void
  168. xscale1pmu_write_pmnc(u32 val)
  169. {
  170. /* upper 4bits and 7, 11 are write-as-0 */
  171. val &= 0xffff77f;
  172. asm volatile("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));
  173. }
  174. static inline int
  175. xscale1_pmnc_counter_has_overflowed(unsigned long pmnc,
  176. enum xscale_counters counter)
  177. {
  178. int ret = 0;
  179. switch (counter) {
  180. case XSCALE_CYCLE_COUNTER:
  181. ret = pmnc & XSCALE1_CCOUNT_OVERFLOW;
  182. break;
  183. case XSCALE_COUNTER0:
  184. ret = pmnc & XSCALE1_COUNT0_OVERFLOW;
  185. break;
  186. case XSCALE_COUNTER1:
  187. ret = pmnc & XSCALE1_COUNT1_OVERFLOW;
  188. break;
  189. default:
  190. WARN_ONCE(1, "invalid counter number (%d)\n", counter);
  191. }
  192. return ret;
  193. }
  194. static irqreturn_t
  195. xscale1pmu_handle_irq(int irq_num, void *dev)
  196. {
  197. unsigned long pmnc;
  198. struct perf_sample_data data;
  199. struct cpu_hw_events *cpuc;
  200. struct pt_regs *regs;
  201. int idx;
  202. /*
  203. * NOTE: there's an A stepping erratum that states if an overflow
  204. * bit already exists and another occurs, the previous
  205. * Overflow bit gets cleared. There's no workaround.
  206. * Fixed in B stepping or later.
  207. */
  208. pmnc = xscale1pmu_read_pmnc();
  209. /*
  210. * Write the value back to clear the overflow flags. Overflow
  211. * flags remain in pmnc for use below. We also disable the PMU
  212. * while we process the interrupt.
  213. */
  214. xscale1pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);
  215. if (!(pmnc & XSCALE1_OVERFLOWED_MASK))
  216. return IRQ_NONE;
  217. regs = get_irq_regs();
  218. perf_sample_data_init(&data, 0);
  219. cpuc = &__get_cpu_var(cpu_hw_events);
  220. for (idx = 0; idx <= armpmu->num_events; ++idx) {
  221. struct perf_event *event = cpuc->events[idx];
  222. struct hw_perf_event *hwc;
  223. if (!test_bit(idx, cpuc->active_mask))
  224. continue;
  225. if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
  226. continue;
  227. hwc = &event->hw;
  228. armpmu_event_update(event, hwc, idx, 1);
  229. data.period = event->hw.last_period;
  230. if (!armpmu_event_set_period(event, hwc, idx))
  231. continue;
  232. if (perf_event_overflow(event, 0, &data, regs))
  233. armpmu->disable(hwc, idx);
  234. }
  235. irq_work_run();
  236. /*
  237. * Re-enable the PMU.
  238. */
  239. pmnc = xscale1pmu_read_pmnc() | XSCALE_PMU_ENABLE;
  240. xscale1pmu_write_pmnc(pmnc);
  241. return IRQ_HANDLED;
  242. }
  243. static void
  244. xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
  245. {
  246. unsigned long val, mask, evt, flags;
  247. switch (idx) {
  248. case XSCALE_CYCLE_COUNTER:
  249. mask = 0;
  250. evt = XSCALE1_CCOUNT_INT_EN;
  251. break;
  252. case XSCALE_COUNTER0:
  253. mask = XSCALE1_COUNT0_EVT_MASK;
  254. evt = (hwc->config_base << XSCALE1_COUNT0_EVT_SHFT) |
  255. XSCALE1_COUNT0_INT_EN;
  256. break;
  257. case XSCALE_COUNTER1:
  258. mask = XSCALE1_COUNT1_EVT_MASK;
  259. evt = (hwc->config_base << XSCALE1_COUNT1_EVT_SHFT) |
  260. XSCALE1_COUNT1_INT_EN;
  261. break;
  262. default:
  263. WARN_ONCE(1, "invalid counter number (%d)\n", idx);
  264. return;
  265. }
  266. raw_spin_lock_irqsave(&pmu_lock, flags);
  267. val = xscale1pmu_read_pmnc();
  268. val &= ~mask;
  269. val |= evt;
  270. xscale1pmu_write_pmnc(val);
  271. raw_spin_unlock_irqrestore(&pmu_lock, flags);
  272. }
  273. static void
  274. xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
  275. {
  276. unsigned long val, mask, evt, flags;
  277. switch (idx) {
  278. case XSCALE_CYCLE_COUNTER:
  279. mask = XSCALE1_CCOUNT_INT_EN;
  280. evt = 0;
  281. break;
  282. case XSCALE_COUNTER0:
  283. mask = XSCALE1_COUNT0_INT_EN | XSCALE1_COUNT0_EVT_MASK;
  284. evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT0_EVT_SHFT;
  285. break;
  286. case XSCALE_COUNTER1:
  287. mask = XSCALE1_COUNT1_INT_EN | XSCALE1_COUNT1_EVT_MASK;
  288. evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT1_EVT_SHFT;
  289. break;
  290. default:
  291. WARN_ONCE(1, "invalid counter number (%d)\n", idx);
  292. return;
  293. }
  294. raw_spin_lock_irqsave(&pmu_lock, flags);
  295. val = xscale1pmu_read_pmnc();
  296. val &= ~mask;
  297. val |= evt;
  298. xscale1pmu_write_pmnc(val);
  299. raw_spin_unlock_irqrestore(&pmu_lock, flags);
  300. }
  301. static int
  302. xscale1pmu_get_event_idx(struct cpu_hw_events *cpuc,
  303. struct hw_perf_event *event)
  304. {
  305. if (XSCALE_PERFCTR_CCNT == event->config_base) {
  306. if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask))
  307. return -EAGAIN;
  308. return XSCALE_CYCLE_COUNTER;
  309. } else {
  310. if (!test_and_set_bit(XSCALE_COUNTER1, cpuc->used_mask))
  311. return XSCALE_COUNTER1;
  312. if (!test_and_set_bit(XSCALE_COUNTER0, cpuc->used_mask))
  313. return XSCALE_COUNTER0;
  314. return -EAGAIN;
  315. }
  316. }
  317. static void
  318. xscale1pmu_start(void)
  319. {
  320. unsigned long flags, val;
  321. raw_spin_lock_irqsave(&pmu_lock, flags);
  322. val = xscale1pmu_read_pmnc();
  323. val |= XSCALE_PMU_ENABLE;
  324. xscale1pmu_write_pmnc(val);
  325. raw_spin_unlock_irqrestore(&pmu_lock, flags);
  326. }
  327. static void
  328. xscale1pmu_stop(void)
  329. {
  330. unsigned long flags, val;
  331. raw_spin_lock_irqsave(&pmu_lock, flags);
  332. val = xscale1pmu_read_pmnc();
  333. val &= ~XSCALE_PMU_ENABLE;
  334. xscale1pmu_write_pmnc(val);
  335. raw_spin_unlock_irqrestore(&pmu_lock, flags);
  336. }
  337. static inline u32
  338. xscale1pmu_read_counter(int counter)
  339. {
  340. u32 val = 0;
  341. switch (counter) {
  342. case XSCALE_CYCLE_COUNTER:
  343. asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (val));
  344. break;
  345. case XSCALE_COUNTER0:
  346. asm volatile("mrc p14, 0, %0, c2, c0, 0" : "=r" (val));
  347. break;
  348. case XSCALE_COUNTER1:
  349. asm volatile("mrc p14, 0, %0, c3, c0, 0" : "=r" (val));
  350. break;
  351. }
  352. return val;
  353. }
  354. static inline void
  355. xscale1pmu_write_counter(int counter, u32 val)
  356. {
  357. switch (counter) {
  358. case XSCALE_CYCLE_COUNTER:
  359. asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val));
  360. break;
  361. case XSCALE_COUNTER0:
  362. asm volatile("mcr p14, 0, %0, c2, c0, 0" : : "r" (val));
  363. break;
  364. case XSCALE_COUNTER1:
  365. asm volatile("mcr p14, 0, %0, c3, c0, 0" : : "r" (val));
  366. break;
  367. }
  368. }
  369. static const struct arm_pmu xscale1pmu = {
  370. .id = ARM_PERF_PMU_ID_XSCALE1,
  371. .name = "xscale1",
  372. .handle_irq = xscale1pmu_handle_irq,
  373. .enable = xscale1pmu_enable_event,
  374. .disable = xscale1pmu_disable_event,
  375. .read_counter = xscale1pmu_read_counter,
  376. .write_counter = xscale1pmu_write_counter,
  377. .get_event_idx = xscale1pmu_get_event_idx,
  378. .start = xscale1pmu_start,
  379. .stop = xscale1pmu_stop,
  380. .cache_map = &xscale_perf_cache_map,
  381. .event_map = &xscale_perf_map,
  382. .raw_event_mask = 0xFF,
  383. .num_events = 3,
  384. .max_period = (1LLU << 32) - 1,
  385. };
  386. static const struct arm_pmu *__init xscale1pmu_init(void)
  387. {
  388. return &xscale1pmu;
  389. }
  390. #define XSCALE2_OVERFLOWED_MASK 0x01f
  391. #define XSCALE2_CCOUNT_OVERFLOW 0x001
  392. #define XSCALE2_COUNT0_OVERFLOW 0x002
  393. #define XSCALE2_COUNT1_OVERFLOW 0x004
  394. #define XSCALE2_COUNT2_OVERFLOW 0x008
  395. #define XSCALE2_COUNT3_OVERFLOW 0x010
  396. #define XSCALE2_CCOUNT_INT_EN 0x001
  397. #define XSCALE2_COUNT0_INT_EN 0x002
  398. #define XSCALE2_COUNT1_INT_EN 0x004
  399. #define XSCALE2_COUNT2_INT_EN 0x008
  400. #define XSCALE2_COUNT3_INT_EN 0x010
  401. #define XSCALE2_COUNT0_EVT_SHFT 0
  402. #define XSCALE2_COUNT0_EVT_MASK (0xff << XSCALE2_COUNT0_EVT_SHFT)
  403. #define XSCALE2_COUNT1_EVT_SHFT 8
  404. #define XSCALE2_COUNT1_EVT_MASK (0xff << XSCALE2_COUNT1_EVT_SHFT)
  405. #define XSCALE2_COUNT2_EVT_SHFT 16
  406. #define XSCALE2_COUNT2_EVT_MASK (0xff << XSCALE2_COUNT2_EVT_SHFT)
  407. #define XSCALE2_COUNT3_EVT_SHFT 24
  408. #define XSCALE2_COUNT3_EVT_MASK (0xff << XSCALE2_COUNT3_EVT_SHFT)
  409. static inline u32
  410. xscale2pmu_read_pmnc(void)
  411. {
  412. u32 val;
  413. asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));
  414. /* bits 1-2 and 4-23 are read-unpredictable */
  415. return val & 0xff000009;
  416. }
  417. static inline void
  418. xscale2pmu_write_pmnc(u32 val)
  419. {
  420. /* bits 4-23 are write-as-0, 24-31 are write ignored */
  421. val &= 0xf;
  422. asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));
  423. }
  424. static inline u32
  425. xscale2pmu_read_overflow_flags(void)
  426. {
  427. u32 val;
  428. asm volatile("mrc p14, 0, %0, c5, c1, 0" : "=r" (val));
  429. return val;
  430. }
  431. static inline void
  432. xscale2pmu_write_overflow_flags(u32 val)
  433. {
  434. asm volatile("mcr p14, 0, %0, c5, c1, 0" : : "r" (val));
  435. }
  436. static inline u32
  437. xscale2pmu_read_event_select(void)
  438. {
  439. u32 val;
  440. asm volatile("mrc p14, 0, %0, c8, c1, 0" : "=r" (val));
  441. return val;
  442. }
  443. static inline void
  444. xscale2pmu_write_event_select(u32 val)
  445. {
  446. asm volatile("mcr p14, 0, %0, c8, c1, 0" : : "r"(val));
  447. }
  448. static inline u32
  449. xscale2pmu_read_int_enable(void)
  450. {
  451. u32 val;
  452. asm volatile("mrc p14, 0, %0, c4, c1, 0" : "=r" (val));
  453. return val;
  454. }
  455. static void
  456. xscale2pmu_write_int_enable(u32 val)
  457. {
  458. asm volatile("mcr p14, 0, %0, c4, c1, 0" : : "r" (val));
  459. }
  460. static inline int
  461. xscale2_pmnc_counter_has_overflowed(unsigned long of_flags,
  462. enum xscale_counters counter)
  463. {
  464. int ret = 0;
  465. switch (counter) {
  466. case XSCALE_CYCLE_COUNTER:
  467. ret = of_flags & XSCALE2_CCOUNT_OVERFLOW;
  468. break;
  469. case XSCALE_COUNTER0:
  470. ret = of_flags & XSCALE2_COUNT0_OVERFLOW;
  471. break;
  472. case XSCALE_COUNTER1:
  473. ret = of_flags & XSCALE2_COUNT1_OVERFLOW;
  474. break;
  475. case XSCALE_COUNTER2:
  476. ret = of_flags & XSCALE2_COUNT2_OVERFLOW;
  477. break;
  478. case XSCALE_COUNTER3:
  479. ret = of_flags & XSCALE2_COUNT3_OVERFLOW;
  480. break;
  481. default:
  482. WARN_ONCE(1, "invalid counter number (%d)\n", counter);
  483. }
  484. return ret;
  485. }
  486. static irqreturn_t
  487. xscale2pmu_handle_irq(int irq_num, void *dev)
  488. {
  489. unsigned long pmnc, of_flags;
  490. struct perf_sample_data data;
  491. struct cpu_hw_events *cpuc;
  492. struct pt_regs *regs;
  493. int idx;
  494. /* Disable the PMU. */
  495. pmnc = xscale2pmu_read_pmnc();
  496. xscale2pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);
  497. /* Check the overflow flag register. */
  498. of_flags = xscale2pmu_read_overflow_flags();
  499. if (!(of_flags & XSCALE2_OVERFLOWED_MASK))
  500. return IRQ_NONE;
  501. /* Clear the overflow bits. */
  502. xscale2pmu_write_overflow_flags(of_flags);
  503. regs = get_irq_regs();
  504. perf_sample_data_init(&data, 0);
  505. cpuc = &__get_cpu_var(cpu_hw_events);
  506. for (idx = 0; idx <= armpmu->num_events; ++idx) {
  507. struct perf_event *event = cpuc->events[idx];
  508. struct hw_perf_event *hwc;
  509. if (!test_bit(idx, cpuc->active_mask))
  510. continue;
  511. if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))
  512. continue;
  513. hwc = &event->hw;
  514. armpmu_event_update(event, hwc, idx, 1);
  515. data.period = event->hw.last_period;
  516. if (!armpmu_event_set_period(event, hwc, idx))
  517. continue;
  518. if (perf_event_overflow(event, 0, &data, regs))
  519. armpmu->disable(hwc, idx);
  520. }
  521. irq_work_run();
  522. /*
  523. * Re-enable the PMU.
  524. */
  525. pmnc = xscale2pmu_read_pmnc() | XSCALE_PMU_ENABLE;
  526. xscale2pmu_write_pmnc(pmnc);
  527. return IRQ_HANDLED;
  528. }
  529. static void
  530. xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
  531. {
  532. unsigned long flags, ien, evtsel;
  533. ien = xscale2pmu_read_int_enable();
  534. evtsel = xscale2pmu_read_event_select();
  535. switch (idx) {
  536. case XSCALE_CYCLE_COUNTER:
  537. ien |= XSCALE2_CCOUNT_INT_EN;
  538. break;
  539. case XSCALE_COUNTER0:
  540. ien |= XSCALE2_COUNT0_INT_EN;
  541. evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
  542. evtsel |= hwc->config_base << XSCALE2_COUNT0_EVT_SHFT;
  543. break;
  544. case XSCALE_COUNTER1:
  545. ien |= XSCALE2_COUNT1_INT_EN;
  546. evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
  547. evtsel |= hwc->config_base << XSCALE2_COUNT1_EVT_SHFT;
  548. break;
  549. case XSCALE_COUNTER2:
  550. ien |= XSCALE2_COUNT2_INT_EN;
  551. evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
  552. evtsel |= hwc->config_base << XSCALE2_COUNT2_EVT_SHFT;
  553. break;
  554. case XSCALE_COUNTER3:
  555. ien |= XSCALE2_COUNT3_INT_EN;
  556. evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
  557. evtsel |= hwc->config_base << XSCALE2_COUNT3_EVT_SHFT;
  558. break;
  559. default:
  560. WARN_ONCE(1, "invalid counter number (%d)\n", idx);
  561. return;
  562. }
  563. raw_spin_lock_irqsave(&pmu_lock, flags);
  564. xscale2pmu_write_event_select(evtsel);
  565. xscale2pmu_write_int_enable(ien);
  566. raw_spin_unlock_irqrestore(&pmu_lock, flags);
  567. }
  568. static void
  569. xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
  570. {
  571. unsigned long flags, ien, evtsel;
  572. ien = xscale2pmu_read_int_enable();
  573. evtsel = xscale2pmu_read_event_select();
  574. switch (idx) {
  575. case XSCALE_CYCLE_COUNTER:
  576. ien &= ~XSCALE2_CCOUNT_INT_EN;
  577. break;
  578. case XSCALE_COUNTER0:
  579. ien &= ~XSCALE2_COUNT0_INT_EN;
  580. evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
  581. evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT;
  582. break;
  583. case XSCALE_COUNTER1:
  584. ien &= ~XSCALE2_COUNT1_INT_EN;
  585. evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
  586. evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT;
  587. break;
  588. case XSCALE_COUNTER2:
  589. ien &= ~XSCALE2_COUNT2_INT_EN;
  590. evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
  591. evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT;
  592. break;
  593. case XSCALE_COUNTER3:
  594. ien &= ~XSCALE2_COUNT3_INT_EN;
  595. evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
  596. evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT;
  597. break;
  598. default:
  599. WARN_ONCE(1, "invalid counter number (%d)\n", idx);
  600. return;
  601. }
  602. raw_spin_lock_irqsave(&pmu_lock, flags);
  603. xscale2pmu_write_event_select(evtsel);
  604. xscale2pmu_write_int_enable(ien);
  605. raw_spin_unlock_irqrestore(&pmu_lock, flags);
  606. }
  607. static int
  608. xscale2pmu_get_event_idx(struct cpu_hw_events *cpuc,
  609. struct hw_perf_event *event)
  610. {
  611. int idx = xscale1pmu_get_event_idx(cpuc, event);
  612. if (idx >= 0)
  613. goto out;
  614. if (!test_and_set_bit(XSCALE_COUNTER3, cpuc->used_mask))
  615. idx = XSCALE_COUNTER3;
  616. else if (!test_and_set_bit(XSCALE_COUNTER2, cpuc->used_mask))
  617. idx = XSCALE_COUNTER2;
  618. out:
  619. return idx;
  620. }
  621. static void
  622. xscale2pmu_start(void)
  623. {
  624. unsigned long flags, val;
  625. raw_spin_lock_irqsave(&pmu_lock, flags);
  626. val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;
  627. val |= XSCALE_PMU_ENABLE;
  628. xscale2pmu_write_pmnc(val);
  629. raw_spin_unlock_irqrestore(&pmu_lock, flags);
  630. }
  631. static void
  632. xscale2pmu_stop(void)
  633. {
  634. unsigned long flags, val;
  635. raw_spin_lock_irqsave(&pmu_lock, flags);
  636. val = xscale2pmu_read_pmnc();
  637. val &= ~XSCALE_PMU_ENABLE;
  638. xscale2pmu_write_pmnc(val);
  639. raw_spin_unlock_irqrestore(&pmu_lock, flags);
  640. }
  641. static inline u32
  642. xscale2pmu_read_counter(int counter)
  643. {
  644. u32 val = 0;
  645. switch (counter) {
  646. case XSCALE_CYCLE_COUNTER:
  647. asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (val));
  648. break;
  649. case XSCALE_COUNTER0:
  650. asm volatile("mrc p14, 0, %0, c0, c2, 0" : "=r" (val));
  651. break;
  652. case XSCALE_COUNTER1:
  653. asm volatile("mrc p14, 0, %0, c1, c2, 0" : "=r" (val));
  654. break;
  655. case XSCALE_COUNTER2:
  656. asm volatile("mrc p14, 0, %0, c2, c2, 0" : "=r" (val));
  657. break;
  658. case XSCALE_COUNTER3:
  659. asm volatile("mrc p14, 0, %0, c3, c2, 0" : "=r" (val));
  660. break;
  661. }
  662. return val;
  663. }
  664. static inline void
  665. xscale2pmu_write_counter(int counter, u32 val)
  666. {
  667. switch (counter) {
  668. case XSCALE_CYCLE_COUNTER:
  669. asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val));
  670. break;
  671. case XSCALE_COUNTER0:
  672. asm volatile("mcr p14, 0, %0, c0, c2, 0" : : "r" (val));
  673. break;
  674. case XSCALE_COUNTER1:
  675. asm volatile("mcr p14, 0, %0, c1, c2, 0" : : "r" (val));
  676. break;
  677. case XSCALE_COUNTER2:
  678. asm volatile("mcr p14, 0, %0, c2, c2, 0" : : "r" (val));
  679. break;
  680. case XSCALE_COUNTER3:
  681. asm volatile("mcr p14, 0, %0, c3, c2, 0" : : "r" (val));
  682. break;
  683. }
  684. }
  685. static const struct arm_pmu xscale2pmu = {
  686. .id = ARM_PERF_PMU_ID_XSCALE2,
  687. .name = "xscale2",
  688. .handle_irq = xscale2pmu_handle_irq,
  689. .enable = xscale2pmu_enable_event,
  690. .disable = xscale2pmu_disable_event,
  691. .read_counter = xscale2pmu_read_counter,
  692. .write_counter = xscale2pmu_write_counter,
  693. .get_event_idx = xscale2pmu_get_event_idx,
  694. .start = xscale2pmu_start,
  695. .stop = xscale2pmu_stop,
  696. .cache_map = &xscale_perf_cache_map,
  697. .event_map = &xscale_perf_map,
  698. .raw_event_mask = 0xFF,
  699. .num_events = 5,
  700. .max_period = (1LLU << 32) - 1,
  701. };
  702. static const struct arm_pmu *__init xscale2pmu_init(void)
  703. {
  704. return &xscale2pmu;
  705. }
  706. #else
  707. static const struct arm_pmu *__init xscale1pmu_init(void)
  708. {
  709. return NULL;
  710. }
  711. static const struct arm_pmu *__init xscale2pmu_init(void)
  712. {
  713. return NULL;
  714. }
  715. #endif /* CONFIG_CPU_XSCALE */