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

drm/amdgpu/vce: Move firmware load to amdgpu_vce_early_init

Try to load the VCE firmware at early_init.

When the correct firmware is not found, return -ENOENT.
This way, the driver initialization will complete even
without VCE, and the GPU will be functional, albeit
without video encoding capabilities.

This is necessary because we are planning to add support
for the VCE1, and AMD hasn't yet publised the correct
firmware for this version. So we need to anticipate that
users will try to boot amdgpu on SI GPUs without the
correct VCE1 firmware present on their system.

Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Leo Liu <leo.liu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Timur Kristóf and committed by
Alex Deucher
f2e18c94 43a0ca33

+91 -46
+75 -46
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
··· 88 88 bool direct, struct dma_fence **fence); 89 89 90 90 /** 91 - * amdgpu_vce_sw_init - allocate memory, load vce firmware 91 + * amdgpu_vce_firmware_name() - determine the firmware file name for VCE 92 92 * 93 93 * @adev: amdgpu_device pointer 94 - * @size: size for the new BO 95 94 * 96 - * First step to get VCE online, allocate memory and load the firmware 95 + * Each chip that has VCE IP may need a different firmware. 96 + * This function returns the name of the VCE firmware file 97 + * appropriate for the current chip. 97 98 */ 98 - int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) 99 + static const char *amdgpu_vce_firmware_name(struct amdgpu_device *adev) 99 100 { 100 - const char *fw_name; 101 - const struct common_firmware_header *hdr; 102 - unsigned int ucode_version, version_major, version_minor, binary_id; 103 - int i, r; 104 - 105 101 switch (adev->asic_type) { 106 102 #ifdef CONFIG_DRM_AMDGPU_CIK 107 103 case CHIP_BONAIRE: 108 - fw_name = FIRMWARE_BONAIRE; 109 - break; 104 + return FIRMWARE_BONAIRE; 110 105 case CHIP_KAVERI: 111 - fw_name = FIRMWARE_KAVERI; 112 - break; 106 + return FIRMWARE_KAVERI; 113 107 case CHIP_KABINI: 114 - fw_name = FIRMWARE_KABINI; 115 - break; 108 + return FIRMWARE_KABINI; 116 109 case CHIP_HAWAII: 117 - fw_name = FIRMWARE_HAWAII; 118 - break; 110 + return FIRMWARE_HAWAII; 119 111 case CHIP_MULLINS: 120 - fw_name = FIRMWARE_MULLINS; 121 - break; 112 + return FIRMWARE_MULLINS; 122 113 #endif 123 114 case CHIP_TONGA: 124 - fw_name = FIRMWARE_TONGA; 125 - break; 115 + return FIRMWARE_TONGA; 126 116 case CHIP_CARRIZO: 127 - fw_name = FIRMWARE_CARRIZO; 128 - break; 117 + return FIRMWARE_CARRIZO; 129 118 case CHIP_FIJI: 130 - fw_name = FIRMWARE_FIJI; 131 - break; 119 + return FIRMWARE_FIJI; 132 120 case CHIP_STONEY: 133 - fw_name = FIRMWARE_STONEY; 134 - break; 121 + return FIRMWARE_STONEY; 135 122 case CHIP_POLARIS10: 136 - fw_name = FIRMWARE_POLARIS10; 137 - break; 123 + return FIRMWARE_POLARIS10; 138 124 case CHIP_POLARIS11: 139 - fw_name = FIRMWARE_POLARIS11; 140 - break; 125 + return FIRMWARE_POLARIS11; 141 126 case CHIP_POLARIS12: 142 - fw_name = FIRMWARE_POLARIS12; 143 - break; 127 + return FIRMWARE_POLARIS12; 144 128 case CHIP_VEGAM: 145 - fw_name = FIRMWARE_VEGAM; 146 - break; 129 + return FIRMWARE_VEGAM; 147 130 case CHIP_VEGA10: 148 - fw_name = FIRMWARE_VEGA10; 149 - break; 131 + return FIRMWARE_VEGA10; 150 132 case CHIP_VEGA12: 151 - fw_name = FIRMWARE_VEGA12; 152 - break; 133 + return FIRMWARE_VEGA12; 153 134 case CHIP_VEGA20: 154 - fw_name = FIRMWARE_VEGA20; 155 - break; 135 + return FIRMWARE_VEGA20; 156 136 157 137 default: 158 - return -EINVAL; 138 + return NULL; 159 139 } 140 + } 141 + 142 + /** 143 + * amdgpu_vce_early_init() - try to load VCE firmware 144 + * 145 + * @adev: amdgpu_device pointer 146 + * 147 + * Tries to load the VCE firmware. 148 + * 149 + * When not found, returns ENOENT so that the driver can 150 + * still load and initialize the rest of the IP blocks. 151 + * The GPU can function just fine without VCE, they will just 152 + * not support video encoding. 153 + */ 154 + int amdgpu_vce_early_init(struct amdgpu_device *adev) 155 + { 156 + const char *fw_name = amdgpu_vce_firmware_name(adev); 157 + const struct common_firmware_header *hdr; 158 + unsigned int ucode_version, version_major, version_minor, binary_id; 159 + int r; 160 + 161 + if (!fw_name) 162 + return -ENOENT; 160 163 161 164 r = amdgpu_ucode_request(adev, &adev->vce.fw, AMDGPU_UCODE_REQUIRED, "%s", fw_name); 162 165 if (r) { 163 - dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n", 164 - fw_name); 166 + dev_err(adev->dev, 167 + "amdgpu_vce: Firmware \"%s\" not found or failed to validate (%d)\n", 168 + fw_name, r); 169 + 165 170 amdgpu_ucode_release(&adev->vce.fw); 166 - return r; 171 + return -ENOENT; 167 172 } 168 173 169 174 hdr = (const struct common_firmware_header *)adev->vce.fw->data; ··· 177 172 version_major = (ucode_version >> 20) & 0xfff; 178 173 version_minor = (ucode_version >> 8) & 0xfff; 179 174 binary_id = ucode_version & 0xff; 180 - DRM_INFO("Found VCE firmware Version: %d.%d Binary ID: %d\n", 175 + dev_info(adev->dev, "Found VCE firmware Version: %d.%d Binary ID: %d\n", 181 176 version_major, version_minor, binary_id); 182 177 adev->vce.fw_version = ((version_major << 24) | (version_minor << 16) | 183 178 (binary_id << 8)); 179 + 180 + return 0; 181 + } 182 + 183 + /** 184 + * amdgpu_vce_sw_init() - allocate memory for VCE BO 185 + * 186 + * @adev: amdgpu_device pointer 187 + * @size: size for the new BO 188 + * 189 + * First step to get VCE online: allocate memory for VCE BO. 190 + * The VCE firmware binary is copied into the VCE BO later, 191 + * in amdgpu_vce_resume. The VCE executes its code from the 192 + * VCE BO and also uses the space in this BO for its stack and data. 193 + * 194 + * Ideally this BO should be placed in VRAM for optimal performance, 195 + * although technically it also runs from system RAM (albeit slowly). 196 + */ 197 + int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) 198 + { 199 + int i, r; 200 + 201 + if (!adev->vce.fw) 202 + return -ENOENT; 184 203 185 204 r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE, 186 205 AMDGPU_GEM_DOMAIN_VRAM |
+1
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
··· 53 53 unsigned num_rings; 54 54 }; 55 55 56 + int amdgpu_vce_early_init(struct amdgpu_device *adev); 56 57 int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size); 57 58 int amdgpu_vce_sw_fini(struct amdgpu_device *adev); 58 59 int amdgpu_vce_entity_init(struct amdgpu_device *adev, struct amdgpu_ring *ring);
+5
drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
··· 407 407 static int vce_v2_0_early_init(struct amdgpu_ip_block *ip_block) 408 408 { 409 409 struct amdgpu_device *adev = ip_block->adev; 410 + int r; 411 + 412 + r = amdgpu_vce_early_init(adev); 413 + if (r) 414 + return r; 410 415 411 416 adev->vce.num_rings = 2; 412 417
+5
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
··· 399 399 static int vce_v3_0_early_init(struct amdgpu_ip_block *ip_block) 400 400 { 401 401 struct amdgpu_device *adev = ip_block->adev; 402 + int r; 402 403 403 404 adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 404 405 ··· 407 406 (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 408 407 (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 409 408 return -ENOENT; 409 + 410 + r = amdgpu_vce_early_init(adev); 411 + if (r) 412 + return r; 410 413 411 414 adev->vce.num_rings = 3; 412 415
+5
drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
··· 410 410 static int vce_v4_0_early_init(struct amdgpu_ip_block *ip_block) 411 411 { 412 412 struct amdgpu_device *adev = ip_block->adev; 413 + int r; 414 + 415 + r = amdgpu_vce_early_init(adev); 416 + if (r) 417 + return r; 413 418 414 419 if (amdgpu_sriov_vf(adev)) /* currently only VCN0 support SRIOV */ 415 420 adev->vce.num_rings = 1;