From 62f5e8156da4e5373a10c7c1d15a4327283f64f2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Adis=20Hamzi=C4=87?= Date: Sun, 2 Jun 2013 16:47:54 +0200 Subject: [PATCH] radeon: Fix system hang issue when using KMS with older cards MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit commit e49f3959a96dc279860af7e86e6dbcfda50580a5 upstream. The current radeon driver initialization routines, when using KMS, are written so that the IRQ installation routine is called before initializing the WB buffer and the CP rings. With some ASICs, though, the IRQ routine tries to access the GFX_INDEX ring causing a call to RREG32 with the value of -1 in radeon_fence_read. This, in turn causes the system to completely hang with some cards, requiring a hard reset. A call stack that can cause such a hang looks like this (using rv515 ASIC for the example here): * rv515_init (rv515.c) * radeon_irq_kms_init (radeon_irq_kms.c) * drm_irq_install (drm_irq.c) * radeon_driver_irq_preinstall_kms (radeon_irq_kms.c) * rs600_irq_process (rs600.c) * radeon_fence_process - due to SW interrupt (radeon_fence.c) * radeon_fence_read (radeon_fence.c) * hang due to RREG32(-1) The patch moves the IRQ installation to the card startup routine, after the ring has been initialized, but before the IRQ has been set. This fixes the issue, but requires a check to see if the IRQ is already installed, as is the case in the system resume codepath. I have tested the patch on three machines using the rv515, the rv770 and the evergreen ASIC. They worked without issues. This seems to be a known issue and has been reported on several bug tracking sites by various distributions (see links below). Most of reports recommend booting the system with KMS disabled and then enabling KMS by reloading the radeon module. For some reason, this was indeed a usable workaround, however, UMS is now deprecated and disabled by default. Bug reports: https://bugzilla.redhat.com/show_bug.cgi?id=845745 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/561789 https://bbs.archlinux.org/viewtopic.php?id=156964 Signed-off-by: Adis Hamzić Signed-off-by: Alex Deucher [bwh: Backported to 3.2: - Adjust context - Drop changes for Southern Islands] Signed-off-by: Ben Hutchings --- drivers/gpu/drm/radeon/evergreen.c | 10 ++++++---- drivers/gpu/drm/radeon/ni.c | 10 ++++++---- drivers/gpu/drm/radeon/r100.c | 9 ++++++--- drivers/gpu/drm/radeon/r300.c | 9 ++++++--- drivers/gpu/drm/radeon/r420.c | 10 ++++++---- drivers/gpu/drm/radeon/r520.c | 9 ++++++--- drivers/gpu/drm/radeon/r600.c | 10 ++++++---- drivers/gpu/drm/radeon/rs400.c | 9 ++++++--- drivers/gpu/drm/radeon/rs600.c | 9 ++++++--- drivers/gpu/drm/radeon/rs690.c | 9 ++++++--- drivers/gpu/drm/radeon/rv515.c | 9 ++++++--- drivers/gpu/drm/radeon/rv770.c | 10 ++++++---- 12 files changed, 72 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 0495a50309e..9bea4a6433c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3086,6 +3086,12 @@ static int evergreen_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = r600_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -3218,10 +3224,6 @@ int evergreen_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 636255bf9e4..3f9705babeb 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1389,6 +1389,12 @@ static int cayman_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = r600_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -1506,10 +1512,6 @@ int cayman_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index fad7cd1dfdb..76c12902ad4 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3905,6 +3905,12 @@ static int r100_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r100_irq_set(rdev); rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -4048,9 +4054,6 @@ int r100_init(struct radeon_device *rdev) r100_mc_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); - if (r) - return r; - r = radeon_irq_kms_init(rdev); if (r) return r; /* Memory manager */ diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index c93bc64707e..441570b9b42 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1397,6 +1397,12 @@ static int r300_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r100_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -1519,9 +1525,6 @@ int r300_init(struct radeon_device *rdev) r300_mc_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); - if (r) - return r; - r = radeon_irq_kms_init(rdev); if (r) return r; /* Memory manager */ diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 417fab81812..5b219b83d4e 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -255,6 +255,12 @@ static int r420_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r100_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -391,10 +397,6 @@ int r420_init(struct radeon_device *rdev) if (r) { return r; } - r = radeon_irq_kms_init(rdev); - if (r) { - return r; - } /* Memory manager */ r = radeon_bo_init(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 3081d07f8de..f36a5c9b82f 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -188,6 +188,12 @@ static int r520_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + rs600_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -279,9 +285,6 @@ int r520_init(struct radeon_device *rdev) rv515_debugfs(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); - if (r) - return r; - r = radeon_irq_kms_init(rdev); if (r) return r; /* Memory manager */ diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index bdfa82a61fb..3d46d7d4c28 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2449,6 +2449,12 @@ int r600_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = r600_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -2592,10 +2598,6 @@ int r600_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 06b90c87f8f..4dd9512fcc5 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -411,6 +411,12 @@ static int rs400_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r100_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -517,9 +523,6 @@ int rs400_init(struct radeon_device *rdev) rs400_mc_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); - if (r) - return r; - r = radeon_irq_kms_init(rdev); if (r) return r; /* Memory manager */ diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index ee898e9bd44..cea482aa1fe 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -848,6 +848,12 @@ static int rs600_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + rs600_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -961,9 +967,6 @@ int rs600_init(struct radeon_device *rdev) rs600_debugfs(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); - if (r) - return r; - r = radeon_irq_kms_init(rdev); if (r) return r; /* Memory manager */ diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index a9049ed1a51..93bce728cdb 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -622,6 +622,12 @@ static int rs690_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + rs600_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -736,9 +742,6 @@ int rs690_init(struct radeon_device *rdev) rv515_debugfs(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); - if (r) - return r; - r = radeon_irq_kms_init(rdev); if (r) return r; /* Memory manager */ diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index d5f45b4c1be..9103638b918 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -380,6 +380,12 @@ static int rv515_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + rs600_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -498,9 +504,6 @@ int rv515_init(struct radeon_device *rdev) rv515_debugfs(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); - if (r) - return r; - r = radeon_irq_kms_init(rdev); if (r) return r; /* Memory manager */ diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index cc79449cdf1..63db75d0c0f 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1092,6 +1092,12 @@ static int rv770_startup(struct radeon_device *rdev) return r; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = r600_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -1220,10 +1226,6 @@ int rv770_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); -- 2.34.1