drm/amdgpu: properly handle vbios fake edid sizing
authorjsg <jsg@openbsd.org>
Mon, 7 Oct 2024 05:12:00 +0000 (05:12 +0000)
committerjsg <jsg@openbsd.org>
Mon, 7 Oct 2024 05:12:00 +0000 (05:12 +0000)
From Alex Deucher
78b9e10b3bd1bb04c40f9f12b899951a6904772b in linux-6.6.y/6.6.54
8155566a26b8d6c1dd914f06a0c652e4e2f2adf1 in mainline linux

sys/dev/pci/drm/amd/amdgpu/amdgpu_atombios_encoders.c

index d95b2dc..157e898 100644 (file)
@@ -2065,26 +2065,29 @@ amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder)
                                        fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
                                        if (fake_edid_record->ucFakeEDIDLength) {
                                                struct edid *edid;
-                                               int edid_size =
-                                                       max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);
-                                               edid = kmalloc(edid_size, GFP_KERNEL);
+                                               int edid_size;
+
+                                               if (fake_edid_record->ucFakeEDIDLength == 128)
+                                                       edid_size = fake_edid_record->ucFakeEDIDLength;
+                                               else
+                                                       edid_size = fake_edid_record->ucFakeEDIDLength * 128;
+                                               edid = kmemdup(&fake_edid_record->ucFakeEDIDString[0],
+                                                              edid_size, GFP_KERNEL);
                                                if (edid) {
-                                                       memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
-                                                              fake_edid_record->ucFakeEDIDLength);
-
                                                        if (drm_edid_is_valid(edid)) {
                                                                adev->mode_info.bios_hardcoded_edid = edid;
                                                                adev->mode_info.bios_hardcoded_edid_size = edid_size;
-                                                       } else
+                                                       } else {
                                                                kfree(edid);
+                                                       }
                                                }
+                                               record += struct_size(fake_edid_record,
+                                                                     ucFakeEDIDString,
+                                                                     edid_size);
+                                       } else {
+                                               /* empty fake edid record must be 3 bytes long */
+                                               record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
                                        }
-                                       record += fake_edid_record->ucFakeEDIDLength ?
-                                                 struct_size(fake_edid_record,
-                                                             ucFakeEDIDString,
-                                                             fake_edid_record->ucFakeEDIDLength) :
-                                                 /* empty fake edid record must be 3 bytes long */
-                                                 sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
                                        break;
                                case LCD_PANEL_RESOLUTION_RECORD_TYPE:
                                        panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;