mirror of
https://github.com/torvalds/linux.git
synced 2024-11-08 05:01:48 +00:00
radeon: Fix system hang issue when using KMS with older cards
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ć <adis@hamzadis.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org
This commit is contained in:
parent
91f8f105f2
commit
e49f3959a9
@ -4754,6 +4754,12 @@ static int evergreen_startup(struct radeon_device *rdev)
|
|||||||
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
|
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = r600_irq_init(rdev);
|
r = r600_irq_init(rdev);
|
||||||
if (r) {
|
if (r) {
|
||||||
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
||||||
@ -4923,10 +4929,6 @@ int evergreen_init(struct radeon_device *rdev)
|
|||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
|
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
|
||||||
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
|
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
|
||||||
|
|
||||||
|
@ -2025,6 +2025,12 @@ static int cayman_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = r600_irq_init(rdev);
|
r = r600_irq_init(rdev);
|
||||||
if (r) {
|
if (r) {
|
||||||
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
||||||
@ -2190,10 +2196,6 @@ int cayman_init(struct radeon_device *rdev)
|
|||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
ring->ring_obj = NULL;
|
ring->ring_obj = NULL;
|
||||||
r600_ring_init(rdev, ring, 1024 * 1024);
|
r600_ring_init(rdev, ring, 1024 * 1024);
|
||||||
|
|
||||||
|
@ -3869,6 +3869,12 @@ static int r100_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r100_irq_set(rdev);
|
r100_irq_set(rdev);
|
||||||
rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
||||||
/* 1M ring buffer */
|
/* 1M ring buffer */
|
||||||
@ -4022,9 +4028,6 @@ int r100_init(struct radeon_device *rdev)
|
|||||||
r100_mc_init(rdev);
|
r100_mc_init(rdev);
|
||||||
/* Fence driver */
|
/* Fence driver */
|
||||||
r = radeon_fence_driver_init(rdev);
|
r = radeon_fence_driver_init(rdev);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
/* Memory manager */
|
/* Memory manager */
|
||||||
|
@ -1382,6 +1382,12 @@ static int r300_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r100_irq_set(rdev);
|
r100_irq_set(rdev);
|
||||||
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
||||||
/* 1M ring buffer */
|
/* 1M ring buffer */
|
||||||
@ -1514,9 +1520,6 @@ int r300_init(struct radeon_device *rdev)
|
|||||||
r300_mc_init(rdev);
|
r300_mc_init(rdev);
|
||||||
/* Fence driver */
|
/* Fence driver */
|
||||||
r = radeon_fence_driver_init(rdev);
|
r = radeon_fence_driver_init(rdev);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
/* Memory manager */
|
/* Memory manager */
|
||||||
|
@ -265,6 +265,12 @@ static int r420_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r100_irq_set(rdev);
|
r100_irq_set(rdev);
|
||||||
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
||||||
/* 1M ring buffer */
|
/* 1M ring buffer */
|
||||||
@ -411,10 +417,6 @@ int r420_init(struct radeon_device *rdev)
|
|||||||
if (r) {
|
if (r) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
/* Memory manager */
|
/* Memory manager */
|
||||||
r = radeon_bo_init(rdev);
|
r = radeon_bo_init(rdev);
|
||||||
if (r) {
|
if (r) {
|
||||||
|
@ -194,6 +194,12 @@ static int r520_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
rs600_irq_set(rdev);
|
rs600_irq_set(rdev);
|
||||||
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
||||||
/* 1M ring buffer */
|
/* 1M ring buffer */
|
||||||
@ -295,9 +301,6 @@ int r520_init(struct radeon_device *rdev)
|
|||||||
rv515_debugfs(rdev);
|
rv515_debugfs(rdev);
|
||||||
/* Fence driver */
|
/* Fence driver */
|
||||||
r = radeon_fence_driver_init(rdev);
|
r = radeon_fence_driver_init(rdev);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
/* Memory manager */
|
/* Memory manager */
|
||||||
|
@ -3202,6 +3202,12 @@ static int r600_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = r600_irq_init(rdev);
|
r = r600_irq_init(rdev);
|
||||||
if (r) {
|
if (r) {
|
||||||
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
||||||
@ -3356,10 +3362,6 @@ int r600_init(struct radeon_device *rdev)
|
|||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
|
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
|
||||||
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
|
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
|
||||||
|
|
||||||
|
@ -417,6 +417,12 @@ static int rs400_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r100_irq_set(rdev);
|
r100_irq_set(rdev);
|
||||||
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
||||||
/* 1M ring buffer */
|
/* 1M ring buffer */
|
||||||
@ -533,9 +539,6 @@ int rs400_init(struct radeon_device *rdev)
|
|||||||
rs400_mc_init(rdev);
|
rs400_mc_init(rdev);
|
||||||
/* Fence driver */
|
/* Fence driver */
|
||||||
r = radeon_fence_driver_init(rdev);
|
r = radeon_fence_driver_init(rdev);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
/* Memory manager */
|
/* Memory manager */
|
||||||
|
@ -923,6 +923,12 @@ static int rs600_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
rs600_irq_set(rdev);
|
rs600_irq_set(rdev);
|
||||||
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
||||||
/* 1M ring buffer */
|
/* 1M ring buffer */
|
||||||
@ -1045,9 +1051,6 @@ int rs600_init(struct radeon_device *rdev)
|
|||||||
rs600_debugfs(rdev);
|
rs600_debugfs(rdev);
|
||||||
/* Fence driver */
|
/* Fence driver */
|
||||||
r = radeon_fence_driver_init(rdev);
|
r = radeon_fence_driver_init(rdev);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
/* Memory manager */
|
/* Memory manager */
|
||||||
|
@ -651,6 +651,12 @@ static int rs690_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
rs600_irq_set(rdev);
|
rs600_irq_set(rdev);
|
||||||
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
||||||
/* 1M ring buffer */
|
/* 1M ring buffer */
|
||||||
@ -774,9 +780,6 @@ int rs690_init(struct radeon_device *rdev)
|
|||||||
rv515_debugfs(rdev);
|
rv515_debugfs(rdev);
|
||||||
/* Fence driver */
|
/* Fence driver */
|
||||||
r = radeon_fence_driver_init(rdev);
|
r = radeon_fence_driver_init(rdev);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
/* Memory manager */
|
/* Memory manager */
|
||||||
|
@ -532,6 +532,12 @@ static int rv515_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
rs600_irq_set(rdev);
|
rs600_irq_set(rdev);
|
||||||
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
|
||||||
/* 1M ring buffer */
|
/* 1M ring buffer */
|
||||||
@ -660,9 +666,6 @@ int rv515_init(struct radeon_device *rdev)
|
|||||||
rv515_debugfs(rdev);
|
rv515_debugfs(rdev);
|
||||||
/* Fence driver */
|
/* Fence driver */
|
||||||
r = radeon_fence_driver_init(rdev);
|
r = radeon_fence_driver_init(rdev);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
/* Memory manager */
|
/* Memory manager */
|
||||||
|
@ -1887,6 +1887,12 @@ static int rv770_startup(struct radeon_device *rdev)
|
|||||||
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
|
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = r600_irq_init(rdev);
|
r = r600_irq_init(rdev);
|
||||||
if (r) {
|
if (r) {
|
||||||
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
||||||
@ -2045,10 +2051,6 @@ int rv770_init(struct radeon_device *rdev)
|
|||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
|
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
|
||||||
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
|
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
|
||||||
|
|
||||||
|
@ -5350,6 +5350,12 @@ static int si_startup(struct radeon_device *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ */
|
/* Enable IRQ */
|
||||||
|
if (!rdev->irq.installed) {
|
||||||
|
r = radeon_irq_kms_init(rdev);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = si_irq_init(rdev);
|
r = si_irq_init(rdev);
|
||||||
if (r) {
|
if (r) {
|
||||||
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
DRM_ERROR("radeon: IH init failed (%d).\n", r);
|
||||||
@ -5533,10 +5539,6 @@ int si_init(struct radeon_device *rdev)
|
|||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = radeon_irq_kms_init(rdev);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
|
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
|
||||||
ring->ring_obj = NULL;
|
ring->ring_obj = NULL;
|
||||||
r600_ring_init(rdev, ring, 1024 * 1024);
|
r600_ring_init(rdev, ring, 1024 * 1024);
|
||||||
|
Loading…
Reference in New Issue
Block a user