1 // SPDX-License-Identifier: GPL-2.0-only OR MIT
3 * Copyright (C) 2020-2024 Intel Corporation
6 #include <drm/drm_file.h>
10 #include "ivpu_jsm_msg.h"
14 #define MS_INFO_BUFFER_SIZE SZ_64K
15 #define MS_NUM_BUFFERS 2
16 #define MS_READ_PERIOD_MULTIPLIER 2
17 #define MS_MIN_SAMPLE_PERIOD_NS 1000000
19 static struct ivpu_ms_instance
*
20 get_instance_by_mask(struct ivpu_file_priv
*file_priv
, u64 metric_mask
)
22 struct ivpu_ms_instance
*ms
;
24 lockdep_assert_held(&file_priv
->ms_lock
);
26 list_for_each_entry(ms
, &file_priv
->ms_instance_list
, ms_instance_node
)
27 if (ms
->mask
== metric_mask
)
33 int ivpu_ms_start_ioctl(struct drm_device
*dev
, void *data
, struct drm_file
*file
)
35 struct ivpu_file_priv
*file_priv
= file
->driver_priv
;
36 struct drm_ivpu_metric_streamer_start
*args
= data
;
37 struct ivpu_device
*vdev
= file_priv
->vdev
;
38 struct ivpu_ms_instance
*ms
;
43 if (!args
->metric_group_mask
|| !args
->read_period_samples
||
44 args
->sampling_period_ns
< MS_MIN_SAMPLE_PERIOD_NS
)
47 mutex_lock(&file_priv
->ms_lock
);
49 if (get_instance_by_mask(file_priv
, args
->metric_group_mask
)) {
50 ivpu_err(vdev
, "Instance already exists (mask %#llx)\n", args
->metric_group_mask
);
55 ms
= kzalloc(sizeof(*ms
), GFP_KERNEL
);
61 ms
->mask
= args
->metric_group_mask
;
63 ret
= ivpu_jsm_metric_streamer_info(vdev
, ms
->mask
, 0, 0, &sample_size
, NULL
);
67 single_buff_size
= sample_size
*
68 ((u64
)args
->read_period_samples
* MS_READ_PERIOD_MULTIPLIER
);
69 ms
->bo
= ivpu_bo_create_global(vdev
, PAGE_ALIGN(single_buff_size
* MS_NUM_BUFFERS
),
70 DRM_IVPU_BO_CACHED
| DRM_IVPU_BO_MAPPABLE
);
72 ivpu_err(vdev
, "Failed to allocate MS buffer (size %llu)\n", single_buff_size
);
77 ms
->buff_size
= ivpu_bo_size(ms
->bo
) / MS_NUM_BUFFERS
;
78 ms
->active_buff_vpu_addr
= ms
->bo
->vpu_addr
;
79 ms
->inactive_buff_vpu_addr
= ms
->bo
->vpu_addr
+ ms
->buff_size
;
80 ms
->active_buff_ptr
= ivpu_bo_vaddr(ms
->bo
);
81 ms
->inactive_buff_ptr
= ivpu_bo_vaddr(ms
->bo
) + ms
->buff_size
;
83 ret
= ivpu_jsm_metric_streamer_start(vdev
, ms
->mask
, args
->sampling_period_ns
,
84 ms
->active_buff_vpu_addr
, ms
->buff_size
);
88 args
->sample_size
= sample_size
;
89 args
->max_data_size
= ivpu_bo_size(ms
->bo
);
90 list_add_tail(&ms
->ms_instance_node
, &file_priv
->ms_instance_list
);
98 mutex_unlock(&file_priv
->ms_lock
);
103 copy_leftover_bytes(struct ivpu_ms_instance
*ms
,
104 void __user
*user_ptr
, u64 user_size
, u64
*user_bytes_copied
)
108 if (ms
->leftover_bytes
) {
109 copy_bytes
= min(user_size
- *user_bytes_copied
, ms
->leftover_bytes
);
110 if (copy_to_user(user_ptr
+ *user_bytes_copied
, ms
->leftover_addr
, copy_bytes
))
113 ms
->leftover_bytes
-= copy_bytes
;
114 ms
->leftover_addr
+= copy_bytes
;
115 *user_bytes_copied
+= copy_bytes
;
122 copy_samples_to_user(struct ivpu_device
*vdev
, struct ivpu_ms_instance
*ms
,
123 void __user
*user_ptr
, u64 user_size
, u64
*user_bytes_copied
)
128 *user_bytes_copied
= 0;
130 ret
= copy_leftover_bytes(ms
, user_ptr
, user_size
, user_bytes_copied
);
134 if (*user_bytes_copied
== user_size
)
137 ret
= ivpu_jsm_metric_streamer_update(vdev
, ms
->mask
, ms
->inactive_buff_vpu_addr
,
138 ms
->buff_size
, &bytes_written
);
142 swap(ms
->active_buff_vpu_addr
, ms
->inactive_buff_vpu_addr
);
143 swap(ms
->active_buff_ptr
, ms
->inactive_buff_ptr
);
145 ms
->leftover_bytes
= bytes_written
;
146 ms
->leftover_addr
= ms
->inactive_buff_ptr
;
148 return copy_leftover_bytes(ms
, user_ptr
, user_size
, user_bytes_copied
);
151 int ivpu_ms_get_data_ioctl(struct drm_device
*dev
, void *data
, struct drm_file
*file
)
153 struct drm_ivpu_metric_streamer_get_data
*args
= data
;
154 struct ivpu_file_priv
*file_priv
= file
->driver_priv
;
155 struct ivpu_device
*vdev
= file_priv
->vdev
;
156 struct ivpu_ms_instance
*ms
;
160 if (!args
->metric_group_mask
)
163 mutex_lock(&file_priv
->ms_lock
);
165 ms
= get_instance_by_mask(file_priv
, args
->metric_group_mask
);
167 ivpu_err(vdev
, "Instance doesn't exist for mask: %#llx\n", args
->metric_group_mask
);
172 if (!args
->buffer_size
) {
173 ret
= ivpu_jsm_metric_streamer_update(vdev
, ms
->mask
, 0, 0, &bytes_written
);
176 args
->data_size
= bytes_written
+ ms
->leftover_bytes
;
180 if (!args
->buffer_ptr
) {
185 ret
= copy_samples_to_user(vdev
, ms
, u64_to_user_ptr(args
->buffer_ptr
),
186 args
->buffer_size
, &args
->data_size
);
188 mutex_unlock(&file_priv
->ms_lock
);
193 static void free_instance(struct ivpu_file_priv
*file_priv
, struct ivpu_ms_instance
*ms
)
195 lockdep_assert_held(&file_priv
->ms_lock
);
197 list_del(&ms
->ms_instance_node
);
198 ivpu_jsm_metric_streamer_stop(file_priv
->vdev
, ms
->mask
);
199 ivpu_bo_free(ms
->bo
);
203 int ivpu_ms_stop_ioctl(struct drm_device
*dev
, void *data
, struct drm_file
*file
)
205 struct ivpu_file_priv
*file_priv
= file
->driver_priv
;
206 struct drm_ivpu_metric_streamer_stop
*args
= data
;
207 struct ivpu_ms_instance
*ms
;
209 if (!args
->metric_group_mask
)
212 mutex_lock(&file_priv
->ms_lock
);
214 ms
= get_instance_by_mask(file_priv
, args
->metric_group_mask
);
216 free_instance(file_priv
, ms
);
218 mutex_unlock(&file_priv
->ms_lock
);
220 return ms
? 0 : -EINVAL
;
223 static inline struct ivpu_bo
*get_ms_info_bo(struct ivpu_file_priv
*file_priv
)
225 lockdep_assert_held(&file_priv
->ms_lock
);
227 if (file_priv
->ms_info_bo
)
228 return file_priv
->ms_info_bo
;
230 file_priv
->ms_info_bo
= ivpu_bo_create_global(file_priv
->vdev
, MS_INFO_BUFFER_SIZE
,
231 DRM_IVPU_BO_CACHED
| DRM_IVPU_BO_MAPPABLE
);
232 return file_priv
->ms_info_bo
;
235 int ivpu_ms_get_info_ioctl(struct drm_device
*dev
, void *data
, struct drm_file
*file
)
237 struct drm_ivpu_metric_streamer_get_data
*args
= data
;
238 struct ivpu_file_priv
*file_priv
= file
->driver_priv
;
239 struct ivpu_device
*vdev
= file_priv
->vdev
;
244 if (!args
->metric_group_mask
)
247 if (!args
->buffer_size
)
248 return ivpu_jsm_metric_streamer_info(vdev
, args
->metric_group_mask
,
249 0, 0, NULL
, &args
->data_size
);
250 if (!args
->buffer_ptr
)
253 mutex_lock(&file_priv
->ms_lock
);
255 bo
= get_ms_info_bo(file_priv
);
261 ret
= ivpu_jsm_metric_streamer_info(vdev
, args
->metric_group_mask
, bo
->vpu_addr
,
262 ivpu_bo_size(bo
), NULL
, &info_size
);
266 if (args
->buffer_size
< info_size
) {
271 if (copy_to_user(u64_to_user_ptr(args
->buffer_ptr
), ivpu_bo_vaddr(bo
), info_size
))
274 args
->data_size
= info_size
;
276 mutex_unlock(&file_priv
->ms_lock
);
281 void ivpu_ms_cleanup(struct ivpu_file_priv
*file_priv
)
283 struct ivpu_ms_instance
*ms
, *tmp
;
285 mutex_lock(&file_priv
->ms_lock
);
287 if (file_priv
->ms_info_bo
) {
288 ivpu_bo_free(file_priv
->ms_info_bo
);
289 file_priv
->ms_info_bo
= NULL
;
292 list_for_each_entry_safe(ms
, tmp
, &file_priv
->ms_instance_list
, ms_instance_node
)
293 free_instance(file_priv
, ms
);
295 mutex_unlock(&file_priv
->ms_lock
);
298 void ivpu_ms_cleanup_all(struct ivpu_device
*vdev
)
300 struct ivpu_file_priv
*file_priv
;
301 unsigned long ctx_id
;
303 mutex_lock(&vdev
->context_list_lock
);
305 xa_for_each(&vdev
->context_xa
, ctx_id
, file_priv
)
306 ivpu_ms_cleanup(file_priv
);
308 mutex_unlock(&vdev
->context_list_lock
);