VBIOS has a structure VRAM_UsageByFirmware to tell the driver that VBIOS need reserve some memory at the specified place on the VRAM. SR-IOV need to enable this feature to exchange data between PF and VF. So add two new method to create and free bo at the exact place. And add a new AMDGPU_GEM_CREATE_VRAM_SPECIFIED flag to tell function to set the ttm_placement to the exact place to avoid eviction whenpinnning. Signed-off-by: Horace Chen <horace.chen at amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 17 +++++ drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 18 ++++- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 58 ++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 109 ++++++++++++++++++++++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 8 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 9 +++ drivers/gpu/drm/amd/include/atombios.h | 1 + include/uapi/drm/amdgpu_drm.h | 2 + 8 files changed, 219 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index a5b0b67..ac53dba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1380,6 +1380,21 @@ struct amdgpu_atcs { }; /* + * Firmware VRAM reservation + */ +#define KB_TO_BYTE(x) ((x) << 10) +#define BYTE_TO_KB(x) ((x) >> 10) + +struct amdgpu_fw_vram_usage { + uint32_t start_address_in_kb; + uint16_t size_in_kb; + struct amdgpu_bo *reserved_bo; + volatile uint32_t *va; +}; + +int amdgpu_fw_reserve_vram_init(struct amdgpu_device *adev); + +/* * CGS */ struct cgs_device *amdgpu_cgs_create_device(struct amdgpu_device *adev); @@ -1588,6 +1603,8 @@ struct amdgpu_device { struct delayed_work late_init_work; struct amdgpu_virt virt; + /* firmware VRAM reservation */ + struct amdgpu_fw_vram_usage fw_vram_usage; /* link all shadow bo */ struct list_head shadow_list; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index ce44358..56bfddf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -1807,6 +1807,8 @@ int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev) uint16_t data_offset; int usage_bytes = 0; struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage; + uint32_t start_addr; + uint16_t size; if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) { firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); @@ -1815,7 +1817,21 @@ int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev) le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware), le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb)); - usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024; + start_addr = firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware; + size = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb; + + if ((uint32_t)(start_addr & ATOM_VRAM_OPERATION_FLAGS_MASK) == + (uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION << + ATOM_VRAM_OPERATION_FLAGS_SHIFT)) { + /* Firmware request VRAM reservation for SR-IOV */ + adev->fw_vram_usage.start_address_in_kb = + start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK); + adev->fw_vram_usage.size_in_kb = size; + /* Use the default scratch size */ + usage_bytes = 0; + } else { + usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024; + } } ctx->scratch_size_bytes = 0; if (usage_bytes == 0) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a86d856..51bee68 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -658,6 +658,62 @@ void amdgpu_gart_location(struct amdgpu_device *adev, struct amdgpu_mc *mc) } /* + * Firmware Reservation function + */ +/** + * amdgpu_fw_reserve_vram_fini - free fw reserved vram + * + * @adev: amdgpu_device pointer + * + * free fw reserved vram if it is reserved. + */ +void amdgpu_fw_reserve_vram_fini(struct amdgpu_device *adev) +{ + + if (adev->fw_vram_usage.reserved_bo == NULL) + return; + + amdgpu_bo_free_vram_specified(&adev->fw_vram_usage.reserved_bo, NULL, + (void **)&adev->fw_vram_usage.va); + adev->fw_vram_usage.reserved_bo = NULL; +} + +/** + * amdgpu_fw_reserve_vram_fini - create bo vram reservation from fw + * + * @adev: amdgpu_device pointer + * + * create bo vram reservation from fw. + */ +int amdgpu_fw_reserve_vram_init(struct amdgpu_device *adev) +{ + int r = 0; + u64 gpu_addr; + u64 vram_size = adev->mc.visible_vram_size; + + adev->fw_vram_usage.va = NULL; + adev->fw_vram_usage.reserved_bo = NULL; + + if (adev->fw_vram_usage.size_in_kb > 0 && + KB_TO_BYTE((u64)adev->fw_vram_usage.size_in_kb) <= vram_size) { + + r = amdgpu_bo_create_vram_specified(adev, + KB_TO_BYTE((u64)adev->fw_vram_usage.start_address_in_kb), + KB_TO_BYTE((u64)adev->fw_vram_usage.size_in_kb), + PAGE_SIZE, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | + AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, + &adev->fw_vram_usage.reserved_bo, + &gpu_addr, (void **)&adev->fw_vram_usage.va); + if (r) + dev_info(adev->dev, "Reserve VRAM for firmware failed"); + } + + return r; +} + + +/* * GPU helpers function. */ /** @@ -2055,6 +2111,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, adev->vm_manager.vm_pte_num_rings = 0; adev->gart.gart_funcs = NULL; adev->fence_context = dma_fence_context_alloc(AMDGPU_MAX_RINGS); + adev->fw_vram_usage.size_in_kb = 0; adev->smc_rreg = &amdgpu_invalid_rreg; adev->smc_wreg = &amdgpu_invalid_wreg; @@ -2331,6 +2388,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) /* evict vram memory */ amdgpu_bo_evict_vram(adev); amdgpu_ib_pool_fini(adev); + amdgpu_fw_reserve_vram_fini(adev); amdgpu_fence_driver_fini(adev); amdgpu_fbdev_fini(adev); r = amdgpu_fini(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 6982bae..8602784 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -87,6 +87,14 @@ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) if (flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS) places[c].flags |= TTM_PL_FLAG_CONTIGUOUS; + + if (flags & AMDGPU_GEM_CREATE_VRAM_SPECIFIED) { + /* specified vram must be contiguous */ + places[c].flags |= TTM_PL_FLAG_CONTIGUOUS; + places[c].fpfn = abo->start_address >> PAGE_SHIFT; + places[c].lpfn = + (abo->start_address + abo->gem_base.size) >> PAGE_SHIFT; + } c++; } @@ -284,6 +292,7 @@ void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr, } static int amdgpu_bo_do_create(struct amdgpu_device *adev, + u64 start_addr, unsigned long size, int byte_align, bool kernel, u32 domain, u64 flags, struct sg_table *sg, @@ -300,6 +309,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT; size = ALIGN(size, PAGE_SIZE); + start_addr = ALIGN(start_addr, PAGE_SIZE); if (kernel) { type = ttm_bo_type_kernel; @@ -333,6 +343,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, if (!kernel && bo->allowed_domains == AMDGPU_GEM_DOMAIN_VRAM) bo->allowed_domains |= AMDGPU_GEM_DOMAIN_GTT; + bo->start_address = start_addr; bo->flags = flags; #ifdef CONFIG_X86_32 @@ -418,6 +429,100 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, return r; } +/** + * amdgpu_bo_create_vram_specified - + * create BO at the specified place on the VRAM. + * + * @adev: amdgpu device object + * @start_addr: start offset of the new BO + * @size: size for the new BO + * @byte_align: alignment for the new BO + * @flags: addition flags for the BO + * @bo_ptr: resulting BO + * @gpu_addr: GPU addr of the pinned BO + * @cpu_addr: optional CPU address mapping + * + * Allocates and pins a BO at the specified place on the VRAM. + * + * Returns 0 on success, negative error code otherwise. + */ +int amdgpu_bo_create_vram_specified(struct amdgpu_device *adev, + u64 start_addr, unsigned long size, int byte_align, + u64 flags, struct amdgpu_bo **bo_ptr, + u64 *gpu_addr, void **cpu_addr) +{ + int r; + /* specified memory must be in contiguous*/ + flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; + flags |= AMDGPU_GEM_CREATE_VRAM_SPECIFIED; + + r = amdgpu_bo_do_create(adev, start_addr, size, byte_align, true, + AMDGPU_GEM_DOMAIN_VRAM, flags, NULL, NULL, 0, bo_ptr); + if (r) + return r; + + r = amdgpu_bo_reserve(*bo_ptr, false); + if (r) + goto error_reserve; + r = amdgpu_bo_pin_restricted(*bo_ptr, + AMDGPU_GEM_DOMAIN_VRAM, start_addr, (start_addr + size), + gpu_addr); + if (r) + goto error_pin; + if (cpu_addr) { + r = amdgpu_bo_kmap(*bo_ptr, + cpu_addr); + if (r) + goto error_kmap; + } + + amdgpu_bo_unreserve(*bo_ptr); + + return r; +error_kmap: + amdgpu_bo_unpin(*bo_ptr); +error_pin: + amdgpu_bo_unreserve(*bo_ptr); +error_reserve: + amdgpu_bo_unref(bo_ptr); + if (cpu_addr) + *cpu_addr = NULL; + if (gpu_addr) + *gpu_addr = 0; + return r; +} + +/** + * amdgpu_bo_free_vram_specified - free BO for specified vram + * + * @bo: amdgpu BO to free + * @gpu_addr : gpu address + * @cpu_addr : cpu address if mapped + * + * unmaps and unpin a BO for specified vram. + */ +void amdgpu_bo_free_vram_specified(struct amdgpu_bo **bo, u64 *gpu_addr, + void **cpu_addr) +{ + if (*bo == NULL) + return; + + if (likely(amdgpu_bo_reserve(*bo, true) == 0)) { + if (cpu_addr) + amdgpu_bo_kunmap(*bo); + amdgpu_bo_unpin(*bo); + amdgpu_bo_unreserve(*bo); + } + amdgpu_bo_unref(bo); + + if (gpu_addr) + *gpu_addr = 0; + + if (cpu_addr) + *cpu_addr = NULL; +} + + static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, unsigned long size, int byte_align, struct amdgpu_bo *bo) @@ -427,7 +532,7 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, if (bo->shadow) return 0; - r = amdgpu_bo_do_create(adev, size, byte_align, true, + r = amdgpu_bo_do_create(adev, 0, size, byte_align, true, AMDGPU_GEM_DOMAIN_GTT, AMDGPU_GEM_CREATE_CPU_GTT_USWC | AMDGPU_GEM_CREATE_SHADOW, @@ -457,7 +562,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, uint64_t parent_flags = flags & ~AMDGPU_GEM_CREATE_SHADOW; int r; - r = amdgpu_bo_do_create(adev, size, byte_align, kernel, domain, + r = amdgpu_bo_do_create(adev, 0, size, byte_align, kernel, domain, parent_flags, sg, resv, init_value, bo_ptr); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 39b6bf6..88f2c5a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -78,6 +78,8 @@ struct amdgpu_bo { void *metadata; u32 metadata_size; unsigned prime_shared_count; + /* specified VRAM place */ + u64 start_address; /* list of all virtual address to which this bo is associated to */ struct list_head va; /* Constant after initialization */ @@ -205,6 +207,12 @@ int amdgpu_bo_create_kernel(struct amdgpu_device *adev, u64 *gpu_addr, void **cpu_addr); void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr, void **cpu_addr); +int amdgpu_bo_create_vram_specified(struct amdgpu_device *adev, + u64 start_addr, unsigned long size, int byte_align, + u64 flags, struct amdgpu_bo **bo_ptr, + u64 *gpu_addr, void **cpu_addr); +void amdgpu_bo_free_vram_specified(struct amdgpu_bo **bo, u64 *gpu_addr, + void **cpu_addr); int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr); void *amdgpu_bo_kptr(struct amdgpu_bo *bo); void amdgpu_bo_kunmap(struct amdgpu_bo *bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 1086f03..a5253cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1256,6 +1256,15 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) /* Change the size here instead of the init above so only lpfn is affected */ amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); + /* + *The reserved vram for firmware must be pinned to the specified + *place on the VRAM, so reserve it early. + */ + r = amdgpu_fw_reserve_vram_init(adev); + if (r) { + return r; + } + r = amdgpu_bo_create_kernel(adev, adev->mc.stolen_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, &adev->stolen_vga_memory, diff --git a/drivers/gpu/drm/amd/include/atombios.h b/drivers/gpu/drm/amd/include/atombios.h index 181a2c3..f696bbb 100644 --- a/drivers/gpu/drm/amd/include/atombios.h +++ b/drivers/gpu/drm/amd/include/atombios.h @@ -4292,6 +4292,7 @@ typedef struct _ATOM_DPCD_INFO #define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30 #define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 #define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0 +#define ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION 0x2 /***********************************************************************************/ // Structure used in VRAM_UsageByFirmwareTable diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 9f5bd97..8c213f0 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -91,6 +91,8 @@ extern "C" { #define AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS (1 << 5) /* Flag that BO is always valid in this VM */ #define AMDGPU_GEM_CREATE_VM_ALWAYS_VALID (1 << 6) +/* Flag that allocating the BO at the specified place on VRAM*/ +#define AMDGPU_GEM_CREATE_VRAM_SPECIFIED (1 << 7) struct drm_amdgpu_gem_create_in { /** the requested memory size */ -- 2.7.4