bwprof.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #define pr_fmt(fmt) "qcom-bwprof: " fmt
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/io.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/of.h>
  11. #include <linux/of_device.h>
  12. #include <linux/hrtimer.h>
  13. #include <linux/ktime.h>
  14. #include "bwprof.h"
  15. #include "trace-dcvs.h"
  16. static LIST_HEAD(bwprof_list);
  17. static DEFINE_MUTEX(bwprof_lock);
  18. enum bwprof_type {
  19. BWPROF_DEV,
  20. BWPROF_MON,
  21. NUM_BWPROF_TYPES
  22. };
  23. struct bwprof_spec {
  24. enum bwprof_type type;
  25. };
  26. struct bwprof_sample {
  27. ktime_t ts;
  28. u32 meas_mbps;
  29. u32 max_mbps;
  30. u32 mem_freq;
  31. };
  32. struct bwmon_node {
  33. struct device *dev;
  34. struct kobject kobj;
  35. void __iomem *base;
  36. struct list_head list;
  37. bool enabled;
  38. struct bwprof_sample last_sample;
  39. u64 curr_sample_bytes;
  40. const char *client;
  41. };
  42. struct bwprof_dev_data {
  43. struct device *dev;
  44. struct kobject kobj;
  45. void __iomem *memfreq_base;
  46. struct work_struct work;
  47. struct workqueue_struct *bwprof_wq;
  48. u32 sample_ms;
  49. u32 sample_cnt;
  50. struct hrtimer bwprof_hrtimer;
  51. u32 mon_count;
  52. u32 bus_width;
  53. };
  54. static struct bwprof_dev_data *bwprof_data;
  55. static void start_bwmon_node(struct bwmon_node *bw_node);
  56. static void stop_bwmon_node(struct bwmon_node *bw_node);
  57. struct qcom_bwprof_attr {
  58. struct attribute attr;
  59. ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
  60. char *buf);
  61. ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
  62. const char *buf, size_t count);
  63. };
  64. #define to_bwprof_attr(_attr) \
  65. container_of(_attr, struct qcom_bwprof_attr, attr)
  66. #define to_bwmon_node(k) container_of(k, struct bwmon_node, kobj)
  67. #define BWPROF_ATTR_RW(_name) \
  68. struct qcom_bwprof_attr _name = \
  69. __ATTR(_name, 0644, show_##_name, store_##_name) \
  70. #define BWPROF_ATTR_RO(_name) \
  71. struct qcom_bwprof_attr _name = \
  72. __ATTR(_name, 0444, show_##_name, NULL) \
  73. #define SAMPLE_MIN_MS 100U
  74. #define SAMPLE_MAX_MS 2000U
  75. static ssize_t store_sample_ms(struct kobject *kobj,
  76. struct attribute *attr, const char *buf,
  77. size_t count)
  78. {
  79. int ret;
  80. unsigned int val;
  81. ret = kstrtoint(buf, 10, &val);
  82. if (ret)
  83. return ret;
  84. val = max(val, SAMPLE_MIN_MS);
  85. val = min(val, SAMPLE_MAX_MS);
  86. bwprof_data->sample_ms = val;
  87. return count;
  88. }
  89. static ssize_t show_sample_ms(struct kobject *kobj,
  90. struct attribute *attr, char *buf)
  91. {
  92. return scnprintf(buf, PAGE_SIZE, "%u\n", bwprof_data->sample_ms);
  93. }
  94. static ssize_t store_mon_enabled(struct kobject *kobj,
  95. struct attribute *attr, const char *buf,
  96. size_t count)
  97. {
  98. struct bwmon_node *bw_node = to_bwmon_node(kobj);
  99. bool val;
  100. int ret;
  101. ret = kstrtobool(buf, &val);
  102. if (ret)
  103. return ret;
  104. if (bw_node->enabled == val)
  105. return count;
  106. mutex_lock(&bwprof_lock);
  107. bw_node->enabled = val;
  108. if (val)
  109. start_bwmon_node(bw_node);
  110. else
  111. stop_bwmon_node(bw_node);
  112. mutex_unlock(&bwprof_lock);
  113. return count;
  114. }
  115. static ssize_t show_mon_enabled(struct kobject *kobj,
  116. struct attribute *attr, char *buf)
  117. {
  118. struct bwmon_node *bw_node = to_bwmon_node(kobj);
  119. return scnprintf(buf, PAGE_SIZE, "%u\n", bw_node->enabled);
  120. }
  121. static ssize_t show_last_sample(struct kobject *kobj,
  122. struct attribute *attr, char *buf)
  123. {
  124. struct bwmon_node *bw_node = to_bwmon_node(kobj);
  125. struct bwprof_sample *sample = &bw_node->last_sample;
  126. return scnprintf(buf, PAGE_SIZE, "%llu\t%u\t%u\t%u\n",
  127. sample->ts, sample->meas_mbps, sample->max_mbps, sample->mem_freq);
  128. }
  129. static ssize_t show_client(struct kobject *kobj,
  130. struct attribute *attr, char *buf)
  131. {
  132. struct bwmon_node *bw_node = to_bwmon_node(kobj);
  133. return scnprintf(buf, PAGE_SIZE, "%s\n", bw_node->client);
  134. }
  135. static BWPROF_ATTR_RW(sample_ms);
  136. static BWPROF_ATTR_RW(mon_enabled);
  137. static BWPROF_ATTR_RO(last_sample);
  138. static BWPROF_ATTR_RO(client);
  139. static struct attribute *bwprof_attrs[] = {
  140. &sample_ms.attr,
  141. NULL,
  142. };
  143. ATTRIBUTE_GROUPS(bwprof);
  144. static struct attribute *mon_attrs[] = {
  145. &mon_enabled.attr,
  146. &last_sample.attr,
  147. &client.attr,
  148. NULL,
  149. };
  150. ATTRIBUTE_GROUPS(mon);
  151. static ssize_t attr_show(struct kobject *kobj, struct attribute *attr,
  152. char *buf)
  153. {
  154. struct qcom_bwprof_attr *bwprof_attr = to_bwprof_attr(attr);
  155. ssize_t ret = -EIO;
  156. if (bwprof_attr->show)
  157. ret = bwprof_attr->show(kobj, attr, buf);
  158. return ret;
  159. }
  160. static ssize_t attr_store(struct kobject *kobj, struct attribute *attr,
  161. const char *buf, size_t count)
  162. {
  163. struct qcom_bwprof_attr *bwprof_attr = to_bwprof_attr(attr);
  164. ssize_t ret = -EIO;
  165. if (bwprof_attr->store)
  166. ret = bwprof_attr->store(kobj, attr, buf, count);
  167. return ret;
  168. }
  169. static const struct sysfs_ops bwprof_sysfs_ops = {
  170. .show = attr_show,
  171. .store = attr_store,
  172. };
  173. static struct kobj_type bwprof_ktype = {
  174. .sysfs_ops = &bwprof_sysfs_ops,
  175. .default_groups = bwprof_groups,
  176. };
  177. static struct kobj_type mon_ktype = {
  178. .sysfs_ops = &bwprof_sysfs_ops,
  179. .default_groups = mon_groups,
  180. };
  181. static inline void bwmon_node_resume(struct bwmon_node *bw_node)
  182. {
  183. writel_relaxed(1, BWMON_EN(bw_node));
  184. }
  185. static inline void bwmon_node_pause(struct bwmon_node *bw_node)
  186. {
  187. writel_relaxed(0, BWMON_EN(bw_node));
  188. }
  189. #define BWMON_CLEAR_BIT 0x1
  190. #define BWMON_CLEAR_ALL_BIT 0x2
  191. static inline void bwmon_node_clear(struct bwmon_node *bw_node, bool clear_all)
  192. {
  193. if (clear_all)
  194. writel_relaxed(BWMON_CLEAR_ALL_BIT, BWMON_CLEAR(bw_node));
  195. else
  196. writel_relaxed(BWMON_CLEAR_BIT, BWMON_CLEAR(bw_node));
  197. /*
  198. * In some hardware versions since BWMON_CLEAR(m) register does not have
  199. * self-clearing capability it needs to be cleared explicitly. But we also
  200. * need to ensure the writes to it are successful before clearing it.
  201. */
  202. wmb();
  203. writel_relaxed(0, BWMON_CLEAR(bw_node));
  204. writel_relaxed(HW_SAMPLE_TICKS, BWMON_SW(bw_node));
  205. }
  206. #define ZONE_THRES_LIM 0xFFFF
  207. #define ZONE_CNT_THRES_LIM 0xFFFFFFFF
  208. static void configure_bwmon_node(struct bwmon_node *bw_node)
  209. {
  210. bwmon_node_pause(bw_node);
  211. bwmon_node_clear(bw_node, false);
  212. writel_relaxed(ZONE_THRES_LIM, BWMON_THRES_HI(bw_node));
  213. writel_relaxed(ZONE_THRES_LIM, BWMON_THRES_MED(bw_node));
  214. writel_relaxed(0, BWMON_THRES_LO(bw_node));
  215. writel_relaxed(ZONE_CNT_THRES_LIM, BWMON_ZONE_CNT_THRES(bw_node));
  216. writel_relaxed(0, BWMON_ZONE_ACTIONS(bw_node));
  217. writel_relaxed(HW_SAMPLE_TICKS, BWMON_SW(bw_node));
  218. }
  219. /* Note: bwprof_lock must be held before calling this function */
  220. static void start_bwmon_node(struct bwmon_node *bw_node)
  221. {
  222. configure_bwmon_node(bw_node);
  223. bwmon_node_resume(bw_node);
  224. if (!hrtimer_active(&bwprof_data->bwprof_hrtimer))
  225. hrtimer_start(&bwprof_data->bwprof_hrtimer,
  226. ms_to_ktime(HW_SAMPLE_MS), HRTIMER_MODE_REL_PINNED);
  227. }
  228. /* Note: bwprof_lock must be held before calling this function */
  229. static void stop_bwmon_node(struct bwmon_node *bw_node)
  230. {
  231. bool all_disabled = true;
  232. struct bwmon_node *itr;
  233. bwmon_node_pause(bw_node);
  234. bwmon_node_clear(bw_node, true);
  235. memset(&bw_node->last_sample, 0, sizeof(bw_node->last_sample));
  236. list_for_each_entry(itr, &bwprof_list, list) {
  237. if (itr->enabled) {
  238. all_disabled = false;
  239. break;
  240. }
  241. }
  242. if (all_disabled) {
  243. hrtimer_cancel(&bwprof_data->bwprof_hrtimer);
  244. cancel_work_sync(&bwprof_data->work);
  245. }
  246. }
  247. #define PICOSECONDS_TO_MHZ(t) ((1000000 / t))
  248. static inline u32 get_memfreq(void)
  249. {
  250. u32 memfreq;
  251. memfreq = readl_relaxed(DDR_FREQ(bwprof_data));
  252. memfreq = PICOSECONDS_TO_MHZ(memfreq);
  253. return memfreq;
  254. }
  255. #define MAX_BYTE_COUNT_MASK 0xFFFF
  256. #define MAX_BYTE_COUNT_SHIFT 16
  257. static void get_bw_and_update_last_sample(struct bwmon_node *bw_node)
  258. {
  259. unsigned long count;
  260. bwmon_node_pause(bw_node);
  261. count = readl_relaxed(BWMON_ZONE1_MAX_BYTE_COUNT(bw_node)) &
  262. MAX_BYTE_COUNT_MASK;
  263. count <<= MAX_BYTE_COUNT_SHIFT;
  264. bw_node->curr_sample_bytes += count;
  265. bwmon_node_clear(bw_node, false);
  266. bwmon_node_resume(bw_node);
  267. }
  268. static void bwprof_update_work(struct work_struct *work)
  269. {
  270. struct bwmon_node *bw_node;
  271. ktime_t now = ktime_get();
  272. u32 mem_freq, max_mbps;
  273. bool update_last_sample = false;
  274. mutex_lock(&bwprof_lock);
  275. bwprof_data->sample_cnt++;
  276. if (bwprof_data->sample_cnt * HW_SAMPLE_MS >= bwprof_data->sample_ms) {
  277. update_last_sample = true;
  278. bwprof_data->sample_cnt = 0;
  279. mem_freq = get_memfreq();
  280. max_mbps = bwprof_data->bus_width * mem_freq;
  281. }
  282. list_for_each_entry(bw_node, &bwprof_list, list) {
  283. if (!bw_node->enabled)
  284. continue;
  285. get_bw_and_update_last_sample(bw_node);
  286. if (update_last_sample) {
  287. bw_node->last_sample.ts = now;
  288. do_div(bw_node->curr_sample_bytes,
  289. bwprof_data->sample_ms * USEC_PER_MSEC);
  290. bw_node->last_sample.meas_mbps = bw_node->curr_sample_bytes;
  291. bw_node->last_sample.mem_freq = mem_freq;
  292. bw_node->last_sample.max_mbps = max_mbps;
  293. trace_bwprof_last_sample(
  294. dev_name(bw_node->dev),
  295. bw_node->client,
  296. bw_node->last_sample.ts,
  297. bw_node->last_sample.meas_mbps,
  298. bw_node->last_sample.max_mbps,
  299. bw_node->last_sample.mem_freq
  300. );
  301. bw_node->curr_sample_bytes = 0;
  302. }
  303. }
  304. mutex_unlock(&bwprof_lock);
  305. }
  306. #define MAX_NAME_LEN 20
  307. #define QCOM_BWPROF_CLIENT_PROP "client"
  308. static int bwprof_mon_probe(struct platform_device *pdev)
  309. {
  310. struct device *dev = &pdev->dev;
  311. struct bwmon_node *bw_node;
  312. char name[MAX_NAME_LEN];
  313. struct resource *res;
  314. int ret;
  315. if (!bwprof_data) {
  316. dev_err(dev, "Missing bwprof dev data!\n");
  317. return -ENODEV;
  318. }
  319. bw_node = devm_kzalloc(dev, sizeof(*bw_node), GFP_KERNEL);
  320. if (!bw_node)
  321. return -ENOMEM;
  322. bw_node->dev = dev;
  323. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
  324. if (!res) {
  325. dev_err(dev, "base not found!\n");
  326. return -EINVAL;
  327. }
  328. bw_node->base = devm_ioremap(dev, res->start, resource_size(res));
  329. if (!bw_node->base) {
  330. dev_err(dev, "Unable map base!\n");
  331. return -ENOMEM;
  332. }
  333. ret = of_property_read_string(dev->of_node, QCOM_BWPROF_CLIENT_PROP,
  334. &bw_node->client);
  335. if (ret < 0) {
  336. dev_err(dev, "client not found!: %d\n", ret);
  337. return ret;
  338. }
  339. snprintf(name, MAX_NAME_LEN, "bwmon%d", bwprof_data->mon_count);
  340. ret = kobject_init_and_add(&bw_node->kobj, &mon_ktype,
  341. &bwprof_data->kobj, name);
  342. if (ret < 0) {
  343. dev_err(dev, "failed to init bwprof mon kobj: %d\n", ret);
  344. kobject_put(&bw_node->kobj);
  345. return ret;
  346. }
  347. configure_bwmon_node(bw_node);
  348. mutex_lock(&bwprof_lock);
  349. list_add_tail(&bw_node->list, &bwprof_list);
  350. mutex_unlock(&bwprof_lock);
  351. bwprof_data->mon_count++;
  352. return 0;
  353. }
  354. static enum hrtimer_restart bwprof_hrtimer_handler(struct hrtimer *timer)
  355. {
  356. ktime_t now = ktime_get();
  357. queue_work(bwprof_data->bwprof_wq, &bwprof_data->work);
  358. hrtimer_forward(timer, now, ms_to_ktime(HW_SAMPLE_MS));
  359. return HRTIMER_RESTART;
  360. }
  361. static int bwprof_dev_probe(struct platform_device *pdev)
  362. {
  363. struct device *dev = &pdev->dev;
  364. struct resource *res;
  365. int ret;
  366. bwprof_data = devm_kzalloc(dev, sizeof(*bwprof_data), GFP_KERNEL);
  367. if (!bwprof_data)
  368. return -ENOMEM;
  369. bwprof_data->dev = dev;
  370. bwprof_data->sample_ms = 100;
  371. bwprof_data->mon_count = 0;
  372. ret = of_property_read_u32(dev->of_node, "qcom,bus-width",
  373. &bwprof_data->bus_width);
  374. if (ret < 0 || !bwprof_data->bus_width) {
  375. dev_err(dev, "Missing or invalid bus-width: %d\n", ret);
  376. return -EINVAL;
  377. }
  378. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem-freq");
  379. if (!res) {
  380. dev_err(dev, "mem-freq not found!\n");
  381. return -EINVAL;
  382. }
  383. bwprof_data->memfreq_base = devm_ioremap(dev, res->start,
  384. resource_size(res));
  385. if (!bwprof_data->memfreq_base) {
  386. dev_err(dev, "Unable map memfreq base!\n");
  387. return -ENOMEM;
  388. }
  389. hrtimer_init(&bwprof_data->bwprof_hrtimer, CLOCK_MONOTONIC,
  390. HRTIMER_MODE_REL);
  391. bwprof_data->bwprof_hrtimer.function = bwprof_hrtimer_handler;
  392. bwprof_data->bwprof_wq = create_freezable_workqueue("bwprof_wq");
  393. if (!bwprof_data->bwprof_wq) {
  394. dev_err(dev, "Couldn't create bwprof workqueue.\n");
  395. return -ENOMEM;
  396. }
  397. INIT_WORK(&bwprof_data->work, &bwprof_update_work);
  398. ret = kobject_init_and_add(&bwprof_data->kobj, &bwprof_ktype,
  399. &cpu_subsys.dev_root->kobj, "bw_prof");
  400. if (ret < 0) {
  401. dev_err(dev, "failed to init bwprof kobj: %d\n", ret);
  402. kobject_put(&bwprof_data->kobj);
  403. return ret;
  404. }
  405. return 0;
  406. }
  407. static int qcom_bwprof_driver_probe(struct platform_device *pdev)
  408. {
  409. struct device *dev = &pdev->dev;
  410. int ret = 0;
  411. const struct bwprof_spec *spec;
  412. enum bwprof_type type = NUM_BWPROF_TYPES;
  413. spec = of_device_get_match_data(dev);
  414. if (spec)
  415. type = spec->type;
  416. switch (type) {
  417. case BWPROF_DEV:
  418. if (bwprof_data) {
  419. dev_err(dev, "only one bwprof device allowed\n");
  420. ret = -ENODEV;
  421. }
  422. ret = bwprof_dev_probe(pdev);
  423. if (!ret && of_get_available_child_count(dev->of_node))
  424. of_platform_populate(dev->of_node, NULL, NULL, dev);
  425. break;
  426. case BWPROF_MON:
  427. ret = bwprof_mon_probe(pdev);
  428. break;
  429. default:
  430. /*
  431. * This should never happen.
  432. */
  433. dev_err(dev, "Invalid bwprof type specified: %u\n", type);
  434. return -EINVAL;
  435. }
  436. if (ret < 0) {
  437. dev_err(dev, "Failure to probe bwprof device: %d\n", ret);
  438. return ret;
  439. }
  440. return 0;
  441. }
  442. static const struct bwprof_spec spec[] = {
  443. [0] = { BWPROF_DEV },
  444. [1] = { BWPROF_MON },
  445. };
  446. static const struct of_device_id qcom_bwprof_match_table[] = {
  447. { .compatible = "qcom,bwprof", .data = &spec[0] },
  448. { .compatible = "qcom,bwprof-mon", .data = &spec[1] },
  449. {}
  450. };
  451. MODULE_DEVICE_TABLE(of, qcom_bwprof_match_table);
  452. static struct platform_driver qcom_bwprof_driver = {
  453. .probe = qcom_bwprof_driver_probe,
  454. .driver = {
  455. .name = "qcom-bwprof",
  456. .of_match_table = qcom_bwprof_match_table,
  457. .suppress_bind_attrs = true,
  458. },
  459. };
  460. module_platform_driver(qcom_bwprof_driver);
  461. MODULE_DESCRIPTION("QCOM BWPROF driver");
  462. MODULE_LICENSE("GPL");