cam_common_util.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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. #if IS_REACHABLE(CONFIG_QCOM_VA_MINIDUMP)
  17. #include <soc/qcom/minidump.h>
  18. static struct cam_common_mini_dump_dev_info g_minidump_dev_info;
  19. #endif
  20. #define CAM_PRESIL_POLL_DELAY 20
  21. static uint timeout_multiplier = 1;
  22. module_param(timeout_multiplier, uint, 0644);
  23. int cam_common_util_get_string_index(const char **strings,
  24. uint32_t num_strings, const char *matching_string, uint32_t *index)
  25. {
  26. int i;
  27. for (i = 0; i < num_strings; i++) {
  28. if (strnstr(strings[i], matching_string, strlen(strings[i]))) {
  29. CAM_DBG(CAM_UTIL, "matched %s : %d\n",
  30. matching_string, i);
  31. *index = i;
  32. return 0;
  33. }
  34. }
  35. return -EINVAL;
  36. }
  37. uint32_t cam_common_util_remove_duplicate_arr(int32_t *arr, uint32_t num)
  38. {
  39. int i, j;
  40. uint32_t wr_idx = 1;
  41. if (!arr) {
  42. CAM_ERR(CAM_UTIL, "Null input array");
  43. return 0;
  44. }
  45. for (i = 1; i < num; i++) {
  46. for (j = 0; j < wr_idx ; j++) {
  47. if (arr[i] == arr[j])
  48. break;
  49. }
  50. if (j == wr_idx)
  51. arr[wr_idx++] = arr[i];
  52. }
  53. return wr_idx;
  54. }
  55. unsigned long cam_common_wait_for_completion_timeout(
  56. struct completion *complete,
  57. unsigned long timeout_jiffies)
  58. {
  59. unsigned long wait_jiffies;
  60. unsigned long rem_jiffies;
  61. if (!complete) {
  62. CAM_ERR(CAM_UTIL, "Null complete pointer");
  63. return 0;
  64. }
  65. if (timeout_multiplier < 1)
  66. timeout_multiplier = 1;
  67. wait_jiffies = timeout_jiffies * timeout_multiplier;
  68. rem_jiffies = wait_for_completion_timeout(complete, wait_jiffies);
  69. return rem_jiffies;
  70. }
  71. int cam_common_read_poll_timeout(
  72. void __iomem *addr,
  73. unsigned long delay,
  74. unsigned long timeout,
  75. uint32_t mask,
  76. uint32_t check_val,
  77. uint32_t *status)
  78. {
  79. unsigned long wait_time_us;
  80. int rc = -EINVAL;
  81. if (!addr || !status) {
  82. CAM_ERR(CAM_UTIL, "Invalid param addr: %pK status: %pK",
  83. addr, status);
  84. return rc;
  85. }
  86. if (timeout_multiplier < 1)
  87. timeout_multiplier = 1;
  88. wait_time_us = timeout * timeout_multiplier;
  89. if (false == cam_presil_mode_enabled()) {
  90. rc = readl_poll_timeout(addr, *status, (*status & mask) == check_val, delay,
  91. wait_time_us);
  92. } else {
  93. rc = cam_presil_readl_poll_timeout(addr, mask,
  94. wait_time_us/(CAM_PRESIL_POLL_DELAY * 1000), CAM_PRESIL_POLL_DELAY);
  95. }
  96. return rc;
  97. }
  98. int cam_common_modify_timer(struct timer_list *timer, int32_t timeout_val)
  99. {
  100. if (!timer) {
  101. CAM_ERR(CAM_UTIL, "Invalid reference to system timer");
  102. return -EINVAL;
  103. }
  104. if (timeout_multiplier < 1)
  105. timeout_multiplier = 1;
  106. CAM_DBG(CAM_UTIL, "Starting timer to fire in %d ms. (jiffies=%lu)\n",
  107. (timeout_val * timeout_multiplier), jiffies);
  108. mod_timer(timer,
  109. (jiffies + msecs_to_jiffies(timeout_val * timeout_multiplier)));
  110. return 0;
  111. }
  112. void cam_common_util_thread_switch_delay_detect(
  113. const char *token, ktime_t scheduled_time, uint32_t threshold)
  114. {
  115. uint64_t diff;
  116. ktime_t cur_time;
  117. struct timespec64 cur_ts;
  118. struct timespec64 scheduled_ts;
  119. cur_time = ktime_get();
  120. diff = ktime_ms_delta(cur_time, scheduled_time);
  121. if (diff > threshold) {
  122. scheduled_ts = ktime_to_timespec64(scheduled_time);
  123. cur_ts = ktime_to_timespec64(cur_time);
  124. CAM_WARN_RATE_LIMIT_CUSTOM(CAM_UTIL, 1, 1,
  125. "%s delay detected %ld:%06ld cur %ld:%06ld diff %ld: threshold %d",
  126. token, scheduled_ts.tv_sec,
  127. scheduled_ts.tv_nsec/NSEC_PER_USEC,
  128. cur_ts.tv_sec, cur_ts.tv_nsec/NSEC_PER_USEC,
  129. diff, threshold);
  130. }
  131. }
  132. #if IS_REACHABLE(CONFIG_QCOM_VA_MINIDUMP)
  133. static void cam_common_mini_dump_handler(void *dst, unsigned long len)
  134. {
  135. int i = 0;
  136. uint8_t *waddr;
  137. unsigned long bytes_written = 0;
  138. unsigned long remain_len = len;
  139. struct cam_common_mini_dump_data *md;
  140. if (len < sizeof(*md)) {
  141. CAM_WARN(CAM_UTIL, "Insufficient len %lu", len);
  142. return;
  143. }
  144. md = (struct cam_common_mini_dump_data *)dst;
  145. waddr = (uint8_t *)md + sizeof(*md);
  146. remain_len -= sizeof(*md);
  147. for (i = 0; i < CAM_COMMON_MINI_DUMP_DEV_NUM; i++) {
  148. if (!g_minidump_dev_info.dump_cb[i])
  149. continue;
  150. memcpy(md->name[i], g_minidump_dev_info.name[i],
  151. strlen(g_minidump_dev_info.name[i]));
  152. md->waddr[i] = (void *)waddr;
  153. bytes_written = g_minidump_dev_info.dump_cb[i](
  154. (void *)waddr, remain_len);
  155. md->size[i] = bytes_written;
  156. if (bytes_written >= len) {
  157. CAM_WARN(CAM_UTIL, "No more space to dump");
  158. goto nomem;
  159. }
  160. remain_len -= bytes_written;
  161. waddr += bytes_written;
  162. }
  163. return;
  164. nomem:
  165. for (; i >=0; i--)
  166. CAM_WARN(CAM_UTIL, "%s: Dumped len: %lu", md->name[i], md->size[i]);
  167. }
  168. static int cam_common_md_notify_handler(struct notifier_block *this,
  169. unsigned long event, void *ptr)
  170. {
  171. struct va_md_entry cbentry;
  172. int rc = 0;
  173. cbentry.vaddr = 0x0;
  174. strlcpy(cbentry.owner, "Camera", sizeof(cbentry.owner));
  175. cbentry.size = CAM_COMMON_MINI_DUMP_SIZE;
  176. cbentry.cb = cam_common_mini_dump_handler;
  177. rc = qcom_va_md_add_region(&cbentry);
  178. if (rc) {
  179. CAM_ERR(CAM_UTIL, "Va Region add falied %d", rc);
  180. return NOTIFY_STOP_MASK;
  181. }
  182. return NOTIFY_OK;
  183. }
  184. static struct notifier_block cam_common_md_notify_blk = {
  185. .notifier_call = cam_common_md_notify_handler,
  186. .priority = INT_MAX,
  187. };
  188. int cam_common_register_mini_dump_cb(
  189. cam_common_mini_dump_cb mini_dump_cb,
  190. uint8_t *dev_name)
  191. {
  192. int rc = 0;
  193. if (g_minidump_dev_info.num_devs >= CAM_COMMON_MINI_DUMP_DEV_NUM) {
  194. CAM_ERR(CAM_UTIL, "No free index available");
  195. return -EINVAL;
  196. }
  197. if (!mini_dump_cb || !dev_name) {
  198. CAM_ERR(CAM_UTIL, "Invalid params");
  199. return -EINVAL;
  200. }
  201. g_minidump_dev_info.dump_cb[g_minidump_dev_info.num_devs] =
  202. mini_dump_cb;
  203. scnprintf(g_minidump_dev_info.name[g_minidump_dev_info.num_devs],
  204. CAM_COMMON_MINI_DUMP_DEV_NAME_LEN, dev_name);
  205. g_minidump_dev_info.num_devs++;
  206. if (!g_minidump_dev_info.is_registered) {
  207. rc = qcom_va_md_register("Camera", &cam_common_md_notify_blk);
  208. if (rc) {
  209. CAM_ERR(CAM_UTIL, "Camera VA minidump register failed");
  210. goto end;
  211. }
  212. g_minidump_dev_info.is_registered = true;
  213. }
  214. end:
  215. return rc;
  216. }
  217. #endif