(void *)&adev->virt.mm_table.cpu_addr);
        adev->virt.mm_table.gpu_addr = 0;
 }
+
+
+int amdgpu_virt_fw_reserve_get_checksum(void *obj,
+                                       unsigned long obj_size,
+                                       unsigned int key,
+                                       unsigned int chksum)
+{
+       unsigned int ret = key;
+       unsigned long i = 0;
+       unsigned char *pos;
+
+       pos = (char *)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)
+               ret -= *(pos + i);
+       return ret;
+}
+
+void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
+{
+       uint32_t pf2vf_ver = 0;
+       uint32_t pf2vf_size = 0;
+       uint32_t checksum = 0;
+       uint32_t checkval;
+       char *str;
+
+       adev->virt.fw_reserve.p_pf2vf = NULL;
+       adev->virt.fw_reserve.p_vf2pf = NULL;
+
+       if (adev->fw_vram_usage.va != NULL) {
+               adev->virt.fw_reserve.p_pf2vf =
+                       (struct amdgim_pf2vf_info_header *)(
+                       adev->fw_vram_usage.va + AMDGIM_DATAEXCHANGE_OFFSET);
+               pf2vf_ver = adev->virt.fw_reserve.p_pf2vf->version;
+               AMDGPU_FW_VRAM_PF2VF_READ(adev, header.size, &pf2vf_size);
+               AMDGPU_FW_VRAM_PF2VF_READ(adev, checksum, &checksum);
+
+               /* pf2vf message must be in 4K */
+               if (pf2vf_size > 0 && pf2vf_size < 4096) {
+                       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);
+                               if (THIS_MODULE->version != NULL)
+                                       strcpy(str, THIS_MODULE->version);
+                               else
+                                       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));
+                       }
+               }
+       }
+}
+
+
 
        void (*trans_msg)(struct amdgpu_device *adev, u32 req, u32 data1, u32 data2, u32 data3);
 };
 
+/*
+ * Firmware Reserve Frame buffer
+ */
+struct amdgpu_virt_fw_reserve {
+       struct amdgim_pf2vf_info_header *p_pf2vf;
+       struct amdgim_vf2pf_info_header *p_vf2pf;
+       unsigned int checksum_key;
+};
+/*
+ * Defination between PF and VF
+ * Structures forcibly aligned to 4 to keep the same style as PF.
+ */
+#define AMDGIM_DATAEXCHANGE_OFFSET             (64 * 1024)
+
+#define AMDGIM_GET_STRUCTURE_RESERVED_SIZE(total, u8, u16, u32, u64) \
+               (total - (((u8)+3) / 4 + ((u16)+1) / 2 + (u32) + (u64)*2))
+
+enum AMDGIM_FEATURE_FLAG {
+       /* GIM supports feature of Error log collecting */
+       AMDGIM_FEATURE_ERROR_LOG_COLLECT = 0x1,
+       /* GIM supports feature of loading uCodes */
+       AMDGIM_FEATURE_GIM_LOAD_UCODES   = 0x2,
+};
+
+struct amdgim_pf2vf_info_header {
+       /* the total structure size in byte. */
+       uint32_t size;
+       /* version of this structure, written by the GIM */
+       uint32_t version;
+} __aligned(4);
+struct  amdgim_pf2vf_info_v1 {
+       /* header contains size and version */
+       struct amdgim_pf2vf_info_header header;
+       /* max_width * max_height */
+       unsigned int uvd_enc_max_pixels_count;
+       /* 16x16 pixels/sec, codec independent */
+       unsigned int uvd_enc_max_bandwidth;
+       /* max_width * max_height */
+       unsigned int vce_enc_max_pixels_count;
+       /* 16x16 pixels/sec, codec independent */
+       unsigned int vce_enc_max_bandwidth;
+       /* MEC FW position in kb from the start of visible frame buffer */
+       unsigned int mecfw_kboffset;
+       /* The features flags of the GIM driver supports. */
+       unsigned int feature_flags;
+       /* use private key from mailbox 2 to create chueksum */
+       unsigned int checksum;
+} __aligned(4);
+
+struct  amdgim_pf2vf_info_v2 {
+       /* header contains size and version */
+       struct amdgim_pf2vf_info_header header;
+       /* use private key from mailbox 2 to create chueksum */
+       uint32_t checksum;
+       /* The features flags of the GIM driver supports. */
+       uint32_t feature_flags;
+       /* max_width * max_height */
+       uint32_t uvd_enc_max_pixels_count;
+       /* 16x16 pixels/sec, codec independent */
+       uint32_t uvd_enc_max_bandwidth;
+       /* max_width * max_height */
+       uint32_t vce_enc_max_pixels_count;
+       /* 16x16 pixels/sec, codec independent */
+       uint32_t vce_enc_max_bandwidth;
+       /* MEC FW position in kb from the start of VF visible frame buffer */
+       uint64_t mecfw_kboffset;
+       /* MEC FW size in KB */
+       uint32_t mecfw_ksize;
+       /* UVD FW position in kb from the start of VF visible frame buffer */
+       uint64_t uvdfw_kboffset;
+       /* UVD FW size in KB */
+       uint32_t uvdfw_ksize;
+       /* VCE FW position in kb from the start of VF visible frame buffer */
+       uint64_t vcefw_kboffset;
+       /* VCE FW size in KB */
+       uint32_t vcefw_ksize;
+       uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 0, 0, (9 + sizeof(struct amdgim_pf2vf_info_header)/sizeof(uint32_t)), 3)];
+} __aligned(4);
+
+
+struct amdgim_vf2pf_info_header {
+       /* the total structure size in byte. */
+       uint32_t size;
+       /*version of this structure, written by the guest */
+       uint32_t version;
+} __aligned(4);
+
+struct amdgim_vf2pf_info_v1 {
+       /* header contains size and version */
+       struct amdgim_vf2pf_info_header header;
+       /* driver version */
+       char driver_version[64];
+       /* driver certification, 1=WHQL, 0=None */
+       unsigned int driver_cert;
+       /* guest OS type and version: need a define */
+       unsigned int os_info;
+       /* in the unit of 1M */
+       unsigned int fb_usage;
+       /* guest gfx engine usage percentage */
+       unsigned int gfx_usage;
+       /* guest gfx engine health percentage */
+       unsigned int gfx_health;
+       /* guest compute engine usage percentage */
+       unsigned int compute_usage;
+       /* guest compute engine health percentage */
+       unsigned int compute_health;
+       /* guest vce engine usage percentage. 0xffff means N/A. */
+       unsigned int vce_enc_usage;
+       /* guest vce engine health percentage. 0xffff means N/A. */
+       unsigned int vce_enc_health;
+       /* guest uvd engine usage percentage. 0xffff means N/A. */
+       unsigned int uvd_enc_usage;
+       /* guest uvd engine usage percentage. 0xffff means N/A. */
+       unsigned int uvd_enc_health;
+       unsigned int checksum;
+} __aligned(4);
+
+struct amdgim_vf2pf_info_v2 {
+       /* header contains size and version */
+       struct amdgim_vf2pf_info_header header;
+       uint32_t checksum;
+       /* driver version */
+       uint8_t driver_version[64];
+       /* driver certification, 1=WHQL, 0=None */
+       uint32_t driver_cert;
+       /* guest OS type and version: need a define */
+       uint32_t os_info;
+       /* in the unit of 1M */
+       uint32_t fb_usage;
+       /* guest gfx engine usage percentage */
+       uint32_t gfx_usage;
+       /* guest gfx engine health percentage */
+       uint32_t gfx_health;
+       /* guest compute engine usage percentage */
+       uint32_t compute_usage;
+       /* guest compute engine health percentage */
+       uint32_t compute_health;
+       /* guest vce engine usage percentage. 0xffff means N/A. */
+       uint32_t vce_enc_usage;
+       /* guest vce engine health percentage. 0xffff means N/A. */
+       uint32_t vce_enc_health;
+       /* guest uvd engine usage percentage. 0xffff means N/A. */
+       uint32_t uvd_enc_usage;
+       /* guest uvd engine usage percentage. 0xffff means N/A. */
+       uint32_t uvd_enc_health;
+       uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 64, 0, (12 + sizeof(struct amdgim_vf2pf_info_header)/sizeof(uint32_t)), 0)];
+} __aligned(4);
+
+#define AMDGPU_FW_VRAM_VF2PF_VER 2
+typedef struct amdgim_vf2pf_info_v2 amdgim_vf2pf_info ;
+
+#define AMDGPU_FW_VRAM_VF2PF_WRITE(adev, field, val) \
+       do { \
+               ((amdgim_vf2pf_info *)adev->virt.fw_reserve.p_vf2pf)->field = (val); \
+       } while (0)
+
+#define AMDGPU_FW_VRAM_VF2PF_READ(adev, field, val) \
+       do { \
+               (*val) = ((amdgim_vf2pf_info *)adev->virt.fw_reserve.p_vf2pf)->field; \
+       } while (0)
+
+#define AMDGPU_FW_VRAM_PF2VF_READ(adev, field, val) \
+       do { \
+               if (!adev->virt.fw_reserve.p_pf2vf) \
+                       *(val) = 0; \
+               else { \
+                       if (adev->virt.fw_reserve.p_pf2vf->version == 1) \
+                               *(val) = ((struct amdgim_pf2vf_info_v1 *)adev->virt.fw_reserve.p_pf2vf)->field; \
+                       if (adev->virt.fw_reserve.p_pf2vf->version == 2) \
+                               *(val) = ((struct amdgim_pf2vf_info_v2 *)adev->virt.fw_reserve.p_pf2vf)->field; \
+               } \
+       } while (0)
+
 /* GPU virtualization */
 struct amdgpu_virt {
        uint32_t                        caps;
        struct amdgpu_mm_table          mm_table;
        const struct amdgpu_virt_ops    *ops;
        struct amdgpu_vf_error_buffer   vf_errors;
+       struct amdgpu_virt_fw_reserve   fw_reserve;
 };
 
 #define AMDGPU_CSA_SIZE    (8 * 1024)
 int amdgpu_sriov_gpu_reset(struct amdgpu_device *adev, struct amdgpu_job *job);
 int amdgpu_virt_alloc_mm_table(struct amdgpu_device *adev);
 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);
+void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev);
 
 #endif