Home | History | Annotate | Line # | Download | only in i915
      1  1.1  riastrad /*	$NetBSD: i915_query.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad /*
      4  1.1  riastrad  * SPDX-License-Identifier: MIT
      5  1.1  riastrad  *
      6  1.1  riastrad  * Copyright  2018 Intel Corporation
      7  1.1  riastrad  */
      8  1.1  riastrad 
      9  1.1  riastrad #include <sys/cdefs.h>
     10  1.1  riastrad __KERNEL_RCSID(0, "$NetBSD: i915_query.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $");
     11  1.1  riastrad 
     12  1.1  riastrad #include <linux/nospec.h>
     13  1.1  riastrad 
     14  1.1  riastrad #include "i915_drv.h"
     15  1.1  riastrad #include "i915_perf.h"
     16  1.1  riastrad #include "i915_query.h"
     17  1.1  riastrad #include <uapi/drm/i915_drm.h>
     18  1.1  riastrad 
     19  1.1  riastrad static int copy_query_item(void *query_hdr, size_t query_sz,
     20  1.1  riastrad 			   u32 total_length,
     21  1.1  riastrad 			   struct drm_i915_query_item *query_item)
     22  1.1  riastrad {
     23  1.1  riastrad 	if (query_item->length == 0)
     24  1.1  riastrad 		return total_length;
     25  1.1  riastrad 
     26  1.1  riastrad 	if (query_item->length < total_length)
     27  1.1  riastrad 		return -EINVAL;
     28  1.1  riastrad 
     29  1.1  riastrad 	if (copy_from_user(query_hdr, u64_to_user_ptr(query_item->data_ptr),
     30  1.1  riastrad 			   query_sz))
     31  1.1  riastrad 		return -EFAULT;
     32  1.1  riastrad 
     33  1.1  riastrad 	if (!access_ok(u64_to_user_ptr(query_item->data_ptr),
     34  1.1  riastrad 		       total_length))
     35  1.1  riastrad 		return -EFAULT;
     36  1.1  riastrad 
     37  1.1  riastrad 	return 0;
     38  1.1  riastrad }
     39  1.1  riastrad 
     40  1.1  riastrad static int query_topology_info(struct drm_i915_private *dev_priv,
     41  1.1  riastrad 			       struct drm_i915_query_item *query_item)
     42  1.1  riastrad {
     43  1.1  riastrad 	const struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
     44  1.1  riastrad 	struct drm_i915_query_topology_info topo;
     45  1.1  riastrad 	u32 slice_length, subslice_length, eu_length, total_length;
     46  1.1  riastrad 	int ret;
     47  1.1  riastrad 
     48  1.1  riastrad 	if (query_item->flags != 0)
     49  1.1  riastrad 		return -EINVAL;
     50  1.1  riastrad 
     51  1.1  riastrad 	if (sseu->max_slices == 0)
     52  1.1  riastrad 		return -ENODEV;
     53  1.1  riastrad 
     54  1.1  riastrad 	BUILD_BUG_ON(sizeof(u8) != sizeof(sseu->slice_mask));
     55  1.1  riastrad 
     56  1.1  riastrad 	slice_length = sizeof(sseu->slice_mask);
     57  1.1  riastrad 	subslice_length = sseu->max_slices * sseu->ss_stride;
     58  1.1  riastrad 	eu_length = sseu->max_slices * sseu->max_subslices * sseu->eu_stride;
     59  1.1  riastrad 	total_length = sizeof(topo) + slice_length + subslice_length +
     60  1.1  riastrad 		       eu_length;
     61  1.1  riastrad 
     62  1.1  riastrad 	ret = copy_query_item(&topo, sizeof(topo), total_length,
     63  1.1  riastrad 			      query_item);
     64  1.1  riastrad 	if (ret != 0)
     65  1.1  riastrad 		return ret;
     66  1.1  riastrad 
     67  1.1  riastrad 	if (topo.flags != 0)
     68  1.1  riastrad 		return -EINVAL;
     69  1.1  riastrad 
     70  1.1  riastrad 	memset(&topo, 0, sizeof(topo));
     71  1.1  riastrad 	topo.max_slices = sseu->max_slices;
     72  1.1  riastrad 	topo.max_subslices = sseu->max_subslices;
     73  1.1  riastrad 	topo.max_eus_per_subslice = sseu->max_eus_per_subslice;
     74  1.1  riastrad 
     75  1.1  riastrad 	topo.subslice_offset = slice_length;
     76  1.1  riastrad 	topo.subslice_stride = sseu->ss_stride;
     77  1.1  riastrad 	topo.eu_offset = slice_length + subslice_length;
     78  1.1  riastrad 	topo.eu_stride = sseu->eu_stride;
     79  1.1  riastrad 
     80  1.1  riastrad 	if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr),
     81  1.1  riastrad 			   &topo, sizeof(topo)))
     82  1.1  riastrad 		return -EFAULT;
     83  1.1  riastrad 
     84  1.1  riastrad 	if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + sizeof(topo)),
     85  1.1  riastrad 			   &sseu->slice_mask, slice_length))
     86  1.1  riastrad 		return -EFAULT;
     87  1.1  riastrad 
     88  1.1  riastrad 	if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr +
     89  1.1  riastrad 					   sizeof(topo) + slice_length),
     90  1.1  riastrad 			   sseu->subslice_mask, subslice_length))
     91  1.1  riastrad 		return -EFAULT;
     92  1.1  riastrad 
     93  1.1  riastrad 	if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr +
     94  1.1  riastrad 					   sizeof(topo) +
     95  1.1  riastrad 					   slice_length + subslice_length),
     96  1.1  riastrad 			   sseu->eu_mask, eu_length))
     97  1.1  riastrad 		return -EFAULT;
     98  1.1  riastrad 
     99  1.1  riastrad 	return total_length;
    100  1.1  riastrad }
    101  1.1  riastrad 
    102  1.1  riastrad static int
    103  1.1  riastrad query_engine_info(struct drm_i915_private *i915,
    104  1.1  riastrad 		  struct drm_i915_query_item *query_item)
    105  1.1  riastrad {
    106  1.1  riastrad 	struct drm_i915_query_engine_info __user *query_ptr =
    107  1.1  riastrad 				u64_to_user_ptr(query_item->data_ptr);
    108  1.1  riastrad 	struct drm_i915_engine_info __user *info_ptr;
    109  1.1  riastrad 	struct drm_i915_query_engine_info query;
    110  1.1  riastrad 	struct drm_i915_engine_info info = { };
    111  1.1  riastrad 	unsigned int num_uabi_engines = 0;
    112  1.1  riastrad 	struct intel_engine_cs *engine;
    113  1.1  riastrad 	int len, ret;
    114  1.1  riastrad 
    115  1.1  riastrad 	if (query_item->flags)
    116  1.1  riastrad 		return -EINVAL;
    117  1.1  riastrad 
    118  1.1  riastrad 	for_each_uabi_engine(engine, i915)
    119  1.1  riastrad 		num_uabi_engines++;
    120  1.1  riastrad 
    121  1.1  riastrad 	len = sizeof(struct drm_i915_query_engine_info) +
    122  1.1  riastrad 	      num_uabi_engines * sizeof(struct drm_i915_engine_info);
    123  1.1  riastrad 
    124  1.1  riastrad 	ret = copy_query_item(&query, sizeof(query), len, query_item);
    125  1.1  riastrad 	if (ret != 0)
    126  1.1  riastrad 		return ret;
    127  1.1  riastrad 
    128  1.1  riastrad 	if (query.num_engines || query.rsvd[0] || query.rsvd[1] ||
    129  1.1  riastrad 	    query.rsvd[2])
    130  1.1  riastrad 		return -EINVAL;
    131  1.1  riastrad 
    132  1.1  riastrad 	info_ptr = &query_ptr->engines[0];
    133  1.1  riastrad 
    134  1.1  riastrad 	for_each_uabi_engine(engine, i915) {
    135  1.1  riastrad 		info.engine.engine_class = engine->uabi_class;
    136  1.1  riastrad 		info.engine.engine_instance = engine->uabi_instance;
    137  1.1  riastrad 		info.capabilities = engine->uabi_capabilities;
    138  1.1  riastrad 
    139  1.1  riastrad 		if (__copy_to_user(info_ptr, &info, sizeof(info)))
    140  1.1  riastrad 			return -EFAULT;
    141  1.1  riastrad 
    142  1.1  riastrad 		query.num_engines++;
    143  1.1  riastrad 		info_ptr++;
    144  1.1  riastrad 	}
    145  1.1  riastrad 
    146  1.1  riastrad 	if (__copy_to_user(query_ptr, &query, sizeof(query)))
    147  1.1  riastrad 		return -EFAULT;
    148  1.1  riastrad 
    149  1.1  riastrad 	return len;
    150  1.1  riastrad }
    151  1.1  riastrad 
    152  1.1  riastrad static int can_copy_perf_config_registers_or_number(u32 user_n_regs,
    153  1.1  riastrad 						    u64 user_regs_ptr,
    154  1.1  riastrad 						    u32 kernel_n_regs)
    155  1.1  riastrad {
    156  1.1  riastrad 	/*
    157  1.1  riastrad 	 * We'll just put the number of registers, and won't copy the
    158  1.1  riastrad 	 * register.
    159  1.1  riastrad 	 */
    160  1.1  riastrad 	if (user_n_regs == 0)
    161  1.1  riastrad 		return 0;
    162  1.1  riastrad 
    163  1.1  riastrad 	if (user_n_regs < kernel_n_regs)
    164  1.1  riastrad 		return -EINVAL;
    165  1.1  riastrad 
    166  1.1  riastrad 	if (!access_ok(u64_to_user_ptr(user_regs_ptr),
    167  1.1  riastrad 		       2 * sizeof(u32) * kernel_n_regs))
    168  1.1  riastrad 		return -EFAULT;
    169  1.1  riastrad 
    170  1.1  riastrad 	return 0;
    171  1.1  riastrad }
    172  1.1  riastrad 
    173  1.1  riastrad static int copy_perf_config_registers_or_number(const struct i915_oa_reg *kernel_regs,
    174  1.1  riastrad 						u32 kernel_n_regs,
    175  1.1  riastrad 						u64 user_regs_ptr,
    176  1.1  riastrad 						u32 *user_n_regs)
    177  1.1  riastrad {
    178  1.1  riastrad 	u32 r;
    179  1.1  riastrad 
    180  1.1  riastrad 	if (*user_n_regs == 0) {
    181  1.1  riastrad 		*user_n_regs = kernel_n_regs;
    182  1.1  riastrad 		return 0;
    183  1.1  riastrad 	}
    184  1.1  riastrad 
    185  1.1  riastrad 	*user_n_regs = kernel_n_regs;
    186  1.1  riastrad 
    187  1.1  riastrad 	for (r = 0; r < kernel_n_regs; r++) {
    188  1.1  riastrad 		u32 __user *user_reg_ptr =
    189  1.1  riastrad 			u64_to_user_ptr(user_regs_ptr + sizeof(u32) * r * 2);
    190  1.1  riastrad 		u32 __user *user_val_ptr =
    191  1.1  riastrad 			u64_to_user_ptr(user_regs_ptr + sizeof(u32) * r * 2 +
    192  1.1  riastrad 					sizeof(u32));
    193  1.1  riastrad 		int ret;
    194  1.1  riastrad 
    195  1.1  riastrad 		ret = __put_user(i915_mmio_reg_offset(kernel_regs[r].addr),
    196  1.1  riastrad 				 user_reg_ptr);
    197  1.1  riastrad 		if (ret)
    198  1.1  riastrad 			return -EFAULT;
    199  1.1  riastrad 
    200  1.1  riastrad 		ret = __put_user(kernel_regs[r].value, user_val_ptr);
    201  1.1  riastrad 		if (ret)
    202  1.1  riastrad 			return -EFAULT;
    203  1.1  riastrad 	}
    204  1.1  riastrad 
    205  1.1  riastrad 	return 0;
    206  1.1  riastrad }
    207  1.1  riastrad 
    208  1.1  riastrad static int query_perf_config_data(struct drm_i915_private *i915,
    209  1.1  riastrad 				  struct drm_i915_query_item *query_item,
    210  1.1  riastrad 				  bool use_uuid)
    211  1.1  riastrad {
    212  1.1  riastrad 	struct drm_i915_query_perf_config __user *user_query_config_ptr =
    213  1.1  riastrad 		u64_to_user_ptr(query_item->data_ptr);
    214  1.1  riastrad 	struct drm_i915_perf_oa_config __user *user_config_ptr =
    215  1.1  riastrad 		u64_to_user_ptr(query_item->data_ptr +
    216  1.1  riastrad 				sizeof(struct drm_i915_query_perf_config));
    217  1.1  riastrad 	struct drm_i915_perf_oa_config user_config;
    218  1.1  riastrad 	struct i915_perf *perf = &i915->perf;
    219  1.1  riastrad 	struct i915_oa_config *oa_config;
    220  1.1  riastrad 	char uuid[UUID_STRING_LEN + 1];
    221  1.1  riastrad 	u64 config_id;
    222  1.1  riastrad 	u32 flags, total_size;
    223  1.1  riastrad 	int ret;
    224  1.1  riastrad 
    225  1.1  riastrad 	if (!perf->i915)
    226  1.1  riastrad 		return -ENODEV;
    227  1.1  riastrad 
    228  1.1  riastrad 	total_size =
    229  1.1  riastrad 		sizeof(struct drm_i915_query_perf_config) +
    230  1.1  riastrad 		sizeof(struct drm_i915_perf_oa_config);
    231  1.1  riastrad 
    232  1.1  riastrad 	if (query_item->length == 0)
    233  1.1  riastrad 		return total_size;
    234  1.1  riastrad 
    235  1.1  riastrad 	if (query_item->length < total_size) {
    236  1.1  riastrad 		DRM_DEBUG("Invalid query config data item size=%u expected=%u\n",
    237  1.1  riastrad 			  query_item->length, total_size);
    238  1.1  riastrad 		return -EINVAL;
    239  1.1  riastrad 	}
    240  1.1  riastrad 
    241  1.1  riastrad 	if (!access_ok(user_query_config_ptr, total_size))
    242  1.1  riastrad 		return -EFAULT;
    243  1.1  riastrad 
    244  1.1  riastrad 	if (__get_user(flags, &user_query_config_ptr->flags))
    245  1.1  riastrad 		return -EFAULT;
    246  1.1  riastrad 
    247  1.1  riastrad 	if (flags != 0)
    248  1.1  riastrad 		return -EINVAL;
    249  1.1  riastrad 
    250  1.1  riastrad 	if (use_uuid) {
    251  1.1  riastrad 		struct i915_oa_config *tmp;
    252  1.1  riastrad 		int id;
    253  1.1  riastrad 
    254  1.1  riastrad 		BUILD_BUG_ON(sizeof(user_query_config_ptr->uuid) >= sizeof(uuid));
    255  1.1  riastrad 
    256  1.1  riastrad 		memset(&uuid, 0, sizeof(uuid));
    257  1.1  riastrad 		if (__copy_from_user(uuid, user_query_config_ptr->uuid,
    258  1.1  riastrad 				     sizeof(user_query_config_ptr->uuid)))
    259  1.1  riastrad 			return -EFAULT;
    260  1.1  riastrad 
    261  1.1  riastrad 		oa_config = NULL;
    262  1.1  riastrad 		rcu_read_lock();
    263  1.1  riastrad 		idr_for_each_entry(&perf->metrics_idr, tmp, id) {
    264  1.1  riastrad 			if (!strcmp(tmp->uuid, uuid)) {
    265  1.1  riastrad 				oa_config = i915_oa_config_get(tmp);
    266  1.1  riastrad 				break;
    267  1.1  riastrad 			}
    268  1.1  riastrad 		}
    269  1.1  riastrad 		rcu_read_unlock();
    270  1.1  riastrad 	} else {
    271  1.1  riastrad 		if (__get_user(config_id, &user_query_config_ptr->config))
    272  1.1  riastrad 			return -EFAULT;
    273  1.1  riastrad 
    274  1.1  riastrad 		oa_config = i915_perf_get_oa_config(perf, config_id);
    275  1.1  riastrad 	}
    276  1.1  riastrad 	if (!oa_config)
    277  1.1  riastrad 		return -ENOENT;
    278  1.1  riastrad 
    279  1.1  riastrad 	if (__copy_from_user(&user_config, user_config_ptr,
    280  1.1  riastrad 			     sizeof(user_config))) {
    281  1.1  riastrad 		ret = -EFAULT;
    282  1.1  riastrad 		goto out;
    283  1.1  riastrad 	}
    284  1.1  riastrad 
    285  1.1  riastrad 	ret = can_copy_perf_config_registers_or_number(user_config.n_boolean_regs,
    286  1.1  riastrad 						       user_config.boolean_regs_ptr,
    287  1.1  riastrad 						       oa_config->b_counter_regs_len);
    288  1.1  riastrad 	if (ret)
    289  1.1  riastrad 		goto out;
    290  1.1  riastrad 
    291  1.1  riastrad 	ret = can_copy_perf_config_registers_or_number(user_config.n_flex_regs,
    292  1.1  riastrad 						       user_config.flex_regs_ptr,
    293  1.1  riastrad 						       oa_config->flex_regs_len);
    294  1.1  riastrad 	if (ret)
    295  1.1  riastrad 		goto out;
    296  1.1  riastrad 
    297  1.1  riastrad 	ret = can_copy_perf_config_registers_or_number(user_config.n_mux_regs,
    298  1.1  riastrad 						       user_config.mux_regs_ptr,
    299  1.1  riastrad 						       oa_config->mux_regs_len);
    300  1.1  riastrad 	if (ret)
    301  1.1  riastrad 		goto out;
    302  1.1  riastrad 
    303  1.1  riastrad 	ret = copy_perf_config_registers_or_number(oa_config->b_counter_regs,
    304  1.1  riastrad 						   oa_config->b_counter_regs_len,
    305  1.1  riastrad 						   user_config.boolean_regs_ptr,
    306  1.1  riastrad 						   &user_config.n_boolean_regs);
    307  1.1  riastrad 	if (ret)
    308  1.1  riastrad 		goto out;
    309  1.1  riastrad 
    310  1.1  riastrad 	ret = copy_perf_config_registers_or_number(oa_config->flex_regs,
    311  1.1  riastrad 						   oa_config->flex_regs_len,
    312  1.1  riastrad 						   user_config.flex_regs_ptr,
    313  1.1  riastrad 						   &user_config.n_flex_regs);
    314  1.1  riastrad 	if (ret)
    315  1.1  riastrad 		goto out;
    316  1.1  riastrad 
    317  1.1  riastrad 	ret = copy_perf_config_registers_or_number(oa_config->mux_regs,
    318  1.1  riastrad 						   oa_config->mux_regs_len,
    319  1.1  riastrad 						   user_config.mux_regs_ptr,
    320  1.1  riastrad 						   &user_config.n_mux_regs);
    321  1.1  riastrad 	if (ret)
    322  1.1  riastrad 		goto out;
    323  1.1  riastrad 
    324  1.1  riastrad 	memcpy(user_config.uuid, oa_config->uuid, sizeof(user_config.uuid));
    325  1.1  riastrad 
    326  1.1  riastrad 	if (__copy_to_user(user_config_ptr, &user_config,
    327  1.1  riastrad 			   sizeof(user_config))) {
    328  1.1  riastrad 		ret = -EFAULT;
    329  1.1  riastrad 		goto out;
    330  1.1  riastrad 	}
    331  1.1  riastrad 
    332  1.1  riastrad 	ret = total_size;
    333  1.1  riastrad 
    334  1.1  riastrad out:
    335  1.1  riastrad 	i915_oa_config_put(oa_config);
    336  1.1  riastrad 	return ret;
    337  1.1  riastrad }
    338  1.1  riastrad 
    339  1.1  riastrad static size_t sizeof_perf_config_list(size_t count)
    340  1.1  riastrad {
    341  1.1  riastrad 	return sizeof(struct drm_i915_query_perf_config) + sizeof(u64) * count;
    342  1.1  riastrad }
    343  1.1  riastrad 
    344  1.1  riastrad static size_t sizeof_perf_metrics(struct i915_perf *perf)
    345  1.1  riastrad {
    346  1.1  riastrad 	struct i915_oa_config *tmp;
    347  1.1  riastrad 	size_t i;
    348  1.1  riastrad 	int id;
    349  1.1  riastrad 
    350  1.1  riastrad 	i = 1;
    351  1.1  riastrad 	rcu_read_lock();
    352  1.1  riastrad 	idr_for_each_entry(&perf->metrics_idr, tmp, id)
    353  1.1  riastrad 		i++;
    354  1.1  riastrad 	rcu_read_unlock();
    355  1.1  riastrad 
    356  1.1  riastrad 	return sizeof_perf_config_list(i);
    357  1.1  riastrad }
    358  1.1  riastrad 
    359  1.1  riastrad static int query_perf_config_list(struct drm_i915_private *i915,
    360  1.1  riastrad 				  struct drm_i915_query_item *query_item)
    361  1.1  riastrad {
    362  1.1  riastrad 	struct drm_i915_query_perf_config __user *user_query_config_ptr =
    363  1.1  riastrad 		u64_to_user_ptr(query_item->data_ptr);
    364  1.1  riastrad 	struct i915_perf *perf = &i915->perf;
    365  1.1  riastrad 	u64 *oa_config_ids = NULL;
    366  1.1  riastrad 	int alloc, n_configs;
    367  1.1  riastrad 	u32 flags;
    368  1.1  riastrad 	int ret;
    369  1.1  riastrad 
    370  1.1  riastrad 	if (!perf->i915)
    371  1.1  riastrad 		return -ENODEV;
    372  1.1  riastrad 
    373  1.1  riastrad 	if (query_item->length == 0)
    374  1.1  riastrad 		return sizeof_perf_metrics(perf);
    375  1.1  riastrad 
    376  1.1  riastrad 	if (get_user(flags, &user_query_config_ptr->flags))
    377  1.1  riastrad 		return -EFAULT;
    378  1.1  riastrad 
    379  1.1  riastrad 	if (flags != 0)
    380  1.1  riastrad 		return -EINVAL;
    381  1.1  riastrad 
    382  1.1  riastrad 	n_configs = 1;
    383  1.1  riastrad 	do {
    384  1.1  riastrad 		struct i915_oa_config *tmp;
    385  1.1  riastrad 		u64 *ids;
    386  1.1  riastrad 		int id;
    387  1.1  riastrad 
    388  1.1  riastrad 		ids = krealloc(oa_config_ids,
    389  1.1  riastrad 			       n_configs * sizeof(*oa_config_ids),
    390  1.1  riastrad 			       GFP_KERNEL);
    391  1.1  riastrad 		if (!ids)
    392  1.1  riastrad 			return -ENOMEM;
    393  1.1  riastrad 
    394  1.1  riastrad 		alloc = fetch_and_zero(&n_configs);
    395  1.1  riastrad 
    396  1.1  riastrad 		ids[n_configs++] = 1ull; /* reserved for test_config */
    397  1.1  riastrad 		rcu_read_lock();
    398  1.1  riastrad 		idr_for_each_entry(&perf->metrics_idr, tmp, id) {
    399  1.1  riastrad 			if (n_configs < alloc)
    400  1.1  riastrad 				ids[n_configs] = id;
    401  1.1  riastrad 			n_configs++;
    402  1.1  riastrad 		}
    403  1.1  riastrad 		rcu_read_unlock();
    404  1.1  riastrad 
    405  1.1  riastrad 		oa_config_ids = ids;
    406  1.1  riastrad 	} while (n_configs > alloc);
    407  1.1  riastrad 
    408  1.1  riastrad 	if (query_item->length < sizeof_perf_config_list(n_configs)) {
    409  1.1  riastrad 		DRM_DEBUG("Invalid query config list item size=%u expected=%zu\n",
    410  1.1  riastrad 			  query_item->length,
    411  1.1  riastrad 			  sizeof_perf_config_list(n_configs));
    412  1.1  riastrad 		kfree(oa_config_ids);
    413  1.1  riastrad 		return -EINVAL;
    414  1.1  riastrad 	}
    415  1.1  riastrad 
    416  1.1  riastrad 	if (put_user(n_configs, &user_query_config_ptr->config)) {
    417  1.1  riastrad 		kfree(oa_config_ids);
    418  1.1  riastrad 		return -EFAULT;
    419  1.1  riastrad 	}
    420  1.1  riastrad 
    421  1.1  riastrad 	ret = copy_to_user(user_query_config_ptr + 1,
    422  1.1  riastrad 			   oa_config_ids,
    423  1.1  riastrad 			   n_configs * sizeof(*oa_config_ids));
    424  1.1  riastrad 	kfree(oa_config_ids);
    425  1.1  riastrad 	if (ret)
    426  1.1  riastrad 		return -EFAULT;
    427  1.1  riastrad 
    428  1.1  riastrad 	return sizeof_perf_config_list(n_configs);
    429  1.1  riastrad }
    430  1.1  riastrad 
    431  1.1  riastrad static int query_perf_config(struct drm_i915_private *i915,
    432  1.1  riastrad 			     struct drm_i915_query_item *query_item)
    433  1.1  riastrad {
    434  1.1  riastrad 	switch (query_item->flags) {
    435  1.1  riastrad 	case DRM_I915_QUERY_PERF_CONFIG_LIST:
    436  1.1  riastrad 		return query_perf_config_list(i915, query_item);
    437  1.1  riastrad 	case DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID:
    438  1.1  riastrad 		return query_perf_config_data(i915, query_item, true);
    439  1.1  riastrad 	case DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID:
    440  1.1  riastrad 		return query_perf_config_data(i915, query_item, false);
    441  1.1  riastrad 	default:
    442  1.1  riastrad 		return -EINVAL;
    443  1.1  riastrad 	}
    444  1.1  riastrad }
    445  1.1  riastrad 
    446  1.1  riastrad static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv,
    447  1.1  riastrad 					struct drm_i915_query_item *query_item) = {
    448  1.1  riastrad 	query_topology_info,
    449  1.1  riastrad 	query_engine_info,
    450  1.1  riastrad 	query_perf_config,
    451  1.1  riastrad };
    452  1.1  riastrad 
    453  1.1  riastrad int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
    454  1.1  riastrad {
    455  1.1  riastrad 	struct drm_i915_private *dev_priv = to_i915(dev);
    456  1.1  riastrad 	struct drm_i915_query *args = data;
    457  1.1  riastrad 	struct drm_i915_query_item __user *user_item_ptr =
    458  1.1  riastrad 		u64_to_user_ptr(args->items_ptr);
    459  1.1  riastrad 	u32 i;
    460  1.1  riastrad 
    461  1.1  riastrad 	if (args->flags != 0)
    462  1.1  riastrad 		return -EINVAL;
    463  1.1  riastrad 
    464  1.1  riastrad 	for (i = 0; i < args->num_items; i++, user_item_ptr++) {
    465  1.1  riastrad 		struct drm_i915_query_item item;
    466  1.1  riastrad 		unsigned long func_idx;
    467  1.1  riastrad 		int ret;
    468  1.1  riastrad 
    469  1.1  riastrad 		if (copy_from_user(&item, user_item_ptr, sizeof(item)))
    470  1.1  riastrad 			return -EFAULT;
    471  1.1  riastrad 
    472  1.1  riastrad 		if (item.query_id == 0)
    473  1.1  riastrad 			return -EINVAL;
    474  1.1  riastrad 
    475  1.1  riastrad 		if (overflows_type(item.query_id - 1, unsigned long))
    476  1.1  riastrad 			return -EINVAL;
    477  1.1  riastrad 
    478  1.1  riastrad 		func_idx = item.query_id - 1;
    479  1.1  riastrad 
    480  1.1  riastrad 		ret = -EINVAL;
    481  1.1  riastrad 		if (func_idx < ARRAY_SIZE(i915_query_funcs)) {
    482  1.1  riastrad 			func_idx = array_index_nospec(func_idx,
    483  1.1  riastrad 						      ARRAY_SIZE(i915_query_funcs));
    484  1.1  riastrad 			ret = i915_query_funcs[func_idx](dev_priv, &item);
    485  1.1  riastrad 		}
    486  1.1  riastrad 
    487  1.1  riastrad 		/* Only write the length back to userspace if they differ. */
    488  1.1  riastrad 		if (ret != item.length && put_user(ret, &user_item_ptr->length))
    489  1.1  riastrad 			return -EFAULT;
    490  1.1  riastrad 	}
    491  1.1  riastrad 
    492  1.1  riastrad 	return 0;
    493  1.1  riastrad }
    494