/* swap out the old fences */
amdgpu_ib_preempt_fences_swap(ring, fences);
- amdgpu_fence_driver_force_completion(ring);
+ amdgpu_fence_driver_force_completion(ring, NULL);
/* resubmit unfinished jobs */
amdgpu_ib_preempt_job_recovery(&ring->sched);
{
int i, r = 0;
struct amdgpu_job *job = NULL;
+ struct dma_fence *fence = NULL;
struct amdgpu_device *tmp_adev = reset_context->reset_req_dev;
bool need_full_reset =
test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
amdgpu_fence_driver_isr_toggle(adev, true);
+ if (job)
+ fence = &job->hw_fence->base;
+
/* block all schedulers and reset given job's ring */
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
struct amdgpu_ring *ring = adev->rings[i];
continue;
/* after all hw jobs are reset, hw fence is meaningless, so force_completion */
- amdgpu_fence_driver_force_completion(ring);
+ amdgpu_fence_driver_force_completion(ring, fence);
}
amdgpu_fence_driver_isr_toggle(adev, false);
r = -ENODEV;
/* no need to trigger GPU reset as we are unloading */
if (r)
- amdgpu_fence_driver_force_completion(ring);
+ amdgpu_fence_driver_force_completion(ring, NULL);
if (!drm_dev_is_unplugged(adev_to_drm(adev)) &&
ring->fence_drv.irq_src &&
* amdgpu_fence_driver_force_completion - force signal latest fence of ring
*
* @ring: fence of the ring to signal
+ * @timedout_fence: fence of the timedout job
*
*/
-void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
+void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring,
+ struct dma_fence *timedout_fence)
{
- amdgpu_fence_driver_set_error(ring, -ECANCELED);
+ struct amdgpu_fence_driver *drv = &ring->fence_drv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv->lock, flags);
+ for (unsigned int i = 0; i <= drv->num_fences_mask; ++i) {
+ struct dma_fence *fence;
+
+ fence = rcu_dereference_protected(drv->fences[i],
+ lockdep_is_held(&drv->lock));
+ if (fence && !dma_fence_is_signaled_locked(fence)) {
+ if (fence == timedout_fence)
+ dma_fence_set_error(fence, -ETIME);
+ else
+ dma_fence_set_error(fence, -ECANCELED);
+ }
+ }
+ spin_unlock_irqrestore(&drv->lock, flags);
+
amdgpu_fence_write(ring, ring->fence_drv.sync_seq);
amdgpu_fence_process(ring);
}
-
/*
* Kernel queue reset handling
*
extern const struct drm_sched_backend_ops amdgpu_sched_ops;
void amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error);
-void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring);
+void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring,
+ struct dma_fence *timedout_fence);
void amdgpu_ring_set_fence_errors_and_reemit(struct amdgpu_ring *ring,
struct amdgpu_fence *guilty_fence);
* to be submitted to the queues after the reset is complete.
*/
if (!ret) {
- amdgpu_fence_driver_force_completion(gfx_ring);
+ amdgpu_fence_driver_force_completion(gfx_ring, NULL);
drm_sched_wqueue_start(&gfx_ring->sched);
if (adev->sdma.has_page_queue) {
- amdgpu_fence_driver_force_completion(page_ring);
+ amdgpu_fence_driver_force_completion(page_ring, NULL);
drm_sched_wqueue_start(&page_ring->sched);
}
}
}
memset_io(ptr, 0, size);
/* to restore uvd fence seq */
- amdgpu_fence_driver_force_completion(&adev->uvd.inst[i].ring);
+ amdgpu_fence_driver_force_completion(&adev->uvd.inst[i].ring, NULL);
}
}
return 0;
/**
* amdgpu_vcn_reset_engine - Reset a specific VCN engine
- * @adev: Pointer to the AMDGPU device
- * @instance_id: VCN engine instance to reset
+ * @ring: Pointer to the VCN ring
+ * @timedout_fence: fence that timed out
*
* Returns: 0 on success, or a negative error code on failure.
*/
-static int amdgpu_vcn_reset_engine(struct amdgpu_device *adev,
- uint32_t instance_id)
+static int amdgpu_vcn_reset_engine(struct amdgpu_ring *ring,
+ struct amdgpu_fence *timedout_fence)
{
- struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[instance_id];
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[ring->me];
int r, i;
mutex_lock(&vinst->engine_reset_mutex);
if (r)
goto unlock;
}
- amdgpu_fence_driver_force_completion(&vinst->ring_dec);
+ amdgpu_fence_driver_force_completion(&vinst->ring_dec,
+ (&vinst->ring_dec == ring) ?
+ &timedout_fence->base : NULL);
for (i = 0; i < vinst->num_enc_rings; i++)
- amdgpu_fence_driver_force_completion(&vinst->ring_enc[i]);
+ amdgpu_fence_driver_force_completion(&vinst->ring_enc[i],
+ (&vinst->ring_enc[i] == ring) ?
+ &timedout_fence->base : NULL);
/* Restart the scheduler's work queue for the dec and enc rings
* if they were stopped by this function. This allows new tasks
if (adev->vcn.inst[ring->me].using_unified_queue)
return -EINVAL;
- return amdgpu_vcn_reset_engine(adev, ring->me);
+ return amdgpu_vcn_reset_engine(ring, timedout_fence);
}
int amdgpu_vcn_reg_dump_init(struct amdgpu_device *adev,
for (i = 0; i < adev->jpeg.num_jpeg_rings; ++i) {
ring = &adev->jpeg.inst[inst].ring_dec[i];
/* Force completion of any remaining jobs */
- amdgpu_fence_driver_force_completion(ring);
+ amdgpu_fence_driver_force_completion(ring, NULL);
if (ring->use_doorbell)
WREG32_SOC15_OFFSET(
for (i = 0; i < adev->jpeg.num_jpeg_rings; ++i) {
ring = &adev->jpeg.inst[inst].ring_dec[i];
/* Force completion of any remaining jobs */
- amdgpu_fence_driver_force_completion(ring);
+ amdgpu_fence_driver_force_completion(ring, NULL);
if (ring->use_doorbell)
WREG32_SOC15_OFFSET(