cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

selftest_guc.c (7349B)


      1// SPDX-License-Identifier: MIT
      2/*
      3 * Copyright �� 2021 Intel Corporation
      4 */
      5
      6#include "selftests/igt_spinner.h"
      7#include "selftests/intel_scheduler_helpers.h"
      8
      9static int request_add_spin(struct i915_request *rq, struct igt_spinner *spin)
     10{
     11	int err = 0;
     12
     13	i915_request_get(rq);
     14	i915_request_add(rq);
     15	if (spin && !igt_wait_for_spinner(spin, rq))
     16		err = -ETIMEDOUT;
     17
     18	return err;
     19}
     20
     21static struct i915_request *nop_user_request(struct intel_context *ce,
     22					     struct i915_request *from)
     23{
     24	struct i915_request *rq;
     25	int ret;
     26
     27	rq = intel_context_create_request(ce);
     28	if (IS_ERR(rq))
     29		return rq;
     30
     31	if (from) {
     32		ret = i915_sw_fence_await_dma_fence(&rq->submit,
     33						    &from->fence, 0,
     34						    I915_FENCE_GFP);
     35		if (ret < 0) {
     36			i915_request_put(rq);
     37			return ERR_PTR(ret);
     38		}
     39	}
     40
     41	i915_request_get(rq);
     42	i915_request_add(rq);
     43
     44	return rq;
     45}
     46
     47static int intel_guc_scrub_ctbs(void *arg)
     48{
     49	struct intel_gt *gt = arg;
     50	int ret = 0;
     51	int i;
     52	struct i915_request *last[3] = {NULL, NULL, NULL}, *rq;
     53	intel_wakeref_t wakeref;
     54	struct intel_engine_cs *engine;
     55	struct intel_context *ce;
     56
     57	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
     58	engine = intel_selftest_find_any_engine(gt);
     59
     60	/* Submit requests and inject errors forcing G2H to be dropped */
     61	for (i = 0; i < 3; ++i) {
     62		ce = intel_context_create(engine);
     63		if (IS_ERR(ce)) {
     64			ret = PTR_ERR(ce);
     65			pr_err("Failed to create context, %d: %d\n", i, ret);
     66			goto err;
     67		}
     68
     69		switch (i) {
     70		case 0:
     71			ce->drop_schedule_enable = true;
     72			break;
     73		case 1:
     74			ce->drop_schedule_disable = true;
     75			break;
     76		case 2:
     77			ce->drop_deregister = true;
     78			break;
     79		}
     80
     81		rq = nop_user_request(ce, NULL);
     82		intel_context_put(ce);
     83
     84		if (IS_ERR(rq)) {
     85			ret = PTR_ERR(rq);
     86			pr_err("Failed to create request, %d: %d\n", i, ret);
     87			goto err;
     88		}
     89
     90		last[i] = rq;
     91	}
     92
     93	for (i = 0; i < 3; ++i) {
     94		ret = i915_request_wait(last[i], 0, HZ);
     95		if (ret < 0) {
     96			pr_err("Last request failed to complete: %d\n", ret);
     97			goto err;
     98		}
     99		i915_request_put(last[i]);
    100		last[i] = NULL;
    101	}
    102
    103	/* Force all H2G / G2H to be submitted / processed */
    104	intel_gt_retire_requests(gt);
    105	msleep(500);
    106
    107	/* Scrub missing G2H */
    108	intel_gt_handle_error(engine->gt, -1, 0, "selftest reset");
    109
    110	/* GT will not idle if G2H are lost */
    111	ret = intel_gt_wait_for_idle(gt, HZ);
    112	if (ret < 0) {
    113		pr_err("GT failed to idle: %d\n", ret);
    114		goto err;
    115	}
    116
    117err:
    118	for (i = 0; i < 3; ++i)
    119		if (last[i])
    120			i915_request_put(last[i]);
    121	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
    122
    123	return ret;
    124}
    125
    126/*
    127 * intel_guc_steal_guc_ids - Test to exhaust all guc_ids and then steal one
    128 *
    129 * This test creates a spinner which is used to block all subsequent submissions
    130 * until it completes. Next, a loop creates a context and a NOP request each
    131 * iteration until the guc_ids are exhausted (request creation returns -EAGAIN).
    132 * The spinner is ended, unblocking all requests created in the loop. At this
    133 * point all guc_ids are exhausted but are available to steal. Try to create
    134 * another request which should successfully steal a guc_id. Wait on last
    135 * request to complete, idle GPU, verify a guc_id was stolen via a counter, and
    136 * exit the test. Test also artificially reduces the number of guc_ids so the
    137 * test runs in a timely manner.
    138 */
    139static int intel_guc_steal_guc_ids(void *arg)
    140{
    141	struct intel_gt *gt = arg;
    142	struct intel_guc *guc = &gt->uc.guc;
    143	int ret, sv, context_index = 0;
    144	intel_wakeref_t wakeref;
    145	struct intel_engine_cs *engine;
    146	struct intel_context **ce;
    147	struct igt_spinner spin;
    148	struct i915_request *spin_rq = NULL, *rq, *last = NULL;
    149	int number_guc_id_stolen = guc->number_guc_id_stolen;
    150
    151	ce = kcalloc(GUC_MAX_CONTEXT_ID, sizeof(*ce), GFP_KERNEL);
    152	if (!ce) {
    153		pr_err("Context array allocation failed\n");
    154		return -ENOMEM;
    155	}
    156
    157	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
    158	engine = intel_selftest_find_any_engine(gt);
    159	sv = guc->submission_state.num_guc_ids;
    160	guc->submission_state.num_guc_ids = 512;
    161
    162	/* Create spinner to block requests in below loop */
    163	ce[context_index] = intel_context_create(engine);
    164	if (IS_ERR(ce[context_index])) {
    165		ret = PTR_ERR(ce[context_index]);
    166		ce[context_index] = NULL;
    167		pr_err("Failed to create context: %d\n", ret);
    168		goto err_wakeref;
    169	}
    170	ret = igt_spinner_init(&spin, engine->gt);
    171	if (ret) {
    172		pr_err("Failed to create spinner: %d\n", ret);
    173		goto err_contexts;
    174	}
    175	spin_rq = igt_spinner_create_request(&spin, ce[context_index],
    176					     MI_ARB_CHECK);
    177	if (IS_ERR(spin_rq)) {
    178		ret = PTR_ERR(spin_rq);
    179		pr_err("Failed to create spinner request: %d\n", ret);
    180		goto err_contexts;
    181	}
    182	ret = request_add_spin(spin_rq, &spin);
    183	if (ret) {
    184		pr_err("Failed to add Spinner request: %d\n", ret);
    185		goto err_spin_rq;
    186	}
    187
    188	/* Use all guc_ids */
    189	while (ret != -EAGAIN) {
    190		ce[++context_index] = intel_context_create(engine);
    191		if (IS_ERR(ce[context_index])) {
    192			ret = PTR_ERR(ce[context_index--]);
    193			ce[context_index] = NULL;
    194			pr_err("Failed to create context: %d\n", ret);
    195			goto err_spin_rq;
    196		}
    197
    198		rq = nop_user_request(ce[context_index], spin_rq);
    199		if (IS_ERR(rq)) {
    200			ret = PTR_ERR(rq);
    201			rq = NULL;
    202			if (ret != -EAGAIN) {
    203				pr_err("Failed to create request, %d: %d\n",
    204				       context_index, ret);
    205				goto err_spin_rq;
    206			}
    207		} else {
    208			if (last)
    209				i915_request_put(last);
    210			last = rq;
    211		}
    212	}
    213
    214	/* Release blocked requests */
    215	igt_spinner_end(&spin);
    216	ret = intel_selftest_wait_for_rq(spin_rq);
    217	if (ret) {
    218		pr_err("Spin request failed to complete: %d\n", ret);
    219		i915_request_put(last);
    220		goto err_spin_rq;
    221	}
    222	i915_request_put(spin_rq);
    223	igt_spinner_fini(&spin);
    224	spin_rq = NULL;
    225
    226	/* Wait for last request */
    227	ret = i915_request_wait(last, 0, HZ * 30);
    228	i915_request_put(last);
    229	if (ret < 0) {
    230		pr_err("Last request failed to complete: %d\n", ret);
    231		goto err_spin_rq;
    232	}
    233
    234	/* Try to steal guc_id */
    235	rq = nop_user_request(ce[context_index], NULL);
    236	if (IS_ERR(rq)) {
    237		ret = PTR_ERR(rq);
    238		pr_err("Failed to steal guc_id, %d: %d\n", context_index, ret);
    239		goto err_spin_rq;
    240	}
    241
    242	/* Wait for request with stolen guc_id */
    243	ret = i915_request_wait(rq, 0, HZ);
    244	i915_request_put(rq);
    245	if (ret < 0) {
    246		pr_err("Request with stolen guc_id failed to complete: %d\n",
    247		       ret);
    248		goto err_spin_rq;
    249	}
    250
    251	/* Wait for idle */
    252	ret = intel_gt_wait_for_idle(gt, HZ * 30);
    253	if (ret < 0) {
    254		pr_err("GT failed to idle: %d\n", ret);
    255		goto err_spin_rq;
    256	}
    257
    258	/* Verify a guc_id was stolen */
    259	if (guc->number_guc_id_stolen == number_guc_id_stolen) {
    260		pr_err("No guc_id was stolen");
    261		ret = -EINVAL;
    262	} else {
    263		ret = 0;
    264	}
    265
    266err_spin_rq:
    267	if (spin_rq) {
    268		igt_spinner_end(&spin);
    269		intel_selftest_wait_for_rq(spin_rq);
    270		i915_request_put(spin_rq);
    271		igt_spinner_fini(&spin);
    272		intel_gt_wait_for_idle(gt, HZ * 30);
    273	}
    274err_contexts:
    275	for (; context_index >= 0 && ce[context_index]; --context_index)
    276		intel_context_put(ce[context_index]);
    277err_wakeref:
    278	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
    279	kfree(ce);
    280	guc->submission_state.num_guc_ids = sv;
    281
    282	return ret;
    283}
    284
    285int intel_guc_live_selftests(struct drm_i915_private *i915)
    286{
    287	static const struct i915_subtest tests[] = {
    288		SUBTEST(intel_guc_scrub_ctbs),
    289		SUBTEST(intel_guc_steal_guc_ids),
    290	};
    291	struct intel_gt *gt = to_gt(i915);
    292
    293	if (intel_gt_is_wedged(gt))
    294		return 0;
    295
    296	if (!intel_uc_uses_guc_submission(&gt->uc))
    297		return 0;
    298
    299	return intel_gt_live_subtests(tests, gt);
    300}