2 * SPDX-License-Identifier: MIT
4 * Copyright © 2018 Intel Corporation
7 #include <linux/nospec.h>
10 #include "i915_query.h"
11 #include <uapi/drm/i915_drm.h>
13 static int query_topology_info(struct drm_i915_private
*dev_priv
,
14 struct drm_i915_query_item
*query_item
)
16 const struct sseu_dev_info
*sseu
= &INTEL_INFO(dev_priv
)->sseu
;
17 struct drm_i915_query_topology_info topo
;
18 u32 slice_length
, subslice_length
, eu_length
, total_length
;
20 if (query_item
->flags
!= 0)
23 if (sseu
->max_slices
== 0)
26 BUILD_BUG_ON(sizeof(u8
) != sizeof(sseu
->slice_mask
));
28 slice_length
= sizeof(sseu
->slice_mask
);
29 subslice_length
= sseu
->max_slices
*
30 DIV_ROUND_UP(sseu
->max_subslices
,
31 sizeof(sseu
->subslice_mask
[0]) * BITS_PER_BYTE
);
32 eu_length
= sseu
->max_slices
* sseu
->max_subslices
*
33 DIV_ROUND_UP(sseu
->max_eus_per_subslice
, BITS_PER_BYTE
);
35 total_length
= sizeof(topo
) + slice_length
+ subslice_length
+ eu_length
;
37 if (query_item
->length
== 0)
40 if (query_item
->length
< total_length
)
43 if (copy_from_user(&topo
, u64_to_user_ptr(query_item
->data_ptr
),
50 if (!access_ok(VERIFY_WRITE
, u64_to_user_ptr(query_item
->data_ptr
),
54 memset(&topo
, 0, sizeof(topo
));
55 topo
.max_slices
= sseu
->max_slices
;
56 topo
.max_subslices
= sseu
->max_subslices
;
57 topo
.max_eus_per_subslice
= sseu
->max_eus_per_subslice
;
59 topo
.subslice_offset
= slice_length
;
60 topo
.subslice_stride
= DIV_ROUND_UP(sseu
->max_subslices
, BITS_PER_BYTE
);
61 topo
.eu_offset
= slice_length
+ subslice_length
;
63 DIV_ROUND_UP(sseu
->max_eus_per_subslice
, BITS_PER_BYTE
);
65 if (__copy_to_user(u64_to_user_ptr(query_item
->data_ptr
),
69 if (__copy_to_user(u64_to_user_ptr(query_item
->data_ptr
+ sizeof(topo
)),
70 &sseu
->slice_mask
, slice_length
))
73 if (__copy_to_user(u64_to_user_ptr(query_item
->data_ptr
+
74 sizeof(topo
) + slice_length
),
75 sseu
->subslice_mask
, subslice_length
))
78 if (__copy_to_user(u64_to_user_ptr(query_item
->data_ptr
+
80 slice_length
+ subslice_length
),
81 sseu
->eu_mask
, eu_length
))
87 static int (* const i915_query_funcs
[])(struct drm_i915_private
*dev_priv
,
88 struct drm_i915_query_item
*query_item
) = {
92 int i915_query_ioctl(struct drm_device
*dev
, void *data
, struct drm_file
*file
)
94 struct drm_i915_private
*dev_priv
= to_i915(dev
);
95 struct drm_i915_query
*args
= data
;
96 struct drm_i915_query_item __user
*user_item_ptr
=
97 u64_to_user_ptr(args
->items_ptr
);
100 if (args
->flags
!= 0)
103 for (i
= 0; i
< args
->num_items
; i
++, user_item_ptr
++) {
104 struct drm_i915_query_item item
;
105 unsigned long func_idx
;
108 if (copy_from_user(&item
, user_item_ptr
, sizeof(item
)))
111 if (item
.query_id
== 0)
114 if (overflows_type(item
.query_id
- 1, unsigned long))
117 func_idx
= item
.query_id
- 1;
120 if (func_idx
< ARRAY_SIZE(i915_query_funcs
)) {
121 func_idx
= array_index_nospec(func_idx
,
122 ARRAY_SIZE(i915_query_funcs
));
123 ret
= i915_query_funcs
[func_idx
](dev_priv
, &item
);
126 /* Only write the length back to userspace if they differ. */
127 if (ret
!= item
.length
&& put_user(ret
, &user_item_ptr
->length
))