]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.0.89/drm-radeon-fix-combios-tables-on-older-cards.patch
Linux 4.14.124
[thirdparty/kernel/stable-queue.git] / releases / 3.0.89 / drm-radeon-fix-combios-tables-on-older-cards.patch
CommitLineData
52a765f8
GKH
1From cef1d00cd56f600121ad121875655ad410a001b8 Mon Sep 17 00:00:00 2001
2From: Mark Kettenis <kettenis@openbsd.org>
3Date: Sun, 21 Jul 2013 16:44:09 -0400
4Subject: drm/radeon: fix combios tables on older cards
5
6From: Mark Kettenis <kettenis@openbsd.org>
7
8commit cef1d00cd56f600121ad121875655ad410a001b8 upstream.
9
10Noticed that my old Radeon 7500 hung after printing
11
12 drm: GPU not posted. posting now...
13
14when it wasn't selected as the primary card the BIOS. Some digging
15revealed that it was hanging in combios_parse_mmio_table() while
16parsing the ASIC INIT 3 table. Looking at the BIOS ROM for the card,
17it becomes obvious that there is no ASIC INIT 3 table in the BIOS.
18The code is just processing random garbage. No surprise it hangs!
19
20Why do I say that there is no ASIC INIT 3 table is the BIOS? This
21table is found through the MISC INFO table. The MISC INFO table can
22be found at offset 0x5e in the COMBIOS header. But the header is
23smaller than that. The COMBIOS header starts at offset 0x126. The
24standard PCI Data Structure (the bit that starts with 'PCIR') lives at
25offset 0x180. That means that the COMBIOS header can not be larger
26than 0x5a bytes and therefore cannot contain a MISC INFO table.
27
28I looked at a dozen or so BIOS images, some my own, some downloaded from:
29
30 <http://www.techpowerup.com/vgabios/index.php?manufacturer=ATI&page=1>
31
32It is fairly obvious that the size of the COMBIOS header can be found
33at offset 0x6 of the header. Not sure if it is a 16-bit number or
34just an 8-bit number, but that doesn't really matter since the tables
35seems to be always smaller than 256 bytes.
36
37So I think combios_get_table_offset() should check if the requested
38table is present. This can be done by checking the offset against the
39size of the header. See the diff below. The diff is against the WIP
40OpenBSD codebase that roughly corresponds to Linux 3.8.13 at this
41point. But I don't think this bit of the code changed much since
42then.
43
44For what it is worth:
45
46Signed-off-by: Mark Kettenis <kettenis@openbsd.org>
47Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
48Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
49
50---
51 drivers/gpu/drm/radeon/radeon_combios.c | 145 +++++++++-----------------------
52 1 file changed, 41 insertions(+), 104 deletions(-)
53
54--- a/drivers/gpu/drm/radeon/radeon_combios.c
55+++ b/drivers/gpu/drm/radeon/radeon_combios.c
56@@ -147,7 +147,7 @@ static uint16_t combios_get_table_offset
57 enum radeon_combios_table_offset table)
58 {
59 struct radeon_device *rdev = dev->dev_private;
60- int rev;
61+ int rev, size;
62 uint16_t offset = 0, check_offset;
63
64 if (!rdev->bios)
65@@ -156,174 +156,106 @@ static uint16_t combios_get_table_offset
66 switch (table) {
67 /* absolute offset tables */
68 case COMBIOS_ASIC_INIT_1_TABLE:
69- check_offset = RBIOS16(rdev->bios_header_start + 0xc);
70- if (check_offset)
71- offset = check_offset;
72+ check_offset = 0xc;
73 break;
74 case COMBIOS_BIOS_SUPPORT_TABLE:
75- check_offset = RBIOS16(rdev->bios_header_start + 0x14);
76- if (check_offset)
77- offset = check_offset;
78+ check_offset = 0x14;
79 break;
80 case COMBIOS_DAC_PROGRAMMING_TABLE:
81- check_offset = RBIOS16(rdev->bios_header_start + 0x2a);
82- if (check_offset)
83- offset = check_offset;
84+ check_offset = 0x2a;
85 break;
86 case COMBIOS_MAX_COLOR_DEPTH_TABLE:
87- check_offset = RBIOS16(rdev->bios_header_start + 0x2c);
88- if (check_offset)
89- offset = check_offset;
90+ check_offset = 0x2c;
91 break;
92 case COMBIOS_CRTC_INFO_TABLE:
93- check_offset = RBIOS16(rdev->bios_header_start + 0x2e);
94- if (check_offset)
95- offset = check_offset;
96+ check_offset = 0x2e;
97 break;
98 case COMBIOS_PLL_INFO_TABLE:
99- check_offset = RBIOS16(rdev->bios_header_start + 0x30);
100- if (check_offset)
101- offset = check_offset;
102+ check_offset = 0x30;
103 break;
104 case COMBIOS_TV_INFO_TABLE:
105- check_offset = RBIOS16(rdev->bios_header_start + 0x32);
106- if (check_offset)
107- offset = check_offset;
108+ check_offset = 0x32;
109 break;
110 case COMBIOS_DFP_INFO_TABLE:
111- check_offset = RBIOS16(rdev->bios_header_start + 0x34);
112- if (check_offset)
113- offset = check_offset;
114+ check_offset = 0x34;
115 break;
116 case COMBIOS_HW_CONFIG_INFO_TABLE:
117- check_offset = RBIOS16(rdev->bios_header_start + 0x36);
118- if (check_offset)
119- offset = check_offset;
120+ check_offset = 0x36;
121 break;
122 case COMBIOS_MULTIMEDIA_INFO_TABLE:
123- check_offset = RBIOS16(rdev->bios_header_start + 0x38);
124- if (check_offset)
125- offset = check_offset;
126+ check_offset = 0x38;
127 break;
128 case COMBIOS_TV_STD_PATCH_TABLE:
129- check_offset = RBIOS16(rdev->bios_header_start + 0x3e);
130- if (check_offset)
131- offset = check_offset;
132+ check_offset = 0x3e;
133 break;
134 case COMBIOS_LCD_INFO_TABLE:
135- check_offset = RBIOS16(rdev->bios_header_start + 0x40);
136- if (check_offset)
137- offset = check_offset;
138+ check_offset = 0x40;
139 break;
140 case COMBIOS_MOBILE_INFO_TABLE:
141- check_offset = RBIOS16(rdev->bios_header_start + 0x42);
142- if (check_offset)
143- offset = check_offset;
144+ check_offset = 0x42;
145 break;
146 case COMBIOS_PLL_INIT_TABLE:
147- check_offset = RBIOS16(rdev->bios_header_start + 0x46);
148- if (check_offset)
149- offset = check_offset;
150+ check_offset = 0x46;
151 break;
152 case COMBIOS_MEM_CONFIG_TABLE:
153- check_offset = RBIOS16(rdev->bios_header_start + 0x48);
154- if (check_offset)
155- offset = check_offset;
156+ check_offset = 0x48;
157 break;
158 case COMBIOS_SAVE_MASK_TABLE:
159- check_offset = RBIOS16(rdev->bios_header_start + 0x4a);
160- if (check_offset)
161- offset = check_offset;
162+ check_offset = 0x4a;
163 break;
164 case COMBIOS_HARDCODED_EDID_TABLE:
165- check_offset = RBIOS16(rdev->bios_header_start + 0x4c);
166- if (check_offset)
167- offset = check_offset;
168+ check_offset = 0x4c;
169 break;
170 case COMBIOS_ASIC_INIT_2_TABLE:
171- check_offset = RBIOS16(rdev->bios_header_start + 0x4e);
172- if (check_offset)
173- offset = check_offset;
174+ check_offset = 0x4e;
175 break;
176 case COMBIOS_CONNECTOR_INFO_TABLE:
177- check_offset = RBIOS16(rdev->bios_header_start + 0x50);
178- if (check_offset)
179- offset = check_offset;
180+ check_offset = 0x50;
181 break;
182 case COMBIOS_DYN_CLK_1_TABLE:
183- check_offset = RBIOS16(rdev->bios_header_start + 0x52);
184- if (check_offset)
185- offset = check_offset;
186+ check_offset = 0x52;
187 break;
188 case COMBIOS_RESERVED_MEM_TABLE:
189- check_offset = RBIOS16(rdev->bios_header_start + 0x54);
190- if (check_offset)
191- offset = check_offset;
192+ check_offset = 0x54;
193 break;
194 case COMBIOS_EXT_TMDS_INFO_TABLE:
195- check_offset = RBIOS16(rdev->bios_header_start + 0x58);
196- if (check_offset)
197- offset = check_offset;
198+ check_offset = 0x58;
199 break;
200 case COMBIOS_MEM_CLK_INFO_TABLE:
201- check_offset = RBIOS16(rdev->bios_header_start + 0x5a);
202- if (check_offset)
203- offset = check_offset;
204+ check_offset = 0x5a;
205 break;
206 case COMBIOS_EXT_DAC_INFO_TABLE:
207- check_offset = RBIOS16(rdev->bios_header_start + 0x5c);
208- if (check_offset)
209- offset = check_offset;
210+ check_offset = 0x5c;
211 break;
212 case COMBIOS_MISC_INFO_TABLE:
213- check_offset = RBIOS16(rdev->bios_header_start + 0x5e);
214- if (check_offset)
215- offset = check_offset;
216+ check_offset = 0x5e;
217 break;
218 case COMBIOS_CRT_INFO_TABLE:
219- check_offset = RBIOS16(rdev->bios_header_start + 0x60);
220- if (check_offset)
221- offset = check_offset;
222+ check_offset = 0x60;
223 break;
224 case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE:
225- check_offset = RBIOS16(rdev->bios_header_start + 0x62);
226- if (check_offset)
227- offset = check_offset;
228+ check_offset = 0x62;
229 break;
230 case COMBIOS_COMPONENT_VIDEO_INFO_TABLE:
231- check_offset = RBIOS16(rdev->bios_header_start + 0x64);
232- if (check_offset)
233- offset = check_offset;
234+ check_offset = 0x64;
235 break;
236 case COMBIOS_FAN_SPEED_INFO_TABLE:
237- check_offset = RBIOS16(rdev->bios_header_start + 0x66);
238- if (check_offset)
239- offset = check_offset;
240+ check_offset = 0x66;
241 break;
242 case COMBIOS_OVERDRIVE_INFO_TABLE:
243- check_offset = RBIOS16(rdev->bios_header_start + 0x68);
244- if (check_offset)
245- offset = check_offset;
246+ check_offset = 0x68;
247 break;
248 case COMBIOS_OEM_INFO_TABLE:
249- check_offset = RBIOS16(rdev->bios_header_start + 0x6a);
250- if (check_offset)
251- offset = check_offset;
252+ check_offset = 0x6a;
253 break;
254 case COMBIOS_DYN_CLK_2_TABLE:
255- check_offset = RBIOS16(rdev->bios_header_start + 0x6c);
256- if (check_offset)
257- offset = check_offset;
258+ check_offset = 0x6c;
259 break;
260 case COMBIOS_POWER_CONNECTOR_INFO_TABLE:
261- check_offset = RBIOS16(rdev->bios_header_start + 0x6e);
262- if (check_offset)
263- offset = check_offset;
264+ check_offset = 0x6e;
265 break;
266 case COMBIOS_I2C_INFO_TABLE:
267- check_offset = RBIOS16(rdev->bios_header_start + 0x70);
268- if (check_offset)
269- offset = check_offset;
270+ check_offset = 0x70;
271 break;
272 /* relative offset tables */
273 case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */
274@@ -439,11 +371,16 @@ static uint16_t combios_get_table_offset
275 }
276 break;
277 default:
278+ check_offset = 0;
279 break;
280 }
281
282- return offset;
283+ size = RBIOS8(rdev->bios_header_start + 0x6);
284+ /* check absolute offset tables */
285+ if (table < COMBIOS_ASIC_INIT_3_TABLE && check_offset && check_offset < size)
286+ offset = RBIOS16(rdev->bios_header_start + check_offset);
287
288+ return offset;
289 }
290
291 bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)