i915_query.c 15 KB

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