i915_query.c 4.8 KB
Newer Older
L
Lionel Landwerlin 已提交
1 2 3 4 5 6
/*
 * SPDX-License-Identifier: MIT
 *
 * Copyright © 2018 Intel Corporation
 */

7 8
#include <linux/nospec.h>

L
Lionel Landwerlin 已提交
9 10 11 12
#include "i915_drv.h"
#include "i915_query.h"
#include <uapi/drm/i915_drm.h>

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
static int copy_query_item(void *query_hdr, size_t query_sz,
			   u32 total_length,
			   struct drm_i915_query_item *query_item)
{
	if (query_item->length == 0)
		return total_length;

	if (query_item->length < total_length)
		return -EINVAL;

	if (copy_from_user(query_hdr, u64_to_user_ptr(query_item->data_ptr),
			   query_sz))
		return -EFAULT;

	if (!access_ok(u64_to_user_ptr(query_item->data_ptr),
		       total_length))
		return -EFAULT;

	return 0;
}

34 35 36
static int query_topology_info(struct drm_i915_private *dev_priv,
			       struct drm_i915_query_item *query_item)
{
37
	const struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
38 39
	struct drm_i915_query_topology_info topo;
	u32 slice_length, subslice_length, eu_length, total_length;
40
	int ret;
41 42 43 44 45 46 47 48 49 50

	if (query_item->flags != 0)
		return -EINVAL;

	if (sseu->max_slices == 0)
		return -ENODEV;

	BUILD_BUG_ON(sizeof(u8) != sizeof(sseu->slice_mask));

	slice_length = sizeof(sseu->slice_mask);
S
Stuart Summers 已提交
51 52
	subslice_length = sseu->max_slices * sseu->ss_stride;
	eu_length = sseu->max_slices * sseu->max_subslices * sseu->eu_stride;
53 54
	total_length = sizeof(topo) + slice_length + subslice_length +
		       eu_length;
55

56 57 58 59
	ret = copy_query_item(&topo, sizeof(topo), total_length,
			      query_item);
	if (ret != 0)
		return ret;
60 61 62 63 64 65 66 67 68 69

	if (topo.flags != 0)
		return -EINVAL;

	memset(&topo, 0, sizeof(topo));
	topo.max_slices = sseu->max_slices;
	topo.max_subslices = sseu->max_subslices;
	topo.max_eus_per_subslice = sseu->max_eus_per_subslice;

	topo.subslice_offset = slice_length;
S
Stuart Summers 已提交
70
	topo.subslice_stride = sseu->ss_stride;
71
	topo.eu_offset = slice_length + subslice_length;
S
Stuart Summers 已提交
72
	topo.eu_stride = sseu->eu_stride;
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

	if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr),
			   &topo, sizeof(topo)))
		return -EFAULT;

	if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + sizeof(topo)),
			   &sseu->slice_mask, slice_length))
		return -EFAULT;

	if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr +
					   sizeof(topo) + slice_length),
			   sseu->subslice_mask, subslice_length))
		return -EFAULT;

	if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr +
					   sizeof(topo) +
					   slice_length + subslice_length),
			   sseu->eu_mask, eu_length))
		return -EFAULT;

	return total_length;
}

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
static int
query_engine_info(struct drm_i915_private *i915,
		  struct drm_i915_query_item *query_item)
{
	struct drm_i915_query_engine_info __user *query_ptr =
				u64_to_user_ptr(query_item->data_ptr);
	struct drm_i915_engine_info __user *info_ptr;
	struct drm_i915_query_engine_info query;
	struct drm_i915_engine_info info = { };
	struct intel_engine_cs *engine;
	enum intel_engine_id id;
	int len, ret;

	if (query_item->flags)
		return -EINVAL;

	len = sizeof(struct drm_i915_query_engine_info) +
	      RUNTIME_INFO(i915)->num_engines *
	      sizeof(struct drm_i915_engine_info);

	ret = copy_query_item(&query, sizeof(query), len, query_item);
	if (ret != 0)
		return ret;

	if (query.num_engines || query.rsvd[0] || query.rsvd[1] ||
	    query.rsvd[2])
		return -EINVAL;

	info_ptr = &query_ptr->engines[0];

	for_each_engine(engine, i915, id) {
		info.engine.engine_class = engine->uabi_class;
		info.engine.engine_instance = engine->instance;
		info.capabilities = engine->uabi_capabilities;

		if (__copy_to_user(info_ptr, &info, sizeof(info)))
			return -EFAULT;

		query.num_engines++;
		info_ptr++;
	}

	if (__copy_to_user(query_ptr, &query, sizeof(query)))
		return -EFAULT;

	return len;
}

L
Lionel Landwerlin 已提交
144 145
static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv,
					struct drm_i915_query_item *query_item) = {
146
	query_topology_info,
147
	query_engine_info,
L
Lionel Landwerlin 已提交
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
};

int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
	struct drm_i915_private *dev_priv = to_i915(dev);
	struct drm_i915_query *args = data;
	struct drm_i915_query_item __user *user_item_ptr =
		u64_to_user_ptr(args->items_ptr);
	u32 i;

	if (args->flags != 0)
		return -EINVAL;

	for (i = 0; i < args->num_items; i++, user_item_ptr++) {
		struct drm_i915_query_item item;
163
		unsigned long func_idx;
L
Lionel Landwerlin 已提交
164 165 166 167 168 169 170 171
		int ret;

		if (copy_from_user(&item, user_item_ptr, sizeof(item)))
			return -EFAULT;

		if (item.query_id == 0)
			return -EINVAL;

172 173 174
		if (overflows_type(item.query_id - 1, unsigned long))
			return -EINVAL;

L
Lionel Landwerlin 已提交
175 176
		func_idx = item.query_id - 1;

177 178 179 180
		ret = -EINVAL;
		if (func_idx < ARRAY_SIZE(i915_query_funcs)) {
			func_idx = array_index_nospec(func_idx,
						      ARRAY_SIZE(i915_query_funcs));
L
Lionel Landwerlin 已提交
181
			ret = i915_query_funcs[func_idx](dev_priv, &item);
182
		}
L
Lionel Landwerlin 已提交
183 184 185 186 187 188 189 190

		/* Only write the length back to userspace if they differ. */
		if (ret != item.length && put_user(ret, &user_item_ptr->length))
			return -EFAULT;
	}

	return 0;
}