#include "svga_reg.h"
 
 typedef uint32 PPN;
+typedef __le64 PPN64;
 
 /*
  * 3D Hardware Version
 #define SVGA_3D_CMD_DESTROY_GB_SHADER        1113
 #define SVGA_3D_CMD_BIND_GB_SHADER           1114
 
-#define SVGA_3D_CMD_BIND_SHADERCONSTS        1115
+#define SVGA_3D_CMD_SET_OTABLE_BASE64        1115
 
 #define SVGA_3D_CMD_BEGIN_GB_QUERY           1116
 #define SVGA_3D_CMD_END_GB_QUERY             1117
 
 #define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE  1130
 
-#define SVGA_3D_CMD_MAX                      1131
+#define SVGA_3D_CMD_DEFINE_GB_MOB64          1135
+#define SVGA_3D_CMD_REDEFINE_GB_MOB64        1136
+
+#define SVGA_3D_CMD_MAX                      1142
 #define SVGA_3D_CMD_FUTURE_MAX               3000
 
 /*
    SVGA3D_MOBFMT_PTDEPTH_1 = 1,
    SVGA3D_MOBFMT_PTDEPTH_2 = 2,
    SVGA3D_MOBFMT_RANGE     = 3,
+   SVGA3D_MOBFMT_PTDEPTH64_0 = 4,
+   SVGA3D_MOBFMT_PTDEPTH64_1 = 5,
+   SVGA3D_MOBFMT_PTDEPTH64_2 = 6,
    SVGA3D_MOBFMT_MAX,
 } SVGAMobFormat;
 
    SVGAMobFormat ptDepth;
 } SVGA3dCmdSetOTableBase;  /* SVGA_3D_CMD_SET_OTABLE_BASE */
 
+typedef
+struct {
+   SVGAOTableType type;
+   PPN64 baseAddress;
+   uint32 sizeInBytes;
+   uint32 validSizeInBytes;
+   SVGAMobFormat ptDepth;
+} SVGA3dCmdSetOTableBase64;  /* SVGA_3D_CMD_SET_OTABLE_BASE64 */
+
 typedef
 struct {
    SVGAOTableType type;
    uint32 sizeInBytes;
 } SVGA3dCmdRedefineGBMob;   /* SVGA_3D_CMD_REDEFINE_GB_MOB */
 
+/*
+ * Define a memory object (Mob) in the OTable with a PPN64 base.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBMob64 {
+   SVGAMobId mobid;
+   SVGAMobFormat ptDepth;
+   PPN64 base;
+   uint32 sizeInBytes;
+}
+SVGA3dCmdDefineGBMob64;   /* SVGA_3D_CMD_DEFINE_GB_MOB64 */
+
+/*
+ * Redefine an object in the OTable with PPN64 base.
+ */
+
+typedef
+struct SVGA3dCmdRedefineGBMob64 {
+   SVGAMobId mobid;
+   SVGAMobFormat ptDepth;
+   PPN64 base;
+   uint32 sizeInBytes;
+}
+SVGA3dCmdRedefineGBMob64;   /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
+
 /*
  * Notification that the page tables have been modified.
  */
    uint32 shid;
 } SVGA3dCmdDestroyGBShader;   /* SVGA_3D_CMD_DESTROY_GB_SHADER */
 
-
-typedef struct SVGA3dCmdBindGBShaderConsts {
-   uint32 cid;
-   SVGA3dShaderType shaderType;
-   SVGA3dShaderConstType shaderConstType;
-   uint32 sid;
-} SVGA3dCmdBindGBShaderConsts;   /* SVGA_3D_CMD_BIND_SHADERCONSTS */
-
 typedef
 struct {
    uint32                  cid;
 
 
 #define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) ? 0 : 1)
 
-/*
- * Currently the MOB interface does not support 64-bit page frame numbers.
- * This might change in the future to be similar to the GMR2 interface
- * when virtual machines support memory beyond 16TB.
- */
-
+#ifdef CONFIG_64BIT
+#define VMW_PPN_SIZE 8
+#define vmw_cmd_set_otable_base SVGA3dCmdSetOTableBase64
+#define VMW_ID_SET_OTABLE_BASE SVGA_3D_CMD_SET_OTABLE_BASE64
+#define vmw_cmd_define_gb_mob SVGA3dCmdDefineGBMob64
+#define VMW_ID_DEFINE_GB_MOB SVGA_3D_CMD_DEFINE_GB_MOB64
+#define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PTDEPTH64_0
+#define VMW_MOBFMT_PTDEPTH_1 SVGA3D_MOBFMT_PTDEPTH64_1
+#define VMW_MOBFMT_PTDEPTH_2 SVGA3D_MOBFMT_PTDEPTH64_2
+#else
 #define VMW_PPN_SIZE 4
+#define vmw_cmd_set_otable_base SVGA3dCmdSetOTableBase
+#define VMW_ID_SET_OTABLE_BASE SVGA_3D_CMD_SET_OTABLE_BASE
+#define vmw_cmd_define_gb_mob SVGA3dCmdDefineGBMob
+#define VMW_ID_DEFINE_GB_MOB SVGA_3D_CMD_DEFINE_GB_MOB
+#define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PTDEPTH_0
+#define VMW_MOBFMT_PTDEPTH_1 SVGA3D_MOBFMT_PTDEPTH_1
+#define VMW_MOBFMT_PTDEPTH_2 SVGA3D_MOBFMT_PTDEPTH_2
+#endif
 
 /*
  * struct vmw_mob - Structure containing page table and metadata for a
 {
        struct {
                SVGA3dCmdHeader header;
-               SVGA3dCmdSetOTableBase body;
+               vmw_cmd_set_otable_base body;
        } *cmd;
        struct vmw_mob *mob;
        const struct vmw_sg_table *vsgt;
        }
 
        if (otable->size <= PAGE_SIZE) {
-               mob->pt_level = SVGA3D_MOBFMT_PTDEPTH_0;
+               mob->pt_level = VMW_MOBFMT_PTDEPTH_0;
                mob->pt_root_page = vmw_piter_dma_addr(&iter);
        } else if (vsgt->num_regions == 1) {
                mob->pt_level = SVGA3D_MOBFMT_RANGE;
                        goto out_no_populate;
 
                vmw_mob_pt_setup(mob, iter, otable->size >> PAGE_SHIFT);
+               mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1;
        }
 
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
        }
 
        memset(cmd, 0, sizeof(*cmd));
-       cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
+       cmd->header.id = VMW_ID_SET_OTABLE_BASE;
        cmd->header.size = sizeof(cmd->body);
        cmd->body.type = type;
        cmd->body.baseAddress = mob->pt_root_page >> PAGE_SHIFT;
        cmd->body.validSizeInBytes = 0;
        cmd->body.ptDepth = mob->pt_level;
 
+       /*
+        * The device doesn't support this, But the otable size is
+        * determined at compile-time, so this BUG shouldn't trigger
+        * randomly.
+        */
+       BUG_ON(mob->pt_level == VMW_MOBFMT_PTDEPTH_2);
+
        vmw_fifo_commit(dev_priv, sizeof(*cmd));
        otable->page_table = mob;
 
        return ret;
 }
 
+/**
+ * vmw_mob_assign_ppn - Assign a value to a page table entry
+ *
+ * @addr: Pointer to pointer to page table entry.
+ * @val: The page table entry
+ *
+ * Assigns a value to a page table entry pointed to by *@addr and increments
+ * *@addr according to the page table entry size.
+ */
+#if (VMW_PPN_SIZE == 8)
+static void vmw_mob_assign_ppn(uint32_t **addr, dma_addr_t val)
+{
+       *((uint64_t *) *addr) = val >> PAGE_SHIFT;
+       *addr += 2;
+}
+#else
+static void vmw_mob_assign_ppn(uint32_t **addr, dma_addr_t val)
+{
+       *(*addr)++ = val >> PAGE_SHIFT;
+}
+#endif
 
 /*
  * vmw_mob_build_pt - Build a pagetable
                save_addr = addr = kmap_atomic(page);
 
                for (i = 0; i < PAGE_SIZE / VMW_PPN_SIZE; ++i) {
-                       u32 tmp = vmw_piter_dma_addr(data_iter) >> PAGE_SHIFT;
-                       *addr++ = tmp;
+                       vmw_mob_assign_ppn(&addr,
+                                          vmw_piter_dma_addr(data_iter));
                        if (unlikely(--num_data_pages == 0))
                                break;
                        WARN_ON(!vmw_piter_next(data_iter));
        struct vmw_piter data_iter;
        struct {
                SVGA3dCmdHeader header;
-               SVGA3dCmdDefineGBMob body;
+               vmw_cmd_define_gb_mob body;
        } *cmd;
 
        mob->id = mob_id;
                return 0;
 
        if (likely(num_data_pages == 1)) {
-               mob->pt_level = SVGA3D_MOBFMT_PTDEPTH_0;
+               mob->pt_level = VMW_MOBFMT_PTDEPTH_0;
                mob->pt_root_page = vmw_piter_dma_addr(&data_iter);
        } else if (vsgt->num_regions == 1) {
                mob->pt_level = SVGA3D_MOBFMT_RANGE;
 
                vmw_mob_pt_setup(mob, data_iter, num_data_pages);
                pt_set_up = true;
+               mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1;
        }
 
        (void) vmw_3d_resource_inc(dev_priv, false);
                goto out_no_cmd_space;
        }
 
-       cmd->header.id = SVGA_3D_CMD_DEFINE_GB_MOB;
+       cmd->header.id = VMW_ID_DEFINE_GB_MOB;
        cmd->header.size = sizeof(cmd->body);
        cmd->body.mobid = mob_id;
        cmd->body.ptDepth = mob->pt_level;