Move the initialization of non-GPU resources out of the full GPU access region during AMDGPU device initialization
Signed-off-by: chong li <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 10 +- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 131 ++++++++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 138 +++++++++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 2 + 4 files changed, 181 insertions(+), 100 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 5442a1fc1c37..247779cbf394 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1953,10 +1953,6 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) amdgpu_device_enable_virtual_display(adev); if (amdgpu_sriov_vf(adev)) { - r = amdgpu_virt_request_full_gpu(adev, true); - if (r) - return r; - r = amdgpu_virt_init_critical_region(adev); if (r) return r; @@ -2118,6 +2114,12 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) if (!total) return -ENODEV; + if (amdgpu_sriov_vf(adev)) { + r = amdgpu_virt_request_full_gpu(adev, true); + if (r) + return r; + } + if (adev->gmc.xgmi.supported) amdgpu_xgmi_early_init(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 029931f4e6ed..26916ebca452 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -26,6 +26,7 @@ #include "amdgpu.h" #include "amdgpu_discovery.h" +#include "amdgpu_virt.h" #include "soc15_hw_ip.h" #include "discovery.h" #include "amdgpu_ras.h" @@ -292,21 +293,54 @@ static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev, 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, - * but generally it should be in the 60-100ms range. Normally this starts - * as soon as the device gets power so by the time the OS loads this has long - * completed. However, when a card is hotplugged via e.g., USB4, we need to - * wait for this to complete. Once the C2PMSG is updated, we can - * continue. - */ + if (amdgpu_sriov_vf(adev)) { + u32 ipd_size_kb = + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb; + + *is_tmr_in_sysmem = false; + + if (ipd_size_kb) { + adev->discovery.offset = + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset; + adev->discovery.size = ipd_size_kb << 10; + if (!adev->discovery.size) + return -EINVAL; + } else if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V1) { + vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); + if (vram_size == U32_MAX) + return -ENXIO; + else if (!vram_size) + return -ENODEV; - for (i = 0; i < 2000; i++) { - msg = RREG32(mmMP0_SMN_C2PMSG_33); - if (msg & 0x80000000) - break; - msleep(1); + adev->discovery.size = DISCOVERY_TMR_SIZE; + adev->discovery.offset = (vram_size << 20) - DISCOVERY_TMR_OFFSET; + } else if (amdgpu_sriov_xgmi_connected_to_cpu(adev)) { + ret = amdgpu_acpi_get_tmr_info(adev, &tmr_offset, &tmr_size); + if (ret) + return ret; + + *is_tmr_in_sysmem = true; + adev->discovery.size = DISCOVERY_TMR_SIZE; + adev->discovery.offset = tmr_offset + tmr_size - DISCOVERY_TMR_OFFSET; + } else { + return -EINVAL; } + goto out; + } + + /* It can take up to two second for IFWI init to complete on some dGPUs, + * but generally it should be in the 60-100ms range. Normally this starts + * as soon as the device gets power so by the time the OS loads this has long + * completed. However, when a card is hotplugged via e.g., USB4, we need to + * wait for this to complete. Once the C2PMSG is updated, we can + * continue. + */ + + for (i = 0; i < 2000; i++) { + msg = RREG32(mmMP0_SMN_C2PMSG_33); + if (msg & 0x80000000) + break; + msleep(1); } vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); @@ -322,35 +356,22 @@ static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev, if (vram_size) adev->discovery.offset = (vram_size << 20) - DISCOVERY_TMR_OFFSET; - if (amdgpu_sriov_vf(adev)) { - if (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.size) - return -EINVAL; - } else { - goto out; - } - } 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 = DISCOVERY_TMR_SIZE; - adev->discovery.offset = tmr_offset + tmr_size - DISCOVERY_TMR_OFFSET; - } + 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 = DISCOVERY_TMR_SIZE; + adev->discovery.offset = tmr_offset + tmr_size - DISCOVERY_TMR_OFFSET; } out: adev->discovery.bin = kzalloc(adev->discovery.size, GFP_KERNEL); @@ -384,23 +405,21 @@ 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) + return amdgpu_discovery_read_binary_from_sysmem(adev, binary); - if (!is_tmr_in_sysmem) { - if (amdgpu_sriov_vf(adev) && - amdgpu_sriov_xgmi_connected_to_cpu(adev)) { - ret = amdgpu_discovery_read_binary_from_sysmem(adev, binary); - } else { - 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 (amdgpu_sriov_vf(adev)) { + adev->discovery.reserve_tmr = true; + return amdgpu_virt_read_vf_fb(adev, adev->discovery.offset, + binary, adev->discovery.size); } - return ret; + amdgpu_device_vram_access(adev, adev->discovery.offset, + (uint32_t *)binary, + adev->discovery.size, false); + adev->discovery.reserve_tmr = true; + + return 0; } static int amdgpu_discovery_read_binary_from_file(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 7b0d42510161..9ade91ff9394 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -754,8 +754,7 @@ static int amdgpu_virt_read_exchange_data_from_mem(struct amdgpu_device *adev, u adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset; uint32_t dataexchange_size = adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb << 10; - uint64_t pos = 0; - + int ret; dev_info(adev->dev, "Got data exchange info from dynamic crit_region_table at offset 0x%x with size of 0x%x bytes.\n", dataexchange_offset, dataexchange_size); @@ -764,12 +763,10 @@ static int amdgpu_virt_read_exchange_data_from_mem(struct amdgpu_device *adev, u dev_err(adev->dev, "Data exchange data not aligned to 4 bytes\n"); return -EINVAL; } + ret = amdgpu_virt_read_vf_fb(adev, dataexchange_offset, pfvf_data, + dataexchange_size); - pos = (uint64_t)dataexchange_offset; - amdgpu_device_vram_access(adev, pos, pfvf_data, - dataexchange_size, false); - - return 0; + return ret; } void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev) @@ -802,7 +799,7 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) schedule_delayed_work(&(adev->virt.vf2pf_work), msecs_to_jiffies(adev->virt.vf2pf_update_interval_ms)); } else if (adev->bios != NULL) { /* got through this logic in early init stage to get necessary flags, e.g. rlcg_acc related*/ - if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V2) { + if (adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb) { pfvf_data = kzalloc(adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb << 10, GFP_KERNEL); @@ -1014,38 +1011,89 @@ static uint8_t amdgpu_virt_crit_region_calc_checksum(uint8_t *buf_start, uint8_t return 0xffffffff - sum; } -int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) +int amdgpu_virt_read_vf_fb(struct amdgpu_device *adev, u64 offset, + void *buf, size_t size) { - struct amd_sriov_msg_init_data_header *init_data_hdr = NULL; - u64 init_hdr_offset = adev->virt.init_data_header.offset; - u64 init_hdr_size = (u64)adev->virt.init_data_header.size_kb << 10; /* KB → bytes */ - u64 vram_size; + resource_size_t bar_start, bar_size, map_base; + void __iomem *vram; + size_t map_offset, map_size; u64 end; - int r = 0; - uint8_t checksum = 0; - /* Skip below init if critical region version != v2 */ - if (adev->virt.req_init_data_ver != GPU_CRIT_REGION_V2) - return 0; - - vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); - if (!vram_size || vram_size == U32_MAX) + if (!buf || !size) return -EINVAL; - vram_size <<= 20; - if (check_add_overflow(init_hdr_offset, init_hdr_size, &end) || end > vram_size) { - dev_err(adev->dev, "init_data_header exceeds VRAM size, exiting\n"); + bar_size = pci_resource_len(adev->pdev, 0); + if (!bar_size) + return -ENODEV; + + if (check_add_overflow(offset, size, &end) || end > bar_size) { + dev_err(adev->dev, + "VF FB read exceeds BAR0 size: offset=0x%llx size=0x%zx BAR0=0x%llx\n", + offset, size, (u64)bar_size); return -EINVAL; } + bar_start = pci_resource_start(adev->pdev, 0); + map_offset = offset_in_page(offset); + map_base = bar_start + (offset & PAGE_MASK); + map_size = PAGE_ALIGN(map_offset + size); + + vram = ioremap_wc(map_base, map_size); + if (!vram) + return -ENOMEM; + + memcpy_fromio(buf, (u8 __iomem *)vram + map_offset, size); + iounmap(vram); + + return 0; +} + +static int amdgpu_virt_init_critical_region_v1(struct amdgpu_device *adev) +{ + memset(&adev->virt.crit_regn, 0, sizeof(adev->virt.crit_regn)); + memset(adev->virt.crit_regn_tbl, 0, sizeof(adev->virt.crit_regn_tbl)); + + adev->virt.crit_regn.offset = 0; + adev->virt.crit_regn.size_kb = AMD_SRIOV_MSG_INIT_DATA_TOT_SIZE_KB_V1; + + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID].offset = + AMD_SRIOV_MSG_VBIOS_OFFSET_V1; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_VBIOS_IMG_TABLE_ID].size_kb = + AMD_SRIOV_MSG_VBIOS_SIZE_KB_V1; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].offset = + AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].size_kb = + AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset = + AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB_V1 << 10; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb = + AMD_SRIOV_MSG_DATAEXCHANGE_SIZE_KB_V1; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID].offset = + AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB_V1 << 10; + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_BAD_PAGE_INFO_TABLE_ID].size_kb = + AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB_V1; + + adev->virt.is_dynamic_crit_regn_enabled = true; + + return 0; +} + +static int amdgpu_virt_init_critical_region_v2(struct amdgpu_device *adev) +{ + struct amd_sriov_msg_init_data_header *init_data_hdr = NULL; + u64 init_hdr_offset = adev->virt.init_data_header.offset; + int r = 0; + uint8_t checksum = 0; + /* Allocate for init_data_hdr */ init_data_hdr = kzalloc(sizeof(struct amd_sriov_msg_init_data_header), GFP_KERNEL); if (!init_data_hdr) return -ENOMEM; - amdgpu_device_vram_access(adev, (uint64_t)init_hdr_offset, (uint32_t *)init_data_hdr, - sizeof(struct amd_sriov_msg_init_data_header), false); - + r = amdgpu_virt_read_vf_fb(adev, init_hdr_offset, init_data_hdr, + sizeof(struct amd_sriov_msg_init_data_header)); + if (r) + goto out; /* Table validation */ if (strncmp(init_data_hdr->signature, AMDGPU_SRIOV_CRIT_DATA_SIGNATURE, @@ -1158,16 +1206,6 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) goto out; } - /* reserved memory starts from crit region base offset with the size of 5MB */ - amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE, - adev->virt.crit_regn.offset, - adev->virt.crit_regn.size_kb << 10, true); - dev_info(adev->dev, - "critical region v%d requested to reserve memory start at %08llx with %llu KB.\n", - init_data_hdr->version, - adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].offset, - adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size >> 10); - adev->virt.is_dynamic_crit_regn_enabled = true; out: @@ -1177,6 +1215,16 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) return r; } +int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) +{ + if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V1) + return amdgpu_virt_init_critical_region_v1(adev); + else if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V2) + return amdgpu_virt_init_critical_region_v2(adev); + + return 0; +} + int amdgpu_virt_get_dynamic_data_info(struct amdgpu_device *adev, int data_id, uint8_t *binary, u32 *size) { @@ -1193,10 +1241,20 @@ int amdgpu_virt_get_dynamic_data_info(struct amdgpu_device *adev, /* Validate on input params */ if (!binary || !size || *size < (uint64_t)data_size) return -EINVAL; + /* + * Proceed to copy the dynamic content. During early VF init the normal + * VRAM aperture is not mapped yet, so read directly from the VF FB BAR. + */ + if (amdgpu_sriov_vf(adev)) { + int r; - /* Proceed to copy the dynamic content */ - amdgpu_device_vram_access(adev, - (uint64_t)data_offset, (uint32_t *)binary, data_size, false); + r = amdgpu_virt_read_vf_fb(adev, data_offset, binary, data_size); + if (r) + return r; + } else { + amdgpu_device_vram_access(adev, (uint64_t)data_offset, + (uint32_t *)binary, data_size, false); + } *size = (uint64_t)data_size; dev_dbg(adev->dev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index d8500c3e48a1..1ffd6065c6be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -452,6 +452,8 @@ static inline bool is_virtual_machine(void) ((adev)->virt.is_xgmi_node_migrate_enabled && (adev)->gmc.xgmi.node_segment_size != 0) bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev); +int amdgpu_virt_read_vf_fb(struct amdgpu_device *adev, u64 offset, + void *buf, size_t size); void amdgpu_virt_init_setting(struct amdgpu_device *adev); int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init); int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init); -- 2.48.1
