cam_common_util.c 6.1 KB

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