msm_iommu_perfmon-v1.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. /**
  13. * This file contains the part of the IOMMUv1 PMU driver that actually touches
  14. * IOMMU PMU registers.
  15. */
  16. #include <linux/io.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/module.h>
  19. #include <mach/iommu_hw-v1.h>
  20. #include <mach/iommu_perfmon.h>
  21. #include <mach/iommu.h>
  22. #define PMCR_P_MASK (0x1)
  23. #define PMCR_P_SHIFT (1)
  24. #define PMCR_P (PMCR_P_MASK << PMCR_P_SHIFT)
  25. #define PMCFGR_NCG_MASK (0xFF)
  26. #define PMCFGR_NCG_SHIFT (24)
  27. #define PMCFGR_NCG (PMCFGR_NCG_MASK << PMCFGR_NCG_SHIFT)
  28. #define PMCFGR_N_MASK (0xFF)
  29. #define PMCFGR_N_SHIFT (0)
  30. #define PMCFGR_N (PMCFGR_N_MASK << PMCFGR_N_SHIFT)
  31. #define CR_E 0x1
  32. #define CGCR_CEN 0x800
  33. #define CGCR_CEN_SHFT (1 << 11)
  34. #define PMCGCR_CGNC_MASK (0x0F)
  35. #define PMCGCR_CGNC_SHIFT (24)
  36. #define PMCGCR_CGNC (PMCGCR_CGNC_MASK << PMCGCR_CGNC_SHIFT)
  37. #define PMCGCR_(group) (PMCGCR_N + group*4)
  38. #define PMOVSCLR_(n) (PMOVSCLR_N + n*4)
  39. #define PMCNTENSET_(n) (PMCNTENSET_N + n*4)
  40. #define PMCNTENCLR_(n) (PMCNTENCLR_N + n*4)
  41. #define PMINTENSET_(n) (PMINTENSET_N + n*4)
  42. #define PMINTENCLR_(n) (PMINTENCLR_N + n*4)
  43. #define PMEVCNTR_(n) (PMEVCNTR_N + n*4)
  44. #define PMEVTYPER_(n) (PMEVTYPER_N + n*4)
  45. static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
  46. {
  47. /*
  48. * IOMMUv1 is not in the always on domain so we need to make sure
  49. * the regulators are turned on in addition to clocks before we allow
  50. * access to the hardware thus we check if we have attached to the
  51. * IOMMU in addition to checking if we have enabled PMU.
  52. */
  53. return pmon->enabled && (pmon->iommu_attach_count > 0);
  54. }
  55. static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
  56. {
  57. unsigned int pmcgcr;
  58. pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
  59. pmcgcr |= CGCR_CEN;
  60. writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
  61. }
  62. static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
  63. {
  64. unsigned int pmcgcr;
  65. pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
  66. pmcgcr &= ~CGCR_CEN;
  67. writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
  68. }
  69. static void iommu_pm_enable(struct iommu_info *iommu)
  70. {
  71. unsigned int pmcr;
  72. pmcr = readl_relaxed(iommu->base + PMCR);
  73. pmcr |= CR_E;
  74. writel_relaxed(pmcr, iommu->base + PMCR);
  75. }
  76. static void iommu_pm_disable(struct iommu_info *iommu)
  77. {
  78. unsigned int pmcr;
  79. pmcr = readl_relaxed(iommu->base + PMCR);
  80. pmcr &= ~CR_E;
  81. writel_relaxed(pmcr, iommu->base + PMCR);
  82. }
  83. static void iommu_pm_reset_counters(const struct iommu_info *iommu)
  84. {
  85. unsigned int pmcr;
  86. pmcr = readl_relaxed(iommu->base + PMCR);
  87. pmcr |= PMCR_P;
  88. writel_relaxed(pmcr, iommu->base + PMCR);
  89. }
  90. static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
  91. {
  92. struct iommu_pmon_counter *counter;
  93. struct iommu_info *iommu = &pmon->iommu;
  94. unsigned int reg_no = 0;
  95. unsigned int bit_no;
  96. unsigned int reg_value;
  97. unsigned int i;
  98. unsigned int j;
  99. unsigned int curr_reg = 0;
  100. reg_value = readl_relaxed(iommu->base + PMOVSCLR_(curr_reg));
  101. for (i = 0; i < pmon->num_groups; ++i) {
  102. struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[i];
  103. for (j = 0; j < cnt_grp->num_counters; ++j) {
  104. counter = &cnt_grp->counters[j];
  105. reg_no = counter->absolute_counter_no / 32;
  106. bit_no = counter->absolute_counter_no % 32;
  107. if (reg_no != curr_reg) {
  108. /* Clear overflow bits */
  109. writel_relaxed(reg_value, iommu->base +
  110. PMOVSCLR_(reg_no));
  111. curr_reg = reg_no;
  112. reg_value = readl_relaxed(iommu->base +
  113. PMOVSCLR_(curr_reg));
  114. }
  115. if (counter->enabled) {
  116. if (reg_value & (1 << bit_no))
  117. counter->overflow_count++;
  118. }
  119. }
  120. }
  121. /* Clear overflow */
  122. writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
  123. }
  124. static irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
  125. {
  126. struct iommu_pmon *pmon = dev_id;
  127. struct iommu_info *iommu = &pmon->iommu;
  128. mutex_lock(&pmon->lock);
  129. if (!iommu_pm_is_hw_access_OK(pmon)) {
  130. mutex_unlock(&pmon->lock);
  131. goto out;
  132. }
  133. iommu->ops->iommu_lock_acquire(0);
  134. iommu_pm_check_for_overflow(pmon);
  135. iommu->ops->iommu_lock_release(0);
  136. mutex_unlock(&pmon->lock);
  137. out:
  138. return IRQ_HANDLED;
  139. }
  140. static void iommu_pm_counter_enable(struct iommu_info *iommu,
  141. struct iommu_pmon_counter *counter)
  142. {
  143. unsigned int reg_no = counter->absolute_counter_no / 32;
  144. unsigned int bit_no = counter->absolute_counter_no % 32;
  145. unsigned int reg_value;
  146. /* Clear overflow of counter */
  147. reg_value = 1 << bit_no;
  148. writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
  149. /* Enable counter */
  150. writel_relaxed(reg_value, iommu->base + PMCNTENSET_(reg_no));
  151. counter->enabled = 1;
  152. }
  153. static void iommu_pm_counter_disable(struct iommu_info *iommu,
  154. struct iommu_pmon_counter *counter)
  155. {
  156. unsigned int reg_no = counter->absolute_counter_no / 32;
  157. unsigned int bit_no = counter->absolute_counter_no % 32;
  158. unsigned int reg_value;
  159. counter->enabled = 0;
  160. /* Disable counter */
  161. reg_value = 1 << bit_no;
  162. writel_relaxed(reg_value, iommu->base + PMCNTENCLR_(reg_no));
  163. /* Clear overflow of counter */
  164. writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
  165. }
  166. /*
  167. * Must be called after iommu_start_access() is called
  168. */
  169. static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
  170. const struct iommu_pmon_counter *counter)
  171. {
  172. unsigned int reg_no = counter->absolute_counter_no / 32;
  173. unsigned int bit_no = counter->absolute_counter_no % 32;
  174. unsigned int reg_value;
  175. /* Enable overflow interrupt for counter */
  176. reg_value = (1 << bit_no);
  177. writel_relaxed(reg_value, iommu->base + PMINTENSET_(reg_no));
  178. }
  179. /*
  180. * Must be called after iommu_start_access() is called
  181. */
  182. static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
  183. const struct iommu_pmon_counter *counter)
  184. {
  185. unsigned int reg_no = counter->absolute_counter_no / 32;
  186. unsigned int bit_no = counter->absolute_counter_no % 32;
  187. unsigned int reg_value;
  188. /* Disable overflow interrupt for counter */
  189. reg_value = 1 << bit_no;
  190. writel_relaxed(reg_value, iommu->base + PMINTENCLR_(reg_no));
  191. }
  192. static void iommu_pm_set_event_class(struct iommu_pmon *pmon,
  193. unsigned int count_no,
  194. unsigned int event_class)
  195. {
  196. writel_relaxed(event_class, pmon->iommu.base + PMEVTYPER_(count_no));
  197. }
  198. static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
  199. {
  200. struct iommu_pmon *pmon = counter->cnt_group->pmon;
  201. struct iommu_info *info = &pmon->iommu;
  202. unsigned int cnt_no = counter->absolute_counter_no;
  203. return readl_relaxed(info->base + PMEVCNTR_(cnt_no));
  204. }
  205. static void iommu_pm_initialize_hw(const struct iommu_pmon *pmon)
  206. {
  207. /* No initialization needed */
  208. }
  209. static struct iommu_pm_hw_ops iommu_pm_hw_ops = {
  210. .initialize_hw = iommu_pm_initialize_hw,
  211. .is_hw_access_OK = iommu_pm_is_hw_access_OK,
  212. .grp_enable = iommu_pm_grp_enable,
  213. .grp_disable = iommu_pm_grp_disable,
  214. .enable_pm = iommu_pm_enable,
  215. .disable_pm = iommu_pm_disable,
  216. .reset_counters = iommu_pm_reset_counters,
  217. .check_for_overflow = iommu_pm_check_for_overflow,
  218. .evt_ovfl_int_handler = iommu_pm_evt_ovfl_int_handler,
  219. .counter_enable = iommu_pm_counter_enable,
  220. .counter_disable = iommu_pm_counter_disable,
  221. .ovfl_int_enable = iommu_pm_ovfl_int_enable,
  222. .ovfl_int_disable = iommu_pm_ovfl_int_disable,
  223. .set_event_class = iommu_pm_set_event_class,
  224. .read_counter = iommu_pm_read_counter,
  225. };
  226. struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void)
  227. {
  228. return &iommu_pm_hw_ops;
  229. }
  230. EXPORT_SYMBOL(iommu_pm_get_hw_ops_v1);