drm/amdgpu: Reserve shared memory on VRAM for SR-IOV
authorHorace Chen <horace.chen@amd.com>
Fri, 29 Sep 2017 06:41:57 +0000 (14:41 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 9 Oct 2017 20:30:16 +0000 (16:30 -0400)
SR-IOV need to reserve a piece of shared VRAM at the exact place
to exchange data betweem PF and VF. The start address and size of
the shared mem are passed to guest through VBIOS structure
VRAM_UsageByFirmware.

VRAM_UsageByFirmware is a general feature in VBIOS, it indicates
that VBIOS need to reserve a piece of memory on the VRAM.

Because the mem address is specified. Reserve it early in
amdgpu_ttm_init to make sure that it can monoplize the space.

Signed-off-by: Horace Chen <horace.chen@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c

index a23b8af953191702346df39260312709e72daa07..5c4bed7778d95aa2895bd5a7f2e4c8145fbe1a76 100644 (file)
@@ -1378,6 +1378,18 @@ struct amdgpu_atcs {
        struct amdgpu_atcs_functions functions;
 };
 
+/*
+ * Firmware VRAM reservation
+ */
+struct amdgpu_fw_vram_usage {
+       u64 start_offset;
+       u64 size;
+       struct amdgpu_bo *reserved_bo;
+       void *va;
+};
+
+int amdgpu_fw_reserve_vram_init(struct amdgpu_device *adev);
+
 /*
  * CGS
  */
@@ -1582,6 +1594,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;
index ce443586a0c71c13bd36472558473c0beae9b081..f66d33e4bacae88ad9e0e4d08478820836c56d7b 100644 (file)
@@ -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;
+       u64 start_addr;
+       u64 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_offset = (start_addr &
+                               (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
+                       adev->fw_vram_usage.size = size << 10;
+                       /* 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)
index 1949d8aedf49ef2c4b0f0a59edd7efa7e486aa6c..7b3e3b5461c33ce7b12ad658c57343c48d20c8cf 100644 (file)
@@ -657,6 +657,81 @@ void amdgpu_gart_location(struct amdgpu_device *adev, struct amdgpu_mc *mc)
                        mc->gart_size >> 20, mc->gart_start, mc->gart_end);
 }
 
+/*
+ * Firmware Reservation functions
+ */
+/**
+ * amdgpu_fw_reserve_vram_fini - free fw reserved vram
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * free fw reserved vram if it has been reserved.
+ */
+void amdgpu_fw_reserve_vram_fini(struct amdgpu_device *adev)
+{
+       amdgpu_bo_free_kernel(&adev->fw_vram_usage.reserved_bo,
+               NULL, &adev->fw_vram_usage.va);
+}
+
+/**
+ * amdgpu_fw_reserve_vram_init - 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 > 0 &&
+               adev->fw_vram_usage.size <= vram_size) {
+
+               r = amdgpu_bo_create(adev, adev->fw_vram_usage.size,
+                       PAGE_SIZE, true, 0,
+                       AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
+                       AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, NULL, NULL, 0,
+                       &adev->fw_vram_usage.reserved_bo);
+               if (r)
+                       goto error_create;
+
+               r = amdgpu_bo_reserve(adev->fw_vram_usage.reserved_bo, false);
+               if (r)
+                       goto error_reserve;
+               r = amdgpu_bo_pin_restricted(adev->fw_vram_usage.reserved_bo,
+                       AMDGPU_GEM_DOMAIN_VRAM,
+                       adev->fw_vram_usage.start_offset,
+                       (adev->fw_vram_usage.start_offset +
+                       adev->fw_vram_usage.size), &gpu_addr);
+               if (r)
+                       goto error_pin;
+               r = amdgpu_bo_kmap(adev->fw_vram_usage.reserved_bo,
+                       &adev->fw_vram_usage.va);
+               if (r)
+                       goto error_kmap;
+
+               amdgpu_bo_unreserve(adev->fw_vram_usage.reserved_bo);
+       }
+       return r;
+
+error_kmap:
+       amdgpu_bo_unpin(adev->fw_vram_usage.reserved_bo);
+error_pin:
+       amdgpu_bo_unreserve(adev->fw_vram_usage.reserved_bo);
+error_reserve:
+       amdgpu_bo_unref(&adev->fw_vram_usage.reserved_bo);
+error_create:
+       adev->fw_vram_usage.va = NULL;
+       adev->fw_vram_usage.reserved_bo = NULL;
+       return r;
+}
+
+
 /*
  * GPU helpers function.
  */
@@ -2300,6 +2375,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);
index 15a28578d4585bcb1523b70ed24d34cfcf7cb71c..1f68a146e26c00d7a663f9065dd7bb1218f25b75 100644 (file)
@@ -1255,6 +1255,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,