ivpu_ms.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // SPDX-License-Identifier: GPL-2.0-only OR MIT
  2. /*
  3. * Copyright (C) 2020-2024 Intel Corporation
  4. */
  5. #include <drm/drm_file.h>
  6. #include <linux/pm_runtime.h>
  7. #include "ivpu_drv.h"
  8. #include "ivpu_gem.h"
  9. #include "ivpu_hw.h"
  10. #include "ivpu_jsm_msg.h"
  11. #include "ivpu_ms.h"
  12. #include "ivpu_pm.h"
  13. #define MS_INFO_BUFFER_SIZE SZ_64K
  14. #define MS_NUM_BUFFERS 2
  15. #define MS_READ_PERIOD_MULTIPLIER 2
  16. #define MS_MIN_SAMPLE_PERIOD_NS 1000000
  17. static struct ivpu_ms_instance *
  18. get_instance_by_mask(struct ivpu_file_priv *file_priv, u64 metric_mask)
  19. {
  20. struct ivpu_ms_instance *ms;
  21. lockdep_assert_held(&file_priv->ms_lock);
  22. list_for_each_entry(ms, &file_priv->ms_instance_list, ms_instance_node)
  23. if (ms->mask == metric_mask)
  24. return ms;
  25. return NULL;
  26. }
  27. int ivpu_ms_start_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
  28. {
  29. struct ivpu_file_priv *file_priv = file->driver_priv;
  30. struct drm_ivpu_metric_streamer_start *args = data;
  31. struct ivpu_device *vdev = file_priv->vdev;
  32. struct ivpu_ms_instance *ms;
  33. u32 sample_size;
  34. u64 buf_size;
  35. int ret;
  36. if (!args->metric_group_mask || !args->read_period_samples ||
  37. args->sampling_period_ns < MS_MIN_SAMPLE_PERIOD_NS)
  38. return -EINVAL;
  39. ret = ivpu_rpm_get(vdev);
  40. if (ret < 0)
  41. return ret;
  42. mutex_lock(&file_priv->ms_lock);
  43. if (get_instance_by_mask(file_priv, args->metric_group_mask)) {
  44. ivpu_dbg(vdev, IOCTL, "Instance already exists (mask %#llx)\n",
  45. args->metric_group_mask);
  46. ret = -EALREADY;
  47. goto unlock;
  48. }
  49. ms = kzalloc_obj(*ms);
  50. if (!ms) {
  51. ret = -ENOMEM;
  52. goto unlock;
  53. }
  54. ms->mask = args->metric_group_mask;
  55. ret = ivpu_jsm_metric_streamer_info(vdev, ms->mask, 0, 0, &sample_size, NULL);
  56. if (ret)
  57. goto err_free_ms;
  58. buf_size = PAGE_ALIGN((u64)args->read_period_samples * sample_size *
  59. MS_READ_PERIOD_MULTIPLIER * MS_NUM_BUFFERS);
  60. if (buf_size > ivpu_hw_range_size(&vdev->hw->ranges.global)) {
  61. ivpu_dbg(vdev, IOCTL, "Requested MS buffer size %llu exceeds range size %llu\n",
  62. buf_size, ivpu_hw_range_size(&vdev->hw->ranges.global));
  63. ret = -EINVAL;
  64. goto err_free_ms;
  65. }
  66. ms->bo = ivpu_bo_create_global(vdev, buf_size, DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
  67. if (!ms->bo) {
  68. ivpu_dbg(vdev, IOCTL, "Failed to allocate MS buffer (size %llu)\n", buf_size);
  69. ret = -ENOMEM;
  70. goto err_free_ms;
  71. }
  72. ms->buff_size = ivpu_bo_size(ms->bo) / MS_NUM_BUFFERS;
  73. ms->active_buff_vpu_addr = ms->bo->vpu_addr;
  74. ms->inactive_buff_vpu_addr = ms->bo->vpu_addr + ms->buff_size;
  75. ms->active_buff_ptr = ivpu_bo_vaddr(ms->bo);
  76. ms->inactive_buff_ptr = ivpu_bo_vaddr(ms->bo) + ms->buff_size;
  77. ret = ivpu_jsm_metric_streamer_start(vdev, ms->mask, args->sampling_period_ns,
  78. ms->active_buff_vpu_addr, ms->buff_size);
  79. if (ret)
  80. goto err_free_bo;
  81. args->sample_size = sample_size;
  82. args->max_data_size = ivpu_bo_size(ms->bo);
  83. list_add_tail(&ms->ms_instance_node, &file_priv->ms_instance_list);
  84. goto unlock;
  85. err_free_bo:
  86. ivpu_bo_free(ms->bo);
  87. err_free_ms:
  88. kfree(ms);
  89. unlock:
  90. mutex_unlock(&file_priv->ms_lock);
  91. ivpu_rpm_put(vdev);
  92. return ret;
  93. }
  94. static int
  95. copy_leftover_bytes(struct ivpu_ms_instance *ms,
  96. void __user *user_ptr, u64 user_size, u64 *user_bytes_copied)
  97. {
  98. u64 copy_bytes;
  99. if (ms->leftover_bytes) {
  100. copy_bytes = min(user_size - *user_bytes_copied, ms->leftover_bytes);
  101. if (copy_to_user(user_ptr + *user_bytes_copied, ms->leftover_addr, copy_bytes))
  102. return -EFAULT;
  103. ms->leftover_bytes -= copy_bytes;
  104. ms->leftover_addr += copy_bytes;
  105. *user_bytes_copied += copy_bytes;
  106. }
  107. return 0;
  108. }
  109. static int
  110. copy_samples_to_user(struct ivpu_device *vdev, struct ivpu_ms_instance *ms,
  111. void __user *user_ptr, u64 user_size, u64 *user_bytes_copied)
  112. {
  113. u64 bytes_written;
  114. int ret;
  115. *user_bytes_copied = 0;
  116. ret = copy_leftover_bytes(ms, user_ptr, user_size, user_bytes_copied);
  117. if (ret)
  118. return ret;
  119. if (*user_bytes_copied == user_size)
  120. return 0;
  121. ret = ivpu_jsm_metric_streamer_update(vdev, ms->mask, ms->inactive_buff_vpu_addr,
  122. ms->buff_size, &bytes_written);
  123. if (ret)
  124. return ret;
  125. swap(ms->active_buff_vpu_addr, ms->inactive_buff_vpu_addr);
  126. swap(ms->active_buff_ptr, ms->inactive_buff_ptr);
  127. ms->leftover_bytes = bytes_written;
  128. ms->leftover_addr = ms->inactive_buff_ptr;
  129. return copy_leftover_bytes(ms, user_ptr, user_size, user_bytes_copied);
  130. }
  131. int ivpu_ms_get_data_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
  132. {
  133. struct drm_ivpu_metric_streamer_get_data *args = data;
  134. struct ivpu_file_priv *file_priv = file->driver_priv;
  135. struct ivpu_device *vdev = file_priv->vdev;
  136. struct ivpu_ms_instance *ms;
  137. u64 bytes_written;
  138. int ret;
  139. if (!args->metric_group_mask)
  140. return -EINVAL;
  141. ret = ivpu_rpm_get(vdev);
  142. if (ret < 0)
  143. return ret;
  144. mutex_lock(&file_priv->ms_lock);
  145. ms = get_instance_by_mask(file_priv, args->metric_group_mask);
  146. if (!ms) {
  147. ivpu_dbg(vdev, IOCTL, "Instance doesn't exist for mask: %#llx\n",
  148. args->metric_group_mask);
  149. ret = -EINVAL;
  150. goto unlock;
  151. }
  152. if (!args->buffer_size) {
  153. ret = ivpu_jsm_metric_streamer_update(vdev, ms->mask, 0, 0, &bytes_written);
  154. if (ret)
  155. goto unlock;
  156. args->data_size = bytes_written + ms->leftover_bytes;
  157. goto unlock;
  158. }
  159. if (!args->buffer_ptr) {
  160. ret = -EINVAL;
  161. goto unlock;
  162. }
  163. ret = copy_samples_to_user(vdev, ms, u64_to_user_ptr(args->buffer_ptr),
  164. args->buffer_size, &args->data_size);
  165. unlock:
  166. mutex_unlock(&file_priv->ms_lock);
  167. ivpu_rpm_put(vdev);
  168. return ret;
  169. }
  170. static void free_instance(struct ivpu_file_priv *file_priv, struct ivpu_ms_instance *ms)
  171. {
  172. lockdep_assert_held(&file_priv->ms_lock);
  173. list_del(&ms->ms_instance_node);
  174. ivpu_jsm_metric_streamer_stop(file_priv->vdev, ms->mask);
  175. ivpu_bo_free(ms->bo);
  176. kfree(ms);
  177. }
  178. int ivpu_ms_stop_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
  179. {
  180. struct ivpu_file_priv *file_priv = file->driver_priv;
  181. struct drm_ivpu_metric_streamer_stop *args = data;
  182. struct ivpu_device *vdev = file_priv->vdev;
  183. struct ivpu_ms_instance *ms;
  184. int ret;
  185. if (!args->metric_group_mask)
  186. return -EINVAL;
  187. ret = ivpu_rpm_get(vdev);
  188. if (ret < 0)
  189. return ret;
  190. mutex_lock(&file_priv->ms_lock);
  191. ms = get_instance_by_mask(file_priv, args->metric_group_mask);
  192. if (ms)
  193. free_instance(file_priv, ms);
  194. mutex_unlock(&file_priv->ms_lock);
  195. ivpu_rpm_put(vdev);
  196. return ms ? 0 : -EINVAL;
  197. }
  198. static inline struct ivpu_bo *get_ms_info_bo(struct ivpu_file_priv *file_priv)
  199. {
  200. lockdep_assert_held(&file_priv->ms_lock);
  201. if (file_priv->ms_info_bo)
  202. return file_priv->ms_info_bo;
  203. file_priv->ms_info_bo = ivpu_bo_create_global(file_priv->vdev, MS_INFO_BUFFER_SIZE,
  204. DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
  205. return file_priv->ms_info_bo;
  206. }
  207. int ivpu_ms_get_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
  208. {
  209. struct drm_ivpu_metric_streamer_get_data *args = data;
  210. struct ivpu_file_priv *file_priv = file->driver_priv;
  211. struct ivpu_device *vdev = file_priv->vdev;
  212. struct ivpu_bo *bo;
  213. u64 info_size;
  214. int ret;
  215. if (!args->metric_group_mask)
  216. return -EINVAL;
  217. if (!args->buffer_size)
  218. return ivpu_jsm_metric_streamer_info(vdev, args->metric_group_mask,
  219. 0, 0, NULL, &args->data_size);
  220. if (!args->buffer_ptr)
  221. return -EINVAL;
  222. mutex_lock(&file_priv->ms_lock);
  223. bo = get_ms_info_bo(file_priv);
  224. if (!bo) {
  225. ret = -ENOMEM;
  226. goto unlock;
  227. }
  228. ret = ivpu_jsm_metric_streamer_info(vdev, args->metric_group_mask, bo->vpu_addr,
  229. ivpu_bo_size(bo), NULL, &info_size);
  230. if (ret)
  231. goto unlock;
  232. if (args->buffer_size < info_size) {
  233. ret = -ENOSPC;
  234. goto unlock;
  235. }
  236. if (copy_to_user(u64_to_user_ptr(args->buffer_ptr), ivpu_bo_vaddr(bo), info_size))
  237. ret = -EFAULT;
  238. args->data_size = info_size;
  239. unlock:
  240. mutex_unlock(&file_priv->ms_lock);
  241. return ret;
  242. }
  243. void ivpu_ms_cleanup(struct ivpu_file_priv *file_priv)
  244. {
  245. struct ivpu_ms_instance *ms, *tmp;
  246. struct ivpu_device *vdev = file_priv->vdev;
  247. pm_runtime_get_sync(vdev->drm.dev);
  248. mutex_lock(&file_priv->ms_lock);
  249. if (file_priv->ms_info_bo) {
  250. ivpu_bo_free(file_priv->ms_info_bo);
  251. file_priv->ms_info_bo = NULL;
  252. }
  253. list_for_each_entry_safe(ms, tmp, &file_priv->ms_instance_list, ms_instance_node)
  254. free_instance(file_priv, ms);
  255. mutex_unlock(&file_priv->ms_lock);
  256. pm_runtime_put_autosuspend(vdev->drm.dev);
  257. }
  258. void ivpu_ms_cleanup_all(struct ivpu_device *vdev)
  259. {
  260. struct ivpu_file_priv *file_priv;
  261. unsigned long ctx_id;
  262. mutex_lock(&vdev->context_list_lock);
  263. xa_for_each(&vdev->context_xa, ctx_id, file_priv)
  264. ivpu_ms_cleanup(file_priv);
  265. mutex_unlock(&vdev->context_list_lock);
  266. }