On 2020-03-04 10:56, Andrey Grodzovsky wrote: > > On 3/3/20 6:14 PM, Luben Tuikov wrote: >> On 2020-03-03 17:02, Andrey Grodzovsky wrote: >>> Add the programming sequence. >>> >>> v2: >>> Change donwload wait loop to more efficient. >>> Move C2PMSG_CMD_GFX_USB_PD_FW_VER defintion >>> >>> v3: Fix lack of loop counter increment typo >>> >>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@xxxxxxx> >>> --- >>> drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h | 3 ++ >>> drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 82 +++++++++++++++++++++++++++++++++ >>> 2 files changed, 85 insertions(+) >>> >>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h >>> index 36b6579..a44fd60 100644 >>> --- a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h >>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h >>> @@ -31,6 +31,9 @@ >>> #define GFX_CMD_RESERVED_MASK 0x7FF00000 >>> #define GFX_CMD_RESPONSE_MASK 0x80000000 >>> >>> +/* USBC PD FW version retrieval command */ >>> +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x2000000 >>> + >>> /* TEE Gfx Command IDs for the register interface. >>> * Command ID must be between 0x00010000 and 0x000F0000. >>> */ >>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c >>> index 8ab3bf3..3db1c0d 100644 >>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c >>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c >>> @@ -65,6 +65,9 @@ MODULE_FIRMWARE("amdgpu/arcturus_ta.bin"); >>> /* memory training timeout define */ >>> #define MEM_TRAIN_SEND_MSG_TIMEOUT_US 3000000 >>> >>> +/* For large FW files the time to complete can be very long */ >>> +#define USBC_PD_POLLING_LIMIT_S 240 >>> + >>> static int psp_v11_0_init_microcode(struct psp_context *psp) >>> { >>> struct amdgpu_device *adev = psp->adev; >>> @@ -1109,6 +1112,83 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value) >>> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value); >>> } >>> >>> +static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_addr) >>> +{ >>> + struct amdgpu_device *adev = psp->adev; >>> + uint32_t reg_status; >>> + int ret, i = 0; >>> + >>> + /* Write lower 32-bit address of the PD Controller FW */ >>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, lower_32_bits(dma_addr)); >>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), >>> + 0x80000000, 0x80000000, false); >>> + if (ret) >>> + return ret; >>> + >>> + /* Fireup interrupt so PSP can pick up the lower address */ >>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x800000); >>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), >>> + 0x80000000, 0x80000000, false); >>> + if (ret) >>> + return ret; >>> + >>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); >>> + >>> + if ((reg_status & 0xFFFF) != 0) { >>> + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n", >>> + reg_status & 0xFFFF); >>> + return -EIO; >>> + } >>> + >>> + /* Write upper 32-bit address of the PD Controller FW */ >>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, upper_32_bits(dma_addr)); >>> + >>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), >>> + 0x80000000, 0x80000000, false); >>> + if (ret) >>> + return ret; >>> + >>> + /* Fireup interrupt so PSP can pick up the upper address */ >>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000); >>> + >>> + /* FW load takes very long time */ >>> + do { >>> + msleep(1000); >>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); >>> + >>> + if (reg_status & 0x80000000) >>> + goto done; >>> + >>> + } while(i++ < USBC_PD_POLLING_LIMIT_S); >> 1. The LKCS wants a space after a keyword ("while") and before parenthesis "(". >> >> 2. In do-while loops, you want to pre-increment, in order to account for the >> already executed iteration of the loop, since the check is done _after_ >> the loop executes, in contrast to "for" and "while" loops. So you'll need >> to do this: >> >> } while (++i < USBC_PD_POLLING_LIMIT_S); >> >>> + >>> + return -ETIME; >>> +done: >>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); >> 3. You had _just_ read the register, right before the goto jump. >> You do not need to read it again. (Else a race would exist, >> and you'd need to poll, _again_.) You shouldn't have to >> read it again. > > > Just went with AlexJ over the relevant PSP code - seems you are right, > both the completion bit (31) and result status bits (bits 0-15) are set > within a single statement and hence the last read inside the loop should > be enough. Will fix, > > Still, I don't see a race in the original code - just a superfluous > register read. There is no race in the original code. I said "would exist", as I knew it doesn't. I knew bit 31 and the address are updated in one go, else there would've been a race and you'd have to poll again. But since you don't, they are updated in one go and no polling needs to be and no race exist: therefore you don't need to read the register again. Thanks in advance for fixing those three issues. Let's see the fixed version of the patch. Regards, Luben > > Andrey > > >> >>> + >>> + if ((reg_status & 0xFFFF) != 0) { >>> + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = x%04x\n", >>> + reg_status & 0xFFFF); >>> + return -EIO; >>> + } >> With those fixed, this patch is, >> Reviewed-by: Luben Tuikov <luben.tuikov@xxxxxxx> >> >> Regards, >> Luben >> >> >> >>> + >>> + return 0; >>> +} >>> + >>> +static int psp_v11_0_read_usbc_pd_fw(struct psp_context *psp, uint32_t *fw_ver) >>> +{ >>> + struct amdgpu_device *adev = psp->adev; >>> + int ret; >>> + >>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, C2PMSG_CMD_GFX_USB_PD_FW_VER); >>> + >>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), >>> + 0x80000000, 0x80000000, false); >>> + if (!ret) >>> + *fw_ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36); >>> + >>> + return ret; >>> +} >>> + >>> static const struct psp_funcs psp_v11_0_funcs = { >>> .init_microcode = psp_v11_0_init_microcode, >>> .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb, >>> @@ -1133,6 +1213,8 @@ static const struct psp_funcs psp_v11_0_funcs = { >>> .mem_training = psp_v11_0_memory_training, >>> .ring_get_wptr = psp_v11_0_ring_get_wptr, >>> .ring_set_wptr = psp_v11_0_ring_set_wptr, >>> + .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw, >>> + .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw >>> }; >>> >>> void psp_v11_0_set_psp_funcs(struct psp_context *psp) >>> _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx