Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/amd/display: Add additional checks for PSP footer size

[WHY & HOW]
Newer ASICs have different PSP footer sizes which lead to driver
failing to locate the DMCUB FW meta info, which in turn causes
improper DMCUB FW loading and causes DMCUB to crash.

Add support for custom PSP footer sizes and check 512B by default
as well.

Reviewed-by: Charlene Liu <charlene.liu@amd.com>
Signed-off-by: Ovidiu Bunea <ovidiu.bunea@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Ovidiu Bunea and committed by
Alex Deucher
e1b38572 c7062be3

+119 -30
+31 -20
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 152 152 #define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin" 153 153 MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB); 154 154 155 - /* Number of bytes in PSP header for firmware. */ 156 - #define PSP_HEADER_BYTES 0x100 157 - 158 - /* Number of bytes in PSP footer for firmware. */ 159 - #define PSP_FOOTER_BYTES 0x100 160 - 161 155 /** 162 156 * DOC: overview 163 157 * ··· 1292 1298 1293 1299 fw_inst_const = dmub_fw->data + 1294 1300 le32_to_cpu(hdr->header.ucode_array_offset_bytes) + 1295 - PSP_HEADER_BYTES; 1301 + PSP_HEADER_BYTES_256; 1296 1302 1297 1303 fw_bss_data = dmub_fw->data + 1298 1304 le32_to_cpu(hdr->header.ucode_array_offset_bytes) + 1299 1305 le32_to_cpu(hdr->inst_const_bytes); 1300 1306 1301 1307 /* Copy firmware and bios info into FB memory. */ 1302 - fw_inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - 1303 - PSP_HEADER_BYTES - PSP_FOOTER_BYTES; 1308 + fw_inst_const_size = adev->dm.fw_inst_size; 1304 1309 1305 1310 fw_bss_data_size = le32_to_cpu(hdr->bss_data_bytes); 1306 1311 ··· 2430 2437 static int dm_dmub_sw_init(struct amdgpu_device *adev) 2431 2438 { 2432 2439 struct dmub_srv_create_params create_params; 2440 + struct dmub_srv_fw_meta_info_params fw_meta_info_params; 2433 2441 struct dmub_srv_region_params region_params; 2434 2442 struct dmub_srv_region_info region_info; 2435 2443 struct dmub_srv_memory_params memory_params; 2444 + struct dmub_fw_meta_info fw_info; 2436 2445 struct dmub_srv_fb_info *fb_info; 2437 2446 struct dmub_srv *dmub_srv; 2438 2447 const struct dmcub_firmware_header_v1_0 *hdr; ··· 2542 2547 return -EINVAL; 2543 2548 } 2544 2549 2550 + /* Extract the FW meta info. */ 2551 + memset(&fw_meta_info_params, 0, sizeof(fw_meta_info_params)); 2552 + 2553 + fw_meta_info_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - 2554 + PSP_HEADER_BYTES_256; 2555 + fw_meta_info_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); 2556 + fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data + 2557 + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + 2558 + PSP_HEADER_BYTES_256; 2559 + fw_meta_info_params.fw_bss_data = region_params.bss_data_size ? adev->dm.dmub_fw->data + 2560 + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + 2561 + le32_to_cpu(hdr->inst_const_bytes) : NULL; 2562 + fw_meta_info_params.custom_psp_footer_size = 0; 2563 + 2564 + status = dmub_srv_get_fw_meta_info_from_raw_fw(&fw_meta_info_params, &fw_info); 2565 + if (status != DMUB_STATUS_OK) { 2566 + /* Skip returning early, just log the error. */ 2567 + drm_err(adev_to_drm(adev), "Error getting DMUB FW meta info: %d\n", status); 2568 + // return -EINVAL; 2569 + } 2570 + 2545 2571 /* Calculate the size of all the regions for the DMUB service. */ 2546 2572 memset(&region_params, 0, sizeof(region_params)); 2547 2573 2548 - region_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - 2549 - PSP_HEADER_BYTES - PSP_FOOTER_BYTES; 2550 - region_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); 2574 + region_params.inst_const_size = fw_meta_info_params.inst_const_size; 2575 + region_params.bss_data_size = fw_meta_info_params.bss_data_size; 2551 2576 region_params.vbios_size = adev->bios_size; 2552 - region_params.fw_bss_data = region_params.bss_data_size ? 2553 - adev->dm.dmub_fw->data + 2554 - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + 2555 - le32_to_cpu(hdr->inst_const_bytes) : NULL; 2556 - region_params.fw_inst_const = 2557 - adev->dm.dmub_fw->data + 2558 - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + 2559 - PSP_HEADER_BYTES; 2577 + region_params.fw_bss_data = fw_meta_info_params.fw_bss_data; 2578 + region_params.fw_inst_const = fw_meta_info_params.fw_inst_const; 2560 2579 region_params.window_memory_type = window_memory_type; 2580 + region_params.fw_info = (status == DMUB_STATUS_OK) ? &fw_info : NULL; 2561 2581 2562 2582 status = dmub_srv_calc_region_info(dmub_srv, &region_params, 2563 2583 &region_info); ··· 2619 2609 } 2620 2610 2621 2611 adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev); 2612 + adev->dm.fw_inst_size = fw_meta_info_params.inst_const_size; 2622 2613 2623 2614 return 0; 2624 2615 }
+7
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
··· 414 414 uint32_t dmcub_fw_version; 415 415 416 416 /** 417 + * @fw_inst_size: 418 + * 419 + * Size of the firmware instruction buffer. 420 + */ 421 + uint32_t fw_inst_size; 422 + 423 + /** 417 424 * @cgs_device: 418 425 * 419 426 * The Common Graphics Services device. It provides an interface for
+1
drivers/gpu/drm/amd/display/dc/dc.h
··· 1188 1188 short auxless_alpm_lfps_t1t2_offset_us; 1189 1189 bool disable_stutter_for_wm_program; 1190 1190 bool enable_block_sequence_programming; 1191 + uint32_t custom_psp_footer_size; 1191 1192 }; 1192 1193 1193 1194
+33
drivers/gpu/drm/amd/display/dmub/dmub_srv.h
··· 72 72 /* Default tracebuffer size if meta is absent. */ 73 73 #define DMUB_TRACE_BUFFER_SIZE (64 * 1024) 74 74 75 + #define PSP_HEADER_BYTES_256 0x100 // 256 bytes 76 + #define PSP_FOOTER_BYTES_256 0x100 // 256 bytes 77 + 75 78 /* Forward declarations */ 76 79 struct dmub_srv; 77 80 struct dmub_srv_common_regs; ··· 230 227 const uint8_t *fw_inst_const; 231 228 const uint8_t *fw_bss_data; 232 229 const enum dmub_window_memory_type *window_memory_type; 230 + const struct dmub_fw_meta_info *fw_info; 231 + }; 232 + 233 + /** 234 + * struct dmub_srv_fw_meta_info_params - params used for fetching fw meta info from fw_image 235 + * @inst_const_size: size of the fw inst const section 236 + * @bss_data_size: size of the fw bss data section 237 + * @fw_inst_const: raw firmware inst const section 238 + * @fw_bss_data: raw firmware bss data section 239 + * @custom_psp_footer_size: custom psp footer size to use when indexing for fw meta info 240 + */ 241 + struct dmub_srv_fw_meta_info_params { 242 + uint32_t inst_const_size; 243 + uint32_t bss_data_size; 244 + const uint8_t *fw_inst_const; 245 + const uint8_t *fw_bss_data; 246 + uint32_t custom_psp_footer_size; 233 247 }; 234 248 235 249 /** ··· 269 249 uint32_t gart_size; 270 250 uint8_t num_regions; 271 251 struct dmub_region regions[DMUB_WINDOW_TOTAL]; 252 + uint32_t verified_psp_footer_size; 272 253 }; 273 254 274 255 /** ··· 1118 1097 * false - preos fw info not retrieved successfully 1119 1098 */ 1120 1099 bool dmub_srv_get_preos_info(struct dmub_srv *dmub); 1100 + 1101 + /** 1102 + * dmub_srv_get_fw_meta_info_from_raw_fw() - Fetch firmware metadata info from raw firmware image 1103 + * @params: parameters for fetching firmware metadata info 1104 + * @fw_info_out: output buffer for firmware metadata info 1105 + * 1106 + * Return: 1107 + * DMUB_STATUS_OK - success 1108 + * DMUB_STATUS_INVALID - no FW meta info found 1109 + */ 1110 + enum dmub_status dmub_srv_get_fw_meta_info_from_raw_fw(struct dmub_srv_fw_meta_info_params *params, 1111 + struct dmub_fw_meta_info *fw_info_out); 1121 1112 1122 1113 #endif /* _DMUB_SRV_H_ */
+47 -10
drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
··· 134 134 } 135 135 136 136 static const struct dmub_fw_meta_info * 137 - dmub_get_fw_meta_info(const struct dmub_srv_region_params *params) 137 + dmub_get_fw_meta_info(const struct dmub_srv_fw_meta_info_params *params) 138 138 { 139 139 const struct dmub_fw_meta_info *info = NULL; 140 140 ··· 157 157 } 158 158 159 159 return info; 160 + } 161 + 162 + enum dmub_status 163 + dmub_srv_get_fw_meta_info_from_raw_fw(struct dmub_srv_fw_meta_info_params *params, 164 + struct dmub_fw_meta_info *fw_info_out) 165 + { 166 + const struct dmub_fw_meta_info *fw_info = NULL; 167 + uint32_t inst_const_size_temp = params->inst_const_size; 168 + 169 + /* First try custom psp footer size, if present */ 170 + if (params->custom_psp_footer_size) { 171 + params->inst_const_size -= params->custom_psp_footer_size; 172 + fw_info = dmub_get_fw_meta_info(params); 173 + if (fw_info) { 174 + memcpy(fw_info_out, fw_info, sizeof(*fw_info)); 175 + return DMUB_STATUS_OK; 176 + } 177 + params->inst_const_size = inst_const_size_temp; 178 + } 179 + 180 + /* Try 256-byte psp footer size */ 181 + params->inst_const_size -= PSP_FOOTER_BYTES_256; 182 + fw_info = dmub_get_fw_meta_info(params); 183 + if (fw_info) { 184 + memcpy(fw_info_out, fw_info, sizeof(*fw_info)); 185 + return DMUB_STATUS_OK; 186 + } 187 + 188 + /* Try 512-byte psp footer size - final attempt */ 189 + params->inst_const_size -= PSP_FOOTER_BYTES_256; // 256 bytes already subtracted, subtract 256 again 190 + fw_info = dmub_get_fw_meta_info(params); 191 + if (fw_info) { 192 + memcpy(fw_info_out, fw_info, sizeof(*fw_info)); 193 + return DMUB_STATUS_OK; 194 + } 195 + 196 + /* Restore original inst_const_size and subtract default PSP footer size - default behaviour */ 197 + params->inst_const_size = inst_const_size_temp - PSP_FOOTER_BYTES_256; 198 + 199 + return DMUB_STATUS_INVALID; 160 200 } 161 201 162 202 static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) ··· 564 524 const struct dmub_srv_region_params *params, 565 525 struct dmub_srv_region_info *out) 566 526 { 567 - const struct dmub_fw_meta_info *fw_info; 568 527 uint32_t fw_state_size = DMUB_FW_STATE_SIZE; 569 528 uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE; 570 529 uint32_t shared_state_size = DMUB_FW_HEADER_SHARED_STATE_SIZE; ··· 577 538 578 539 out->num_regions = DMUB_NUM_WINDOWS; 579 540 580 - fw_info = dmub_get_fw_meta_info(params); 541 + if (params->fw_info) { 542 + memcpy(&dmub->meta_info, params->fw_info, sizeof(*params->fw_info)); 581 543 582 - if (fw_info) { 583 - memcpy(&dmub->meta_info, fw_info, sizeof(*fw_info)); 584 - 585 - fw_state_size = fw_info->fw_region_size; 586 - trace_buffer_size = fw_info->trace_buffer_size; 587 - shared_state_size = fw_info->shared_state_size; 544 + fw_state_size = params->fw_info->fw_region_size; 545 + trace_buffer_size = params->fw_info->trace_buffer_size; 546 + shared_state_size = params->fw_info->shared_state_size; 588 547 589 548 /** 590 549 * If DM didn't fill in a version, then fill it in based on ··· 592 555 * pass during creation. 593 556 */ 594 557 if (dmub->fw_version == 0) 595 - dmub->fw_version = fw_info->fw_version; 558 + dmub->fw_version = params->fw_info->fw_version; 596 559 } 597 560 598 561 window_sizes[DMUB_WINDOW_0_INST_CONST] = params->inst_const_size;