From: Hawking Zhang <[email protected]> Implement a driver path to read the IP discovery binary offset and size from DRIVER_SCRATCH registers BIOS signals usage by setting a feature flag that instructs the driver to use this method. Otherwise, fallback to legacy approach.
v2: Simplify discovery offset/size retrieval in get_tmr_info v3: Update get_tmr_info to cover discovery offset and size retrieval for both bare-metal and sriov Signed-off-by: Hawking Zhang <[email protected]> Reviewed-by: Likun Gao <[email protected]> Signed-off-by: Alex Deucher <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 165 ++++++++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h | 1 + 2 files changed, 93 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 415849bf568b7..36dc0add26f32 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -132,6 +132,7 @@ MODULE_FIRMWARE("amdgpu/picasso_ip_discovery.bin"); MODULE_FIRMWARE("amdgpu/arcturus_ip_discovery.bin"); MODULE_FIRMWARE("amdgpu/aldebaran_ip_discovery.bin"); +/* Note: These registers are consistent across all the SOCs */ #define mmIP_DISCOVERY_VERSION 0x16A00 #define mmRCC_CONFIG_MEMSIZE 0xde3 #define mmMP0_SMN_C2PMSG_33 0x16061 @@ -139,6 +140,10 @@ MODULE_FIRMWARE("amdgpu/aldebaran_ip_discovery.bin"); #define mmMM_INDEX_HI 0x6 #define mmMM_DATA 0x1 +#define mmDRIVER_SCRATCH_0 0x94 +#define mmDRIVER_SCRATCH_1 0x95 +#define mmDRIVER_SCRATCH_2 0x96 + static const char *hw_id_names[HW_ID_MAX] = { [MP1_HWID] = "MP1", [MP2_HWID] = "MP2", @@ -253,39 +258,12 @@ static int hw_id_map[MAX_HWIP] = { [ATU_HWIP] = ATU_HWID, }; -static int amdgpu_discovery_read_binary_from_sysmem(struct amdgpu_device *adev, uint8_t *binary) +static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev, + bool *is_tmr_in_sysmem) { - u64 tmr_offset, tmr_size, pos; - void *discv_regn; - int ret; - - ret = amdgpu_acpi_get_tmr_info(adev, &tmr_offset, &tmr_size); - if (ret) - return ret; - - pos = tmr_offset + tmr_size - DISCOVERY_TMR_OFFSET; - - /* This region is read-only and reserved from system use */ - discv_regn = memremap(pos, adev->discovery.size, MEMREMAP_WC); - if (discv_regn) { - memcpy(binary, discv_regn, adev->discovery.size); - memunmap(discv_regn); - return 0; - } - - return -ENOENT; -} - -#define IP_DISCOVERY_V2 2 -#define IP_DISCOVERY_V4 4 - -static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, - uint8_t *binary) -{ - bool sz_valid = true; - uint64_t vram_size; - int i, ret = 0; - u32 msg; + u64 vram_size, tmr_offset, tmr_size; + u32 msg, tmr_offset_lo, tmr_offset_hi; + int i, ret; if (!amdgpu_sriov_vf(adev)) { /* It can take up to two second for IFWI init to complete on some dGPUs, @@ -305,51 +283,93 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, } vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); - if (!vram_size || vram_size == U32_MAX) - sz_valid = false; + if (vram_size == U32_MAX) + return -ENXIO; + else if (!vram_size) + *is_tmr_in_sysmem = true; else - vram_size <<= 20; - - /* - * If in VRAM, discovery TMR is marked for reservation. If it is in system mem, - * then it is not required to be reserved. - */ - if (sz_valid) { - if (amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled) { - /* For SRIOV VFs with dynamic critical region enabled, - * we will get the IPD binary via below call. - * If dynamic critical is disabled, fall through to normal seq. - */ - if (amdgpu_virt_get_dynamic_data_info(adev, - AMD_SRIOV_MSG_IPD_TABLE_ID, binary, - &adev->discovery.size)) { - dev_err(adev->dev, - "failed to read discovery info from dynamic critical region."); - ret = -EINVAL; - goto exit; - } - } else { - uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET; + *is_tmr_in_sysmem = false; - amdgpu_device_vram_access(adev, pos, (uint32_t *)binary, - adev->discovery.size, false); - adev->discovery.reserve_tmr = true; + /* init the default tmr size and offset */ + adev->discovery.size = DISCOVERY_TMR_SIZE; + if (vram_size) + adev->discovery.offset = (vram_size << 20) - DISCOVERY_TMR_OFFSET; + + if (amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled) { + adev->discovery.offset = + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset; + adev->discovery.size = + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb << 10; + if (!adev->discovery.offset || !adev->discovery.size) + return -EINVAL; + } else { + tmr_size = RREG32(mmDRIVER_SCRATCH_2); + if (tmr_size) { + /* It's preferred to transition to PSP mailbox reg interface + * for both bare-metal and passthrough if available */ + adev->discovery.size = (u32)tmr_size; + tmr_offset_lo = RREG32(mmDRIVER_SCRATCH_0); + tmr_offset_hi = RREG32(mmDRIVER_SCRATCH_1); + adev->discovery.offset = ((u64)le32_to_cpu(tmr_offset_hi) << 32 | + le32_to_cpu(tmr_offset_lo)); + } else if (!vram_size) { + /* fall back to apci approach to query tmr offset if vram_size is 0 */ + ret = amdgpu_acpi_get_tmr_info(adev, &tmr_offset, &tmr_size); + if (ret) + return ret; + adev->discovery.size = (u32)tmr_size; + adev->discovery.offset = tmr_offset + tmr_size - DISCOVERY_TMR_OFFSET; } + } + + adev->discovery.bin = kzalloc(adev->discovery.size, GFP_KERNEL); + if (!adev->discovery.bin) + return -ENOMEM; + adev->discovery.debugfs_blob.data = adev->discovery.bin; + adev->discovery.debugfs_blob.size = adev->discovery.size; + + return 0; +} + +static int amdgpu_discovery_read_binary_from_sysmem(struct amdgpu_device *adev, uint8_t *binary) +{ + void *discv_regn; + + /* This region is read-only and reserved from system use */ + discv_regn = memremap(adev->discovery.offset, adev->discovery.size, MEMREMAP_WC); + if (discv_regn) { + memcpy(binary, discv_regn, adev->discovery.size); + memunmap(discv_regn); + return 0; + } + + return -ENOENT; +} + +#define IP_DISCOVERY_V2 2 +#define IP_DISCOVERY_V4 4 + +static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, + uint8_t *binary, + bool is_tmr_in_sysmem) +{ + int ret = 0; + + if (!is_tmr_in_sysmem) { + amdgpu_device_vram_access(adev, adev->discovery.offset, + (uint32_t *)binary, + adev->discovery.size, false); + adev->discovery.reserve_tmr = true; } else { ret = amdgpu_discovery_read_binary_from_sysmem(adev, binary); } - if (ret) - dev_err(adev->dev, - "failed to read discovery info from memory, vram size read: %llx", - vram_size); -exit: return ret; } static int amdgpu_discovery_read_binary_from_file(struct amdgpu_device *adev, - uint8_t *binary, - const char *fw_name) + uint8_t *binary, + const char *fw_name) { const struct firmware *fw; int r; @@ -602,14 +622,12 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) uint16_t size; uint16_t checksum; uint16_t table_id; + bool is_tmr_in_sysmem; int r; - adev->discovery.bin = kzalloc(DISCOVERY_TMR_SIZE, GFP_KERNEL); - if (!adev->discovery.bin) - return -ENOMEM; - adev->discovery.size = DISCOVERY_TMR_SIZE; - adev->discovery.debugfs_blob.data = adev->discovery.bin; - adev->discovery.debugfs_blob.size = adev->discovery.size; + r = amdgpu_discovery_get_tmr_info(adev, &is_tmr_in_sysmem); + if (r) + return r; discovery_bin = adev->discovery.bin; /* Read from file if it is the preferred option */ @@ -622,7 +640,8 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) goto out; } else { drm_dbg(&adev->ddev, "use ip discovery information from memory"); - r = amdgpu_discovery_read_binary_from_mem(adev, discovery_bin); + r = amdgpu_discovery_read_binary_from_mem(adev, discovery_bin, + is_tmr_in_sysmem); if (r) goto out; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h index 4ce04486cc319..0f8736b49f217 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h @@ -34,6 +34,7 @@ struct ip_discovery_top; struct amdgpu_discovery_info { struct debugfs_blob_wrapper debugfs_blob; struct ip_discovery_top *ip_top; + uint64_t offset; uint32_t size; uint8_t *bin; bool reserve_tmr; -- 2.53.0
