i915_query.c 4.9 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 41
	u8 subslice_stride = GEN_SSEU_STRIDE(sseu->max_subslices);
	u8 eu_stride = GEN_SSEU_STRIDE(sseu->max_eus_per_subslice);
42
	int ret;
43 44 45 46 47 48 49 50 51 52

	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);
53 54 55 56
	subslice_length = sseu->max_slices * subslice_stride;
	eu_length = sseu->max_slices * sseu->max_subslices * eu_stride;
	total_length = sizeof(topo) + slice_length + subslice_length +
		       eu_length;
57

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

	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;
72
	topo.subslice_stride = subslice_stride;
73
	topo.eu_offset = slice_length + subslice_length;
74
	topo.eu_stride = eu_stride;
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

	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;
}

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

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;
165
		unsigned long func_idx;
L
Lionel Landwerlin 已提交
166 167 168 169 170 171 172 173
		int ret;

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

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

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

L
Lionel Landwerlin 已提交
177 178
		func_idx = item.query_id - 1;

179 180 181 182
		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 已提交
183
			ret = i915_query_funcs[func_idx](dev_priv, &item);
184
		}
L
Lionel Landwerlin 已提交
185 186 187 188 189 190 191 192

		/* 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;
}