]> git.ipfire.org Git - people/arne_f/kernel.git/commitdiff
radeon: Fix system hang issue when using KMS with older cards
authorAdis Hamzić <adis@hamzadis.com>
Sun, 2 Jun 2013 14:47:54 +0000 (16:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Jun 2013 16:45:00 +0000 (09:45 -0700)
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ć <adis@hamzadis.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
13 files changed:
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/si.c

index 6a8776eae1aebfd28f0dc97910c5218e78ac63d7..300099d3118798de9c784c04108388b8d7bca536 100644 (file)
@@ -3258,6 +3258,12 @@ static int evergreen_startup(struct radeon_device *rdev)
        }
 
        /* 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);
@@ -3409,10 +3415,6 @@ int evergreen_init(struct radeon_device *rdev)
        if (r)
                return r;
 
-       r = radeon_irq_kms_init(rdev);
-       if (r)
-               return r;
-
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
        r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
 
index d706da8986b42b1090bd2ac730e3e986274fb99c..f5387b3e699f757c139100b816f4ae17bf1090e7 100644 (file)
@@ -1614,6 +1614,12 @@ static int cayman_startup(struct radeon_device *rdev)
        }
 
        /* 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);
@@ -1744,10 +1750,6 @@ int cayman_init(struct radeon_device *rdev)
        if (r)
                return r;
 
-       r = radeon_irq_kms_init(rdev);
-       if (r)
-               return r;
-
        ring->ring_obj = NULL;
        r600_ring_init(rdev, ring, 1024 * 1024);
 
index fe33d35dae8c6ca851103e476426e12194d7d4b1..40ed0e5b95a3ba0a01101f9f9ba8c02beb162fde 100644 (file)
@@ -3952,6 +3952,12 @@ static int r100_startup(struct radeon_device *rdev)
        }
 
        /* 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 */
@@ -4111,9 +4117,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 */
index fa14383f9ca09cea2c8f1aaf486f9a7c241ff04e..63b53aa9536fb78b27130bcab7d81eeef897c303 100644 (file)
@@ -1405,6 +1405,12 @@ static int r300_startup(struct radeon_device *rdev)
        }
 
        /* 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 */
@@ -1543,9 +1549,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 */
index f3fcaacfea01eb873583bf7728d5a8e27c5f1ec5..1a9347fdd15e95192aee12051e3708853f0f6e33 100644 (file)
@@ -265,6 +265,12 @@ static int r420_startup(struct radeon_device *rdev)
        }
 
        /* 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 */
@@ -417,10 +423,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) {
index ebcc15b03c9f9223d738ec15cef74b64d699cc68..57be78461ab579a67ca8045bbe13e7e8ad595a63 100644 (file)
@@ -194,6 +194,12 @@ static int r520_startup(struct radeon_device *rdev)
        }
 
        /* 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 */
@@ -299,9 +305,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 */
index b1ff9ccd2d6253226f6c007cf411054c354bc14a..8c403d946acc7ce92889959a6ac0a75b28a3119f 100644 (file)
@@ -2470,6 +2470,12 @@ int r600_startup(struct radeon_device *rdev)
        }
 
        /* 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);
@@ -2624,10 +2630,6 @@ int r600_init(struct radeon_device *rdev)
        if (r)
                return r;
 
-       r = radeon_irq_kms_init(rdev);
-       if (r)
-               return r;
-
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
        r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
 
index 4cf381b3a6d81eee21fdc666d24001b4d75e34be..5099bd32e19539359d2d86c2beffdf7cae213900 100644 (file)
@@ -417,6 +417,12 @@ static int rs400_startup(struct radeon_device *rdev)
        }
 
        /* 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 */
@@ -539,9 +545,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 */
index d25cf869d08dddaa2e0d9f0aec49e2b173297f54..52480010156d6922e0b5bfb618bba33345d85754 100644 (file)
@@ -864,6 +864,12 @@ static int rs600_startup(struct radeon_device *rdev)
        }
 
        /* 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 */
@@ -992,9 +998,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 */
index f2c3b9d75f188d0622a5cdb7c3ad697894546d70..c46900c2c1aa66a4f143eb78e6e9f2dc142af88c 100644 (file)
@@ -628,6 +628,12 @@ static int rs690_startup(struct radeon_device *rdev)
        }
 
        /* 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 */
@@ -757,9 +763,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 */
index 43af363ead3763abba247342305c9f56823ea8ac..0532bbee9f95ff441c0c3a11a89fd9317b9d8202 100644 (file)
@@ -386,6 +386,12 @@ static int rv515_startup(struct radeon_device *rdev)
        }
 
        /* 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 */
@@ -518,9 +524,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 */
index 591040b9466010950c1c59f097ed516dcdc6ff50..4a3937fa2dc7699cdf4bb6a95e8591b29c7bdd7b 100644 (file)
@@ -1099,6 +1099,12 @@ static int rv770_startup(struct radeon_device *rdev)
        }
 
        /* 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);
@@ -1237,10 +1243,6 @@ int rv770_init(struct radeon_device *rdev)
        if (r)
                return r;
 
-       r = radeon_irq_kms_init(rdev);
-       if (r)
-               return r;
-
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
        r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
 
index 2dbd585c81f19926e37ed81e6c03cd0da1a5f146..e22b460a4f0c1b812bc7915e1cec203453acf19f 100644 (file)
@@ -3876,6 +3876,12 @@ static int si_startup(struct radeon_device *rdev)
        }
 
        /* Enable IRQ */
+       if (!rdev->irq.installed) {
+               r = radeon_irq_kms_init(rdev);
+               if (r)
+                       return r;
+       }
+
        r = si_irq_init(rdev);
        if (r) {
                DRM_ERROR("radeon: IH init failed (%d).\n", r);
@@ -4044,10 +4050,6 @@ int si_init(struct radeon_device *rdev)
        if (r)
                return r;
 
-       r = radeon_irq_kms_init(rdev);
-       if (r)
-               return r;
-
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        ring->ring_obj = NULL;
        r600_ring_init(rdev, ring, 1024 * 1024);