pmu.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * Cell Broadband Engine Performance Monitor
  3. *
  4. * (C) Copyright IBM Corporation 2001,2006
  5. *
  6. * Author:
  7. * David Erb (djerb@us.ibm.com)
  8. * Kevin Corry (kevcorry@us.ibm.com)
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2, or (at your option)
  13. * any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23. */
  24. #include <linux/types.h>
  25. #include <asm/io.h>
  26. #include <asm/machdep.h>
  27. #include <asm/reg.h>
  28. #include <asm/spu.h>
  29. #include "cbe_regs.h"
  30. #include "interrupt.h"
  31. /*
  32. * When writing to write-only mmio addresses, save a shadow copy. All of the
  33. * registers are 32-bit, but stored in the upper-half of a 64-bit field in
  34. * pmd_regs.
  35. */
  36. #define WRITE_WO_MMIO(reg, x) \
  37. do { \
  38. u32 _x = (x); \
  39. struct cbe_pmd_regs __iomem *pmd_regs; \
  40. struct cbe_pmd_shadow_regs *shadow_regs; \
  41. pmd_regs = cbe_get_cpu_pmd_regs(cpu); \
  42. shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
  43. out_be64(&(pmd_regs->reg), (((u64)_x) << 32)); \
  44. shadow_regs->reg = _x; \
  45. } while (0)
  46. #define READ_SHADOW_REG(val, reg) \
  47. do { \
  48. struct cbe_pmd_shadow_regs *shadow_regs; \
  49. shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
  50. (val) = shadow_regs->reg; \
  51. } while (0)
  52. #define READ_MMIO_UPPER32(val, reg) \
  53. do { \
  54. struct cbe_pmd_regs __iomem *pmd_regs; \
  55. pmd_regs = cbe_get_cpu_pmd_regs(cpu); \
  56. (val) = (u32)(in_be64(&pmd_regs->reg) >> 32); \
  57. } while (0)
  58. /*
  59. * Physical counter registers.
  60. * Each physical counter can act as one 32-bit counter or two 16-bit counters.
  61. */
  62. u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr)
  63. {
  64. u32 val_in_latch, val = 0;
  65. if (phys_ctr < NR_PHYS_CTRS) {
  66. READ_SHADOW_REG(val_in_latch, counter_value_in_latch);
  67. /* Read the latch or the actual counter, whichever is newer. */
  68. if (val_in_latch & (1 << phys_ctr)) {
  69. READ_SHADOW_REG(val, pm_ctr[phys_ctr]);
  70. } else {
  71. READ_MMIO_UPPER32(val, pm_ctr[phys_ctr]);
  72. }
  73. }
  74. return val;
  75. }
  76. EXPORT_SYMBOL_GPL(cbe_read_phys_ctr);
  77. void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
  78. {
  79. struct cbe_pmd_shadow_regs *shadow_regs;
  80. u32 pm_ctrl;
  81. if (phys_ctr < NR_PHYS_CTRS) {
  82. /* Writing to a counter only writes to a hardware latch.
  83. * The new value is not propagated to the actual counter
  84. * until the performance monitor is enabled.
  85. */
  86. WRITE_WO_MMIO(pm_ctr[phys_ctr], val);
  87. pm_ctrl = cbe_read_pm(cpu, pm_control);
  88. if (pm_ctrl & CBE_PM_ENABLE_PERF_MON) {
  89. /* The counters are already active, so we need to
  90. * rewrite the pm_control register to "re-enable"
  91. * the PMU.
  92. */
  93. cbe_write_pm(cpu, pm_control, pm_ctrl);
  94. } else {
  95. shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
  96. shadow_regs->counter_value_in_latch |= (1 << phys_ctr);
  97. }
  98. }
  99. }
  100. EXPORT_SYMBOL_GPL(cbe_write_phys_ctr);
  101. /*
  102. * "Logical" counter registers.
  103. * These will read/write 16-bits or 32-bits depending on the
  104. * current size of the counter. Counters 4 - 7 are always 16-bit.
  105. */
  106. u32 cbe_read_ctr(u32 cpu, u32 ctr)
  107. {
  108. u32 val;
  109. u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
  110. val = cbe_read_phys_ctr(cpu, phys_ctr);
  111. if (cbe_get_ctr_size(cpu, phys_ctr) == 16)
  112. val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
  113. return val;
  114. }
  115. EXPORT_SYMBOL_GPL(cbe_read_ctr);
  116. void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
  117. {
  118. u32 phys_ctr;
  119. u32 phys_val;
  120. phys_ctr = ctr & (NR_PHYS_CTRS - 1);
  121. if (cbe_get_ctr_size(cpu, phys_ctr) == 16) {
  122. phys_val = cbe_read_phys_ctr(cpu, phys_ctr);
  123. if (ctr < NR_PHYS_CTRS)
  124. val = (val << 16) | (phys_val & 0xffff);
  125. else
  126. val = (val & 0xffff) | (phys_val & 0xffff0000);
  127. }
  128. cbe_write_phys_ctr(cpu, phys_ctr, val);
  129. }
  130. EXPORT_SYMBOL_GPL(cbe_write_ctr);
  131. /*
  132. * Counter-control registers.
  133. * Each "logical" counter has a corresponding control register.
  134. */
  135. u32 cbe_read_pm07_control(u32 cpu, u32 ctr)
  136. {
  137. u32 pm07_control = 0;
  138. if (ctr < NR_CTRS)
  139. READ_SHADOW_REG(pm07_control, pm07_control[ctr]);
  140. return pm07_control;
  141. }
  142. EXPORT_SYMBOL_GPL(cbe_read_pm07_control);
  143. void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val)
  144. {
  145. if (ctr < NR_CTRS)
  146. WRITE_WO_MMIO(pm07_control[ctr], val);
  147. }
  148. EXPORT_SYMBOL_GPL(cbe_write_pm07_control);
  149. /*
  150. * Other PMU control registers. Most of these are write-only.
  151. */
  152. u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
  153. {
  154. u32 val = 0;
  155. switch (reg) {
  156. case group_control:
  157. READ_SHADOW_REG(val, group_control);
  158. break;
  159. case debug_bus_control:
  160. READ_SHADOW_REG(val, debug_bus_control);
  161. break;
  162. case trace_address:
  163. READ_MMIO_UPPER32(val, trace_address);
  164. break;
  165. case ext_tr_timer:
  166. READ_SHADOW_REG(val, ext_tr_timer);
  167. break;
  168. case pm_status:
  169. READ_MMIO_UPPER32(val, pm_status);
  170. break;
  171. case pm_control:
  172. READ_SHADOW_REG(val, pm_control);
  173. break;
  174. case pm_interval:
  175. READ_SHADOW_REG(val, pm_interval);
  176. break;
  177. case pm_start_stop:
  178. READ_SHADOW_REG(val, pm_start_stop);
  179. break;
  180. }
  181. return val;
  182. }
  183. EXPORT_SYMBOL_GPL(cbe_read_pm);
  184. void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
  185. {
  186. switch (reg) {
  187. case group_control:
  188. WRITE_WO_MMIO(group_control, val);
  189. break;
  190. case debug_bus_control:
  191. WRITE_WO_MMIO(debug_bus_control, val);
  192. break;
  193. case trace_address:
  194. WRITE_WO_MMIO(trace_address, val);
  195. break;
  196. case ext_tr_timer:
  197. WRITE_WO_MMIO(ext_tr_timer, val);
  198. break;
  199. case pm_status:
  200. WRITE_WO_MMIO(pm_status, val);
  201. break;
  202. case pm_control:
  203. WRITE_WO_MMIO(pm_control, val);
  204. break;
  205. case pm_interval:
  206. WRITE_WO_MMIO(pm_interval, val);
  207. break;
  208. case pm_start_stop:
  209. WRITE_WO_MMIO(pm_start_stop, val);
  210. break;
  211. }
  212. }
  213. EXPORT_SYMBOL_GPL(cbe_write_pm);
  214. /*
  215. * Get/set the size of a physical counter to either 16 or 32 bits.
  216. */
  217. u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr)
  218. {
  219. u32 pm_ctrl, size = 0;
  220. if (phys_ctr < NR_PHYS_CTRS) {
  221. pm_ctrl = cbe_read_pm(cpu, pm_control);
  222. size = (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
  223. }
  224. return size;
  225. }
  226. EXPORT_SYMBOL_GPL(cbe_get_ctr_size);
  227. void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
  228. {
  229. u32 pm_ctrl;
  230. if (phys_ctr < NR_PHYS_CTRS) {
  231. pm_ctrl = cbe_read_pm(cpu, pm_control);
  232. switch (ctr_size) {
  233. case 16:
  234. pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
  235. break;
  236. case 32:
  237. pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
  238. break;
  239. }
  240. cbe_write_pm(cpu, pm_control, pm_ctrl);
  241. }
  242. }
  243. EXPORT_SYMBOL_GPL(cbe_set_ctr_size);
  244. /*
  245. * Enable/disable the entire performance monitoring unit.
  246. * When we enable the PMU, all pending writes to counters get committed.
  247. */
  248. void cbe_enable_pm(u32 cpu)
  249. {
  250. struct cbe_pmd_shadow_regs *shadow_regs;
  251. u32 pm_ctrl;
  252. shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
  253. shadow_regs->counter_value_in_latch = 0;
  254. pm_ctrl = cbe_read_pm(cpu, pm_control) | CBE_PM_ENABLE_PERF_MON;
  255. cbe_write_pm(cpu, pm_control, pm_ctrl);
  256. }
  257. EXPORT_SYMBOL_GPL(cbe_enable_pm);
  258. void cbe_disable_pm(u32 cpu)
  259. {
  260. u32 pm_ctrl;
  261. pm_ctrl = cbe_read_pm(cpu, pm_control) & ~CBE_PM_ENABLE_PERF_MON;
  262. cbe_write_pm(cpu, pm_control, pm_ctrl);
  263. }
  264. EXPORT_SYMBOL_GPL(cbe_disable_pm);
  265. /*
  266. * Reading from the trace_buffer.
  267. * The trace buffer is two 64-bit registers. Reading from
  268. * the second half automatically increments the trace_address.
  269. */
  270. void cbe_read_trace_buffer(u32 cpu, u64 *buf)
  271. {
  272. struct cbe_pmd_regs __iomem *pmd_regs = cbe_get_cpu_pmd_regs(cpu);
  273. *buf++ = in_be64(&pmd_regs->trace_buffer_0_63);
  274. *buf++ = in_be64(&pmd_regs->trace_buffer_64_127);
  275. }
  276. EXPORT_SYMBOL_GPL(cbe_read_trace_buffer);