Merge tag 'seccomp-v5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_virt.c
index 1203c20..2d51b76 100644 (file)
 #include "soc15.h"
 #include "nv.h"
 
+#define POPULATE_UCODE_INFO(vf2pf_info, ucode, ver) \
+       do { \
+               vf2pf_info->ucode_info[ucode].id = ucode; \
+               vf2pf_info->ucode_info[ucode].version = ver; \
+       } while (0)
+
 bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev)
 {
        /* By now all MMIO pages except mailbox are blocked */
@@ -41,11 +47,13 @@ bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev)
 
 void amdgpu_virt_init_setting(struct amdgpu_device *adev)
 {
+       struct drm_device *ddev = adev_to_drm(adev);
+
        /* enable virtual display */
        if (adev->mode_info.num_crtc == 0)
                adev->mode_info.num_crtc = 1;
        adev->enable_virtual_display = true;
-       adev->ddev->driver->driver_features &= ~DRIVER_ATOMIC;
+       ddev->driver_features &= ~DRIVER_ATOMIC;
        adev->cg_flags = 0;
        adev->pg_flags = 0;
 }
@@ -93,12 +101,12 @@ failed_undo:
        amdgpu_ring_undo(ring);
        spin_unlock_irqrestore(&kiq->ring_lock, flags);
 failed_kiq:
-       pr_err("failed to write reg %x wait reg %x\n", reg0, reg1);
+       dev_err(adev->dev, "failed to write reg %x wait reg %x\n", reg0, reg1);
 }
 
 /**
  * amdgpu_virt_request_full_gpu() - request full gpu access
- * @amdgpu:    amdgpu device.
+ * @adev:      amdgpu device.
  * @init:      is driver init time.
  * When start to init/fini driver, first need to request full gpu access.
  * Return: Zero if request success, otherwise will return error.
@@ -121,7 +129,7 @@ int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init)
 
 /**
  * amdgpu_virt_release_full_gpu() - release full gpu access
- * @amdgpu:    amdgpu device.
+ * @adev:      amdgpu device.
  * @init:      is driver init time.
  * When finishing driver init/fini, need to release full gpu access.
  * Return: Zero if release success, otherwise will returen error.
@@ -143,7 +151,7 @@ int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init)
 
 /**
  * amdgpu_virt_reset_gpu() - reset gpu
- * @amdgpu:    amdgpu device.
+ * @adev:      amdgpu device.
  * Send reset command to GPU hypervisor to reset GPU that VM is using
  * Return: Zero if reset success, otherwise will return error.
  */
@@ -178,7 +186,7 @@ void amdgpu_virt_request_init_data(struct amdgpu_device *adev)
 
 /**
  * amdgpu_virt_wait_reset() - wait for reset gpu completed
- * @amdgpu:    amdgpu device.
+ * @adev:      amdgpu device.
  * Wait for GPU reset completed.
  * Return: Zero if reset success, otherwise will return error.
  */
@@ -194,7 +202,7 @@ int amdgpu_virt_wait_reset(struct amdgpu_device *adev)
 
 /**
  * amdgpu_virt_alloc_mm_table() - alloc memory for mm table
- * @amdgpu:    amdgpu device.
+ * @adev:      amdgpu device.
  * MM table is used by UVD and VCE for its initialization
  * Return: Zero if allocate success.
  */
@@ -224,7 +232,7 @@ int amdgpu_virt_alloc_mm_table(struct amdgpu_device *adev)
 
 /**
  * amdgpu_virt_free_mm_table() - free mm table memory
- * @amdgpu:    amdgpu device.
+ * @adev:      amdgpu device.
  * Free MM table memory
  */
 void amdgpu_virt_free_mm_table(struct amdgpu_device *adev)
@@ -239,10 +247,10 @@ void amdgpu_virt_free_mm_table(struct amdgpu_device *adev)
 }
 
 
-int amdgpu_virt_fw_reserve_get_checksum(void *obj,
-                                       unsigned long obj_size,
-                                       unsigned int key,
-                                       unsigned int chksum)
+unsigned int amd_sriov_msg_checksum(void *obj,
+                               unsigned long obj_size,
+                               unsigned int key,
+                               unsigned int checksum)
 {
        unsigned int ret = key;
        unsigned long i = 0;
@@ -252,9 +260,9 @@ int amdgpu_virt_fw_reserve_get_checksum(void *obj,
        /* calculate checksum */
        for (i = 0; i < obj_size; ++i)
                ret += *(pos + i);
-       /* minus the chksum itself */
-       pos = (char *)&chksum;
-       for (i = 0; i < sizeof(chksum); ++i)
+       /* minus the checksum itself */
+       pos = (char *)&checksum;
+       for (i = 0; i < sizeof(checksum); ++i)
                ret -= *(pos + i);
        return ret;
 }
@@ -274,8 +282,8 @@ static int amdgpu_virt_init_ras_err_handler_data(struct amdgpu_device *adev)
        if (!*data)
                return -ENOMEM;
 
-       bps = kmalloc(align_space * sizeof((*data)->bps), GFP_KERNEL);
-       bps_bo = kmalloc(align_space * sizeof((*data)->bps_bo), GFP_KERNEL);
+       bps = kmalloc_array(align_space, sizeof((*data)->bps), GFP_KERNEL);
+       bps_bo = kmalloc_array(align_space, sizeof((*data)->bps_bo), GFP_KERNEL);
 
        if (!bps || !bps_bo) {
                kfree(bps);
@@ -401,7 +409,7 @@ static void amdgpu_virt_add_bad_page(struct amdgpu_device *adev,
        if (bp_block_size) {
                bp_cnt = bp_block_size / sizeof(uint64_t);
                for (bp_idx = 0; bp_idx < bp_cnt; bp_idx++) {
-                       retired_page = *(uint64_t *)(adev->fw_vram_usage.va +
+                       retired_page = *(uint64_t *)(adev->mman.fw_vram_usage_va +
                                        bp_block_offset + bp_idx * sizeof(uint64_t));
                        bp.retired_page = retired_page;
 
@@ -415,33 +423,188 @@ static void amdgpu_virt_add_bad_page(struct amdgpu_device *adev,
        }
 }
 
-void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
+static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev)
 {
-       uint32_t pf2vf_size = 0;
-       uint32_t checksum = 0;
+       struct amd_sriov_msg_pf2vf_info_header *pf2vf_info = adev->virt.fw_reserve.p_pf2vf;
+       uint32_t checksum;
        uint32_t checkval;
-       char *str;
+
+       if (adev->virt.fw_reserve.p_pf2vf == NULL)
+               return -EINVAL;
+
+       if (pf2vf_info->size > 1024) {
+               DRM_ERROR("invalid pf2vf message size\n");
+               return -EINVAL;
+       }
+
+       switch (pf2vf_info->version) {
+       case 1:
+               checksum = ((struct amdgim_pf2vf_info_v1 *)pf2vf_info)->checksum;
+               checkval = amd_sriov_msg_checksum(
+                       adev->virt.fw_reserve.p_pf2vf, pf2vf_info->size,
+                       adev->virt.fw_reserve.checksum_key, checksum);
+               if (checksum != checkval) {
+                       DRM_ERROR("invalid pf2vf message\n");
+                       return -EINVAL;
+               }
+
+               adev->virt.gim_feature =
+                       ((struct amdgim_pf2vf_info_v1 *)pf2vf_info)->feature_flags;
+               break;
+       case 2:
+               /* TODO: missing key, need to add it later */
+               checksum = ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->checksum;
+               checkval = amd_sriov_msg_checksum(
+                       adev->virt.fw_reserve.p_pf2vf, pf2vf_info->size,
+                       0, checksum);
+               if (checksum != checkval) {
+                       DRM_ERROR("invalid pf2vf message\n");
+                       return -EINVAL;
+               }
+
+               adev->virt.vf2pf_update_interval_ms =
+                       ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->vf2pf_update_interval_ms;
+               adev->virt.gim_feature =
+                       ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->feature_flags.all;
+
+               break;
+       default:
+               DRM_ERROR("invalid pf2vf version\n");
+               return -EINVAL;
+       }
+
+       /* correct too large or too little interval value */
+       if (adev->virt.vf2pf_update_interval_ms < 200 || adev->virt.vf2pf_update_interval_ms > 10000)
+               adev->virt.vf2pf_update_interval_ms = 2000;
+
+       return 0;
+}
+
+static void amdgpu_virt_populate_vf2pf_ucode_info(struct amdgpu_device *adev)
+{
+       struct amd_sriov_msg_vf2pf_info *vf2pf_info;
+       vf2pf_info = (struct amd_sriov_msg_vf2pf_info *) adev->virt.fw_reserve.p_vf2pf;
+
+       if (adev->virt.fw_reserve.p_vf2pf == NULL)
+               return;
+
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_VCE,      adev->vce.fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_UVD,      adev->uvd.fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_MC,       adev->gmc.fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_ME,       adev->gfx.me_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_PFP,      adev->gfx.pfp_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_CE,       adev->gfx.ce_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_RLC,      adev->gfx.rlc_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_RLC_SRLC, adev->gfx.rlc_srlc_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_RLC_SRLG, adev->gfx.rlc_srlg_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_RLC_SRLS, adev->gfx.rlc_srls_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_MEC,      adev->gfx.mec_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_MEC2,     adev->gfx.mec2_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_SOS,      adev->psp.sos_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_ASD,      adev->psp.asd_fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_TA_RAS,   adev->psp.ta_ras_ucode_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_TA_XGMI,  adev->psp.ta_xgmi_ucode_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_SMC,      adev->pm.fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_SDMA,     adev->sdma.instance[0].fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_SDMA2,    adev->sdma.instance[1].fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_VCN,      adev->vcn.fw_version);
+       POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_DMCU,     adev->dm.dmcu_fw_version);
+}
+
+static int amdgpu_virt_write_vf2pf_data(struct amdgpu_device *adev)
+{
+       struct amd_sriov_msg_vf2pf_info *vf2pf_info;
+       struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
+
+       vf2pf_info = (struct amd_sriov_msg_vf2pf_info *) adev->virt.fw_reserve.p_vf2pf;
+
+       if (adev->virt.fw_reserve.p_vf2pf == NULL)
+               return -EINVAL;
+
+       memset(vf2pf_info, 0, sizeof(struct amd_sriov_msg_vf2pf_info));
+
+       vf2pf_info->header.size = sizeof(struct amd_sriov_msg_vf2pf_info);
+       vf2pf_info->header.version = AMD_SRIOV_MSG_FW_VRAM_VF2PF_VER;
+
+#ifdef MODULE
+       if (THIS_MODULE->version != NULL)
+               strcpy(vf2pf_info->driver_version, THIS_MODULE->version);
+       else
+#endif
+               strcpy(vf2pf_info->driver_version, "N/A");
+
+       vf2pf_info->pf2vf_version_required = 0; // no requirement, guest understands all
+       vf2pf_info->driver_cert = 0;
+       vf2pf_info->os_info.all = 0;
+
+       vf2pf_info->fb_usage = amdgpu_vram_mgr_usage(vram_man) >> 20;
+       vf2pf_info->fb_vis_usage = amdgpu_vram_mgr_vis_usage(vram_man) >> 20;
+       vf2pf_info->fb_size = adev->gmc.real_vram_size >> 20;
+       vf2pf_info->fb_vis_size = adev->gmc.visible_vram_size >> 20;
+
+       amdgpu_virt_populate_vf2pf_ucode_info(adev);
+
+       /* TODO: read dynamic info */
+       vf2pf_info->gfx_usage = 0;
+       vf2pf_info->compute_usage = 0;
+       vf2pf_info->encode_usage = 0;
+       vf2pf_info->decode_usage = 0;
+
+       vf2pf_info->checksum =
+               amd_sriov_msg_checksum(
+               vf2pf_info, vf2pf_info->header.size, 0, 0);
+
+       return 0;
+}
+
+static void amdgpu_virt_update_vf2pf_work_item(struct work_struct *work)
+{
+       struct amdgpu_device *adev = container_of(work, struct amdgpu_device, virt.vf2pf_work.work);
+
+       amdgpu_virt_read_pf2vf_data(adev);
+       amdgpu_virt_write_vf2pf_data(adev);
+
+       schedule_delayed_work(&(adev->virt.vf2pf_work), adev->virt.vf2pf_update_interval_ms);
+}
+
+void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev)
+{
+       if (adev->virt.vf2pf_update_interval_ms != 0) {
+               DRM_INFO("clean up the vf2pf work item\n");
+               flush_delayed_work(&adev->virt.vf2pf_work);
+               cancel_delayed_work_sync(&adev->virt.vf2pf_work);
+       }
+}
+
+void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
+{
        uint64_t bp_block_offset = 0;
        uint32_t bp_block_size = 0;
-       struct amdgim_pf2vf_info_v2 *pf2vf_v2 = NULL;
+       struct amd_sriov_msg_pf2vf_info *pf2vf_v2 = NULL;
 
        adev->virt.fw_reserve.p_pf2vf = NULL;
        adev->virt.fw_reserve.p_vf2pf = NULL;
+       adev->virt.vf2pf_update_interval_ms = 0;
+
+       if (adev->mman.fw_vram_usage_va != NULL) {
+               adev->virt.vf2pf_update_interval_ms = 2000;
 
-       if (adev->fw_vram_usage.va != NULL) {
                adev->virt.fw_reserve.p_pf2vf =
-                       (struct amd_sriov_msg_pf2vf_info_header *)(
-                       adev->fw_vram_usage.va + AMDGIM_DATAEXCHANGE_OFFSET);
-               AMDGPU_FW_VRAM_PF2VF_READ(adev, header.size, &pf2vf_size);
-               AMDGPU_FW_VRAM_PF2VF_READ(adev, checksum, &checksum);
-               AMDGPU_FW_VRAM_PF2VF_READ(adev, feature_flags, &adev->virt.gim_feature);
-
-               /* pf2vf message must be in 4K */
-               if (pf2vf_size > 0 && pf2vf_size < 4096) {
-                       if (adev->virt.fw_reserve.p_pf2vf->version == 2) {
-                               pf2vf_v2 = (struct amdgim_pf2vf_info_v2 *)adev->virt.fw_reserve.p_pf2vf;
-                               bp_block_offset = ((uint64_t)pf2vf_v2->bp_block_offset_L & 0xFFFFFFFF) |
-                                               ((((uint64_t)pf2vf_v2->bp_block_offset_H) << 32) & 0xFFFFFFFF00000000);
+                       (struct amd_sriov_msg_pf2vf_info_header *)
+                       (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10));
+               adev->virt.fw_reserve.p_vf2pf =
+                       (struct amd_sriov_msg_vf2pf_info_header *)
+                       (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10));
+
+               amdgpu_virt_read_pf2vf_data(adev);
+               amdgpu_virt_write_vf2pf_data(adev);
+
+               /* bad page handling for version 2 */
+               if (adev->virt.fw_reserve.p_pf2vf->version == 2) {
+                               pf2vf_v2 = (struct amd_sriov_msg_pf2vf_info *)adev->virt.fw_reserve.p_pf2vf;
+
+                               bp_block_offset = ((uint64_t)pf2vf_v2->bp_block_offset_low & 0xFFFFFFFF) |
+                                               ((((uint64_t)pf2vf_v2->bp_block_offset_high) << 32) & 0xFFFFFFFF00000000);
                                bp_block_size = pf2vf_v2->bp_block_size;
 
                                if (bp_block_size && !adev->virt.ras_init_done)
@@ -450,37 +613,11 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
                                if (adev->virt.ras_init_done)
                                        amdgpu_virt_add_bad_page(adev, bp_block_offset, bp_block_size);
                        }
+       }
 
-                       checkval = amdgpu_virt_fw_reserve_get_checksum(
-                               adev->virt.fw_reserve.p_pf2vf, pf2vf_size,
-                               adev->virt.fw_reserve.checksum_key, checksum);
-                       if (checkval == checksum) {
-                               adev->virt.fw_reserve.p_vf2pf =
-                                       ((void *)adev->virt.fw_reserve.p_pf2vf +
-                                       pf2vf_size);
-                               memset((void *)adev->virt.fw_reserve.p_vf2pf, 0,
-                                       sizeof(amdgim_vf2pf_info));
-                               AMDGPU_FW_VRAM_VF2PF_WRITE(adev, header.version,
-                                       AMDGPU_FW_VRAM_VF2PF_VER);
-                               AMDGPU_FW_VRAM_VF2PF_WRITE(adev, header.size,
-                                       sizeof(amdgim_vf2pf_info));
-                               AMDGPU_FW_VRAM_VF2PF_READ(adev, driver_version,
-                                       &str);
-#ifdef MODULE
-                               if (THIS_MODULE->version != NULL)
-                                       strcpy(str, THIS_MODULE->version);
-                               else
-#endif
-                                       strcpy(str, "N/A");
-                               AMDGPU_FW_VRAM_VF2PF_WRITE(adev, driver_cert,
-                                       0);
-                               AMDGPU_FW_VRAM_VF2PF_WRITE(adev, checksum,
-                                       amdgpu_virt_fw_reserve_get_checksum(
-                                       adev->virt.fw_reserve.p_vf2pf,
-                                       pf2vf_size,
-                                       adev->virt.fw_reserve.checksum_key, 0));
-                       }
-               }
+       if (adev->virt.vf2pf_update_interval_ms != 0) {
+               INIT_DELAYED_WORK(&adev->virt.vf2pf_work, amdgpu_virt_update_vf2pf_work_item);
+               schedule_delayed_work(&(adev->virt.vf2pf_work), adev->virt.vf2pf_update_interval_ms);
        }
 }