]> Git Repo - J-linux.git/blob - drivers/gpu/drm/xe/xe_query.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / gpu / drm / xe / xe_query.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2022 Intel Corporation
4  */
5
6 #include "xe_query.h"
7
8 #include <linux/nospec.h>
9 #include <linux/sched/clock.h>
10
11 #include <drm/ttm/ttm_placement.h>
12 #include <generated/xe_wa_oob.h>
13 #include <uapi/drm/xe_drm.h>
14
15 #include "regs/xe_engine_regs.h"
16 #include "regs/xe_gt_regs.h"
17 #include "xe_bo.h"
18 #include "xe_device.h"
19 #include "xe_exec_queue.h"
20 #include "xe_force_wake.h"
21 #include "xe_ggtt.h"
22 #include "xe_gt.h"
23 #include "xe_guc_hwconfig.h"
24 #include "xe_macros.h"
25 #include "xe_mmio.h"
26 #include "xe_ttm_vram_mgr.h"
27 #include "xe_wa.h"
28
29 static const u16 xe_to_user_engine_class[] = {
30         [XE_ENGINE_CLASS_RENDER] = DRM_XE_ENGINE_CLASS_RENDER,
31         [XE_ENGINE_CLASS_COPY] = DRM_XE_ENGINE_CLASS_COPY,
32         [XE_ENGINE_CLASS_VIDEO_DECODE] = DRM_XE_ENGINE_CLASS_VIDEO_DECODE,
33         [XE_ENGINE_CLASS_VIDEO_ENHANCE] = DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE,
34         [XE_ENGINE_CLASS_COMPUTE] = DRM_XE_ENGINE_CLASS_COMPUTE,
35 };
36
37 static const enum xe_engine_class user_to_xe_engine_class[] = {
38         [DRM_XE_ENGINE_CLASS_RENDER] = XE_ENGINE_CLASS_RENDER,
39         [DRM_XE_ENGINE_CLASS_COPY] = XE_ENGINE_CLASS_COPY,
40         [DRM_XE_ENGINE_CLASS_VIDEO_DECODE] = XE_ENGINE_CLASS_VIDEO_DECODE,
41         [DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE] = XE_ENGINE_CLASS_VIDEO_ENHANCE,
42         [DRM_XE_ENGINE_CLASS_COMPUTE] = XE_ENGINE_CLASS_COMPUTE,
43 };
44
45 static size_t calc_hw_engine_info_size(struct xe_device *xe)
46 {
47         struct xe_hw_engine *hwe;
48         enum xe_hw_engine_id id;
49         struct xe_gt *gt;
50         u8 gt_id;
51         int i = 0;
52
53         for_each_gt(gt, xe, gt_id)
54                 for_each_hw_engine(hwe, gt, id) {
55                         if (xe_hw_engine_is_reserved(hwe))
56                                 continue;
57                         i++;
58                 }
59
60         return sizeof(struct drm_xe_query_engines) +
61                 i * sizeof(struct drm_xe_engine);
62 }
63
64 typedef u64 (*__ktime_func_t)(void);
65 static __ktime_func_t __clock_id_to_func(clockid_t clk_id)
66 {
67         /*
68          * Use logic same as the perf subsystem to allow user to select the
69          * reference clock id to be used for timestamps.
70          */
71         switch (clk_id) {
72         case CLOCK_MONOTONIC:
73                 return &ktime_get_ns;
74         case CLOCK_MONOTONIC_RAW:
75                 return &ktime_get_raw_ns;
76         case CLOCK_REALTIME:
77                 return &ktime_get_real_ns;
78         case CLOCK_BOOTTIME:
79                 return &ktime_get_boottime_ns;
80         case CLOCK_TAI:
81                 return &ktime_get_clocktai_ns;
82         default:
83                 return NULL;
84         }
85 }
86
87 static void
88 hwe_read_timestamp(struct xe_hw_engine *hwe, u64 *engine_ts, u64 *cpu_ts,
89                    u64 *cpu_delta, __ktime_func_t cpu_clock)
90 {
91         struct xe_mmio *mmio = &hwe->gt->mmio;
92         u32 upper, lower, old_upper, loop = 0;
93         struct xe_reg upper_reg = RING_TIMESTAMP_UDW(hwe->mmio_base),
94                       lower_reg = RING_TIMESTAMP(hwe->mmio_base);
95
96         upper = xe_mmio_read32(mmio, upper_reg);
97         do {
98                 *cpu_delta = local_clock();
99                 *cpu_ts = cpu_clock();
100                 lower = xe_mmio_read32(mmio, lower_reg);
101                 *cpu_delta = local_clock() - *cpu_delta;
102                 old_upper = upper;
103                 upper = xe_mmio_read32(mmio, upper_reg);
104         } while (upper != old_upper && loop++ < 2);
105
106         *engine_ts = (u64)upper << 32 | lower;
107 }
108
109 static int
110 query_engine_cycles(struct xe_device *xe,
111                     struct drm_xe_device_query *query)
112 {
113         struct drm_xe_query_engine_cycles __user *query_ptr;
114         struct drm_xe_engine_class_instance *eci;
115         struct drm_xe_query_engine_cycles resp;
116         size_t size = sizeof(resp);
117         __ktime_func_t cpu_clock;
118         struct xe_hw_engine *hwe;
119         struct xe_gt *gt;
120         unsigned int fw_ref;
121
122         if (query->size == 0) {
123                 query->size = size;
124                 return 0;
125         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
126                 return -EINVAL;
127         }
128
129         query_ptr = u64_to_user_ptr(query->data);
130         if (copy_from_user(&resp, query_ptr, size))
131                 return -EFAULT;
132
133         cpu_clock = __clock_id_to_func(resp.clockid);
134         if (!cpu_clock)
135                 return -EINVAL;
136
137         eci = &resp.eci;
138         if (eci->gt_id >= XE_MAX_GT_PER_TILE)
139                 return -EINVAL;
140
141         gt = xe_device_get_gt(xe, eci->gt_id);
142         if (!gt)
143                 return -EINVAL;
144
145         if (eci->engine_class >= ARRAY_SIZE(user_to_xe_engine_class))
146                 return -EINVAL;
147
148         hwe = xe_gt_hw_engine(gt, user_to_xe_engine_class[eci->engine_class],
149                               eci->engine_instance, true);
150         if (!hwe)
151                 return -EINVAL;
152
153         fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
154         if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))  {
155                 xe_force_wake_put(gt_to_fw(gt), fw_ref);
156                 return -EIO;
157         }
158
159         hwe_read_timestamp(hwe, &resp.engine_cycles, &resp.cpu_timestamp,
160                            &resp.cpu_delta, cpu_clock);
161
162         xe_force_wake_put(gt_to_fw(gt), fw_ref);
163
164         if (GRAPHICS_VER(xe) >= 20)
165                 resp.width = 64;
166         else
167                 resp.width = 36;
168
169         /* Only write to the output fields of user query */
170         if (put_user(resp.cpu_timestamp, &query_ptr->cpu_timestamp) ||
171             put_user(resp.cpu_delta, &query_ptr->cpu_delta) ||
172             put_user(resp.engine_cycles, &query_ptr->engine_cycles) ||
173             put_user(resp.width, &query_ptr->width))
174                 return -EFAULT;
175
176         return 0;
177 }
178
179 static int query_engines(struct xe_device *xe,
180                          struct drm_xe_device_query *query)
181 {
182         size_t size = calc_hw_engine_info_size(xe);
183         struct drm_xe_query_engines __user *query_ptr =
184                 u64_to_user_ptr(query->data);
185         struct drm_xe_query_engines *engines;
186         struct xe_hw_engine *hwe;
187         enum xe_hw_engine_id id;
188         struct xe_gt *gt;
189         u8 gt_id;
190         int i = 0;
191
192         if (query->size == 0) {
193                 query->size = size;
194                 return 0;
195         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
196                 return -EINVAL;
197         }
198
199         engines = kzalloc(size, GFP_KERNEL);
200         if (!engines)
201                 return -ENOMEM;
202
203         for_each_gt(gt, xe, gt_id)
204                 for_each_hw_engine(hwe, gt, id) {
205                         if (xe_hw_engine_is_reserved(hwe))
206                                 continue;
207
208                         engines->engines[i].instance.engine_class =
209                                 xe_to_user_engine_class[hwe->class];
210                         engines->engines[i].instance.engine_instance =
211                                 hwe->logical_instance;
212                         engines->engines[i].instance.gt_id = gt->info.id;
213
214                         i++;
215                 }
216
217         engines->num_engines = i;
218
219         if (copy_to_user(query_ptr, engines, size)) {
220                 kfree(engines);
221                 return -EFAULT;
222         }
223         kfree(engines);
224
225         return 0;
226 }
227
228 static size_t calc_mem_regions_size(struct xe_device *xe)
229 {
230         u32 num_managers = 1;
231         int i;
232
233         for (i = XE_PL_VRAM0; i <= XE_PL_VRAM1; ++i)
234                 if (ttm_manager_type(&xe->ttm, i))
235                         num_managers++;
236
237         return offsetof(struct drm_xe_query_mem_regions, mem_regions[num_managers]);
238 }
239
240 static int query_mem_regions(struct xe_device *xe,
241                             struct drm_xe_device_query *query)
242 {
243         size_t size = calc_mem_regions_size(xe);
244         struct drm_xe_query_mem_regions *mem_regions;
245         struct drm_xe_query_mem_regions __user *query_ptr =
246                 u64_to_user_ptr(query->data);
247         struct ttm_resource_manager *man;
248         int ret, i;
249
250         if (query->size == 0) {
251                 query->size = size;
252                 return 0;
253         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
254                 return -EINVAL;
255         }
256
257         mem_regions = kzalloc(size, GFP_KERNEL);
258         if (XE_IOCTL_DBG(xe, !mem_regions))
259                 return -ENOMEM;
260
261         man = ttm_manager_type(&xe->ttm, XE_PL_TT);
262         mem_regions->mem_regions[0].mem_class = DRM_XE_MEM_REGION_CLASS_SYSMEM;
263         /*
264          * The instance needs to be a unique number that represents the index
265          * in the placement mask used at xe_gem_create_ioctl() for the
266          * xe_bo_create() placement.
267          */
268         mem_regions->mem_regions[0].instance = 0;
269         mem_regions->mem_regions[0].min_page_size = PAGE_SIZE;
270         mem_regions->mem_regions[0].total_size = man->size << PAGE_SHIFT;
271         if (perfmon_capable())
272                 mem_regions->mem_regions[0].used = ttm_resource_manager_usage(man);
273         mem_regions->num_mem_regions = 1;
274
275         for (i = XE_PL_VRAM0; i <= XE_PL_VRAM1; ++i) {
276                 man = ttm_manager_type(&xe->ttm, i);
277                 if (man) {
278                         mem_regions->mem_regions[mem_regions->num_mem_regions].mem_class =
279                                 DRM_XE_MEM_REGION_CLASS_VRAM;
280                         mem_regions->mem_regions[mem_regions->num_mem_regions].instance =
281                                 mem_regions->num_mem_regions;
282                         mem_regions->mem_regions[mem_regions->num_mem_regions].min_page_size =
283                                 xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ?
284                                 SZ_64K : PAGE_SIZE;
285                         mem_regions->mem_regions[mem_regions->num_mem_regions].total_size =
286                                 man->size;
287
288                         if (perfmon_capable()) {
289                                 xe_ttm_vram_get_used(man,
290                                         &mem_regions->mem_regions
291                                         [mem_regions->num_mem_regions].used,
292                                         &mem_regions->mem_regions
293                                         [mem_regions->num_mem_regions].cpu_visible_used);
294                         }
295
296                         mem_regions->mem_regions[mem_regions->num_mem_regions].cpu_visible_size =
297                                 xe_ttm_vram_get_cpu_visible_size(man);
298                         mem_regions->num_mem_regions++;
299                 }
300         }
301
302         if (!copy_to_user(query_ptr, mem_regions, size))
303                 ret = 0;
304         else
305                 ret = -ENOSPC;
306
307         kfree(mem_regions);
308         return ret;
309 }
310
311 static int query_config(struct xe_device *xe, struct drm_xe_device_query *query)
312 {
313         const u32 num_params = DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY + 1;
314         size_t size =
315                 sizeof(struct drm_xe_query_config) + num_params * sizeof(u64);
316         struct drm_xe_query_config __user *query_ptr =
317                 u64_to_user_ptr(query->data);
318         struct drm_xe_query_config *config;
319
320         if (query->size == 0) {
321                 query->size = size;
322                 return 0;
323         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
324                 return -EINVAL;
325         }
326
327         config = kzalloc(size, GFP_KERNEL);
328         if (!config)
329                 return -ENOMEM;
330
331         config->num_params = num_params;
332         config->info[DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID] =
333                 xe->info.devid | (xe->info.revid << 16);
334         if (xe_device_get_root_tile(xe)->mem.vram.usable_size)
335                 config->info[DRM_XE_QUERY_CONFIG_FLAGS] =
336                         DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM;
337         config->info[DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT] =
338                 xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K;
339         config->info[DRM_XE_QUERY_CONFIG_VA_BITS] = xe->info.va_bits;
340         config->info[DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY] =
341                 xe_exec_queue_device_get_max_priority(xe);
342
343         if (copy_to_user(query_ptr, config, size)) {
344                 kfree(config);
345                 return -EFAULT;
346         }
347         kfree(config);
348
349         return 0;
350 }
351
352 static int query_gt_list(struct xe_device *xe, struct drm_xe_device_query *query)
353 {
354         struct xe_gt *gt;
355         size_t size = sizeof(struct drm_xe_query_gt_list) +
356                 xe->info.gt_count * sizeof(struct drm_xe_gt);
357         struct drm_xe_query_gt_list __user *query_ptr =
358                 u64_to_user_ptr(query->data);
359         struct drm_xe_query_gt_list *gt_list;
360         u8 id;
361
362         if (query->size == 0) {
363                 query->size = size;
364                 return 0;
365         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
366                 return -EINVAL;
367         }
368
369         gt_list = kzalloc(size, GFP_KERNEL);
370         if (!gt_list)
371                 return -ENOMEM;
372
373         gt_list->num_gt = xe->info.gt_count;
374
375         for_each_gt(gt, xe, id) {
376                 if (xe_gt_is_media_type(gt))
377                         gt_list->gt_list[id].type = DRM_XE_QUERY_GT_TYPE_MEDIA;
378                 else
379                         gt_list->gt_list[id].type = DRM_XE_QUERY_GT_TYPE_MAIN;
380                 gt_list->gt_list[id].tile_id = gt_to_tile(gt)->id;
381                 gt_list->gt_list[id].gt_id = gt->info.id;
382                 gt_list->gt_list[id].reference_clock = gt->info.reference_clock;
383                 /*
384                  * The mem_regions indexes in the mask below need to
385                  * directly identify the struct
386                  * drm_xe_query_mem_regions' instance constructed at
387                  * query_mem_regions()
388                  *
389                  * For our current platforms:
390                  * Bit 0 -> System Memory
391                  * Bit 1 -> VRAM0 on Tile0
392                  * Bit 2 -> VRAM1 on Tile1
393                  * However the uAPI is generic and it's userspace's
394                  * responsibility to check the mem_class, without any
395                  * assumption.
396                  */
397                 if (!IS_DGFX(xe))
398                         gt_list->gt_list[id].near_mem_regions = 0x1;
399                 else
400                         gt_list->gt_list[id].near_mem_regions =
401                                 BIT(gt_to_tile(gt)->id) << 1;
402                 gt_list->gt_list[id].far_mem_regions = xe->info.mem_region_mask ^
403                         gt_list->gt_list[id].near_mem_regions;
404
405                 gt_list->gt_list[id].ip_ver_major =
406                         REG_FIELD_GET(GMD_ID_ARCH_MASK, gt->info.gmdid);
407                 gt_list->gt_list[id].ip_ver_minor =
408                         REG_FIELD_GET(GMD_ID_RELEASE_MASK, gt->info.gmdid);
409                 gt_list->gt_list[id].ip_ver_rev =
410                         REG_FIELD_GET(GMD_ID_REVID, gt->info.gmdid);
411         }
412
413         if (copy_to_user(query_ptr, gt_list, size)) {
414                 kfree(gt_list);
415                 return -EFAULT;
416         }
417         kfree(gt_list);
418
419         return 0;
420 }
421
422 static int query_hwconfig(struct xe_device *xe,
423                           struct drm_xe_device_query *query)
424 {
425         struct xe_gt *gt = xe_root_mmio_gt(xe);
426         size_t size = xe_guc_hwconfig_size(&gt->uc.guc);
427         void __user *query_ptr = u64_to_user_ptr(query->data);
428         void *hwconfig;
429
430         if (query->size == 0) {
431                 query->size = size;
432                 return 0;
433         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
434                 return -EINVAL;
435         }
436
437         hwconfig = kzalloc(size, GFP_KERNEL);
438         if (!hwconfig)
439                 return -ENOMEM;
440
441         xe_guc_hwconfig_copy(&gt->uc.guc, hwconfig);
442
443         if (copy_to_user(query_ptr, hwconfig, size)) {
444                 kfree(hwconfig);
445                 return -EFAULT;
446         }
447         kfree(hwconfig);
448
449         return 0;
450 }
451
452 static size_t calc_topo_query_size(struct xe_device *xe)
453 {
454         struct xe_gt *gt;
455         size_t query_size = 0;
456         int id;
457
458         for_each_gt(gt, xe, id) {
459                 query_size += 3 * sizeof(struct drm_xe_query_topology_mask) +
460                         sizeof_field(struct xe_gt, fuse_topo.g_dss_mask) +
461                         sizeof_field(struct xe_gt, fuse_topo.c_dss_mask) +
462                         sizeof_field(struct xe_gt, fuse_topo.eu_mask_per_dss);
463
464                 /* L3bank mask may not be available for some GTs */
465                 if (!XE_WA(gt, no_media_l3))
466                         query_size += sizeof(struct drm_xe_query_topology_mask) +
467                                 sizeof_field(struct xe_gt, fuse_topo.l3_bank_mask);
468         }
469
470         return query_size;
471 }
472
473 static int copy_mask(void __user **ptr,
474                      struct drm_xe_query_topology_mask *topo,
475                      void *mask, size_t mask_size)
476 {
477         topo->num_bytes = mask_size;
478
479         if (copy_to_user(*ptr, topo, sizeof(*topo)))
480                 return -EFAULT;
481         *ptr += sizeof(topo);
482
483         if (copy_to_user(*ptr, mask, mask_size))
484                 return -EFAULT;
485         *ptr += mask_size;
486
487         return 0;
488 }
489
490 static int query_gt_topology(struct xe_device *xe,
491                              struct drm_xe_device_query *query)
492 {
493         void __user *query_ptr = u64_to_user_ptr(query->data);
494         size_t size = calc_topo_query_size(xe);
495         struct drm_xe_query_topology_mask topo;
496         struct xe_gt *gt;
497         int id;
498
499         if (query->size == 0) {
500                 query->size = size;
501                 return 0;
502         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
503                 return -EINVAL;
504         }
505
506         for_each_gt(gt, xe, id) {
507                 int err;
508
509                 topo.gt_id = id;
510
511                 topo.type = DRM_XE_TOPO_DSS_GEOMETRY;
512                 err = copy_mask(&query_ptr, &topo, gt->fuse_topo.g_dss_mask,
513                                 sizeof(gt->fuse_topo.g_dss_mask));
514                 if (err)
515                         return err;
516
517                 topo.type = DRM_XE_TOPO_DSS_COMPUTE;
518                 err = copy_mask(&query_ptr, &topo, gt->fuse_topo.c_dss_mask,
519                                 sizeof(gt->fuse_topo.c_dss_mask));
520                 if (err)
521                         return err;
522
523                 /*
524                  * If the kernel doesn't have a way to obtain a correct L3bank
525                  * mask, then it's better to omit L3 from the query rather than
526                  * reporting bogus or zeroed information to userspace.
527                  */
528                 if (!XE_WA(gt, no_media_l3)) {
529                         topo.type = DRM_XE_TOPO_L3_BANK;
530                         err = copy_mask(&query_ptr, &topo, gt->fuse_topo.l3_bank_mask,
531                                         sizeof(gt->fuse_topo.l3_bank_mask));
532                         if (err)
533                                 return err;
534                 }
535
536                 topo.type = gt->fuse_topo.eu_type == XE_GT_EU_TYPE_SIMD16 ?
537                         DRM_XE_TOPO_SIMD16_EU_PER_DSS :
538                         DRM_XE_TOPO_EU_PER_DSS;
539                 err = copy_mask(&query_ptr, &topo,
540                                 gt->fuse_topo.eu_mask_per_dss,
541                                 sizeof(gt->fuse_topo.eu_mask_per_dss));
542                 if (err)
543                         return err;
544         }
545
546         return 0;
547 }
548
549 static int
550 query_uc_fw_version(struct xe_device *xe, struct drm_xe_device_query *query)
551 {
552         struct drm_xe_query_uc_fw_version __user *query_ptr = u64_to_user_ptr(query->data);
553         size_t size = sizeof(struct drm_xe_query_uc_fw_version);
554         struct drm_xe_query_uc_fw_version resp;
555         struct xe_uc_fw_version *version = NULL;
556
557         if (query->size == 0) {
558                 query->size = size;
559                 return 0;
560         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
561                 return -EINVAL;
562         }
563
564         if (copy_from_user(&resp, query_ptr, size))
565                 return -EFAULT;
566
567         if (XE_IOCTL_DBG(xe, resp.pad || resp.pad2 || resp.reserved))
568                 return -EINVAL;
569
570         switch (resp.uc_type) {
571         case XE_QUERY_UC_TYPE_GUC_SUBMISSION: {
572                 struct xe_guc *guc = &xe->tiles[0].primary_gt->uc.guc;
573
574                 version = &guc->fw.versions.found[XE_UC_FW_VER_COMPATIBILITY];
575                 break;
576         }
577         case XE_QUERY_UC_TYPE_HUC: {
578                 struct xe_gt *media_gt = NULL;
579                 struct xe_huc *huc;
580
581                 if (MEDIA_VER(xe) >= 13) {
582                         struct xe_tile *tile;
583                         u8 gt_id;
584
585                         for_each_tile(tile, xe, gt_id) {
586                                 if (tile->media_gt) {
587                                         media_gt = tile->media_gt;
588                                         break;
589                                 }
590                         }
591                 } else {
592                         media_gt = xe->tiles[0].primary_gt;
593                 }
594
595                 if (!media_gt)
596                         break;
597
598                 huc = &media_gt->uc.huc;
599                 if (huc->fw.status == XE_UC_FIRMWARE_RUNNING)
600                         version = &huc->fw.versions.found[XE_UC_FW_VER_RELEASE];
601                 break;
602         }
603         default:
604                 return -EINVAL;
605         }
606
607         if (version) {
608                 resp.branch_ver = 0;
609                 resp.major_ver = version->major;
610                 resp.minor_ver = version->minor;
611                 resp.patch_ver = version->patch;
612         } else {
613                 return -ENODEV;
614         }
615
616         if (copy_to_user(query_ptr, &resp, size))
617                 return -EFAULT;
618
619         return 0;
620 }
621
622 static size_t calc_oa_unit_query_size(struct xe_device *xe)
623 {
624         size_t size = sizeof(struct drm_xe_query_oa_units);
625         struct xe_gt *gt;
626         int i, id;
627
628         for_each_gt(gt, xe, id) {
629                 for (i = 0; i < gt->oa.num_oa_units; i++) {
630                         size += sizeof(struct drm_xe_oa_unit);
631                         size += gt->oa.oa_unit[i].num_engines *
632                                 sizeof(struct drm_xe_engine_class_instance);
633                 }
634         }
635
636         return size;
637 }
638
639 static int query_oa_units(struct xe_device *xe,
640                           struct drm_xe_device_query *query)
641 {
642         void __user *query_ptr = u64_to_user_ptr(query->data);
643         size_t size = calc_oa_unit_query_size(xe);
644         struct drm_xe_query_oa_units *qoa;
645         enum xe_hw_engine_id hwe_id;
646         struct drm_xe_oa_unit *du;
647         struct xe_hw_engine *hwe;
648         struct xe_oa_unit *u;
649         int gt_id, i, j, ret;
650         struct xe_gt *gt;
651         u8 *pdu;
652
653         if (query->size == 0) {
654                 query->size = size;
655                 return 0;
656         } else if (XE_IOCTL_DBG(xe, query->size != size)) {
657                 return -EINVAL;
658         }
659
660         qoa = kzalloc(size, GFP_KERNEL);
661         if (!qoa)
662                 return -ENOMEM;
663
664         pdu = (u8 *)&qoa->oa_units[0];
665         for_each_gt(gt, xe, gt_id) {
666                 for (i = 0; i < gt->oa.num_oa_units; i++) {
667                         u = &gt->oa.oa_unit[i];
668                         du = (struct drm_xe_oa_unit *)pdu;
669
670                         du->oa_unit_id = u->oa_unit_id;
671                         du->oa_unit_type = u->type;
672                         du->oa_timestamp_freq = xe_oa_timestamp_frequency(gt);
673                         du->capabilities = DRM_XE_OA_CAPS_BASE | DRM_XE_OA_CAPS_SYNCS;
674
675                         j = 0;
676                         for_each_hw_engine(hwe, gt, hwe_id) {
677                                 if (!xe_hw_engine_is_reserved(hwe) &&
678                                     xe_oa_unit_id(hwe) == u->oa_unit_id) {
679                                         du->eci[j].engine_class =
680                                                 xe_to_user_engine_class[hwe->class];
681                                         du->eci[j].engine_instance = hwe->logical_instance;
682                                         du->eci[j].gt_id = gt->info.id;
683                                         j++;
684                                 }
685                         }
686                         du->num_engines = j;
687                         pdu += sizeof(*du) + j * sizeof(du->eci[0]);
688                         qoa->num_oa_units++;
689                 }
690         }
691
692         ret = copy_to_user(query_ptr, qoa, size);
693         kfree(qoa);
694
695         return ret ? -EFAULT : 0;
696 }
697
698 static int (* const xe_query_funcs[])(struct xe_device *xe,
699                                       struct drm_xe_device_query *query) = {
700         query_engines,
701         query_mem_regions,
702         query_config,
703         query_gt_list,
704         query_hwconfig,
705         query_gt_topology,
706         query_engine_cycles,
707         query_uc_fw_version,
708         query_oa_units,
709 };
710
711 int xe_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
712 {
713         struct xe_device *xe = to_xe_device(dev);
714         struct drm_xe_device_query *query = data;
715         u32 idx;
716
717         if (XE_IOCTL_DBG(xe, query->extensions) ||
718             XE_IOCTL_DBG(xe, query->reserved[0] || query->reserved[1]))
719                 return -EINVAL;
720
721         if (XE_IOCTL_DBG(xe, query->query >= ARRAY_SIZE(xe_query_funcs)))
722                 return -EINVAL;
723
724         idx = array_index_nospec(query->query, ARRAY_SIZE(xe_query_funcs));
725         if (XE_IOCTL_DBG(xe, !xe_query_funcs[idx]))
726                 return -EINVAL;
727
728         return xe_query_funcs[idx](xe, query);
729 }
This page took 0.06795 seconds and 4 git commands to generate.