162306a36Sopenharmony_ci/* SPDX-License-Identifier: MIT */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#ifndef INTEL_RING_H
762306a36Sopenharmony_ci#define INTEL_RING_H
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "i915_gem.h" /* GEM_BUG_ON */
1062306a36Sopenharmony_ci#include "i915_request.h"
1162306a36Sopenharmony_ci#include "intel_ring_types.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct intel_engine_cs;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct intel_ring *
1662306a36Sopenharmony_ciintel_engine_create_ring(struct intel_engine_cs *engine, int size);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciu32 *intel_ring_begin(struct i915_request *rq, unsigned int num_dwords);
1962306a36Sopenharmony_ciint intel_ring_cacheline_align(struct i915_request *rq);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciunsigned int intel_ring_update_space(struct intel_ring *ring);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_civoid __intel_ring_pin(struct intel_ring *ring);
2462306a36Sopenharmony_ciint intel_ring_pin(struct intel_ring *ring, struct i915_gem_ww_ctx *ww);
2562306a36Sopenharmony_civoid intel_ring_unpin(struct intel_ring *ring);
2662306a36Sopenharmony_civoid intel_ring_reset(struct intel_ring *ring, u32 tail);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_civoid intel_ring_free(struct kref *ref);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic inline struct intel_ring *intel_ring_get(struct intel_ring *ring)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	kref_get(&ring->ref);
3362306a36Sopenharmony_ci	return ring;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic inline void intel_ring_put(struct intel_ring *ring)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	kref_put(&ring->ref, intel_ring_free);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic inline void intel_ring_advance(struct i915_request *rq, u32 *cs)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	/* Dummy function.
4462306a36Sopenharmony_ci	 *
4562306a36Sopenharmony_ci	 * This serves as a placeholder in the code so that the reader
4662306a36Sopenharmony_ci	 * can compare against the preceding intel_ring_begin() and
4762306a36Sopenharmony_ci	 * check that the number of dwords emitted matches the space
4862306a36Sopenharmony_ci	 * reserved for the command packet (i.e. the value passed to
4962306a36Sopenharmony_ci	 * intel_ring_begin()).
5062306a36Sopenharmony_ci	 */
5162306a36Sopenharmony_ci	GEM_BUG_ON((rq->ring->vaddr + rq->ring->emit) != cs);
5262306a36Sopenharmony_ci	GEM_BUG_ON(!IS_ALIGNED(rq->ring->emit, 8)); /* RING_TAIL qword align */
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline u32 intel_ring_wrap(const struct intel_ring *ring, u32 pos)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	return pos & (ring->size - 1);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic inline int intel_ring_direction(const struct intel_ring *ring,
6162306a36Sopenharmony_ci				       u32 next, u32 prev)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	typecheck(typeof(ring->size), next);
6462306a36Sopenharmony_ci	typecheck(typeof(ring->size), prev);
6562306a36Sopenharmony_ci	return (next - prev) << ring->wrap;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic inline bool
6962306a36Sopenharmony_ciintel_ring_offset_valid(const struct intel_ring *ring,
7062306a36Sopenharmony_ci			unsigned int pos)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	if (pos & -ring->size) /* must be strictly within the ring */
7362306a36Sopenharmony_ci		return false;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (!IS_ALIGNED(pos, 8)) /* must be qword aligned */
7662306a36Sopenharmony_ci		return false;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return true;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
8462306a36Sopenharmony_ci	u32 offset = addr - rq->ring->vaddr;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	GEM_BUG_ON(offset > rq->ring->size);
8762306a36Sopenharmony_ci	return intel_ring_wrap(rq->ring, offset);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic inline void
9162306a36Sopenharmony_ciassert_ring_tail_valid(const struct intel_ring *ring, unsigned int tail)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	unsigned int head = READ_ONCE(ring->head);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	GEM_BUG_ON(!intel_ring_offset_valid(ring, tail));
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/*
9862306a36Sopenharmony_ci	 * "Ring Buffer Use"
9962306a36Sopenharmony_ci	 *	Gen2 BSpec "1. Programming Environment" / 1.4.4.6
10062306a36Sopenharmony_ci	 *	Gen3 BSpec "1c Memory Interface Functions" / 2.3.4.5
10162306a36Sopenharmony_ci	 *	Gen4+ BSpec "1c Memory Interface and Command Stream" / 5.3.4.5
10262306a36Sopenharmony_ci	 * "If the Ring Buffer Head Pointer and the Tail Pointer are on the
10362306a36Sopenharmony_ci	 * same cacheline, the Head Pointer must not be greater than the Tail
10462306a36Sopenharmony_ci	 * Pointer."
10562306a36Sopenharmony_ci	 *
10662306a36Sopenharmony_ci	 * We use ring->head as the last known location of the actual RING_HEAD,
10762306a36Sopenharmony_ci	 * it may have advanced but in the worst case it is equally the same
10862306a36Sopenharmony_ci	 * as ring->head and so we should never program RING_TAIL to advance
10962306a36Sopenharmony_ci	 * into the same cacheline as ring->head.
11062306a36Sopenharmony_ci	 */
11162306a36Sopenharmony_ci#define cacheline(a) round_down(a, CACHELINE_BYTES)
11262306a36Sopenharmony_ci	GEM_BUG_ON(cacheline(tail) == cacheline(head) && tail < head);
11362306a36Sopenharmony_ci#undef cacheline
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic inline unsigned int
11762306a36Sopenharmony_ciintel_ring_set_tail(struct intel_ring *ring, unsigned int tail)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	/* Whilst writes to the tail are strictly order, there is no
12062306a36Sopenharmony_ci	 * serialisation between readers and the writers. The tail may be
12162306a36Sopenharmony_ci	 * read by i915_request_retire() just as it is being updated
12262306a36Sopenharmony_ci	 * by execlists, as although the breadcrumb is complete, the context
12362306a36Sopenharmony_ci	 * switch hasn't been seen.
12462306a36Sopenharmony_ci	 */
12562306a36Sopenharmony_ci	assert_ring_tail_valid(ring, tail);
12662306a36Sopenharmony_ci	ring->tail = tail;
12762306a36Sopenharmony_ci	return tail;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic inline unsigned int
13162306a36Sopenharmony_ci__intel_ring_space(unsigned int head, unsigned int tail, unsigned int size)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	/*
13462306a36Sopenharmony_ci	 * "If the Ring Buffer Head Pointer and the Tail Pointer are on the
13562306a36Sopenharmony_ci	 * same cacheline, the Head Pointer must not be greater than the Tail
13662306a36Sopenharmony_ci	 * Pointer."
13762306a36Sopenharmony_ci	 */
13862306a36Sopenharmony_ci	GEM_BUG_ON(!is_power_of_2(size));
13962306a36Sopenharmony_ci	return (head - tail - CACHELINE_BYTES) & (size - 1);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#endif /* INTEL_RING_H */
143