]>
Commit | Line | Data |
---|---|---|
a446ae2c LL |
1 | /* |
2 | * SPDX-License-Identifier: MIT | |
3 | * | |
4 | * Copyright © 2018 Intel Corporation | |
5 | */ | |
6 | ||
84b510e2 CW |
7 | #include <linux/nospec.h> |
8 | ||
a446ae2c LL |
9 | #include "i915_drv.h" |
10 | #include "i915_query.h" | |
11 | #include <uapi/drm/i915_drm.h> | |
12 | ||
c822e059 LL |
13 | static int query_topology_info(struct drm_i915_private *dev_priv, |
14 | struct drm_i915_query_item *query_item) | |
15 | { | |
0258404f | 16 | const struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; |
c822e059 LL |
17 | struct drm_i915_query_topology_info topo; |
18 | u32 slice_length, subslice_length, eu_length, total_length; | |
19 | ||
20 | if (query_item->flags != 0) | |
21 | return -EINVAL; | |
22 | ||
23 | if (sseu->max_slices == 0) | |
24 | return -ENODEV; | |
25 | ||
26 | BUILD_BUG_ON(sizeof(u8) != sizeof(sseu->slice_mask)); | |
27 | ||
28 | slice_length = sizeof(sseu->slice_mask); | |
29 | subslice_length = sseu->max_slices * | |
eef4670e | 30 | DIV_ROUND_UP(sseu->max_subslices, BITS_PER_BYTE); |
c822e059 LL |
31 | eu_length = sseu->max_slices * sseu->max_subslices * |
32 | DIV_ROUND_UP(sseu->max_eus_per_subslice, BITS_PER_BYTE); | |
33 | ||
34 | total_length = sizeof(topo) + slice_length + subslice_length + eu_length; | |
35 | ||
36 | if (query_item->length == 0) | |
37 | return total_length; | |
38 | ||
39 | if (query_item->length < total_length) | |
40 | return -EINVAL; | |
41 | ||
42 | if (copy_from_user(&topo, u64_to_user_ptr(query_item->data_ptr), | |
43 | sizeof(topo))) | |
44 | return -EFAULT; | |
45 | ||
46 | if (topo.flags != 0) | |
47 | return -EINVAL; | |
48 | ||
96d4f267 | 49 | if (!access_ok(u64_to_user_ptr(query_item->data_ptr), |
c822e059 LL |
50 | total_length)) |
51 | return -EFAULT; | |
52 | ||
53 | memset(&topo, 0, sizeof(topo)); | |
54 | topo.max_slices = sseu->max_slices; | |
55 | topo.max_subslices = sseu->max_subslices; | |
56 | topo.max_eus_per_subslice = sseu->max_eus_per_subslice; | |
57 | ||
58 | topo.subslice_offset = slice_length; | |
59 | topo.subslice_stride = DIV_ROUND_UP(sseu->max_subslices, BITS_PER_BYTE); | |
60 | topo.eu_offset = slice_length + subslice_length; | |
61 | topo.eu_stride = | |
62 | DIV_ROUND_UP(sseu->max_eus_per_subslice, BITS_PER_BYTE); | |
63 | ||
64 | if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr), | |
65 | &topo, sizeof(topo))) | |
66 | return -EFAULT; | |
67 | ||
68 | if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + sizeof(topo)), | |
69 | &sseu->slice_mask, slice_length)) | |
70 | return -EFAULT; | |
71 | ||
72 | if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + | |
73 | sizeof(topo) + slice_length), | |
74 | sseu->subslice_mask, subslice_length)) | |
75 | return -EFAULT; | |
76 | ||
77 | if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + | |
78 | sizeof(topo) + | |
79 | slice_length + subslice_length), | |
80 | sseu->eu_mask, eu_length)) | |
81 | return -EFAULT; | |
82 | ||
83 | return total_length; | |
84 | } | |
85 | ||
a446ae2c LL |
86 | static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv, |
87 | struct drm_i915_query_item *query_item) = { | |
c822e059 | 88 | query_topology_info, |
a446ae2c LL |
89 | }; |
90 | ||
91 | int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) | |
92 | { | |
93 | struct drm_i915_private *dev_priv = to_i915(dev); | |
94 | struct drm_i915_query *args = data; | |
95 | struct drm_i915_query_item __user *user_item_ptr = | |
96 | u64_to_user_ptr(args->items_ptr); | |
97 | u32 i; | |
98 | ||
99 | if (args->flags != 0) | |
100 | return -EINVAL; | |
101 | ||
102 | for (i = 0; i < args->num_items; i++, user_item_ptr++) { | |
103 | struct drm_i915_query_item item; | |
a33b1dc8 | 104 | unsigned long func_idx; |
a446ae2c LL |
105 | int ret; |
106 | ||
107 | if (copy_from_user(&item, user_item_ptr, sizeof(item))) | |
108 | return -EFAULT; | |
109 | ||
110 | if (item.query_id == 0) | |
111 | return -EINVAL; | |
112 | ||
a33b1dc8 CW |
113 | if (overflows_type(item.query_id - 1, unsigned long)) |
114 | return -EINVAL; | |
115 | ||
a446ae2c LL |
116 | func_idx = item.query_id - 1; |
117 | ||
84b510e2 CW |
118 | ret = -EINVAL; |
119 | if (func_idx < ARRAY_SIZE(i915_query_funcs)) { | |
120 | func_idx = array_index_nospec(func_idx, | |
121 | ARRAY_SIZE(i915_query_funcs)); | |
a446ae2c | 122 | ret = i915_query_funcs[func_idx](dev_priv, &item); |
84b510e2 | 123 | } |
a446ae2c LL |
124 | |
125 | /* Only write the length back to userspace if they differ. */ | |
126 | if (ret != item.length && put_user(ret, &user_item_ptr->length)) | |
127 | return -EFAULT; | |
128 | } | |
129 | ||
130 | return 0; | |
131 | } |