162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse.
362306a36Sopenharmony_ci * All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
662306a36Sopenharmony_ci * copy of this software and associated documentation files (the
762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
962306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1162306a36Sopenharmony_ci * the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1462306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1562306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1662306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
1762306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1862306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1962306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
2262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
2362306a36Sopenharmony_ci * of the Software.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * Authors:
2862306a36Sopenharmony_ci *    Jerome Glisse <glisse@freedesktop.org>
2962306a36Sopenharmony_ci *    Dave Airlie
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ci#include <linux/seq_file.h>
3262306a36Sopenharmony_ci#include <linux/atomic.h>
3362306a36Sopenharmony_ci#include <linux/wait.h>
3462306a36Sopenharmony_ci#include <linux/kref.h>
3562306a36Sopenharmony_ci#include <linux/slab.h>
3662306a36Sopenharmony_ci#include <linux/firmware.h>
3762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include <drm/drm_drv.h>
4062306a36Sopenharmony_ci#include "amdgpu.h"
4162306a36Sopenharmony_ci#include "amdgpu_trace.h"
4262306a36Sopenharmony_ci#include "amdgpu_reset.h"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*
4562306a36Sopenharmony_ci * Fences mark an event in the GPUs pipeline and are used
4662306a36Sopenharmony_ci * for GPU/CPU synchronization.  When the fence is written,
4762306a36Sopenharmony_ci * it is expected that all buffers associated with that fence
4862306a36Sopenharmony_ci * are no longer in use by the associated ring on the GPU and
4962306a36Sopenharmony_ci * that the relevant GPU caches have been flushed.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct amdgpu_fence {
5362306a36Sopenharmony_ci	struct dma_fence base;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* RB, DMA, etc. */
5662306a36Sopenharmony_ci	struct amdgpu_ring		*ring;
5762306a36Sopenharmony_ci	ktime_t				start_timestamp;
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic struct kmem_cache *amdgpu_fence_slab;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciint amdgpu_fence_slab_init(void)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	amdgpu_fence_slab = kmem_cache_create(
6562306a36Sopenharmony_ci		"amdgpu_fence", sizeof(struct amdgpu_fence), 0,
6662306a36Sopenharmony_ci		SLAB_HWCACHE_ALIGN, NULL);
6762306a36Sopenharmony_ci	if (!amdgpu_fence_slab)
6862306a36Sopenharmony_ci		return -ENOMEM;
6962306a36Sopenharmony_ci	return 0;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_civoid amdgpu_fence_slab_fini(void)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	rcu_barrier();
7562306a36Sopenharmony_ci	kmem_cache_destroy(amdgpu_fence_slab);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * Cast helper
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_cistatic const struct dma_fence_ops amdgpu_fence_ops;
8162306a36Sopenharmony_cistatic const struct dma_fence_ops amdgpu_job_fence_ops;
8262306a36Sopenharmony_cistatic inline struct amdgpu_fence *to_amdgpu_fence(struct dma_fence *f)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct amdgpu_fence *__f = container_of(f, struct amdgpu_fence, base);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	if (__f->base.ops == &amdgpu_fence_ops ||
8762306a36Sopenharmony_ci	    __f->base.ops == &amdgpu_job_fence_ops)
8862306a36Sopenharmony_ci		return __f;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return NULL;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/**
9462306a36Sopenharmony_ci * amdgpu_fence_write - write a fence value
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * @ring: ring the fence is associated with
9762306a36Sopenharmony_ci * @seq: sequence number to write
9862306a36Sopenharmony_ci *
9962306a36Sopenharmony_ci * Writes a fence value to memory (all asics).
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_cistatic void amdgpu_fence_write(struct amdgpu_ring *ring, u32 seq)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct amdgpu_fence_driver *drv = &ring->fence_drv;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (drv->cpu_addr)
10662306a36Sopenharmony_ci		*drv->cpu_addr = cpu_to_le32(seq);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/**
11062306a36Sopenharmony_ci * amdgpu_fence_read - read a fence value
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * @ring: ring the fence is associated with
11362306a36Sopenharmony_ci *
11462306a36Sopenharmony_ci * Reads a fence value from memory (all asics).
11562306a36Sopenharmony_ci * Returns the value of the fence read from memory.
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_cistatic u32 amdgpu_fence_read(struct amdgpu_ring *ring)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct amdgpu_fence_driver *drv = &ring->fence_drv;
12062306a36Sopenharmony_ci	u32 seq = 0;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	if (drv->cpu_addr)
12362306a36Sopenharmony_ci		seq = le32_to_cpu(*drv->cpu_addr);
12462306a36Sopenharmony_ci	else
12562306a36Sopenharmony_ci		seq = atomic_read(&drv->last_seq);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return seq;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/**
13162306a36Sopenharmony_ci * amdgpu_fence_emit - emit a fence on the requested ring
13262306a36Sopenharmony_ci *
13362306a36Sopenharmony_ci * @ring: ring the fence is associated with
13462306a36Sopenharmony_ci * @f: resulting fence object
13562306a36Sopenharmony_ci * @job: job the fence is embedded in
13662306a36Sopenharmony_ci * @flags: flags to pass into the subordinate .emit_fence() call
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci * Emits a fence command on the requested ring (all asics).
13962306a36Sopenharmony_ci * Returns 0 on success, -ENOMEM on failure.
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ciint amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amdgpu_job *job,
14262306a36Sopenharmony_ci		      unsigned int flags)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
14562306a36Sopenharmony_ci	struct dma_fence *fence;
14662306a36Sopenharmony_ci	struct amdgpu_fence *am_fence;
14762306a36Sopenharmony_ci	struct dma_fence __rcu **ptr;
14862306a36Sopenharmony_ci	uint32_t seq;
14962306a36Sopenharmony_ci	int r;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (job == NULL) {
15262306a36Sopenharmony_ci		/* create a sperate hw fence */
15362306a36Sopenharmony_ci		am_fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_ATOMIC);
15462306a36Sopenharmony_ci		if (am_fence == NULL)
15562306a36Sopenharmony_ci			return -ENOMEM;
15662306a36Sopenharmony_ci		fence = &am_fence->base;
15762306a36Sopenharmony_ci		am_fence->ring = ring;
15862306a36Sopenharmony_ci	} else {
15962306a36Sopenharmony_ci		/* take use of job-embedded fence */
16062306a36Sopenharmony_ci		fence = &job->hw_fence;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	seq = ++ring->fence_drv.sync_seq;
16462306a36Sopenharmony_ci	if (job && job->job_run_counter) {
16562306a36Sopenharmony_ci		/* reinit seq for resubmitted jobs */
16662306a36Sopenharmony_ci		fence->seqno = seq;
16762306a36Sopenharmony_ci		/* TO be inline with external fence creation and other drivers */
16862306a36Sopenharmony_ci		dma_fence_get(fence);
16962306a36Sopenharmony_ci	} else {
17062306a36Sopenharmony_ci		if (job) {
17162306a36Sopenharmony_ci			dma_fence_init(fence, &amdgpu_job_fence_ops,
17262306a36Sopenharmony_ci				       &ring->fence_drv.lock,
17362306a36Sopenharmony_ci				       adev->fence_context + ring->idx, seq);
17462306a36Sopenharmony_ci			/* Against remove in amdgpu_job_{free, free_cb} */
17562306a36Sopenharmony_ci			dma_fence_get(fence);
17662306a36Sopenharmony_ci		} else {
17762306a36Sopenharmony_ci			dma_fence_init(fence, &amdgpu_fence_ops,
17862306a36Sopenharmony_ci				       &ring->fence_drv.lock,
17962306a36Sopenharmony_ci				       adev->fence_context + ring->idx, seq);
18062306a36Sopenharmony_ci		}
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
18462306a36Sopenharmony_ci			       seq, flags | AMDGPU_FENCE_FLAG_INT);
18562306a36Sopenharmony_ci	pm_runtime_get_noresume(adev_to_drm(adev)->dev);
18662306a36Sopenharmony_ci	ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
18762306a36Sopenharmony_ci	if (unlikely(rcu_dereference_protected(*ptr, 1))) {
18862306a36Sopenharmony_ci		struct dma_fence *old;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		rcu_read_lock();
19162306a36Sopenharmony_ci		old = dma_fence_get_rcu_safe(ptr);
19262306a36Sopenharmony_ci		rcu_read_unlock();
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		if (old) {
19562306a36Sopenharmony_ci			r = dma_fence_wait(old, false);
19662306a36Sopenharmony_ci			dma_fence_put(old);
19762306a36Sopenharmony_ci			if (r)
19862306a36Sopenharmony_ci				return r;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	to_amdgpu_fence(fence)->start_timestamp = ktime_get();
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* This function can't be called concurrently anyway, otherwise
20562306a36Sopenharmony_ci	 * emitting the fence would mess up the hardware ring buffer.
20662306a36Sopenharmony_ci	 */
20762306a36Sopenharmony_ci	rcu_assign_pointer(*ptr, dma_fence_get(fence));
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	*f = fence;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/**
21562306a36Sopenharmony_ci * amdgpu_fence_emit_polling - emit a fence on the requeste ring
21662306a36Sopenharmony_ci *
21762306a36Sopenharmony_ci * @ring: ring the fence is associated with
21862306a36Sopenharmony_ci * @s: resulting sequence number
21962306a36Sopenharmony_ci * @timeout: the timeout for waiting in usecs
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * Emits a fence command on the requested ring (all asics).
22262306a36Sopenharmony_ci * Used For polling fence.
22362306a36Sopenharmony_ci * Returns 0 on success, -ENOMEM on failure.
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_ciint amdgpu_fence_emit_polling(struct amdgpu_ring *ring, uint32_t *s,
22662306a36Sopenharmony_ci			      uint32_t timeout)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	uint32_t seq;
22962306a36Sopenharmony_ci	signed long r;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (!s)
23262306a36Sopenharmony_ci		return -EINVAL;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	seq = ++ring->fence_drv.sync_seq;
23562306a36Sopenharmony_ci	r = amdgpu_fence_wait_polling(ring,
23662306a36Sopenharmony_ci				      seq - ring->fence_drv.num_fences_mask,
23762306a36Sopenharmony_ci				      timeout);
23862306a36Sopenharmony_ci	if (r < 1)
23962306a36Sopenharmony_ci		return -ETIMEDOUT;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
24262306a36Sopenharmony_ci			       seq, 0);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	*s = seq;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/**
25062306a36Sopenharmony_ci * amdgpu_fence_schedule_fallback - schedule fallback check
25162306a36Sopenharmony_ci *
25262306a36Sopenharmony_ci * @ring: pointer to struct amdgpu_ring
25362306a36Sopenharmony_ci *
25462306a36Sopenharmony_ci * Start a timer as fallback to our interrupts.
25562306a36Sopenharmony_ci */
25662306a36Sopenharmony_cistatic void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	mod_timer(&ring->fence_drv.fallback_timer,
25962306a36Sopenharmony_ci		  jiffies + AMDGPU_FENCE_JIFFIES_TIMEOUT);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/**
26362306a36Sopenharmony_ci * amdgpu_fence_process - check for fence activity
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * @ring: pointer to struct amdgpu_ring
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * Checks the current fence value and calculates the last
26862306a36Sopenharmony_ci * signalled fence value. Wakes the fence queue if the
26962306a36Sopenharmony_ci * sequence number has increased.
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * Returns true if fence was processed
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_cibool amdgpu_fence_process(struct amdgpu_ring *ring)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct amdgpu_fence_driver *drv = &ring->fence_drv;
27662306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
27762306a36Sopenharmony_ci	uint32_t seq, last_seq;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	do {
28062306a36Sopenharmony_ci		last_seq = atomic_read(&ring->fence_drv.last_seq);
28162306a36Sopenharmony_ci		seq = amdgpu_fence_read(ring);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	} while (atomic_cmpxchg(&drv->last_seq, last_seq, seq) != last_seq);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (del_timer(&ring->fence_drv.fallback_timer) &&
28662306a36Sopenharmony_ci	    seq != ring->fence_drv.sync_seq)
28762306a36Sopenharmony_ci		amdgpu_fence_schedule_fallback(ring);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (unlikely(seq == last_seq))
29062306a36Sopenharmony_ci		return false;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	last_seq &= drv->num_fences_mask;
29362306a36Sopenharmony_ci	seq &= drv->num_fences_mask;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	do {
29662306a36Sopenharmony_ci		struct dma_fence *fence, **ptr;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		++last_seq;
29962306a36Sopenharmony_ci		last_seq &= drv->num_fences_mask;
30062306a36Sopenharmony_ci		ptr = &drv->fences[last_seq];
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		/* There is always exactly one thread signaling this fence slot */
30362306a36Sopenharmony_ci		fence = rcu_dereference_protected(*ptr, 1);
30462306a36Sopenharmony_ci		RCU_INIT_POINTER(*ptr, NULL);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		if (!fence)
30762306a36Sopenharmony_ci			continue;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		dma_fence_signal(fence);
31062306a36Sopenharmony_ci		dma_fence_put(fence);
31162306a36Sopenharmony_ci		pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
31262306a36Sopenharmony_ci		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
31362306a36Sopenharmony_ci	} while (last_seq != seq);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return true;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci/**
31962306a36Sopenharmony_ci * amdgpu_fence_fallback - fallback for hardware interrupts
32062306a36Sopenharmony_ci *
32162306a36Sopenharmony_ci * @t: timer context used to obtain the pointer to ring structure
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * Checks for fence activity.
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_cistatic void amdgpu_fence_fallback(struct timer_list *t)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct amdgpu_ring *ring = from_timer(ring, t,
32862306a36Sopenharmony_ci					      fence_drv.fallback_timer);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (amdgpu_fence_process(ring))
33162306a36Sopenharmony_ci		DRM_WARN("Fence fallback timer expired on ring %s\n", ring->name);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/**
33562306a36Sopenharmony_ci * amdgpu_fence_wait_empty - wait for all fences to signal
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * @ring: ring index the fence is associated with
33862306a36Sopenharmony_ci *
33962306a36Sopenharmony_ci * Wait for all fences on the requested ring to signal (all asics).
34062306a36Sopenharmony_ci * Returns 0 if the fences have passed, error for all other cases.
34162306a36Sopenharmony_ci */
34262306a36Sopenharmony_ciint amdgpu_fence_wait_empty(struct amdgpu_ring *ring)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	uint64_t seq = READ_ONCE(ring->fence_drv.sync_seq);
34562306a36Sopenharmony_ci	struct dma_fence *fence, **ptr;
34662306a36Sopenharmony_ci	int r;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (!seq)
34962306a36Sopenharmony_ci		return 0;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
35262306a36Sopenharmony_ci	rcu_read_lock();
35362306a36Sopenharmony_ci	fence = rcu_dereference(*ptr);
35462306a36Sopenharmony_ci	if (!fence || !dma_fence_get_rcu(fence)) {
35562306a36Sopenharmony_ci		rcu_read_unlock();
35662306a36Sopenharmony_ci		return 0;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci	rcu_read_unlock();
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	r = dma_fence_wait(fence, false);
36162306a36Sopenharmony_ci	dma_fence_put(fence);
36262306a36Sopenharmony_ci	return r;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/**
36662306a36Sopenharmony_ci * amdgpu_fence_wait_polling - busy wait for givn sequence number
36762306a36Sopenharmony_ci *
36862306a36Sopenharmony_ci * @ring: ring index the fence is associated with
36962306a36Sopenharmony_ci * @wait_seq: sequence number to wait
37062306a36Sopenharmony_ci * @timeout: the timeout for waiting in usecs
37162306a36Sopenharmony_ci *
37262306a36Sopenharmony_ci * Wait for all fences on the requested ring to signal (all asics).
37362306a36Sopenharmony_ci * Returns left time if no timeout, 0 or minus if timeout.
37462306a36Sopenharmony_ci */
37562306a36Sopenharmony_cisigned long amdgpu_fence_wait_polling(struct amdgpu_ring *ring,
37662306a36Sopenharmony_ci				      uint32_t wait_seq,
37762306a36Sopenharmony_ci				      signed long timeout)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	while ((int32_t)(wait_seq - amdgpu_fence_read(ring)) > 0 && timeout > 0) {
38162306a36Sopenharmony_ci		udelay(2);
38262306a36Sopenharmony_ci		timeout -= 2;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	return timeout > 0 ? timeout : 0;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci/**
38762306a36Sopenharmony_ci * amdgpu_fence_count_emitted - get the count of emitted fences
38862306a36Sopenharmony_ci *
38962306a36Sopenharmony_ci * @ring: ring the fence is associated with
39062306a36Sopenharmony_ci *
39162306a36Sopenharmony_ci * Get the number of fences emitted on the requested ring (all asics).
39262306a36Sopenharmony_ci * Returns the number of emitted fences on the ring.  Used by the
39362306a36Sopenharmony_ci * dynpm code to ring track activity.
39462306a36Sopenharmony_ci */
39562306a36Sopenharmony_ciunsigned int amdgpu_fence_count_emitted(struct amdgpu_ring *ring)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	uint64_t emitted;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* We are not protected by ring lock when reading the last sequence
40062306a36Sopenharmony_ci	 * but it's ok to report slightly wrong fence count here.
40162306a36Sopenharmony_ci	 */
40262306a36Sopenharmony_ci	emitted = 0x100000000ull;
40362306a36Sopenharmony_ci	emitted -= atomic_read(&ring->fence_drv.last_seq);
40462306a36Sopenharmony_ci	emitted += READ_ONCE(ring->fence_drv.sync_seq);
40562306a36Sopenharmony_ci	return lower_32_bits(emitted);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci/**
40962306a36Sopenharmony_ci * amdgpu_fence_last_unsignaled_time_us - the time fence emitted until now
41062306a36Sopenharmony_ci * @ring: ring the fence is associated with
41162306a36Sopenharmony_ci *
41262306a36Sopenharmony_ci * Find the earliest fence unsignaled until now, calculate the time delta
41362306a36Sopenharmony_ci * between the time fence emitted and now.
41462306a36Sopenharmony_ci */
41562306a36Sopenharmony_ciu64 amdgpu_fence_last_unsignaled_time_us(struct amdgpu_ring *ring)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	struct amdgpu_fence_driver *drv = &ring->fence_drv;
41862306a36Sopenharmony_ci	struct dma_fence *fence;
41962306a36Sopenharmony_ci	uint32_t last_seq, sync_seq;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	last_seq = atomic_read(&ring->fence_drv.last_seq);
42262306a36Sopenharmony_ci	sync_seq = READ_ONCE(ring->fence_drv.sync_seq);
42362306a36Sopenharmony_ci	if (last_seq == sync_seq)
42462306a36Sopenharmony_ci		return 0;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	++last_seq;
42762306a36Sopenharmony_ci	last_seq &= drv->num_fences_mask;
42862306a36Sopenharmony_ci	fence = drv->fences[last_seq];
42962306a36Sopenharmony_ci	if (!fence)
43062306a36Sopenharmony_ci		return 0;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	return ktime_us_delta(ktime_get(),
43362306a36Sopenharmony_ci		to_amdgpu_fence(fence)->start_timestamp);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/**
43762306a36Sopenharmony_ci * amdgpu_fence_update_start_timestamp - update the timestamp of the fence
43862306a36Sopenharmony_ci * @ring: ring the fence is associated with
43962306a36Sopenharmony_ci * @seq: the fence seq number to update.
44062306a36Sopenharmony_ci * @timestamp: the start timestamp to update.
44162306a36Sopenharmony_ci *
44262306a36Sopenharmony_ci * The function called at the time the fence and related ib is about to
44362306a36Sopenharmony_ci * resubmit to gpu in MCBP scenario. Thus we do not consider race condition
44462306a36Sopenharmony_ci * with amdgpu_fence_process to modify the same fence.
44562306a36Sopenharmony_ci */
44662306a36Sopenharmony_civoid amdgpu_fence_update_start_timestamp(struct amdgpu_ring *ring, uint32_t seq, ktime_t timestamp)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct amdgpu_fence_driver *drv = &ring->fence_drv;
44962306a36Sopenharmony_ci	struct dma_fence *fence;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	seq &= drv->num_fences_mask;
45262306a36Sopenharmony_ci	fence = drv->fences[seq];
45362306a36Sopenharmony_ci	if (!fence)
45462306a36Sopenharmony_ci		return;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	to_amdgpu_fence(fence)->start_timestamp = timestamp;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci/**
46062306a36Sopenharmony_ci * amdgpu_fence_driver_start_ring - make the fence driver
46162306a36Sopenharmony_ci * ready for use on the requested ring.
46262306a36Sopenharmony_ci *
46362306a36Sopenharmony_ci * @ring: ring to start the fence driver on
46462306a36Sopenharmony_ci * @irq_src: interrupt source to use for this ring
46562306a36Sopenharmony_ci * @irq_type: interrupt type to use for this ring
46662306a36Sopenharmony_ci *
46762306a36Sopenharmony_ci * Make the fence driver ready for processing (all asics).
46862306a36Sopenharmony_ci * Not all asics have all rings, so each asic will only
46962306a36Sopenharmony_ci * start the fence driver on the rings it has.
47062306a36Sopenharmony_ci * Returns 0 for success, errors for failure.
47162306a36Sopenharmony_ci */
47262306a36Sopenharmony_ciint amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
47362306a36Sopenharmony_ci				   struct amdgpu_irq_src *irq_src,
47462306a36Sopenharmony_ci				   unsigned int irq_type)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
47762306a36Sopenharmony_ci	uint64_t index;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (ring->funcs->type != AMDGPU_RING_TYPE_UVD) {
48062306a36Sopenharmony_ci		ring->fence_drv.cpu_addr = ring->fence_cpu_addr;
48162306a36Sopenharmony_ci		ring->fence_drv.gpu_addr = ring->fence_gpu_addr;
48262306a36Sopenharmony_ci	} else {
48362306a36Sopenharmony_ci		/* put fence directly behind firmware */
48462306a36Sopenharmony_ci		index = ALIGN(adev->uvd.fw->size, 8);
48562306a36Sopenharmony_ci		ring->fence_drv.cpu_addr = adev->uvd.inst[ring->me].cpu_addr + index;
48662306a36Sopenharmony_ci		ring->fence_drv.gpu_addr = adev->uvd.inst[ring->me].gpu_addr + index;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci	amdgpu_fence_write(ring, atomic_read(&ring->fence_drv.last_seq));
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ring->fence_drv.irq_src = irq_src;
49162306a36Sopenharmony_ci	ring->fence_drv.irq_type = irq_type;
49262306a36Sopenharmony_ci	ring->fence_drv.initialized = true;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	DRM_DEV_DEBUG(adev->dev, "fence driver on ring %s use gpu addr 0x%016llx\n",
49562306a36Sopenharmony_ci		      ring->name, ring->fence_drv.gpu_addr);
49662306a36Sopenharmony_ci	return 0;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/**
50062306a36Sopenharmony_ci * amdgpu_fence_driver_init_ring - init the fence driver
50162306a36Sopenharmony_ci * for the requested ring.
50262306a36Sopenharmony_ci *
50362306a36Sopenharmony_ci * @ring: ring to init the fence driver on
50462306a36Sopenharmony_ci *
50562306a36Sopenharmony_ci * Init the fence driver for the requested ring (all asics).
50662306a36Sopenharmony_ci * Helper function for amdgpu_fence_driver_init().
50762306a36Sopenharmony_ci */
50862306a36Sopenharmony_ciint amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (!adev)
51362306a36Sopenharmony_ci		return -EINVAL;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (!is_power_of_2(ring->num_hw_submission))
51662306a36Sopenharmony_ci		return -EINVAL;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	ring->fence_drv.cpu_addr = NULL;
51962306a36Sopenharmony_ci	ring->fence_drv.gpu_addr = 0;
52062306a36Sopenharmony_ci	ring->fence_drv.sync_seq = 0;
52162306a36Sopenharmony_ci	atomic_set(&ring->fence_drv.last_seq, 0);
52262306a36Sopenharmony_ci	ring->fence_drv.initialized = false;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	timer_setup(&ring->fence_drv.fallback_timer, amdgpu_fence_fallback, 0);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	ring->fence_drv.num_fences_mask = ring->num_hw_submission * 2 - 1;
52762306a36Sopenharmony_ci	spin_lock_init(&ring->fence_drv.lock);
52862306a36Sopenharmony_ci	ring->fence_drv.fences = kcalloc(ring->num_hw_submission * 2, sizeof(void *),
52962306a36Sopenharmony_ci					 GFP_KERNEL);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (!ring->fence_drv.fences)
53262306a36Sopenharmony_ci		return -ENOMEM;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return 0;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci/**
53862306a36Sopenharmony_ci * amdgpu_fence_driver_sw_init - init the fence driver
53962306a36Sopenharmony_ci * for all possible rings.
54062306a36Sopenharmony_ci *
54162306a36Sopenharmony_ci * @adev: amdgpu device pointer
54262306a36Sopenharmony_ci *
54362306a36Sopenharmony_ci * Init the fence driver for all possible rings (all asics).
54462306a36Sopenharmony_ci * Not all asics have all rings, so each asic will only
54562306a36Sopenharmony_ci * start the fence driver on the rings it has using
54662306a36Sopenharmony_ci * amdgpu_fence_driver_start_ring().
54762306a36Sopenharmony_ci * Returns 0 for success.
54862306a36Sopenharmony_ci */
54962306a36Sopenharmony_ciint amdgpu_fence_driver_sw_init(struct amdgpu_device *adev)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	return 0;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/**
55562306a36Sopenharmony_ci * amdgpu_fence_need_ring_interrupt_restore - helper function to check whether
55662306a36Sopenharmony_ci * fence driver interrupts need to be restored.
55762306a36Sopenharmony_ci *
55862306a36Sopenharmony_ci * @ring: ring that to be checked
55962306a36Sopenharmony_ci *
56062306a36Sopenharmony_ci * Interrupts for rings that belong to GFX IP don't need to be restored
56162306a36Sopenharmony_ci * when the target power state is s0ix.
56262306a36Sopenharmony_ci *
56362306a36Sopenharmony_ci * Return true if need to restore interrupts, false otherwise.
56462306a36Sopenharmony_ci */
56562306a36Sopenharmony_cistatic bool amdgpu_fence_need_ring_interrupt_restore(struct amdgpu_ring *ring)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
56862306a36Sopenharmony_ci	bool is_gfx_power_domain = false;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	switch (ring->funcs->type) {
57162306a36Sopenharmony_ci	case AMDGPU_RING_TYPE_SDMA:
57262306a36Sopenharmony_ci	/* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */
57362306a36Sopenharmony_ci		if (adev->ip_versions[SDMA0_HWIP][0] >= IP_VERSION(5, 0, 0))
57462306a36Sopenharmony_ci			is_gfx_power_domain = true;
57562306a36Sopenharmony_ci		break;
57662306a36Sopenharmony_ci	case AMDGPU_RING_TYPE_GFX:
57762306a36Sopenharmony_ci	case AMDGPU_RING_TYPE_COMPUTE:
57862306a36Sopenharmony_ci	case AMDGPU_RING_TYPE_KIQ:
57962306a36Sopenharmony_ci	case AMDGPU_RING_TYPE_MES:
58062306a36Sopenharmony_ci		is_gfx_power_domain = true;
58162306a36Sopenharmony_ci		break;
58262306a36Sopenharmony_ci	default:
58362306a36Sopenharmony_ci		break;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	return !(adev->in_s0ix && is_gfx_power_domain);
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci/**
59062306a36Sopenharmony_ci * amdgpu_fence_driver_hw_fini - tear down the fence driver
59162306a36Sopenharmony_ci * for all possible rings.
59262306a36Sopenharmony_ci *
59362306a36Sopenharmony_ci * @adev: amdgpu device pointer
59462306a36Sopenharmony_ci *
59562306a36Sopenharmony_ci * Tear down the fence driver for all possible rings (all asics).
59662306a36Sopenharmony_ci */
59762306a36Sopenharmony_civoid amdgpu_fence_driver_hw_fini(struct amdgpu_device *adev)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	int i, r;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
60262306a36Sopenharmony_ci		struct amdgpu_ring *ring = adev->rings[i];
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci		if (!ring || !ring->fence_drv.initialized)
60562306a36Sopenharmony_ci			continue;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci		/* You can't wait for HW to signal if it's gone */
60862306a36Sopenharmony_ci		if (!drm_dev_is_unplugged(adev_to_drm(adev)))
60962306a36Sopenharmony_ci			r = amdgpu_fence_wait_empty(ring);
61062306a36Sopenharmony_ci		else
61162306a36Sopenharmony_ci			r = -ENODEV;
61262306a36Sopenharmony_ci		/* no need to trigger GPU reset as we are unloading */
61362306a36Sopenharmony_ci		if (r)
61462306a36Sopenharmony_ci			amdgpu_fence_driver_force_completion(ring);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		if (!drm_dev_is_unplugged(adev_to_drm(adev)) &&
61762306a36Sopenharmony_ci		    ring->fence_drv.irq_src &&
61862306a36Sopenharmony_ci		    amdgpu_fence_need_ring_interrupt_restore(ring))
61962306a36Sopenharmony_ci			amdgpu_irq_put(adev, ring->fence_drv.irq_src,
62062306a36Sopenharmony_ci				       ring->fence_drv.irq_type);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		del_timer_sync(&ring->fence_drv.fallback_timer);
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci/* Will either stop and flush handlers for amdgpu interrupt or reanble it */
62762306a36Sopenharmony_civoid amdgpu_fence_driver_isr_toggle(struct amdgpu_device *adev, bool stop)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	int i;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
63262306a36Sopenharmony_ci		struct amdgpu_ring *ring = adev->rings[i];
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		if (!ring || !ring->fence_drv.initialized || !ring->fence_drv.irq_src)
63562306a36Sopenharmony_ci			continue;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		if (stop)
63862306a36Sopenharmony_ci			disable_irq(adev->irq.irq);
63962306a36Sopenharmony_ci		else
64062306a36Sopenharmony_ci			enable_irq(adev->irq.irq);
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_civoid amdgpu_fence_driver_sw_fini(struct amdgpu_device *adev)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	unsigned int i, j;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
64962306a36Sopenharmony_ci		struct amdgpu_ring *ring = adev->rings[i];
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		if (!ring || !ring->fence_drv.initialized)
65262306a36Sopenharmony_ci			continue;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci		/*
65562306a36Sopenharmony_ci		 * Notice we check for sched.ops since there's some
65662306a36Sopenharmony_ci		 * override on the meaning of sched.ready by amdgpu.
65762306a36Sopenharmony_ci		 * The natural check would be sched.ready, which is
65862306a36Sopenharmony_ci		 * set as drm_sched_init() finishes...
65962306a36Sopenharmony_ci		 */
66062306a36Sopenharmony_ci		if (ring->sched.ops)
66162306a36Sopenharmony_ci			drm_sched_fini(&ring->sched);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j)
66462306a36Sopenharmony_ci			dma_fence_put(ring->fence_drv.fences[j]);
66562306a36Sopenharmony_ci		kfree(ring->fence_drv.fences);
66662306a36Sopenharmony_ci		ring->fence_drv.fences = NULL;
66762306a36Sopenharmony_ci		ring->fence_drv.initialized = false;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci/**
67262306a36Sopenharmony_ci * amdgpu_fence_driver_hw_init - enable the fence driver
67362306a36Sopenharmony_ci * for all possible rings.
67462306a36Sopenharmony_ci *
67562306a36Sopenharmony_ci * @adev: amdgpu device pointer
67662306a36Sopenharmony_ci *
67762306a36Sopenharmony_ci * Enable the fence driver for all possible rings (all asics).
67862306a36Sopenharmony_ci * Not all asics have all rings, so each asic will only
67962306a36Sopenharmony_ci * start the fence driver on the rings it has using
68062306a36Sopenharmony_ci * amdgpu_fence_driver_start_ring().
68162306a36Sopenharmony_ci * Returns 0 for success.
68262306a36Sopenharmony_ci */
68362306a36Sopenharmony_civoid amdgpu_fence_driver_hw_init(struct amdgpu_device *adev)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	int i;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
68862306a36Sopenharmony_ci		struct amdgpu_ring *ring = adev->rings[i];
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci		if (!ring || !ring->fence_drv.initialized)
69162306a36Sopenharmony_ci			continue;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		/* enable the interrupt */
69462306a36Sopenharmony_ci		if (ring->fence_drv.irq_src &&
69562306a36Sopenharmony_ci		    amdgpu_fence_need_ring_interrupt_restore(ring))
69662306a36Sopenharmony_ci			amdgpu_irq_get(adev, ring->fence_drv.irq_src,
69762306a36Sopenharmony_ci				       ring->fence_drv.irq_type);
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci/**
70262306a36Sopenharmony_ci * amdgpu_fence_driver_clear_job_fences - clear job embedded fences of ring
70362306a36Sopenharmony_ci *
70462306a36Sopenharmony_ci * @ring: fence of the ring to be cleared
70562306a36Sopenharmony_ci *
70662306a36Sopenharmony_ci */
70762306a36Sopenharmony_civoid amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	int i;
71062306a36Sopenharmony_ci	struct dma_fence *old, **ptr;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) {
71362306a36Sopenharmony_ci		ptr = &ring->fence_drv.fences[i];
71462306a36Sopenharmony_ci		old = rcu_dereference_protected(*ptr, 1);
71562306a36Sopenharmony_ci		if (old && old->ops == &amdgpu_job_fence_ops) {
71662306a36Sopenharmony_ci			struct amdgpu_job *job;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci			/* For non-scheduler bad job, i.e. failed ib test, we need to signal
71962306a36Sopenharmony_ci			 * it right here or we won't be able to track them in fence_drv
72062306a36Sopenharmony_ci			 * and they will remain unsignaled during sa_bo free.
72162306a36Sopenharmony_ci			 */
72262306a36Sopenharmony_ci			job = container_of(old, struct amdgpu_job, hw_fence);
72362306a36Sopenharmony_ci			if (!job->base.s_fence && !dma_fence_is_signaled(old))
72462306a36Sopenharmony_ci				dma_fence_signal(old);
72562306a36Sopenharmony_ci			RCU_INIT_POINTER(*ptr, NULL);
72662306a36Sopenharmony_ci			dma_fence_put(old);
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci/**
73262306a36Sopenharmony_ci * amdgpu_fence_driver_set_error - set error code on fences
73362306a36Sopenharmony_ci * @ring: the ring which contains the fences
73462306a36Sopenharmony_ci * @error: the error code to set
73562306a36Sopenharmony_ci *
73662306a36Sopenharmony_ci * Set an error code to all the fences pending on the ring.
73762306a36Sopenharmony_ci */
73862306a36Sopenharmony_civoid amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct amdgpu_fence_driver *drv = &ring->fence_drv;
74162306a36Sopenharmony_ci	unsigned long flags;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	spin_lock_irqsave(&drv->lock, flags);
74462306a36Sopenharmony_ci	for (unsigned int i = 0; i <= drv->num_fences_mask; ++i) {
74562306a36Sopenharmony_ci		struct dma_fence *fence;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		fence = rcu_dereference_protected(drv->fences[i],
74862306a36Sopenharmony_ci						  lockdep_is_held(&drv->lock));
74962306a36Sopenharmony_ci		if (fence && !dma_fence_is_signaled_locked(fence))
75062306a36Sopenharmony_ci			dma_fence_set_error(fence, error);
75162306a36Sopenharmony_ci	}
75262306a36Sopenharmony_ci	spin_unlock_irqrestore(&drv->lock, flags);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/**
75662306a36Sopenharmony_ci * amdgpu_fence_driver_force_completion - force signal latest fence of ring
75762306a36Sopenharmony_ci *
75862306a36Sopenharmony_ci * @ring: fence of the ring to signal
75962306a36Sopenharmony_ci *
76062306a36Sopenharmony_ci */
76162306a36Sopenharmony_civoid amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	amdgpu_fence_driver_set_error(ring, -ECANCELED);
76462306a36Sopenharmony_ci	amdgpu_fence_write(ring, ring->fence_drv.sync_seq);
76562306a36Sopenharmony_ci	amdgpu_fence_process(ring);
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci/*
76962306a36Sopenharmony_ci * Common fence implementation
77062306a36Sopenharmony_ci */
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic const char *amdgpu_fence_get_driver_name(struct dma_fence *fence)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	return "amdgpu";
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic const char *amdgpu_fence_get_timeline_name(struct dma_fence *f)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	return (const char *)to_amdgpu_fence(f)->ring->name;
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic const char *amdgpu_job_fence_get_timeline_name(struct dma_fence *f)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	return (const char *)to_amdgpu_ring(job->base.sched)->name;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci/**
79062306a36Sopenharmony_ci * amdgpu_fence_enable_signaling - enable signalling on fence
79162306a36Sopenharmony_ci * @f: fence
79262306a36Sopenharmony_ci *
79362306a36Sopenharmony_ci * This function is called with fence_queue lock held, and adds a callback
79462306a36Sopenharmony_ci * to fence_queue that checks if this fence is signaled, and if so it
79562306a36Sopenharmony_ci * signals the fence and removes itself.
79662306a36Sopenharmony_ci */
79762306a36Sopenharmony_cistatic bool amdgpu_fence_enable_signaling(struct dma_fence *f)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	if (!timer_pending(&to_amdgpu_fence(f)->ring->fence_drv.fallback_timer))
80062306a36Sopenharmony_ci		amdgpu_fence_schedule_fallback(to_amdgpu_fence(f)->ring);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return true;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci/**
80662306a36Sopenharmony_ci * amdgpu_job_fence_enable_signaling - enable signalling on job fence
80762306a36Sopenharmony_ci * @f: fence
80862306a36Sopenharmony_ci *
80962306a36Sopenharmony_ci * This is the simliar function with amdgpu_fence_enable_signaling above, it
81062306a36Sopenharmony_ci * only handles the job embedded fence.
81162306a36Sopenharmony_ci */
81262306a36Sopenharmony_cistatic bool amdgpu_job_fence_enable_signaling(struct dma_fence *f)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	if (!timer_pending(&to_amdgpu_ring(job->base.sched)->fence_drv.fallback_timer))
81762306a36Sopenharmony_ci		amdgpu_fence_schedule_fallback(to_amdgpu_ring(job->base.sched));
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return true;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci/**
82362306a36Sopenharmony_ci * amdgpu_fence_free - free up the fence memory
82462306a36Sopenharmony_ci *
82562306a36Sopenharmony_ci * @rcu: RCU callback head
82662306a36Sopenharmony_ci *
82762306a36Sopenharmony_ci * Free up the fence memory after the RCU grace period.
82862306a36Sopenharmony_ci */
82962306a36Sopenharmony_cistatic void amdgpu_fence_free(struct rcu_head *rcu)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	/* free fence_slab if it's separated fence*/
83462306a36Sopenharmony_ci	kmem_cache_free(amdgpu_fence_slab, to_amdgpu_fence(f));
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci/**
83862306a36Sopenharmony_ci * amdgpu_job_fence_free - free up the job with embedded fence
83962306a36Sopenharmony_ci *
84062306a36Sopenharmony_ci * @rcu: RCU callback head
84162306a36Sopenharmony_ci *
84262306a36Sopenharmony_ci * Free up the job with embedded fence after the RCU grace period.
84362306a36Sopenharmony_ci */
84462306a36Sopenharmony_cistatic void amdgpu_job_fence_free(struct rcu_head *rcu)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* free job if fence has a parent job */
84962306a36Sopenharmony_ci	kfree(container_of(f, struct amdgpu_job, hw_fence));
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci/**
85362306a36Sopenharmony_ci * amdgpu_fence_release - callback that fence can be freed
85462306a36Sopenharmony_ci *
85562306a36Sopenharmony_ci * @f: fence
85662306a36Sopenharmony_ci *
85762306a36Sopenharmony_ci * This function is called when the reference count becomes zero.
85862306a36Sopenharmony_ci * It just RCU schedules freeing up the fence.
85962306a36Sopenharmony_ci */
86062306a36Sopenharmony_cistatic void amdgpu_fence_release(struct dma_fence *f)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	call_rcu(&f->rcu, amdgpu_fence_free);
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci/**
86662306a36Sopenharmony_ci * amdgpu_job_fence_release - callback that job embedded fence can be freed
86762306a36Sopenharmony_ci *
86862306a36Sopenharmony_ci * @f: fence
86962306a36Sopenharmony_ci *
87062306a36Sopenharmony_ci * This is the simliar function with amdgpu_fence_release above, it
87162306a36Sopenharmony_ci * only handles the job embedded fence.
87262306a36Sopenharmony_ci */
87362306a36Sopenharmony_cistatic void amdgpu_job_fence_release(struct dma_fence *f)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci	call_rcu(&f->rcu, amdgpu_job_fence_free);
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic const struct dma_fence_ops amdgpu_fence_ops = {
87962306a36Sopenharmony_ci	.get_driver_name = amdgpu_fence_get_driver_name,
88062306a36Sopenharmony_ci	.get_timeline_name = amdgpu_fence_get_timeline_name,
88162306a36Sopenharmony_ci	.enable_signaling = amdgpu_fence_enable_signaling,
88262306a36Sopenharmony_ci	.release = amdgpu_fence_release,
88362306a36Sopenharmony_ci};
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic const struct dma_fence_ops amdgpu_job_fence_ops = {
88662306a36Sopenharmony_ci	.get_driver_name = amdgpu_fence_get_driver_name,
88762306a36Sopenharmony_ci	.get_timeline_name = amdgpu_job_fence_get_timeline_name,
88862306a36Sopenharmony_ci	.enable_signaling = amdgpu_job_fence_enable_signaling,
88962306a36Sopenharmony_ci	.release = amdgpu_job_fence_release,
89062306a36Sopenharmony_ci};
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci/*
89362306a36Sopenharmony_ci * Fence debugfs
89462306a36Sopenharmony_ci */
89562306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
89662306a36Sopenharmony_cistatic int amdgpu_debugfs_fence_info_show(struct seq_file *m, void *unused)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct amdgpu_device *adev = m->private;
89962306a36Sopenharmony_ci	int i;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
90262306a36Sopenharmony_ci		struct amdgpu_ring *ring = adev->rings[i];
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci		if (!ring || !ring->fence_drv.initialized)
90562306a36Sopenharmony_ci			continue;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci		amdgpu_fence_process(ring);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci		seq_printf(m, "--- ring %d (%s) ---\n", i, ring->name);
91062306a36Sopenharmony_ci		seq_printf(m, "Last signaled fence          0x%08x\n",
91162306a36Sopenharmony_ci			   atomic_read(&ring->fence_drv.last_seq));
91262306a36Sopenharmony_ci		seq_printf(m, "Last emitted                 0x%08x\n",
91362306a36Sopenharmony_ci			   ring->fence_drv.sync_seq);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci		if (ring->funcs->type == AMDGPU_RING_TYPE_GFX ||
91662306a36Sopenharmony_ci		    ring->funcs->type == AMDGPU_RING_TYPE_SDMA) {
91762306a36Sopenharmony_ci			seq_printf(m, "Last signaled trailing fence 0x%08x\n",
91862306a36Sopenharmony_ci				   le32_to_cpu(*ring->trail_fence_cpu_addr));
91962306a36Sopenharmony_ci			seq_printf(m, "Last emitted                 0x%08x\n",
92062306a36Sopenharmony_ci				   ring->trail_seq);
92162306a36Sopenharmony_ci		}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci		if (ring->funcs->type != AMDGPU_RING_TYPE_GFX)
92462306a36Sopenharmony_ci			continue;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		/* set in CP_VMID_PREEMPT and preemption occurred */
92762306a36Sopenharmony_ci		seq_printf(m, "Last preempted               0x%08x\n",
92862306a36Sopenharmony_ci			   le32_to_cpu(*(ring->fence_drv.cpu_addr + 2)));
92962306a36Sopenharmony_ci		/* set in CP_VMID_RESET and reset occurred */
93062306a36Sopenharmony_ci		seq_printf(m, "Last reset                   0x%08x\n",
93162306a36Sopenharmony_ci			   le32_to_cpu(*(ring->fence_drv.cpu_addr + 4)));
93262306a36Sopenharmony_ci		/* Both preemption and reset occurred */
93362306a36Sopenharmony_ci		seq_printf(m, "Last both                    0x%08x\n",
93462306a36Sopenharmony_ci			   le32_to_cpu(*(ring->fence_drv.cpu_addr + 6)));
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci	return 0;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci/*
94062306a36Sopenharmony_ci * amdgpu_debugfs_gpu_recover - manually trigger a gpu reset & recover
94162306a36Sopenharmony_ci *
94262306a36Sopenharmony_ci * Manually trigger a gpu reset at the next fence wait.
94362306a36Sopenharmony_ci */
94462306a36Sopenharmony_cistatic int gpu_recover_get(void *data, u64 *val)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct amdgpu_device *adev = (struct amdgpu_device *)data;
94762306a36Sopenharmony_ci	struct drm_device *dev = adev_to_drm(adev);
94862306a36Sopenharmony_ci	int r;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	r = pm_runtime_get_sync(dev->dev);
95162306a36Sopenharmony_ci	if (r < 0) {
95262306a36Sopenharmony_ci		pm_runtime_put_autosuspend(dev->dev);
95362306a36Sopenharmony_ci		return 0;
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if (amdgpu_reset_domain_schedule(adev->reset_domain, &adev->reset_work))
95762306a36Sopenharmony_ci		flush_work(&adev->reset_work);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	*val = atomic_read(&adev->reset_domain->reset_res);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dev->dev);
96262306a36Sopenharmony_ci	pm_runtime_put_autosuspend(dev->dev);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	return 0;
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_fence_info);
96862306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_gpu_recover_fops, gpu_recover_get, NULL,
96962306a36Sopenharmony_ci			 "%lld\n");
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic void amdgpu_debugfs_reset_work(struct work_struct *work)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
97462306a36Sopenharmony_ci						  reset_work);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	struct amdgpu_reset_context reset_context;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	memset(&reset_context, 0, sizeof(reset_context));
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	reset_context.method = AMD_RESET_METHOD_NONE;
98162306a36Sopenharmony_ci	reset_context.reset_req_dev = adev;
98262306a36Sopenharmony_ci	set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	amdgpu_device_gpu_recover(adev, NULL, &reset_context);
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci#endif
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_civoid amdgpu_debugfs_fence_init(struct amdgpu_device *adev)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
99262306a36Sopenharmony_ci	struct drm_minor *minor = adev_to_drm(adev)->primary;
99362306a36Sopenharmony_ci	struct dentry *root = minor->debugfs_root;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	debugfs_create_file("amdgpu_fence_info", 0444, root, adev,
99662306a36Sopenharmony_ci			    &amdgpu_debugfs_fence_info_fops);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	if (!amdgpu_sriov_vf(adev)) {
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		INIT_WORK(&adev->reset_work, amdgpu_debugfs_reset_work);
100162306a36Sopenharmony_ci		debugfs_create_file("amdgpu_gpu_recover", 0444, root, adev,
100262306a36Sopenharmony_ci				    &amdgpu_debugfs_gpu_recover_fops);
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci#endif
100562306a36Sopenharmony_ci}
100662306a36Sopenharmony_ci
1007