msm: kgsl: Synchronize access to IOMMU cfg port
Add a software based spinlock between CPU and GPU.
This spinlock is used to grant mutually exclusive access to
SMMU configuration between CPU and GPU. This mutual exclusion
is required to prevent deadlock in the system.
CRs-Fixed: 409198
Change-Id: Ic375beaaf4c5505b41d3fabc4adf15965d71b13a
Signed-off-by: Tarun Karra <tkarra@codeaurora.org>
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Rajeev Kulkarnie <krajeev@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 65b4e16..cdf606c 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -139,6 +139,7 @@
*/
#define ANY_ID (~0)
+#define NO_VER (~0)
static const struct {
enum adreno_gpurev gpurev;
@@ -148,45 +149,53 @@
struct adreno_gpudev *gpudev;
unsigned int istore_size;
unsigned int pix_shader_start;
- unsigned int instruction_size; /* Size of an instruction in dwords */
- unsigned int gmem_size; /* size of gmem for gpu*/
+ /* Size of an instruction in dwords */
+ unsigned int instruction_size;
+ /* size of gmem for gpu*/
+ unsigned int gmem_size;
+ /* version of pm4 microcode that supports sync_lock
+ between CPU and GPU for SMMU-v1 programming */
+ unsigned int sync_lock_pm4_ver;
+ /* version of pfp microcode that supports sync_lock
+ between CPU and GPU for SMMU-v1 programming */
+ unsigned int sync_lock_pfp_ver;
} adreno_gpulist[] = {
{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
- 512, 384, 3, SZ_256K },
+ 512, 384, 3, SZ_256K, NO_VER, NO_VER },
{ ADRENO_REV_A203, 0, 1, 1, ANY_ID,
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
- 512, 384, 3, SZ_256K },
+ 512, 384, 3, SZ_256K, NO_VER, NO_VER },
{ ADRENO_REV_A205, 0, 1, 0, ANY_ID,
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
- 512, 384, 3, SZ_256K },
+ 512, 384, 3, SZ_256K, NO_VER, NO_VER },
{ ADRENO_REV_A220, 2, 1, ANY_ID, ANY_ID,
"leia_pm4_470.fw", "leia_pfp_470.fw", &adreno_a2xx_gpudev,
- 512, 384, 3, SZ_512K },
+ 512, 384, 3, SZ_512K, NO_VER, NO_VER },
/*
* patchlevel 5 (8960v2) needs special pm4 firmware to work around
* a hardware problem.
*/
{ ADRENO_REV_A225, 2, 2, 0, 5,
"a225p5_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
- 1536, 768, 3, SZ_512K },
+ 1536, 768, 3, SZ_512K, NO_VER, NO_VER },
{ ADRENO_REV_A225, 2, 2, 0, 6,
"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
- 1536, 768, 3, SZ_512K },
+ 1536, 768, 3, SZ_512K, 0x225011, 0x225002 },
{ ADRENO_REV_A225, 2, 2, ANY_ID, ANY_ID,
"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
- 1536, 768, 3, SZ_512K },
+ 1536, 768, 3, SZ_512K, 0x225011, 0x225002 },
/* A3XX doesn't use the pix_shader_start */
{ ADRENO_REV_A305, 3, 0, 5, ANY_ID,
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
- 512, 0, 2, SZ_256K },
+ 512, 0, 2, SZ_256K, 0x3FF037, 0x3FF016 },
/* A3XX doesn't use the pix_shader_start */
{ ADRENO_REV_A320, 3, 2, ANY_ID, ANY_ID,
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
- 512, 0, 2, SZ_512K },
+ 512, 0, 2, SZ_512K, 0x3FF037, 0x3FF016 },
{ ADRENO_REV_A330, 3, 3, 0, 0,
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
- 512, 0, 2, SZ_1M },
+ 512, 0, 2, SZ_1M, NO_VER, NO_VER },
};
static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
@@ -273,7 +282,7 @@
uint32_t flags)
{
unsigned int pt_val, reg_pt_val;
- unsigned int link[200];
+ unsigned int link[250];
unsigned int *cmds = &link[0];
int sizedwords = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -306,6 +315,11 @@
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+ cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
+ /* Acquire GPU-CPU sync Lock here */
+ cmds += kgsl_mmu_sync_lock(&device->mmu, cmds);
+
pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
device->mmu.hwpagetable);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
@@ -367,6 +381,9 @@
}
}
+ /* Release GPU-CPU sync Lock here */
+ cmds += kgsl_mmu_sync_unlock(&device->mmu, cmds);
+
if (cpu_is_msm8960())
cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
@@ -379,6 +396,8 @@
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+ cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
sizedwords += (cmds - &link[0]);
if (sizedwords) {
/* invalidate all base pointers */
@@ -393,6 +412,11 @@
kgsl_mmu_disable_clk_on_ts(&device->mmu,
adreno_dev->ringbuffer.timestamp[KGSL_MEMSTORE_GLOBAL], true);
}
+
+ if (sizedwords > (sizeof(link)/sizeof(unsigned int))) {
+ KGSL_DRV_ERR(device, "Temp command buffer overflow\n");
+ BUG();
+ }
}
static void adreno_gpummu_setstate(struct kgsl_device *device,
@@ -628,6 +652,8 @@
adreno_dev->pix_shader_start = adreno_gpulist[i].pix_shader_start;
adreno_dev->instruction_size = adreno_gpulist[i].instruction_size;
adreno_dev->gmem_size = adreno_gpulist[i].gmem_size;
+ adreno_dev->gpulist_index = i;
+
}
static struct platform_device_id adreno_id_table[] = {
@@ -1174,12 +1200,36 @@
/* Identify the specific GPU */
adreno_identify_gpu(adreno_dev);
+ if (adreno_ringbuffer_read_pm4_ucode(device)) {
+ KGSL_DRV_ERR(device, "Reading pm4 microcode failed %s\n",
+ adreno_dev->pm4_fwfile);
+ BUG_ON(1);
+ }
+
+ if (adreno_ringbuffer_read_pfp_ucode(device)) {
+ KGSL_DRV_ERR(device, "Reading pfp microcode failed %s\n",
+ adreno_dev->pfp_fwfile);
+ BUG_ON(1);
+ }
+
if (adreno_dev->gpurev == ADRENO_REV_UNKNOWN) {
KGSL_DRV_ERR(device, "Unknown chip ID %x\n",
adreno_dev->chip_id);
goto error_clk_off;
}
+
+ /*
+ * Check if firmware supports the sync lock PM4 packets needed
+ * for IOMMUv1
+ */
+
+ if ((adreno_dev->pm4_fw_version >=
+ adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pm4_ver) &&
+ (adreno_dev->pfp_fw_version >=
+ adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pfp_ver))
+ device->mmu.flags |= KGSL_MMU_FLAGS_IOMMU_SYNC;
+
/* Set up the MMU */
if (adreno_is_a2xx(adreno_dev)) {
/*