summaryrefslogtreecommitdiffstats
path: root/debian/patches/bugfix/all/radeon-amdgpu-firmware-is-required-for-drm-and-kms-on-r600-onward.patch
blob: fe502df7e1b864876f490d4d725605512124e4f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
From: Ben Hutchings <ben@decadent.org.uk>
Subject: radeon, amdgpu: Firmware is required for DRM and KMS on R600 onward
Date: Tue, 08 Jan 2013 03:25:52 +0000
Bug-Debian: https://bugs.debian.org/607194
Bug-Debian: https://bugs.debian.org/607471
Bug-Debian: https://bugs.debian.org/610851
Bug-Debian: https://bugs.debian.org/627497
Bug-Debian: https://bugs.debian.org/632212
Bug-Debian: https://bugs.debian.org/637943
Bug-Debian: https://bugs.debian.org/649448
Bug-Debian: https://bugs.debian.org/697229
Forwarded: no

radeon requires firmware/microcode for the GPU in all chips, but for
newer chips (apparently R600 'Evergreen' onward) it also expects
firmware for the memory controller and other sub-blocks.

radeon attempts to gracefully fall back and disable some features if
the firmware is not available, but becomes unstable - the framebuffer
and/or system memory may be corrupted, or the display may stay black.

Therefore, perform a basic check for the existence of
/lib/firmware/{radeon,amdgpu} when a device is probed, and abort if it
is missing, except for the pre-R600 case.

---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 29 ++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon_drv.c     | 30 +++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -39,6 +39,8 @@
 #include <linux/cc_platform.h>
 #include <linux/fb.h>
 #include <linux/dynamic_debug.h>
+#include <linux/namei.h>
+#include <linux/path.h>
 
 #include "amdgpu.h"
 #include "amdgpu_irq.h"
@@ -2039,6 +2041,28 @@ static void amdgpu_get_secondary_funcs(s
 	}
 }
 
+/* Test that /lib/firmware/amdgpu is a directory (or symlink to a
+ * directory).  We could try to match the udev search path, but let's
+ * keep it simple.
+ */
+static bool amdgpu_firmware_installed(void)
+{
+#if IS_BUILTIN(CONFIG_DRM_AMDGPU)
+	/* It may be too early to tell.  Assume it's there. */
+	return true;
+#else
+	struct path path;
+
+	if (kern_path("/lib/firmware/amdgpu", LOOKUP_DIRECTORY | LOOKUP_FOLLOW,
+		      &path) == 0) {
+		path_put(&path);
+		return true;
+	}
+
+	return false;
+#endif
+}
+
 static int amdgpu_pci_probe(struct pci_dev *pdev,
 			    const struct pci_device_id *ent)
 {
@@ -2122,6 +2146,11 @@ static int amdgpu_pci_probe(struct pci_d
 	}
 #endif
 
+	if (!amdgpu_firmware_installed()) {
+		DRM_ERROR("amdgpu requires firmware installed\n");
+		return -ENODEV;
+	}
+
 	adev = devm_drm_dev_alloc(&pdev->dev, &amdgpu_kms_driver, typeof(*adev), ddev);
 	if (IS_ERR(adev))
 		return PTR_ERR(adev);
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -48,6 +48,8 @@
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 #include <drm/radeon_drm.h>
+#include <linux/namei.h>
+#include <linux/path.h>
 
 #include "radeon_drv.h"
 #include "radeon.h"
@@ -284,6 +286,28 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 
 static const struct drm_driver kms_driver;
 
+/* Test that /lib/firmware/radeon is a directory (or symlink to a
+ * directory).  We could try to match the udev search path, but let's
+ * keep it simple.
+ */
+static bool radeon_firmware_installed(void)
+{
+#if IS_BUILTIN(CONFIG_DRM_RADEON)
+	/* It may be too early to tell.  Assume it's there. */
+	return true;
+#else
+	struct path path;
+
+	if (kern_path("/lib/firmware/radeon", LOOKUP_DIRECTORY | LOOKUP_FOLLOW,
+		      &path) == 0) {
+		path_put(&path);
+		return true;
+	}
+
+	return false;
+#endif
+}
+
 static int radeon_pci_probe(struct pci_dev *pdev,
 			    const struct pci_device_id *ent)
 {
@@ -324,6 +348,12 @@ static int radeon_pci_probe(struct pci_d
 	if (vga_switcheroo_client_probe_defer(pdev))
 		return -EPROBE_DEFER;
 
+	if ((ent->driver_data & RADEON_FAMILY_MASK) >= CHIP_R600 &&
+	    !radeon_firmware_installed()) {
+		DRM_ERROR("radeon kernel modesetting for R600 or later requires firmware installed\n");
+		return -ENODEV;
+	}
+
 	/* Get rid of things like offb */
 	ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &kms_driver);
 	if (ret)