Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f8f635e authored by Jerome Glisse's avatar Jerome Glisse Committed by Alex Deucher
Browse files

drm/radeon: avoid deadlock in pm path when waiting for fence



radeon_fence_wait_empty_locked should not trigger GPU reset as no
place where it's call from would benefit from such thing and it
actually lead to a kernel deadlock in case the reset is triggered
from pm codepath. Instead force ring completion in place where it
makes sense or return early in others.

Signed-off-by: default avatarJerome Glisse <jglisse@redhat.com>
Reviewed-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
parent 76903b96
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -231,7 +231,7 @@ void radeon_fence_process(struct radeon_device *rdev, int ring);
bool radeon_fence_signaled(struct radeon_fence *fence);
int radeon_fence_wait(struct radeon_fence *fence, bool interruptible);
int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring);
void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring);
int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring);
int radeon_fence_wait_any(struct radeon_device *rdev,
			  struct radeon_fence **fences,
			  bool intr);
+11 −2
Original line number Diff line number Diff line
@@ -1164,6 +1164,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
	struct drm_crtc *crtc;
	struct drm_connector *connector;
	int i, r;
	bool force_completion = false;

	if (dev == NULL || dev->dev_private == NULL) {
		return -ENODEV;
@@ -1206,8 +1207,16 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)

	mutex_lock(&rdev->ring_lock);
	/* wait for gpu to finish processing current batch */
	for (i = 0; i < RADEON_NUM_RINGS; i++)
		radeon_fence_wait_empty_locked(rdev, i);
	for (i = 0; i < RADEON_NUM_RINGS; i++) {
		r = radeon_fence_wait_empty_locked(rdev, i);
		if (r) {
			/* delay GPU reset to resume */
			force_completion = true;
		}
	}
	if (force_completion) {
		radeon_fence_driver_force_completion(rdev);
	}
	mutex_unlock(&rdev->ring_lock);

	radeon_save_bios_scratch_regs(rdev);
+14 −16
Original line number Diff line number Diff line
@@ -609,26 +609,20 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)
 * Returns 0 if the fences have passed, error for all other cases.
 * Caller must hold ring lock.
 */
void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
{
	uint64_t seq = rdev->fence_drv[ring].sync_seq[ring];

	while(1) {
	int r;

	r = radeon_fence_wait_seq(rdev, seq, ring, false, false);
		if (r == -EDEADLK) {
			mutex_unlock(&rdev->ring_lock);
			r = radeon_gpu_reset(rdev);
			mutex_lock(&rdev->ring_lock);
			if (!r)
				continue;
		}
	if (r) {
			dev_err(rdev->dev, "error waiting for ring to become"
				" idle (%d)\n", r);
		if (r == -EDEADLK) {
			return -EDEADLK;
		}
		return;
		dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n",
			ring, r);
	}
	return 0;
}

/**
@@ -854,13 +848,17 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
 */
void radeon_fence_driver_fini(struct radeon_device *rdev)
{
	int ring;
	int ring, r;

	mutex_lock(&rdev->ring_lock);
	for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
		if (!rdev->fence_drv[ring].initialized)
			continue;
		radeon_fence_wait_empty_locked(rdev, ring);
		r = radeon_fence_wait_empty_locked(rdev, ring);
		if (r) {
			/* no need to trigger GPU reset as we are unloading */
			radeon_fence_driver_force_completion(rdev);
		}
		wake_up_all(&rdev->fence_queue);
		radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
		rdev->fence_drv[ring].initialized = false;
+12 −3
Original line number Diff line number Diff line
@@ -234,7 +234,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)

static void radeon_pm_set_clocks(struct radeon_device *rdev)
{
	int i;
	int i, r;

	/* no need to take locks, etc. if nothing's going to change */
	if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) &&
@@ -248,8 +248,17 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
	/* wait for the rings to drain */
	for (i = 0; i < RADEON_NUM_RINGS; i++) {
		struct radeon_ring *ring = &rdev->ring[i];
		if (ring->ready)
			radeon_fence_wait_empty_locked(rdev, i);
		if (!ring->ready) {
			continue;
		}
		r = radeon_fence_wait_empty_locked(rdev, i);
		if (r) {
			/* needs a GPU reset dont reset here */
			mutex_unlock(&rdev->ring_lock);
			up_write(&rdev->pm.mclk_lock);
			mutex_unlock(&rdev->ddev->struct_mutex);
			return;
		}
	}

	radeon_unmap_vram_bos(rdev);