18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * SPDX-License-Identifier: MIT
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2019 Intel Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#ifndef INTEL_RING_H
88c2ecf20Sopenharmony_ci#define INTEL_RING_H
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "i915_gem.h" /* GEM_BUG_ON */
118c2ecf20Sopenharmony_ci#include "i915_request.h"
128c2ecf20Sopenharmony_ci#include "intel_ring_types.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistruct intel_engine_cs;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistruct intel_ring *
178c2ecf20Sopenharmony_ciintel_engine_create_ring(struct intel_engine_cs *engine, int size);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciu32 *intel_ring_begin(struct i915_request *rq, unsigned int num_dwords);
208c2ecf20Sopenharmony_ciint intel_ring_cacheline_align(struct i915_request *rq);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciunsigned int intel_ring_update_space(struct intel_ring *ring);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_civoid __intel_ring_pin(struct intel_ring *ring);
258c2ecf20Sopenharmony_ciint intel_ring_pin(struct intel_ring *ring, struct i915_gem_ww_ctx *ww);
268c2ecf20Sopenharmony_civoid intel_ring_unpin(struct intel_ring *ring);
278c2ecf20Sopenharmony_civoid intel_ring_reset(struct intel_ring *ring, u32 tail);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_civoid intel_ring_free(struct kref *ref);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic inline struct intel_ring *intel_ring_get(struct intel_ring *ring)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	kref_get(&ring->ref);
348c2ecf20Sopenharmony_ci	return ring;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic inline void intel_ring_put(struct intel_ring *ring)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	kref_put(&ring->ref, intel_ring_free);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline void intel_ring_advance(struct i915_request *rq, u32 *cs)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	/* Dummy function.
458c2ecf20Sopenharmony_ci	 *
468c2ecf20Sopenharmony_ci	 * This serves as a placeholder in the code so that the reader
478c2ecf20Sopenharmony_ci	 * can compare against the preceding intel_ring_begin() and
488c2ecf20Sopenharmony_ci	 * check that the number of dwords emitted matches the space
498c2ecf20Sopenharmony_ci	 * reserved for the command packet (i.e. the value passed to
508c2ecf20Sopenharmony_ci	 * intel_ring_begin()).
518c2ecf20Sopenharmony_ci	 */
528c2ecf20Sopenharmony_ci	GEM_BUG_ON((rq->ring->vaddr + rq->ring->emit) != cs);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic inline u32 intel_ring_wrap(const struct intel_ring *ring, u32 pos)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	return pos & (ring->size - 1);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic inline int intel_ring_direction(const struct intel_ring *ring,
618c2ecf20Sopenharmony_ci				       u32 next, u32 prev)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	typecheck(typeof(ring->size), next);
648c2ecf20Sopenharmony_ci	typecheck(typeof(ring->size), prev);
658c2ecf20Sopenharmony_ci	return (next - prev) << ring->wrap;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic inline bool
698c2ecf20Sopenharmony_ciintel_ring_offset_valid(const struct intel_ring *ring,
708c2ecf20Sopenharmony_ci			unsigned int pos)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	if (pos & -ring->size) /* must be strictly within the ring */
738c2ecf20Sopenharmony_ci		return false;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(pos, 8)) /* must be qword aligned */
768c2ecf20Sopenharmony_ci		return false;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return true;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
848c2ecf20Sopenharmony_ci	u32 offset = addr - rq->ring->vaddr;
858c2ecf20Sopenharmony_ci	GEM_BUG_ON(offset > rq->ring->size);
868c2ecf20Sopenharmony_ci	return intel_ring_wrap(rq->ring, offset);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic inline void
908c2ecf20Sopenharmony_ciassert_ring_tail_valid(const struct intel_ring *ring, unsigned int tail)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	unsigned int head = READ_ONCE(ring->head);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	GEM_BUG_ON(!intel_ring_offset_valid(ring, tail));
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/*
978c2ecf20Sopenharmony_ci	 * "Ring Buffer Use"
988c2ecf20Sopenharmony_ci	 *	Gen2 BSpec "1. Programming Environment" / 1.4.4.6
998c2ecf20Sopenharmony_ci	 *	Gen3 BSpec "1c Memory Interface Functions" / 2.3.4.5
1008c2ecf20Sopenharmony_ci	 *	Gen4+ BSpec "1c Memory Interface and Command Stream" / 5.3.4.5
1018c2ecf20Sopenharmony_ci	 * "If the Ring Buffer Head Pointer and the Tail Pointer are on the
1028c2ecf20Sopenharmony_ci	 * same cacheline, the Head Pointer must not be greater than the Tail
1038c2ecf20Sopenharmony_ci	 * Pointer."
1048c2ecf20Sopenharmony_ci	 *
1058c2ecf20Sopenharmony_ci	 * We use ring->head as the last known location of the actual RING_HEAD,
1068c2ecf20Sopenharmony_ci	 * it may have advanced but in the worst case it is equally the same
1078c2ecf20Sopenharmony_ci	 * as ring->head and so we should never program RING_TAIL to advance
1088c2ecf20Sopenharmony_ci	 * into the same cacheline as ring->head.
1098c2ecf20Sopenharmony_ci	 */
1108c2ecf20Sopenharmony_ci#define cacheline(a) round_down(a, CACHELINE_BYTES)
1118c2ecf20Sopenharmony_ci	GEM_BUG_ON(cacheline(tail) == cacheline(head) && tail < head);
1128c2ecf20Sopenharmony_ci#undef cacheline
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic inline unsigned int
1168c2ecf20Sopenharmony_ciintel_ring_set_tail(struct intel_ring *ring, unsigned int tail)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	/* Whilst writes to the tail are strictly order, there is no
1198c2ecf20Sopenharmony_ci	 * serialisation between readers and the writers. The tail may be
1208c2ecf20Sopenharmony_ci	 * read by i915_request_retire() just as it is being updated
1218c2ecf20Sopenharmony_ci	 * by execlists, as although the breadcrumb is complete, the context
1228c2ecf20Sopenharmony_ci	 * switch hasn't been seen.
1238c2ecf20Sopenharmony_ci	 */
1248c2ecf20Sopenharmony_ci	assert_ring_tail_valid(ring, tail);
1258c2ecf20Sopenharmony_ci	ring->tail = tail;
1268c2ecf20Sopenharmony_ci	return tail;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic inline unsigned int
1308c2ecf20Sopenharmony_ci__intel_ring_space(unsigned int head, unsigned int tail, unsigned int size)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	/*
1338c2ecf20Sopenharmony_ci	 * "If the Ring Buffer Head Pointer and the Tail Pointer are on the
1348c2ecf20Sopenharmony_ci	 * same cacheline, the Head Pointer must not be greater than the Tail
1358c2ecf20Sopenharmony_ci	 * Pointer."
1368c2ecf20Sopenharmony_ci	 */
1378c2ecf20Sopenharmony_ci	GEM_BUG_ON(!is_power_of_2(size));
1388c2ecf20Sopenharmony_ci	return (head - tail - CACHELINE_BYTES) & (size - 1);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci#endif /* INTEL_RING_H */
142