qcom_llcc_pmu.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/of.h>
  7. #include <linux/of_device.h>
  8. #include <linux/bitops.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/io.h>
  11. #include <linux/list.h>
  12. #include <linux/module.h>
  13. #include <linux/perf_event.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/spinlock.h>
  16. #include <linux/ktime.h>
  17. #include <soc/qcom/qcom_llcc_pmu.h>
  18. static uint32_t phys_cpu[NR_CPUS];
  19. enum llcc_pmu_version {
  20. LLCC_PMU_VER1 = 1,
  21. LLCC_PMU_VER2,
  22. };
  23. struct llcc_pmu {
  24. struct pmu pmu;
  25. struct hlist_node node;
  26. void __iomem *lagg_base;
  27. struct perf_event event;
  28. enum llcc_pmu_version ver;
  29. };
  30. #define MON_CFG(m) ((m)->lagg_base + 0x200)
  31. #define MON_CNT(m, cpu) ((m)->lagg_base + 0x220 + 0x4 * cpu)
  32. #define LLCC_RD_EV QCOM_LLCC_PMU_RD_EV
  33. #define ENABLE 0x1
  34. #define CLEAR 0x10
  35. #define CLEAR_POS 16
  36. #define DISABLE 0x0
  37. #define SCALING_FACTOR 0x3
  38. #define NUM_COUNTERS NR_CPUS
  39. #define VALUE_MASK 0xFFFFFF
  40. static u64 llcc_stats[NUM_COUNTERS];
  41. static unsigned int users;
  42. static raw_spinlock_t counter_lock;
  43. static raw_spinlock_t users_lock;
  44. static ktime_t last_read;
  45. static DEFINE_PER_CPU(unsigned int, users_alive);
  46. static struct llcc_pmu *llccpmu;
  47. int qcom_llcc_pmu_hw_type(u32 *type)
  48. {
  49. if (!llccpmu || !llccpmu->pmu.type)
  50. return -EPROBE_DEFER;
  51. *type = llccpmu->pmu.type;
  52. return 0;
  53. }
  54. EXPORT_SYMBOL(qcom_llcc_pmu_hw_type);
  55. static void mon_disable(int cpu)
  56. {
  57. u32 reg;
  58. cpu = phys_cpu[cpu];
  59. if (!llccpmu->ver) {
  60. pr_err("LLCCPMU version not correct\n");
  61. return;
  62. }
  63. switch (llccpmu->ver) {
  64. case LLCC_PMU_VER1:
  65. writel_relaxed(DISABLE, MON_CFG(llccpmu));
  66. break;
  67. case LLCC_PMU_VER2:
  68. reg = readl_relaxed(MON_CFG(llccpmu));
  69. reg &= ~(ENABLE << cpu);
  70. writel_relaxed(reg, MON_CFG(llccpmu));
  71. break;
  72. }
  73. }
  74. static void mon_clear(int cpu)
  75. {
  76. int clear_bit;
  77. u32 reg;
  78. cpu = phys_cpu[cpu];
  79. clear_bit = CLEAR_POS + cpu;
  80. if (!llccpmu->ver) {
  81. pr_err("LLCCPMU version not correct\n");
  82. return;
  83. }
  84. switch (llccpmu->ver) {
  85. case LLCC_PMU_VER1:
  86. writel_relaxed(CLEAR, MON_CFG(llccpmu));
  87. break;
  88. case LLCC_PMU_VER2:
  89. reg = readl_relaxed(MON_CFG(llccpmu));
  90. reg |= (ENABLE << clear_bit);
  91. writel_relaxed(reg, MON_CFG(llccpmu));
  92. reg &= ~(ENABLE << clear_bit);
  93. writel_relaxed(reg, MON_CFG(llccpmu));
  94. break;
  95. }
  96. }
  97. static void mon_enable(int cpu)
  98. {
  99. u32 reg;
  100. cpu = phys_cpu[cpu];
  101. if (!llccpmu->ver) {
  102. pr_err("LLCCPMU version not correct\n");
  103. return;
  104. }
  105. switch (llccpmu->ver) {
  106. case LLCC_PMU_VER1:
  107. writel_relaxed(ENABLE, MON_CFG(llccpmu));
  108. break;
  109. case LLCC_PMU_VER2:
  110. reg = readl_relaxed(MON_CFG(llccpmu));
  111. reg |= (ENABLE << cpu);
  112. writel_relaxed(reg, MON_CFG(llccpmu));
  113. break;
  114. }
  115. }
  116. static unsigned long read_cnt(int cpu)
  117. {
  118. unsigned long value;
  119. cpu = phys_cpu[cpu];
  120. if (!llccpmu->ver) {
  121. pr_err("LLCCPMU version not correct\n");
  122. return -EINVAL;
  123. }
  124. switch (llccpmu->ver) {
  125. case LLCC_PMU_VER1:
  126. value = readl_relaxed(MON_CNT(llccpmu, cpu));
  127. break;
  128. case LLCC_PMU_VER2:
  129. value = readl_relaxed(MON_CNT(llccpmu, cpu));
  130. break;
  131. }
  132. return value;
  133. }
  134. static int qcom_llcc_event_init(struct perf_event *event)
  135. {
  136. u64 config = event->attr.config;
  137. if (config == LLCC_RD_EV) {
  138. event->hw.config_base = event->attr.config;
  139. return 0;
  140. } else
  141. return -ENOENT;
  142. }
  143. static void qcom_llcc_event_read(struct perf_event *event)
  144. {
  145. int i = 0, cpu = event->cpu;
  146. unsigned long raw, irq_flags;
  147. ktime_t cur;
  148. raw_spin_lock_irqsave(&counter_lock, irq_flags);
  149. if (llccpmu->ver == LLCC_PMU_VER1) {
  150. cur = ktime_get();
  151. if (ktime_ms_delta(cur, last_read) > 1) {
  152. mon_disable(cpu);
  153. for (i = 0; i < NUM_COUNTERS; i++) {
  154. raw = read_cnt(i);
  155. raw &= VALUE_MASK;
  156. llcc_stats[i] += (u64) raw << SCALING_FACTOR;
  157. }
  158. last_read = cur;
  159. mon_clear(cpu);
  160. mon_enable(cpu);
  161. }
  162. } else {
  163. mon_disable(cpu);
  164. raw = read_cnt(cpu);
  165. raw &= VALUE_MASK;
  166. llcc_stats[cpu] += (u64) raw << SCALING_FACTOR;
  167. mon_clear(cpu);
  168. mon_enable(cpu);
  169. }
  170. if (!(event->hw.state & PERF_HES_STOPPED))
  171. local64_set(&event->count, llcc_stats[cpu]);
  172. raw_spin_unlock_irqrestore(&counter_lock, irq_flags);
  173. }
  174. static void qcom_llcc_event_start(struct perf_event *event, int flags)
  175. {
  176. if (flags & PERF_EF_RELOAD)
  177. WARN_ON(!(event->hw.state & PERF_HES_UPTODATE));
  178. event->hw.state = 0;
  179. }
  180. static void qcom_llcc_event_stop(struct perf_event *event, int flags)
  181. {
  182. qcom_llcc_event_read(event);
  183. event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
  184. }
  185. static int qcom_llcc_event_add(struct perf_event *event, int flags)
  186. {
  187. unsigned int cpu_users;
  188. raw_spin_lock(&users_lock);
  189. if (llccpmu->ver == LLCC_PMU_VER1) {
  190. if (!users)
  191. mon_enable(event->cpu);
  192. users++;
  193. } else {
  194. cpu_users = per_cpu(users_alive, event->cpu);
  195. if (!cpu_users)
  196. mon_enable(event->cpu);
  197. cpu_users++;
  198. per_cpu(users_alive, event->cpu) = cpu_users;
  199. }
  200. raw_spin_unlock(&users_lock);
  201. event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
  202. if (flags & PERF_EF_START)
  203. qcom_llcc_event_start(event, PERF_EF_RELOAD);
  204. return 0;
  205. }
  206. static void qcom_llcc_event_del(struct perf_event *event, int flags)
  207. {
  208. unsigned int cpu_users;
  209. raw_spin_lock(&users_lock);
  210. if (llccpmu->ver == LLCC_PMU_VER1) {
  211. users--;
  212. if (!users)
  213. mon_disable(event->cpu);
  214. } else {
  215. cpu_users = per_cpu(users_alive, event->cpu);
  216. cpu_users--;
  217. if (!cpu_users)
  218. mon_disable(event->cpu);
  219. per_cpu(users_alive, event->cpu) = cpu_users;
  220. }
  221. raw_spin_unlock(&users_lock);
  222. }
  223. static void get_mpidr_cpu(void *cpu)
  224. {
  225. u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
  226. *((uint32_t *)cpu) = MPIDR_AFFINITY_LEVEL(mpidr, 1);
  227. }
  228. static int qcom_llcc_pmu_probe(struct platform_device *pdev)
  229. {
  230. struct resource *res;
  231. int ret;
  232. uint32_t cpu, pcpu;
  233. if (llccpmu) {
  234. dev_err(&pdev->dev, "Only one LLCC PMU allowed!\n");
  235. return -ENODEV;
  236. }
  237. llccpmu = devm_kzalloc(&pdev->dev, sizeof(struct llcc_pmu), GFP_KERNEL);
  238. if (!llccpmu)
  239. return -ENOMEM;
  240. llccpmu->ver = (enum llcc_pmu_version)
  241. of_device_get_match_data(&pdev->dev);
  242. if (!llccpmu->ver) {
  243. pr_err("Unknown device type!\n");
  244. return -ENODEV;
  245. }
  246. llccpmu->pmu = (struct pmu) {
  247. .task_ctx_nr = perf_invalid_context,
  248. .type = 0,
  249. .event_init = qcom_llcc_event_init,
  250. .add = qcom_llcc_event_add,
  251. .del = qcom_llcc_event_del,
  252. .start = qcom_llcc_event_start,
  253. .stop = qcom_llcc_event_stop,
  254. .read = qcom_llcc_event_read,
  255. };
  256. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lagg-base");
  257. llccpmu->lagg_base = devm_ioremap_resource(&pdev->dev, res);
  258. if (IS_ERR(llccpmu->lagg_base)) {
  259. dev_err(&pdev->dev, "Can't map PMU lagg base: @%pa\n",
  260. &res->start);
  261. return PTR_ERR(llccpmu->lagg_base);
  262. }
  263. raw_spin_lock_init(&counter_lock);
  264. raw_spin_lock_init(&users_lock);
  265. ret = perf_pmu_register(&llccpmu->pmu, "llcc-pmu", -1);
  266. if (ret < 0)
  267. dev_err(&pdev->dev, "Failed to register LLCC PMU (%d)\n", ret);
  268. for_each_possible_cpu(cpu) {
  269. smp_call_function_single(cpu, get_mpidr_cpu,
  270. &pcpu, true);
  271. phys_cpu[cpu] = pcpu;
  272. }
  273. dev_info(&pdev->dev, "Registered llcc_pmu, type: %d\n",
  274. llccpmu->pmu.type);
  275. return 0;
  276. }
  277. static const struct of_device_id qcom_llcc_pmu_match_table[] = {
  278. { .compatible = "qcom,llcc-pmu-ver1", .data = (void *) LLCC_PMU_VER1 },
  279. { .compatible = "qcom,llcc-pmu-ver2", .data = (void *) LLCC_PMU_VER2 },
  280. {}
  281. };
  282. static struct platform_driver qcom_llcc_pmu_driver = {
  283. .driver = {
  284. .name = "qcom-llcc-pmu",
  285. .of_match_table = qcom_llcc_pmu_match_table,
  286. .suppress_bind_attrs = true,
  287. },
  288. .probe = qcom_llcc_pmu_probe,
  289. };
  290. module_platform_driver(qcom_llcc_pmu_driver);
  291. MODULE_DESCRIPTION("QCOM LLCC PMU");
  292. MODULE_LICENSE("GPL");