162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "gem/i915_gem_internal.h"
762306a36Sopenharmony_ci#include "gem/i915_gem_lmem.h"
862306a36Sopenharmony_ci#include "gem/i915_gem_object.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "i915_drv.h"
1162306a36Sopenharmony_ci#include "i915_vma.h"
1262306a36Sopenharmony_ci#include "intel_engine.h"
1362306a36Sopenharmony_ci#include "intel_engine_regs.h"
1462306a36Sopenharmony_ci#include "intel_gpu_commands.h"
1562306a36Sopenharmony_ci#include "intel_ring.h"
1662306a36Sopenharmony_ci#include "intel_gt.h"
1762306a36Sopenharmony_ci#include "intel_timeline.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciunsigned int intel_ring_update_space(struct intel_ring *ring)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	unsigned int space;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	space = __intel_ring_space(ring->head, ring->emit, ring->size);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	ring->space = space;
2662306a36Sopenharmony_ci	return space;
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_civoid __intel_ring_pin(struct intel_ring *ring)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	GEM_BUG_ON(!atomic_read(&ring->pin_count));
3262306a36Sopenharmony_ci	atomic_inc(&ring->pin_count);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciint intel_ring_pin(struct intel_ring *ring, struct i915_gem_ww_ctx *ww)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct i915_vma *vma = ring->vma;
3862306a36Sopenharmony_ci	unsigned int flags;
3962306a36Sopenharmony_ci	void *addr;
4062306a36Sopenharmony_ci	int ret;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (atomic_fetch_inc(&ring->pin_count))
4362306a36Sopenharmony_ci		return 0;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* Ring wraparound at offset 0 sometimes hangs. No idea why. */
4662306a36Sopenharmony_ci	flags = PIN_OFFSET_BIAS | i915_ggtt_pin_bias(vma);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	if (i915_gem_object_is_stolen(vma->obj))
4962306a36Sopenharmony_ci		flags |= PIN_MAPPABLE;
5062306a36Sopenharmony_ci	else
5162306a36Sopenharmony_ci		flags |= PIN_HIGH;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ret = i915_ggtt_pin(vma, ww, 0, flags);
5462306a36Sopenharmony_ci	if (unlikely(ret))
5562306a36Sopenharmony_ci		goto err_unpin;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (i915_vma_is_map_and_fenceable(vma) && !HAS_LLC(vma->vm->i915)) {
5862306a36Sopenharmony_ci		addr = (void __force *)i915_vma_pin_iomap(vma);
5962306a36Sopenharmony_ci	} else {
6062306a36Sopenharmony_ci		int type = intel_gt_coherent_map_type(vma->vm->gt, vma->obj, false);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci		addr = i915_gem_object_pin_map(vma->obj, type);
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (IS_ERR(addr)) {
6662306a36Sopenharmony_ci		ret = PTR_ERR(addr);
6762306a36Sopenharmony_ci		goto err_ring;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	i915_vma_make_unshrinkable(vma);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* Discard any unused bytes beyond that submitted to hw. */
7362306a36Sopenharmony_ci	intel_ring_reset(ring, ring->emit);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	ring->vaddr = addr;
7662306a36Sopenharmony_ci	return 0;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cierr_ring:
7962306a36Sopenharmony_ci	i915_vma_unpin(vma);
8062306a36Sopenharmony_cierr_unpin:
8162306a36Sopenharmony_ci	atomic_dec(&ring->pin_count);
8262306a36Sopenharmony_ci	return ret;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_civoid intel_ring_reset(struct intel_ring *ring, u32 tail)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	tail = intel_ring_wrap(ring, tail);
8862306a36Sopenharmony_ci	ring->tail = tail;
8962306a36Sopenharmony_ci	ring->head = tail;
9062306a36Sopenharmony_ci	ring->emit = tail;
9162306a36Sopenharmony_ci	intel_ring_update_space(ring);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_civoid intel_ring_unpin(struct intel_ring *ring)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct i915_vma *vma = ring->vma;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (!atomic_dec_and_test(&ring->pin_count))
9962306a36Sopenharmony_ci		return;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	i915_vma_unset_ggtt_write(vma);
10262306a36Sopenharmony_ci	if (i915_vma_is_map_and_fenceable(vma) && !HAS_LLC(vma->vm->i915))
10362306a36Sopenharmony_ci		i915_vma_unpin_iomap(vma);
10462306a36Sopenharmony_ci	else
10562306a36Sopenharmony_ci		i915_gem_object_unpin_map(vma->obj);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	i915_vma_make_purgeable(vma);
10862306a36Sopenharmony_ci	i915_vma_unpin(vma);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic struct i915_vma *create_ring_vma(struct i915_ggtt *ggtt, int size)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct i915_address_space *vm = &ggtt->vm;
11462306a36Sopenharmony_ci	struct drm_i915_private *i915 = vm->i915;
11562306a36Sopenharmony_ci	struct drm_i915_gem_object *obj;
11662306a36Sopenharmony_ci	struct i915_vma *vma;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	obj = i915_gem_object_create_lmem(i915, size, I915_BO_ALLOC_VOLATILE |
11962306a36Sopenharmony_ci					  I915_BO_ALLOC_PM_VOLATILE);
12062306a36Sopenharmony_ci	if (IS_ERR(obj) && i915_ggtt_has_aperture(ggtt) && !HAS_LLC(i915))
12162306a36Sopenharmony_ci		obj = i915_gem_object_create_stolen(i915, size);
12262306a36Sopenharmony_ci	if (IS_ERR(obj))
12362306a36Sopenharmony_ci		obj = i915_gem_object_create_internal(i915, size);
12462306a36Sopenharmony_ci	if (IS_ERR(obj))
12562306a36Sopenharmony_ci		return ERR_CAST(obj);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/*
12862306a36Sopenharmony_ci	 * Mark ring buffers as read-only from GPU side (so no stray overwrites)
12962306a36Sopenharmony_ci	 * if supported by the platform's GGTT.
13062306a36Sopenharmony_ci	 */
13162306a36Sopenharmony_ci	if (vm->has_read_only)
13262306a36Sopenharmony_ci		i915_gem_object_set_readonly(obj);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	vma = i915_vma_instance(obj, vm, NULL);
13562306a36Sopenharmony_ci	if (IS_ERR(vma))
13662306a36Sopenharmony_ci		goto err;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return vma;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cierr:
14162306a36Sopenharmony_ci	i915_gem_object_put(obj);
14262306a36Sopenharmony_ci	return vma;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistruct intel_ring *
14662306a36Sopenharmony_ciintel_engine_create_ring(struct intel_engine_cs *engine, int size)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct drm_i915_private *i915 = engine->i915;
14962306a36Sopenharmony_ci	struct intel_ring *ring;
15062306a36Sopenharmony_ci	struct i915_vma *vma;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	GEM_BUG_ON(!is_power_of_2(size));
15362306a36Sopenharmony_ci	GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
15662306a36Sopenharmony_ci	if (!ring)
15762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	kref_init(&ring->ref);
16062306a36Sopenharmony_ci	ring->size = size;
16162306a36Sopenharmony_ci	ring->wrap = BITS_PER_TYPE(ring->size) - ilog2(size);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/*
16462306a36Sopenharmony_ci	 * Workaround an erratum on the i830 which causes a hang if
16562306a36Sopenharmony_ci	 * the TAIL pointer points to within the last 2 cachelines
16662306a36Sopenharmony_ci	 * of the buffer.
16762306a36Sopenharmony_ci	 */
16862306a36Sopenharmony_ci	ring->effective_size = size;
16962306a36Sopenharmony_ci	if (IS_I830(i915) || IS_I845G(i915))
17062306a36Sopenharmony_ci		ring->effective_size -= 2 * CACHELINE_BYTES;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	intel_ring_update_space(ring);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	vma = create_ring_vma(engine->gt->ggtt, size);
17562306a36Sopenharmony_ci	if (IS_ERR(vma)) {
17662306a36Sopenharmony_ci		kfree(ring);
17762306a36Sopenharmony_ci		return ERR_CAST(vma);
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	ring->vma = vma;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return ring;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_civoid intel_ring_free(struct kref *ref)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	struct intel_ring *ring = container_of(ref, typeof(*ring), ref);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	i915_vma_put(ring->vma);
18962306a36Sopenharmony_ci	kfree(ring);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic noinline int
19362306a36Sopenharmony_ciwait_for_space(struct intel_ring *ring,
19462306a36Sopenharmony_ci	       struct intel_timeline *tl,
19562306a36Sopenharmony_ci	       unsigned int bytes)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct i915_request *target;
19862306a36Sopenharmony_ci	long timeout;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (intel_ring_update_space(ring) >= bytes)
20162306a36Sopenharmony_ci		return 0;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	GEM_BUG_ON(list_empty(&tl->requests));
20462306a36Sopenharmony_ci	list_for_each_entry(target, &tl->requests, link) {
20562306a36Sopenharmony_ci		if (target->ring != ring)
20662306a36Sopenharmony_ci			continue;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci		/* Would completion of this request free enough space? */
20962306a36Sopenharmony_ci		if (bytes <= __intel_ring_space(target->postfix,
21062306a36Sopenharmony_ci						ring->emit, ring->size))
21162306a36Sopenharmony_ci			break;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (GEM_WARN_ON(&target->link == &tl->requests))
21562306a36Sopenharmony_ci		return -ENOSPC;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	timeout = i915_request_wait(target,
21862306a36Sopenharmony_ci				    I915_WAIT_INTERRUPTIBLE,
21962306a36Sopenharmony_ci				    MAX_SCHEDULE_TIMEOUT);
22062306a36Sopenharmony_ci	if (timeout < 0)
22162306a36Sopenharmony_ci		return timeout;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	i915_request_retire_upto(target);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	intel_ring_update_space(ring);
22662306a36Sopenharmony_ci	GEM_BUG_ON(ring->space < bytes);
22762306a36Sopenharmony_ci	return 0;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ciu32 *intel_ring_begin(struct i915_request *rq, unsigned int num_dwords)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct intel_ring *ring = rq->ring;
23362306a36Sopenharmony_ci	const unsigned int remain_usable = ring->effective_size - ring->emit;
23462306a36Sopenharmony_ci	const unsigned int bytes = num_dwords * sizeof(u32);
23562306a36Sopenharmony_ci	unsigned int need_wrap = 0;
23662306a36Sopenharmony_ci	unsigned int total_bytes;
23762306a36Sopenharmony_ci	u32 *cs;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* Packets must be qword aligned. */
24062306a36Sopenharmony_ci	GEM_BUG_ON(num_dwords & 1);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	total_bytes = bytes + rq->reserved_space;
24362306a36Sopenharmony_ci	GEM_BUG_ON(total_bytes > ring->effective_size);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (unlikely(total_bytes > remain_usable)) {
24662306a36Sopenharmony_ci		const int remain_actual = ring->size - ring->emit;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		if (bytes > remain_usable) {
24962306a36Sopenharmony_ci			/*
25062306a36Sopenharmony_ci			 * Not enough space for the basic request. So need to
25162306a36Sopenharmony_ci			 * flush out the remainder and then wait for
25262306a36Sopenharmony_ci			 * base + reserved.
25362306a36Sopenharmony_ci			 */
25462306a36Sopenharmony_ci			total_bytes += remain_actual;
25562306a36Sopenharmony_ci			need_wrap = remain_actual | 1;
25662306a36Sopenharmony_ci		} else  {
25762306a36Sopenharmony_ci			/*
25862306a36Sopenharmony_ci			 * The base request will fit but the reserved space
25962306a36Sopenharmony_ci			 * falls off the end. So we don't need an immediate
26062306a36Sopenharmony_ci			 * wrap and only need to effectively wait for the
26162306a36Sopenharmony_ci			 * reserved size from the start of ringbuffer.
26262306a36Sopenharmony_ci			 */
26362306a36Sopenharmony_ci			total_bytes = rq->reserved_space + remain_actual;
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (unlikely(total_bytes > ring->space)) {
26862306a36Sopenharmony_ci		int ret;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		/*
27162306a36Sopenharmony_ci		 * Space is reserved in the ringbuffer for finalising the
27262306a36Sopenharmony_ci		 * request, as that cannot be allowed to fail. During request
27362306a36Sopenharmony_ci		 * finalisation, reserved_space is set to 0 to stop the
27462306a36Sopenharmony_ci		 * overallocation and the assumption is that then we never need
27562306a36Sopenharmony_ci		 * to wait (which has the risk of failing with EINTR).
27662306a36Sopenharmony_ci		 *
27762306a36Sopenharmony_ci		 * See also i915_request_alloc() and i915_request_add().
27862306a36Sopenharmony_ci		 */
27962306a36Sopenharmony_ci		GEM_BUG_ON(!rq->reserved_space);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		ret = wait_for_space(ring,
28262306a36Sopenharmony_ci				     i915_request_timeline(rq),
28362306a36Sopenharmony_ci				     total_bytes);
28462306a36Sopenharmony_ci		if (unlikely(ret))
28562306a36Sopenharmony_ci			return ERR_PTR(ret);
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (unlikely(need_wrap)) {
28962306a36Sopenharmony_ci		need_wrap &= ~1;
29062306a36Sopenharmony_ci		GEM_BUG_ON(need_wrap > ring->space);
29162306a36Sopenharmony_ci		GEM_BUG_ON(ring->emit + need_wrap > ring->size);
29262306a36Sopenharmony_ci		GEM_BUG_ON(!IS_ALIGNED(need_wrap, sizeof(u64)));
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		/* Fill the tail with MI_NOOP */
29562306a36Sopenharmony_ci		memset64(ring->vaddr + ring->emit, 0, need_wrap / sizeof(u64));
29662306a36Sopenharmony_ci		ring->space -= need_wrap;
29762306a36Sopenharmony_ci		ring->emit = 0;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	GEM_BUG_ON(ring->emit > ring->size - bytes);
30162306a36Sopenharmony_ci	GEM_BUG_ON(ring->space < bytes);
30262306a36Sopenharmony_ci	cs = ring->vaddr + ring->emit;
30362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
30462306a36Sopenharmony_ci		memset32(cs, POISON_INUSE, bytes / sizeof(*cs));
30562306a36Sopenharmony_ci	ring->emit += bytes;
30662306a36Sopenharmony_ci	ring->space -= bytes;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return cs;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/* Align the ring tail to a cacheline boundary */
31262306a36Sopenharmony_ciint intel_ring_cacheline_align(struct i915_request *rq)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	int num_dwords;
31562306a36Sopenharmony_ci	void *cs;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	num_dwords = (rq->ring->emit & (CACHELINE_BYTES - 1)) / sizeof(u32);
31862306a36Sopenharmony_ci	if (num_dwords == 0)
31962306a36Sopenharmony_ci		return 0;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	num_dwords = CACHELINE_DWORDS - num_dwords;
32262306a36Sopenharmony_ci	GEM_BUG_ON(num_dwords & 1);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	cs = intel_ring_begin(rq, num_dwords);
32562306a36Sopenharmony_ci	if (IS_ERR(cs))
32662306a36Sopenharmony_ci		return PTR_ERR(cs);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	memset64(cs, (u64)MI_NOOP << 32 | MI_NOOP, num_dwords / 2);
32962306a36Sopenharmony_ci	intel_ring_advance(rq, cs + num_dwords);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	GEM_BUG_ON(rq->ring->emit & (CACHELINE_BYTES - 1));
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
33662306a36Sopenharmony_ci#include "selftest_ring.c"
33762306a36Sopenharmony_ci#endif
338