ivpu_ms.c 8.1 KB

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