drm/vmwgfx: Implement 64-bit Otable- and MOB binding v2

Adds the relevant commands to the device interface header and
implements 64-bit binding for 64 bit VMs.

v2: Uppercase command IDs, Correctly use also 64 bit page tables.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
index 388b64d..ad29651 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
@@ -33,13 +33,25 @@
 
 #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
@@ -93,7 +105,7 @@
 {
 	struct {
 		SVGA3dCmdHeader header;
-		SVGA3dCmdSetOTableBase body;
+		vmw_cmd_set_otable_base body;
 	} *cmd;
 	struct vmw_mob *mob;
 	const struct vmw_sg_table *vsgt;
@@ -113,7 +125,7 @@
 	}
 
 	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;
@@ -124,6 +136,7 @@
 			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));
@@ -133,7 +146,7 @@
 	}
 
 	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;
@@ -141,6 +154,13 @@
 	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;
 
@@ -403,6 +423,27 @@
 	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
@@ -432,8 +473,8 @@
 		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));
@@ -565,7 +606,7 @@
 	struct vmw_piter data_iter;
 	struct {
 		SVGA3dCmdHeader header;
-		SVGA3dCmdDefineGBMob body;
+		vmw_cmd_define_gb_mob body;
 	} *cmd;
 
 	mob->id = mob_id;
@@ -574,7 +615,7 @@
 		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;
@@ -586,6 +627,7 @@
 
 		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);
@@ -597,7 +639,7 @@
 		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;