msm: kgsl: Add support for GPUHTW System Cache usage

Activate and deactivate the slice for GPU pagetable walks
in the system cache upon GPU power collapse/restore.
Configure the SCID for the slice.
Also enable the SMMU domain attribute to allocate pagetable
memory with the right memory attributes for them to be
allocated into the system cache.

CRs-Fixed: 1081617
Change-Id: I16c174b413eaa4aa5c6a3514c9a18f8c990812da
Signed-off-by: Sushmita Susheelendra <ssusheel@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 06a6b1f..9425ea3 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1037,6 +1037,15 @@
 		adreno_dev->gpu_llc_slice = NULL;
 	}
 
+	/* Get the system cache slice descriptor for GPU pagetables */
+	adreno_dev->gpuhtw_llc_slice = adreno_llc_getd(&pdev->dev, "gpuhtw");
+	if (IS_ERR(adreno_dev->gpuhtw_llc_slice)) {
+		KGSL_DRV_WARN(device,
+			"Failed to get gpuhtw LLC slice descriptor (%ld)\n",
+			PTR_ERR(adreno_dev->gpuhtw_llc_slice));
+		adreno_dev->gpuhtw_llc_slice = NULL;
+	}
+
 	adreno_input_handler.private = device;
 
 #ifdef CONFIG_INPUT
@@ -1109,6 +1118,8 @@
 	/* Release the system cache slice descriptor */
 	if (adreno_dev->gpu_llc_slice)
 		adreno_llc_putd(adreno_dev->gpu_llc_slice);
+	if (adreno_dev->gpuhtw_llc_slice)
+		adreno_llc_putd(adreno_dev->gpuhtw_llc_slice);
 
 	kgsl_pwrscale_close(device);
 
@@ -1578,6 +1589,8 @@
 
 	if (adreno_dev->gpu_llc_slice)
 		adreno_llc_deactivate_slice(adreno_dev->gpu_llc_slice);
+	if (adreno_dev->gpuhtw_llc_slice)
+		adreno_llc_deactivate_slice(adreno_dev->gpuhtw_llc_slice);
 
 	/* Save active coresight registers if applicable */
 	adreno_coresight_stop(adreno_dev);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 6120736..6278c7b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -398,6 +398,7 @@
  * @active_list_lock: Lock to protect active_list
  * @gpu_llc_slice: GPU system cache slice descriptor
  * @gpu_llc_slice_enable: To enable the GPU system cache slice or not
+ * @gpuhtw_llc_slice: GPU pagetables system cache slice descriptor
  */
 struct adreno_device {
 	struct kgsl_device dev;    /* Must be first field in this struct */
@@ -459,6 +460,7 @@
 
 	void *gpu_llc_slice;
 	bool gpu_llc_slice_enable;
+	void *gpuhtw_llc_slice;
 };
 
 /**
@@ -815,6 +817,7 @@
 	void (*clk_set_options)(struct adreno_device *,
 				const char *, struct clk *);
 	void (*llc_configure_gpu_scid)(struct adreno_device *adreno_dev);
+	void (*llc_configure_gpuhtw_scid)(struct adreno_device *adreno_dev);
 	void (*llc_enable_overrides)(struct adreno_device *adreno_dev);
 };
 
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 8e20806..de5fed5 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -35,6 +35,10 @@
 #define A6XX_GPU_LLC_SCID_NUM_BITS	5
 #define A6XX_GPU_LLC_SCID_MASK \
 	((1 << (A6XX_LLC_NUM_GPU_SCIDS * A6XX_GPU_LLC_SCID_NUM_BITS)) - 1)
+#define A6XX_GPUHTW_LLC_SCID_SHIFT	25
+#define A6XX_GPUHTW_LLC_SCID_MASK \
+	(((1 << A6XX_GPU_LLC_SCID_NUM_BITS) - 1) << A6XX_GPUHTW_LLC_SCID_SHIFT)
+
 #define A6XX_GPU_CX_REG_BASE		0x509E000
 #define A6XX_GPU_CX_REG_SIZE		0x1000
 
@@ -630,6 +634,24 @@
 }
 
 /*
+ * a6xx_llc_configure_gpuhtw_scid() - Program the SCID for GPU pagetables
+ * @adreno_dev: The adreno device pointer
+ */
+static void a6xx_llc_configure_gpuhtw_scid(struct adreno_device *adreno_dev)
+{
+	uint32_t gpuhtw_scid;
+	void __iomem *gpu_cx_reg;
+
+	gpuhtw_scid = adreno_llc_get_scid(adreno_dev->gpuhtw_llc_slice);
+
+	gpu_cx_reg = ioremap(A6XX_GPU_CX_REG_BASE, A6XX_GPU_CX_REG_SIZE);
+	extregrmw(gpu_cx_reg + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1,
+			A6XX_GPUHTW_LLC_SCID_MASK,
+			gpuhtw_scid << A6XX_GPUHTW_LLC_SCID_SHIFT);
+	iounmap(gpu_cx_reg);
+}
+
+/*
  * a6xx_llc_enable_overrides() - Override the page attributes
  * @adreno_dev: The adreno device pointer
  */
@@ -762,5 +784,6 @@
 	.microcode_read = a6xx_microcode_read,
 	.enable_64bit = a6xx_enable_64bit,
 	.llc_configure_gpu_scid = a6xx_llc_configure_gpu_scid,
+	.llc_configure_gpuhtw_scid = a6xx_llc_configure_gpuhtw_scid,
 	.llc_enable_overrides = a6xx_llc_enable_overrides
 };
diff --git a/drivers/gpu/msm/adreno_llc.h b/drivers/gpu/msm/adreno_llc.h
index ca8422cf..16c2e4e 100644
--- a/drivers/gpu/msm/adreno_llc.h
+++ b/drivers/gpu/msm/adreno_llc.h
@@ -52,9 +52,16 @@
 		if (!llcc_slice_activate(adreno_dev->gpu_llc_slice)) {
 			if (gpudev->llc_configure_gpu_scid)
 				gpudev->llc_configure_gpu_scid(adreno_dev);
-			if (gpudev->llc_enable_overrides)
-				gpudev->llc_enable_overrides(adreno_dev);
 		}
+
+	if (adreno_dev->gpuhtw_llc_slice)
+		if (!llcc_slice_activate(adreno_dev->gpuhtw_llc_slice)) {
+			if (gpudev->llc_configure_gpuhtw_scid)
+				gpudev->llc_configure_gpuhtw_scid(adreno_dev);
+		}
+
+	if (gpudev->llc_enable_overrides)
+		gpudev->llc_enable_overrides(adreno_dev);
 }
 
 #else
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index fdb6e0e..cfd5cd1 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1142,6 +1142,28 @@
 	kfree(iommu_pt);
 }
 
+void _enable_gpuhtw_llc(struct kgsl_mmu *mmu, struct kgsl_iommu_pt *iommu_pt)
+{
+	struct kgsl_device *device = KGSL_MMU_DEVICE(mmu);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int gpuhtw_llc_enable = 1;
+	int ret;
+
+	/* GPU pagetable walk LLC slice not enabled */
+	if (!adreno_dev->gpuhtw_llc_slice)
+		return;
+
+	/* Domain attribute to enable system cache for GPU pagetable walks */
+	ret = iommu_domain_set_attr(iommu_pt->domain,
+			DOMAIN_ATTR_USE_UPSTREAM_HINT, &gpuhtw_llc_enable);
+	/*
+	 * Warn that the system cache will not be used for GPU
+	 * pagetable walks. This is not a fatal error.
+	 */
+	WARN_ONCE(ret,
+		"System cache not enabled for GPU pagetable walks: %d\n", ret);
+}
+
 static int _init_global_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt)
 {
 	int ret = 0;
@@ -1165,6 +1187,8 @@
 		}
 	}
 
+	_enable_gpuhtw_llc(mmu, iommu_pt);
+
 	ret = _attach_pt(iommu_pt, ctx);
 	if (ret)
 		goto done;
@@ -1237,6 +1261,8 @@
 		goto done;
 	}
 
+	_enable_gpuhtw_llc(mmu, iommu_pt);
+
 	ret = _attach_pt(iommu_pt, ctx);
 
 	if (MMU_FEATURE(mmu, KGSL_MMU_HYP_SECURE_ALLOC))
@@ -1297,6 +1323,8 @@
 		goto done;
 	}
 
+	_enable_gpuhtw_llc(mmu, iommu_pt);
+
 	ret = _attach_pt(iommu_pt, ctx);
 	if (ret)
 		goto done;