cam_common_util.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/string.h>
  6. #include <linux/types.h>
  7. #include <linux/slab.h>
  8. #include <linux/timer.h>
  9. #include <linux/completion.h>
  10. #include <linux/module.h>
  11. #include <linux/iopoll.h>
  12. #include <linux/moduleparam.h>
  13. #include "cam_common_util.h"
  14. #include "cam_debug_util.h"
  15. #include "cam_presil_hw_access.h"
  16. #include "cam_hw.h"
  17. #if IS_REACHABLE(CONFIG_QCOM_VA_MINIDUMP)
  18. #include <soc/qcom/minidump.h>
  19. static struct cam_common_mini_dump_dev_info g_minidump_dev_info;
  20. #endif
  21. #define CAM_PRESIL_POLL_DELAY 20
  22. static uint timeout_multiplier = 1;
  23. module_param(timeout_multiplier, uint, 0644);
  24. int cam_common_util_get_string_index(const char **strings,
  25. uint32_t num_strings, const char *matching_string, uint32_t *index)
  26. {
  27. int i;
  28. for (i = 0; i < num_strings; i++) {
  29. if (strnstr(strings[i], matching_string, strlen(strings[i]))) {
  30. CAM_DBG(CAM_UTIL, "matched %s : %d\n",
  31. matching_string, i);
  32. *index = i;
  33. return 0;
  34. }
  35. }
  36. return -EINVAL;
  37. }
  38. uint32_t cam_common_util_remove_duplicate_arr(int32_t *arr, uint32_t num)
  39. {
  40. int i, j;
  41. uint32_t wr_idx = 1;
  42. if (!arr) {
  43. CAM_ERR(CAM_UTIL, "Null input array");
  44. return 0;
  45. }
  46. for (i = 1; i < num; i++) {
  47. for (j = 0; j < wr_idx ; j++) {
  48. if (arr[i] == arr[j])
  49. break;
  50. }
  51. if (j == wr_idx)
  52. arr[wr_idx++] = arr[i];
  53. }
  54. return wr_idx;
  55. }
  56. unsigned long cam_common_wait_for_completion_timeout(
  57. struct completion *complete,
  58. unsigned long timeout_jiffies)
  59. {
  60. unsigned long wait_jiffies;
  61. unsigned long rem_jiffies;
  62. if (!complete) {
  63. CAM_ERR(CAM_UTIL, "Null complete pointer");
  64. return 0;
  65. }
  66. if (timeout_multiplier < 1)
  67. timeout_multiplier = 1;
  68. wait_jiffies = timeout_jiffies * timeout_multiplier;
  69. rem_jiffies = wait_for_completion_timeout(complete, wait_jiffies);
  70. return rem_jiffies;
  71. }
  72. int cam_common_read_poll_timeout(
  73. void __iomem *addr,
  74. unsigned long delay,
  75. unsigned long timeout,
  76. uint32_t mask,
  77. uint32_t check_val,
  78. uint32_t *status)
  79. {
  80. unsigned long wait_time_us;
  81. int rc = -EINVAL;
  82. if (!addr || !status) {
  83. CAM_ERR(CAM_UTIL, "Invalid param addr: %pK status: %pK",
  84. addr, status);
  85. return rc;
  86. }
  87. if (timeout_multiplier < 1)
  88. timeout_multiplier = 1;
  89. wait_time_us = timeout * timeout_multiplier;
  90. if (false == cam_presil_mode_enabled()) {
  91. rc = readl_poll_timeout(addr, *status, (*status & mask) == check_val, delay,
  92. wait_time_us);
  93. } else {
  94. rc = cam_presil_readl_poll_timeout(addr, mask,
  95. wait_time_us/(CAM_PRESIL_POLL_DELAY * 1000), CAM_PRESIL_POLL_DELAY);
  96. }
  97. return rc;
  98. }
  99. int cam_common_modify_timer(struct timer_list *timer, int32_t timeout_val)
  100. {
  101. if (!timer) {
  102. CAM_ERR(CAM_UTIL, "Invalid reference to system timer");
  103. return -EINVAL;
  104. }
  105. if (timeout_multiplier < 1)
  106. timeout_multiplier = 1;
  107. CAM_DBG(CAM_UTIL, "Starting timer to fire in %d ms. (jiffies=%lu)\n",
  108. (timeout_val * timeout_multiplier), jiffies);
  109. mod_timer(timer,
  110. (jiffies + msecs_to_jiffies(timeout_val * timeout_multiplier)));
  111. return 0;
  112. }
  113. void cam_common_util_thread_switch_delay_detect(
  114. const char *token, ktime_t scheduled_time, uint32_t threshold)
  115. {
  116. uint64_t diff;
  117. ktime_t cur_time;
  118. struct timespec64 cur_ts;
  119. struct timespec64 scheduled_ts;
  120. cur_time = ktime_get();
  121. diff = ktime_ms_delta(cur_time, scheduled_time);
  122. if (diff > threshold) {
  123. scheduled_ts = ktime_to_timespec64(scheduled_time);
  124. cur_ts = ktime_to_timespec64(cur_time);
  125. CAM_WARN_RATE_LIMIT_CUSTOM(CAM_UTIL, 1, 1,
  126. "%s delay detected %ld:%06ld cur %ld:%06ld diff %ld: threshold %d",
  127. token, scheduled_ts.tv_sec,
  128. scheduled_ts.tv_nsec/NSEC_PER_USEC,
  129. cur_ts.tv_sec, cur_ts.tv_nsec/NSEC_PER_USEC,
  130. diff, threshold);
  131. }
  132. }
  133. #if IS_REACHABLE(CONFIG_QCOM_VA_MINIDUMP)
  134. static void cam_common_mini_dump_handler(void *dst, unsigned long len)
  135. {
  136. int i = 0;
  137. uint8_t *waddr;
  138. unsigned long bytes_written = 0;
  139. unsigned long remain_len = len;
  140. struct cam_common_mini_dump_data *md;
  141. if (len < sizeof(*md)) {
  142. CAM_WARN(CAM_UTIL, "Insufficient len %lu", len);
  143. return;
  144. }
  145. md = (struct cam_common_mini_dump_data *)dst;
  146. waddr = (uint8_t *)md + sizeof(*md);
  147. remain_len -= sizeof(*md);
  148. for (i = 0; i < CAM_COMMON_MINI_DUMP_DEV_NUM; i++) {
  149. if (!g_minidump_dev_info.dump_cb[i])
  150. continue;
  151. memcpy(md->name[i], g_minidump_dev_info.name[i],
  152. strlen(g_minidump_dev_info.name[i]));
  153. md->waddr[i] = (void *)waddr;
  154. bytes_written = g_minidump_dev_info.dump_cb[i](
  155. (void *)waddr, remain_len);
  156. md->size[i] = bytes_written;
  157. if (bytes_written >= len) {
  158. CAM_WARN(CAM_UTIL, "No more space to dump");
  159. goto nomem;
  160. }
  161. remain_len -= bytes_written;
  162. waddr += bytes_written;
  163. }
  164. return;
  165. nomem:
  166. for (; i >=0; i--)
  167. CAM_WARN(CAM_UTIL, "%s: Dumped len: %lu", md->name[i], md->size[i]);
  168. }
  169. static int cam_common_md_notify_handler(struct notifier_block *this,
  170. unsigned long event, void *ptr)
  171. {
  172. struct va_md_entry cbentry;
  173. int rc = 0;
  174. cbentry.vaddr = 0x0;
  175. strlcpy(cbentry.owner, "Camera", sizeof(cbentry.owner));
  176. cbentry.size = CAM_COMMON_MINI_DUMP_SIZE;
  177. cbentry.cb = cam_common_mini_dump_handler;
  178. rc = qcom_va_md_add_region(&cbentry);
  179. if (rc) {
  180. CAM_ERR(CAM_UTIL, "Va Region add falied %d", rc);
  181. return NOTIFY_STOP_MASK;
  182. }
  183. return NOTIFY_OK;
  184. }
  185. static struct notifier_block cam_common_md_notify_blk = {
  186. .notifier_call = cam_common_md_notify_handler,
  187. .priority = INT_MAX,
  188. };
  189. int cam_common_register_mini_dump_cb(
  190. cam_common_mini_dump_cb mini_dump_cb,
  191. uint8_t *dev_name)
  192. {
  193. int rc = 0;
  194. if (g_minidump_dev_info.num_devs >= CAM_COMMON_MINI_DUMP_DEV_NUM) {
  195. CAM_ERR(CAM_UTIL, "No free index available");
  196. return -EINVAL;
  197. }
  198. if (!mini_dump_cb || !dev_name) {
  199. CAM_ERR(CAM_UTIL, "Invalid params");
  200. return -EINVAL;
  201. }
  202. g_minidump_dev_info.dump_cb[g_minidump_dev_info.num_devs] =
  203. mini_dump_cb;
  204. scnprintf(g_minidump_dev_info.name[g_minidump_dev_info.num_devs],
  205. CAM_COMMON_MINI_DUMP_DEV_NAME_LEN, dev_name);
  206. g_minidump_dev_info.num_devs++;
  207. if (!g_minidump_dev_info.is_registered) {
  208. rc = qcom_va_md_register("Camera", &cam_common_md_notify_blk);
  209. if (rc) {
  210. CAM_ERR(CAM_UTIL, "Camera VA minidump register failed");
  211. goto end;
  212. }
  213. g_minidump_dev_info.is_registered = true;
  214. }
  215. end:
  216. return rc;
  217. }
  218. #endif
  219. void *cam_common_user_dump_clock(
  220. void *dump_struct, uint8_t *addr_ptr)
  221. {
  222. struct cam_hw_info *hw_info = NULL;
  223. uint64_t *addr = NULL;
  224. hw_info = (struct cam_hw_info *)dump_struct;
  225. if (!hw_info || !addr_ptr) {
  226. CAM_ERR(CAM_ISP, "HW info or address pointer NULL");
  227. return addr;
  228. }
  229. addr = (uint64_t *)addr_ptr;
  230. *addr++ = hw_info->soc_info.applied_src_clk_rate;
  231. return addr;
  232. }
  233. int cam_common_user_dump_helper(
  234. void *cmd_args,
  235. void *(*func)(void *dump_struct, uint8_t *addr_ptr),
  236. void *dump_struct,
  237. size_t size,
  238. const char *tag, ...)
  239. {
  240. uint8_t *dst;
  241. uint8_t *addr, *start;
  242. void *returned_ptr;
  243. struct cam_common_hw_dump_args *dump_args;
  244. struct cam_common_hw_dump_header *hdr;
  245. va_list args;
  246. void*(*func_ptr)(void *dump_struct, uint8_t *addr_ptr);
  247. dump_args = (struct cam_common_hw_dump_args *)cmd_args;
  248. if (!dump_args->cpu_addr || !dump_args->buf_len) {
  249. CAM_ERR(CAM_UTIL,
  250. "Invalid params %pK %zu",
  251. (void *)dump_args->cpu_addr,
  252. dump_args->buf_len);
  253. return -EINVAL;
  254. }
  255. if (dump_args->buf_len <= dump_args->offset) {
  256. CAM_WARN(CAM_UTIL,
  257. "Dump offset overshoot offset %zu buf_len %zu",
  258. dump_args->offset, dump_args->buf_len);
  259. return -ENOSPC;
  260. }
  261. dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset;
  262. hdr = (struct cam_common_hw_dump_header *)dst;
  263. va_start(args, tag);
  264. vscnprintf(hdr->tag, CAM_COMMON_HW_DUMP_TAG_MAX_LEN, tag, args);
  265. va_end(args);
  266. hdr->word_size = size;
  267. addr = (uint8_t *)(dst + sizeof(struct cam_common_hw_dump_header));
  268. start = addr;
  269. func_ptr = func;
  270. returned_ptr = func_ptr(dump_struct, addr);
  271. if (IS_ERR(returned_ptr))
  272. return PTR_ERR(returned_ptr);
  273. addr = (uint8_t *)returned_ptr;
  274. hdr->size = addr - start;
  275. CAM_DBG(CAM_UTIL, "hdr size: %d, word size: %d, addr: %x, start: %x",
  276. hdr->size, hdr->word_size, addr, start);
  277. dump_args->offset += hdr->size +
  278. sizeof(struct cam_common_hw_dump_header);
  279. return 0;
  280. }