18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * SPDX-License-Identifier: MIT
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2018 Intel Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include "gt/intel_gt.h"
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "gem/selftests/igt_gem_utils.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "igt_spinner.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ciint igt_spinner_init(struct igt_spinner *spin, struct intel_gt *gt)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	unsigned int mode;
158c2ecf20Sopenharmony_ci	void *vaddr;
168c2ecf20Sopenharmony_ci	int err;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	memset(spin, 0, sizeof(*spin));
198c2ecf20Sopenharmony_ci	spin->gt = gt;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	spin->hws = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
228c2ecf20Sopenharmony_ci	if (IS_ERR(spin->hws)) {
238c2ecf20Sopenharmony_ci		err = PTR_ERR(spin->hws);
248c2ecf20Sopenharmony_ci		goto err;
258c2ecf20Sopenharmony_ci	}
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	spin->obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
288c2ecf20Sopenharmony_ci	if (IS_ERR(spin->obj)) {
298c2ecf20Sopenharmony_ci		err = PTR_ERR(spin->obj);
308c2ecf20Sopenharmony_ci		goto err_hws;
318c2ecf20Sopenharmony_ci	}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	i915_gem_object_set_cache_coherency(spin->hws, I915_CACHE_LLC);
348c2ecf20Sopenharmony_ci	vaddr = i915_gem_object_pin_map(spin->hws, I915_MAP_WB);
358c2ecf20Sopenharmony_ci	if (IS_ERR(vaddr)) {
368c2ecf20Sopenharmony_ci		err = PTR_ERR(vaddr);
378c2ecf20Sopenharmony_ci		goto err_obj;
388c2ecf20Sopenharmony_ci	}
398c2ecf20Sopenharmony_ci	spin->seqno = memset(vaddr, 0xff, PAGE_SIZE);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	mode = i915_coherent_map_type(gt->i915);
428c2ecf20Sopenharmony_ci	vaddr = i915_gem_object_pin_map(spin->obj, mode);
438c2ecf20Sopenharmony_ci	if (IS_ERR(vaddr)) {
448c2ecf20Sopenharmony_ci		err = PTR_ERR(vaddr);
458c2ecf20Sopenharmony_ci		goto err_unpin_hws;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci	spin->batch = vaddr;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	return 0;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cierr_unpin_hws:
528c2ecf20Sopenharmony_ci	i915_gem_object_unpin_map(spin->hws);
538c2ecf20Sopenharmony_cierr_obj:
548c2ecf20Sopenharmony_ci	i915_gem_object_put(spin->obj);
558c2ecf20Sopenharmony_cierr_hws:
568c2ecf20Sopenharmony_ci	i915_gem_object_put(spin->hws);
578c2ecf20Sopenharmony_cierr:
588c2ecf20Sopenharmony_ci	return err;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic unsigned int seqno_offset(u64 fence)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	return offset_in_page(sizeof(u32) * fence);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic u64 hws_address(const struct i915_vma *hws,
678c2ecf20Sopenharmony_ci		       const struct i915_request *rq)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	return hws->node.start + seqno_offset(rq->fence.context);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int move_to_active(struct i915_vma *vma,
738c2ecf20Sopenharmony_ci			  struct i915_request *rq,
748c2ecf20Sopenharmony_ci			  unsigned int flags)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	int err;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	i915_vma_lock(vma);
798c2ecf20Sopenharmony_ci	err = i915_request_await_object(rq, vma->obj,
808c2ecf20Sopenharmony_ci					flags & EXEC_OBJECT_WRITE);
818c2ecf20Sopenharmony_ci	if (err == 0)
828c2ecf20Sopenharmony_ci		err = i915_vma_move_to_active(vma, rq, flags);
838c2ecf20Sopenharmony_ci	i915_vma_unlock(vma);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return err;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistruct i915_request *
898c2ecf20Sopenharmony_ciigt_spinner_create_request(struct igt_spinner *spin,
908c2ecf20Sopenharmony_ci			   struct intel_context *ce,
918c2ecf20Sopenharmony_ci			   u32 arbitration_command)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine = ce->engine;
948c2ecf20Sopenharmony_ci	struct i915_request *rq = NULL;
958c2ecf20Sopenharmony_ci	struct i915_vma *hws, *vma;
968c2ecf20Sopenharmony_ci	unsigned int flags;
978c2ecf20Sopenharmony_ci	u32 *batch;
988c2ecf20Sopenharmony_ci	int err;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	GEM_BUG_ON(spin->gt != ce->vm->gt);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if (!intel_engine_can_store_dword(ce->engine))
1038c2ecf20Sopenharmony_ci		return ERR_PTR(-ENODEV);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	vma = i915_vma_instance(spin->obj, ce->vm, NULL);
1068c2ecf20Sopenharmony_ci	if (IS_ERR(vma))
1078c2ecf20Sopenharmony_ci		return ERR_CAST(vma);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	hws = i915_vma_instance(spin->hws, ce->vm, NULL);
1108c2ecf20Sopenharmony_ci	if (IS_ERR(hws))
1118c2ecf20Sopenharmony_ci		return ERR_CAST(hws);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	err = i915_vma_pin(vma, 0, 0, PIN_USER);
1148c2ecf20Sopenharmony_ci	if (err)
1158c2ecf20Sopenharmony_ci		return ERR_PTR(err);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	err = i915_vma_pin(hws, 0, 0, PIN_USER);
1188c2ecf20Sopenharmony_ci	if (err)
1198c2ecf20Sopenharmony_ci		goto unpin_vma;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	rq = intel_context_create_request(ce);
1228c2ecf20Sopenharmony_ci	if (IS_ERR(rq)) {
1238c2ecf20Sopenharmony_ci		err = PTR_ERR(rq);
1248c2ecf20Sopenharmony_ci		goto unpin_hws;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	err = move_to_active(vma, rq, 0);
1288c2ecf20Sopenharmony_ci	if (err)
1298c2ecf20Sopenharmony_ci		goto cancel_rq;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	err = move_to_active(hws, rq, 0);
1328c2ecf20Sopenharmony_ci	if (err)
1338c2ecf20Sopenharmony_ci		goto cancel_rq;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	batch = spin->batch;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (INTEL_GEN(rq->engine->i915) >= 8) {
1388c2ecf20Sopenharmony_ci		*batch++ = MI_STORE_DWORD_IMM_GEN4;
1398c2ecf20Sopenharmony_ci		*batch++ = lower_32_bits(hws_address(hws, rq));
1408c2ecf20Sopenharmony_ci		*batch++ = upper_32_bits(hws_address(hws, rq));
1418c2ecf20Sopenharmony_ci	} else if (INTEL_GEN(rq->engine->i915) >= 6) {
1428c2ecf20Sopenharmony_ci		*batch++ = MI_STORE_DWORD_IMM_GEN4;
1438c2ecf20Sopenharmony_ci		*batch++ = 0;
1448c2ecf20Sopenharmony_ci		*batch++ = hws_address(hws, rq);
1458c2ecf20Sopenharmony_ci	} else if (INTEL_GEN(rq->engine->i915) >= 4) {
1468c2ecf20Sopenharmony_ci		*batch++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
1478c2ecf20Sopenharmony_ci		*batch++ = 0;
1488c2ecf20Sopenharmony_ci		*batch++ = hws_address(hws, rq);
1498c2ecf20Sopenharmony_ci	} else {
1508c2ecf20Sopenharmony_ci		*batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
1518c2ecf20Sopenharmony_ci		*batch++ = hws_address(hws, rq);
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci	*batch++ = rq->fence.seqno;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	*batch++ = arbitration_command;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (INTEL_GEN(rq->engine->i915) >= 8)
1588c2ecf20Sopenharmony_ci		*batch++ = MI_BATCH_BUFFER_START | BIT(8) | 1;
1598c2ecf20Sopenharmony_ci	else if (IS_HASWELL(rq->engine->i915))
1608c2ecf20Sopenharmony_ci		*batch++ = MI_BATCH_BUFFER_START | MI_BATCH_PPGTT_HSW;
1618c2ecf20Sopenharmony_ci	else if (INTEL_GEN(rq->engine->i915) >= 6)
1628c2ecf20Sopenharmony_ci		*batch++ = MI_BATCH_BUFFER_START;
1638c2ecf20Sopenharmony_ci	else
1648c2ecf20Sopenharmony_ci		*batch++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT;
1658c2ecf20Sopenharmony_ci	*batch++ = lower_32_bits(vma->node.start);
1668c2ecf20Sopenharmony_ci	*batch++ = upper_32_bits(vma->node.start);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	*batch++ = MI_BATCH_BUFFER_END; /* not reached */
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	intel_gt_chipset_flush(engine->gt);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (engine->emit_init_breadcrumb) {
1738c2ecf20Sopenharmony_ci		err = engine->emit_init_breadcrumb(rq);
1748c2ecf20Sopenharmony_ci		if (err)
1758c2ecf20Sopenharmony_ci			goto cancel_rq;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	flags = 0;
1798c2ecf20Sopenharmony_ci	if (INTEL_GEN(rq->engine->i915) <= 5)
1808c2ecf20Sopenharmony_ci		flags |= I915_DISPATCH_SECURE;
1818c2ecf20Sopenharmony_ci	err = engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, flags);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cicancel_rq:
1848c2ecf20Sopenharmony_ci	if (err) {
1858c2ecf20Sopenharmony_ci		i915_request_set_error_once(rq, err);
1868c2ecf20Sopenharmony_ci		i915_request_add(rq);
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ciunpin_hws:
1898c2ecf20Sopenharmony_ci	i915_vma_unpin(hws);
1908c2ecf20Sopenharmony_ciunpin_vma:
1918c2ecf20Sopenharmony_ci	i915_vma_unpin(vma);
1928c2ecf20Sopenharmony_ci	return err ? ERR_PTR(err) : rq;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic u32
1968c2ecf20Sopenharmony_cihws_seqno(const struct igt_spinner *spin, const struct i915_request *rq)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	u32 *seqno = spin->seqno + seqno_offset(rq->fence.context);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	return READ_ONCE(*seqno);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_civoid igt_spinner_end(struct igt_spinner *spin)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	*spin->batch = MI_BATCH_BUFFER_END;
2068c2ecf20Sopenharmony_ci	intel_gt_chipset_flush(spin->gt);
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_civoid igt_spinner_fini(struct igt_spinner *spin)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	igt_spinner_end(spin);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	i915_gem_object_unpin_map(spin->obj);
2148c2ecf20Sopenharmony_ci	i915_gem_object_put(spin->obj);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	i915_gem_object_unpin_map(spin->hws);
2178c2ecf20Sopenharmony_ci	i915_gem_object_put(spin->hws);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cibool igt_wait_for_spinner(struct igt_spinner *spin, struct i915_request *rq)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	return !(wait_for_us(i915_seqno_passed(hws_seqno(spin, rq),
2238c2ecf20Sopenharmony_ci					       rq->fence.seqno),
2248c2ecf20Sopenharmony_ci			     100) &&
2258c2ecf20Sopenharmony_ci		 wait_for(i915_seqno_passed(hws_seqno(spin, rq),
2268c2ecf20Sopenharmony_ci					    rq->fence.seqno),
2278c2ecf20Sopenharmony_ci			  50));
2288c2ecf20Sopenharmony_ci}
229