Adds support for IP discovery via PSP mailbox using guest phys addr for passthrough A+A.
Keep the discovery firmware file as the preferred source. Use the mailbox only when no firmware file is selected and the device is in passthrough with a zero-sized BAR0. The mailbox registers are fixed MMIO indexes. This runs before IP discovery has programmed the hardware register bases. Signed-off-by: Dejan Andjelkovic <[email protected]> --- v5 -> v6: - Drop the post-wait status read in amdgpu_psp_read_discovery(). drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 6 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 61 +++++++++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 2 + drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h | 4 +- 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 5a32b54b1e9b..20570ab1d2c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1019,6 +1019,11 @@ static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_device *bdev) return container_of(bdev, struct amdgpu_device, mman.bdev); } +static inline bool amdgpu_is_spm_passthrough(struct amdgpu_device *adev) +{ + return amdgpu_passthrough(adev) && !pci_resource_len(adev->pdev, 0); +} + static inline bool amdgpu_is_multi_aid(struct amdgpu_device *adev) { return !!adev->aid_mask; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 79a2b1268b23..8b976e363f16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -771,6 +771,12 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) fw_name); if (r) goto out; + } else if (amdgpu_is_spm_passthrough(adev)) { + drm_dbg(&adev->ddev, "use ip discovery information from psp mailbox\n"); + r = amdgpu_psp_read_discovery(adev, discovery_bin, + GFX_CTRL_ADDR_TYPE_GUEST_PHY_ADDR); + if (r) + goto out; } else { drm_dbg(&adev->ddev, "use ip discovery information from memory\n"); r = amdgpu_discovery_read_binary_from_mem(adev, discovery_bin, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index c0ed3e24b684..50861175d661 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -52,6 +52,12 @@ #define PSP_IRQ_DEFAULT_HANDLER_ID 0xFFFFFFFF +/* Note: These are pre-IP-discovery fixed MMIO indexes */ +#define mmMP0_SMN_C2PMSG_64_MMIO 0x16080 +#define mmMP0_SMN_C2PMSG_69_MMIO 0x16085 +#define mmMP0_SMN_C2PMSG_70_MMIO 0x16086 +#define mmMP0_SMN_C2PMSG_71_MMIO 0x16087 + static int psp_load_smu_fw(struct psp_context *psp); static int psp_rap_terminate(struct psp_context *psp); static int psp_securedisplay_terminate(struct psp_context *psp); @@ -761,17 +767,13 @@ static int psp_sw_fini(struct amdgpu_ip_block *ip_block) return 0; } -int psp_wait_for(struct psp_context *psp, uint32_t reg_index, uint32_t reg_val, - uint32_t mask, uint32_t flags) +static int __psp_wait_for(struct amdgpu_device *adev, uint32_t reg_index, uint32_t reg_val, + uint32_t mask, uint32_t flags) { bool check_changed = flags & PSP_WAITREG_CHANGED; bool verbose = !(flags & PSP_WAITREG_NOVERBOSE); uint32_t val; int i; - struct amdgpu_device *adev = psp->adev; - - if (psp->adev->no_hw_access) - return 0; for (i = 0; i < adev->usec_timeout; i++) { val = RREG32(reg_index); @@ -793,6 +795,17 @@ int psp_wait_for(struct psp_context *psp, uint32_t reg_index, uint32_t reg_val, return -ETIME; } +int psp_wait_for(struct psp_context *psp, uint32_t reg_index, uint32_t reg_val, + uint32_t mask, uint32_t flags) +{ + struct amdgpu_device *adev = psp->adev; + + if (psp->adev->no_hw_access) + return 0; + + return __psp_wait_for(adev, reg_index, reg_val, mask, flags); +} + int psp_wait_for_spirom_update(struct psp_context *psp, uint32_t reg_index, uint32_t reg_val, uint32_t mask, uint32_t msec_timeout) { @@ -3347,6 +3360,42 @@ int psp_securedisplay_invoke(struct psp_context *psp, uint32_t ta_cmd_id) } /* SECUREDISPLAY end */ +int amdgpu_psp_read_discovery(struct amdgpu_device *adev, uint8_t *binary, + GFX_CTRL_ADDR_TYPE addr_type) +{ + void *cpu_addr; + dma_addr_t dma_addr; + u32 length; + int ret; + + cpu_addr = dma_alloc_coherent(adev->dev, adev->discovery.size, + &dma_addr, GFP_KERNEL); + if (!cpu_addr) + return -ENOMEM; + + length = adev->discovery.size; + length = (length & 0x0fffffffU) | ((u32)addr_type << 28); + + WREG32(mmMP0_SMN_C2PMSG_69_MMIO, lower_32_bits((u64)dma_addr)); + WREG32(mmMP0_SMN_C2PMSG_70_MMIO, upper_32_bits((u64)dma_addr)); + WREG32(mmMP0_SMN_C2PMSG_71_MMIO, length); + + WREG32(mmMP0_SMN_C2PMSG_64_MMIO, GFX_CTRL_CMD_ID_GET_IP_DISCOVERY); + + ret = __psp_wait_for(adev, mmMP0_SMN_C2PMSG_64_MMIO, + MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, + PSP_WAITREG_NOVERBOSE); + if (ret) { + dev_err(adev->dev, "ip_discovery: PSP cmd failed\n"); + } else { + memcpy(binary, cpu_addr, adev->discovery.size); + } + + dma_free_coherent(adev->dev, adev->discovery.size, cpu_addr, dma_addr); + + return ret; +} + int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev) { struct psp_context *psp = &adev->psp; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 975d12359358..fe3d053d9924 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -688,6 +688,8 @@ int psp_memory_partition(struct psp_context *psp, int mode); int is_psp_fw_valid(struct psp_bin_desc bin); +int amdgpu_psp_read_discovery(struct amdgpu_device *adev, uint8_t *binary, + GFX_CTRL_ADDR_TYPE addr_type); int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev); bool amdgpu_psp_get_ras_capability(struct psp_context *psp); diff --git a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h index 49aa95c76745..d13ae1756887 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h +++ b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h @@ -49,6 +49,7 @@ enum psp_gfx_crtl_cmd_id GFX_CTRL_CMD_ID_GBR_IH_SET = 0x00080000, /* set Gbr IH_RB_CNTL registers */ GFX_CTRL_CMD_ID_CONSUME_CMD = 0x00090000, /* send interrupt to psp for updating write pointer of vf */ GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING = 0x000C0000, /* destroy GPCOM ring */ + GFX_CTRL_CMD_ID_GET_IP_DISCOVERY = 0x000D0000, /* Copy IP_DISCOVERY_DATA to host-specified address */ GFX_CTRL_CMD_ID_MAX = 0x000F0000, /* max command ID */ }; @@ -58,7 +59,8 @@ typedef enum GFX_CTRL_ADDR_TYPE_AUTO_DETECT = 0, GFX_CTRL_ADDR_TYPE_SYS_PHY_ADDR, GFX_CTRL_ADDR_TYPE_GPU_PHY_ADDR, - GFX_CTRL_ADDR_TYPE_GPU_VIRT_ADDR + GFX_CTRL_ADDR_TYPE_GPU_VIRT_ADDR, + GFX_CTRL_ADDR_TYPE_GUEST_PHY_ADDR } GFX_CTRL_ADDR_TYPE; /*----------------------------------------------------------------------------- -- 2.43.0
