msm: kgsl: Restructure offset definitions for IOMMU registers
Define the IOMMU register offsets in a structure array. This
offers flexibility in defining IOMMU v2 offsets in another array
and the right array to be used can be setup during MMU
initialization.
Also, restrict the usage of IOMMU offsets only in the iommu file
by redifining the functions that return iommu information. Remove
the function to get iommu mapped register address and replace
it with a function that returns the gpuaddress of given iommu
register. Only return the valid address bits of an iommu pagetable
instead of just returning the pagetable base register value.
Change-Id: Ib88e605f57e551c7b84029647451cb20f06025a0
Signed-off-by: Shubhraprakash Das <sadas@codeaurora.org>
Signed-off-by: Rajeev Kulkarni <krajeev@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index de6b0d5..c47c1ac 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -275,25 +275,20 @@
unsigned int *cmds = &link[0];
int sizedwords = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct kgsl_memdesc **reg_map_desc;
- void *reg_map_array = NULL;
int num_iommu_units, i;
struct kgsl_context *context;
struct adreno_context *adreno_ctx = NULL;
if (!adreno_dev->drawctxt_active)
return kgsl_mmu_device_setstate(&device->mmu, flags);
- num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
- ®_map_array);
+ num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
context = idr_find(&device->context_idr, context_id);
adreno_ctx = context->devctxt;
- reg_map_desc = reg_map_array;
-
if (kgsl_mmu_enable_clk(&device->mmu,
KGSL_IOMMU_CONTEXT_USER))
- goto done;
+ return;
cmds += __adreno_add_idle_indirect_cmds(cmds,
device->mmu.setstate_memory.gpuaddr +
@@ -309,26 +304,23 @@
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
- pt_val = kgsl_mmu_pt_get_base_addr(device->mmu.hwpagetable);
+ pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
+ device->mmu.hwpagetable);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
/*
* We need to perfrom the following operations for all
* IOMMU units
*/
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val &
- (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT)) +
- kgsl_mmu_get_pt_lsb(&device->mmu, i,
- KGSL_IOMMU_CONTEXT_USER);
+ reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+ i, KGSL_IOMMU_CONTEXT_USER));
/*
* Set address of the new pagetable by writng to IOMMU
* TTBR0 register
*/
*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
- *cmds++ = reg_map_desc[i]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER <<
- KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0;
+ *cmds++ = kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER, KGSL_IOMMU_CTX_TTBR0);
*cmds++ = reg_pt_val;
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
*cmds++ = 0x00000000;
@@ -338,9 +330,8 @@
* above writes have completed
*/
cmds += adreno_add_read_cmds(device, cmds,
- reg_map_desc[i]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER <<
- KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+ kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER, KGSL_IOMMU_CTX_TTBR0),
reg_pt_val,
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
@@ -358,16 +349,12 @@
* tlb flush
*/
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val &
- (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT)) +
- kgsl_mmu_get_pt_lsb(&device->mmu, i,
- KGSL_IOMMU_CONTEXT_USER);
+ reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+ i, KGSL_IOMMU_CONTEXT_USER));
*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
- *cmds++ = (reg_map_desc[i]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER <<
- KGSL_IOMMU_CTX_SHIFT) +
+ *cmds++ = kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER,
KGSL_IOMMU_CTX_TLBIALL);
*cmds++ = 1;
@@ -376,9 +363,9 @@
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
cmds += adreno_add_read_cmds(device, cmds,
- reg_map_desc[i]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER <<
- KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+ kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER,
+ KGSL_IOMMU_CTX_TTBR0),
reg_pt_val,
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
@@ -387,7 +374,8 @@
if (cpu_is_msm8960())
cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
- reg_map_desc[0]->gpuaddr,
+ kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
+ 0, KGSL_IOMMU_GLOBAL_BASE),
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
else
@@ -413,9 +401,6 @@
kgsl_mmu_disable_clk_on_ts(&device->mmu,
adreno_dev->ringbuffer.timestamp[KGSL_MEMSTORE_GLOBAL], true);
}
-done:
- if (num_iommu_units)
- kfree(reg_map_array);
}
static void adreno_gpummu_setstate(struct kgsl_device *device,
@@ -453,7 +438,7 @@
/* set page table base */
*cmds++ = cp_type0_packet(MH_MMU_PT_BASE, 1);
- *cmds++ = kgsl_mmu_pt_get_base_addr(
+ *cmds++ = kgsl_mmu_get_pt_base_addr(&device->mmu,
device->mmu.hwpagetable);
sizedwords += 4;
}
@@ -2035,7 +2020,8 @@
adreno_context = (struct adreno_context *)context->devctxt;
- if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
+ if (kgsl_mmu_pt_equal(&device->mmu, adreno_context->pagetable,
+ pt_base)) {
struct kgsl_memdesc *desc;
desc = &adreno_context->gpustate;
@@ -2074,7 +2060,7 @@
size))
return &device->mmu.setstate_memory;
- entry = kgsl_get_mem_entry(pt_base, gpuaddr, size);
+ entry = kgsl_get_mem_entry(device, pt_base, gpuaddr, size);
if (entry)
return &entry->memdesc;
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 2038c10..261e518 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -697,8 +697,6 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct kgsl_memdesc **reg_map;
- void *reg_map_array;
int num_iommu_units = 0;
mb();
@@ -783,9 +781,7 @@
ib_list.count = 0;
i = 0;
/* get the register mapped array in case we are using IOMMU */
- num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
- ®_map_array);
- reg_map = reg_map_array;
+ num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
for (read_idx = 0; read_idx < num_item; ) {
uint32_t this_cmd = rb_copy[read_idx++];
if (adreno_cmd_is_ib(this_cmd)) {
@@ -799,13 +795,14 @@
ib_list.bases[i],
ib_list.sizes[i], 0);
} else if (this_cmd == cp_type0_packet(MH_MMU_PT_BASE, 1) ||
- (num_iommu_units && this_cmd == (reg_map[0]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
- KGSL_IOMMU_TTBR0))) {
-
+ (num_iommu_units && this_cmd ==
+ kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
+ KGSL_IOMMU_CONTEXT_USER,
+ KGSL_IOMMU_CTX_TTBR0))) {
KGSL_LOG_DUMP(device, "Current pagetable: %x\t"
"pagetable base: %x\n",
- kgsl_mmu_get_ptname_from_ptbase(cur_pt_base),
+ kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+ cur_pt_base),
cur_pt_base);
/* Set cur_pt_base to the new pagetable base */
@@ -813,12 +810,11 @@
KGSL_LOG_DUMP(device, "New pagetable: %x\t"
"pagetable base: %x\n",
- kgsl_mmu_get_ptname_from_ptbase(cur_pt_base),
+ kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+ cur_pt_base),
cur_pt_base);
}
}
- if (num_iommu_units)
- kfree(reg_map_array);
/* Restore cur_pt_base back to the pt_base of
the process in whose context the GPU hung */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index bd31d17..64c8343 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -194,13 +194,14 @@
EXPORT_SYMBOL(kgsl_cancel_events);
/* kgsl_get_mem_entry - get the mem_entry structure for the specified object
+ * @device - Pointer to the device structure
* @ptbase - the pagetable base of the object
* @gpuaddr - the GPU address of the object
* @size - Size of the region to search
*/
-struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
- unsigned int gpuaddr, unsigned int size)
+struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
+ unsigned int ptbase, unsigned int gpuaddr, unsigned int size)
{
struct kgsl_process_private *priv;
struct kgsl_mem_entry *entry;
@@ -208,7 +209,7 @@
mutex_lock(&kgsl_driver.process_mutex);
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
- if (!kgsl_mmu_pt_equal(priv->pagetable, ptbase))
+ if (!kgsl_mmu_pt_equal(&device->mmu, priv->pagetable, ptbase))
continue;
spin_lock(&priv->mem_lock);
entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index ac04c56..416eda9 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -175,8 +175,8 @@
void kgsl_mem_entry_destroy(struct kref *kref);
int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
-struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
- unsigned int gpuaddr, unsigned int size);
+struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
+ unsigned int ptbase, unsigned int gpuaddr, unsigned int size);
struct kgsl_mem_entry *kgsl_sharedmem_find_region(
struct kgsl_process_private *private, unsigned int gpuaddr,
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 8cf00ea..326e79d 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -355,8 +355,9 @@
return NULL;
}
-int kgsl_gpummu_pt_equal(struct kgsl_pagetable *pt,
- unsigned int pt_base)
+int kgsl_gpummu_pt_equal(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt,
+ unsigned int pt_base)
{
struct kgsl_gpummu_pt *gpummu_pt = pt ? pt->priv : NULL;
return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
@@ -409,10 +410,10 @@
KGSL_MEM_CRIT(mmu->device,
"mmu page fault: page=0x%lx pt=%d op=%s axi=%d\n",
reg & ~(PAGE_SIZE - 1),
- kgsl_mmu_get_ptname_from_ptbase(ptbase),
+ kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
reg & 0x02 ? "WRITE" : "READ", (reg >> 4) & 0xF);
trace_kgsl_mmu_pagefault(mmu->device, reg & ~(PAGE_SIZE - 1),
- kgsl_mmu_get_ptname_from_ptbase(ptbase),
+ kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
reg & 0x02 ? "WRITE" : "READ");
}
@@ -714,12 +715,18 @@
}
static unsigned int
-kgsl_gpummu_pt_get_base_addr(struct kgsl_pagetable *pt)
+kgsl_gpummu_get_pt_base_addr(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt)
{
struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
return gpummu_pt->base.gpuaddr;
}
+static int kgsl_gpummu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+ return 1;
+}
+
struct kgsl_mmu_ops gpummu_ops = {
.mmu_init = kgsl_gpummu_init,
.mmu_close = kgsl_gpummu_close,
@@ -729,10 +736,13 @@
.mmu_device_setstate = kgsl_gpummu_default_setstate,
.mmu_pagefault = kgsl_gpummu_pagefault,
.mmu_get_current_ptbase = kgsl_gpummu_get_current_ptbase,
+ .mmu_pt_equal = kgsl_gpummu_pt_equal,
+ .mmu_get_pt_base_addr = kgsl_gpummu_get_pt_base_addr,
.mmu_enable_clk = NULL,
.mmu_disable_clk_on_ts = NULL,
.mmu_get_pt_lsb = NULL,
- .mmu_get_reg_map_desc = NULL,
+ .mmu_get_reg_gpuaddr = NULL,
+ .mmu_get_num_iommu_units = kgsl_gpummu_get_num_iommu_units,
};
struct kgsl_mmu_pt_ops gpummu_pt_ops = {
@@ -740,6 +750,4 @@
.mmu_unmap = kgsl_gpummu_unmap,
.mmu_create_pagetable = kgsl_gpummu_create_pagetable,
.mmu_destroy_pagetable = kgsl_gpummu_destroy_pagetable,
- .mmu_pt_equal = kgsl_gpummu_pt_equal,
- .mmu_pt_get_base_addr = kgsl_gpummu_pt_get_base_addr,
};
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 6dc7dc5..7254647 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -28,7 +28,16 @@
#include "adreno.h"
#include "kgsl_trace.h"
-static struct kgsl_iommu_unit *get_iommu_unit(struct device *dev)
+static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
+ { 0, 0, 0 }, /* GLOBAL_BASE */
+ { 0x10, 0x0003FFFF, 14 }, /* TTBR0 */
+ { 0x14, 0x0003FFFF, 14 }, /* TTBR1 */
+ { 0x20, 0, 0 }, /* FSR */
+ { 0x800, 0, 0 }, /* TLBIALL */
+};
+
+static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
+ struct kgsl_iommu_unit **iommu_unit_out)
{
int i, j, k;
@@ -49,13 +58,16 @@
struct kgsl_iommu_unit *iommu_unit =
&iommu->iommu_units[j];
for (k = 0; k < iommu_unit->dev_count; k++) {
- if (iommu_unit->dev[k].dev == dev)
- return iommu_unit;
+ if (iommu_unit->dev[k].dev == dev) {
+ *mmu_out = mmu;
+ *iommu_unit_out = iommu_unit;
+ return 0;
+ }
}
}
}
- return NULL;
+ return -EINVAL;
}
static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
@@ -74,31 +86,41 @@
static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
struct device *dev, unsigned long addr, int flags)
{
- struct kgsl_iommu_unit *iommu_unit = get_iommu_unit(dev);
- struct kgsl_iommu_device *iommu_dev = get_iommu_device(iommu_unit, dev);
+ int ret = 0;
+ struct kgsl_mmu *mmu;
+ struct kgsl_iommu *iommu;
+ struct kgsl_iommu_unit *iommu_unit;
+ struct kgsl_iommu_device *iommu_dev;
unsigned int ptbase, fsr;
+ ret = get_iommu_unit(dev, &mmu, &iommu_unit);
+ if (ret)
+ goto done;
+ iommu_dev = get_iommu_device(iommu_unit, dev);
if (!iommu_dev) {
KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
- return -ENOSYS;
+ ret = -ENOSYS;
+ goto done;
}
+ iommu = mmu->priv;
- ptbase = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
+ ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
iommu_dev->ctx_id, TTBR0);
- fsr = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
+ fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
iommu_dev->ctx_id, FSR);
KGSL_MEM_CRIT(iommu_dev->kgsldev,
"GPU PAGE FAULT: addr = %lX pid = %d\n",
- addr, kgsl_mmu_get_ptname_from_ptbase(ptbase));
+ addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
iommu_dev->ctx_id, fsr);
trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
- kgsl_mmu_get_ptname_from_ptbase(ptbase), 0);
+ kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
- return 0;
+done:
+ return ret;
}
/*
@@ -271,6 +293,7 @@
/*
* kgsl_iommu_pt_equal - Check if pagetables are equal
+ * @mmu - Pointer to mmu structure
* @pt - Pointer to pagetable
* @pt_base - Address of a pagetable that the IOMMU register is
* programmed with
@@ -279,17 +302,23 @@
* the pagetable which is contained in the pt structure
* Return - Non-zero if the pagetable addresses are equal else 0
*/
-static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
- unsigned int pt_base)
+static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt,
+ unsigned int pt_base)
{
+ struct kgsl_iommu *iommu = mmu->priv;
struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
unsigned int domain_ptbase = iommu_pt ?
iommu_get_pt_base_addr(iommu_pt->domain) : 0;
/* Only compare the valid address bits of the pt_base */
- domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT);
- pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT);
+ domain_ptbase &=
+ (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+
+ pt_base &=
+ (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+
return domain_ptbase && pt_base &&
(domain_ptbase == pt_base);
}
@@ -326,7 +355,7 @@
return NULL;
}
iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
- MSM_IOMMU_DOMAIN_PT_CACHEABLE);
+ MSM_IOMMU_DOMAIN_PT_CACHEABLE);
if (!iommu_pt->domain) {
KGSL_CORE_ERR("Failed to create iommu domain\n");
kfree(iommu_pt);
@@ -581,17 +610,22 @@
}
/*
- * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
+ * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
* IOMMU ttbr0 register is programmed with
+ * @mmu - Pointer to mmu
* @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
*
* Return - actual pagetable address that the ttbr0 register is programmed
* with
*/
-static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
+static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt)
{
+ struct kgsl_iommu *iommu = mmu->priv;
struct kgsl_iommu_pt *iommu_pt = pt->priv;
- return iommu_get_pt_base_addr(iommu_pt->domain);
+ return iommu_get_pt_base_addr(iommu_pt->domain) &
+ (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
}
/*
@@ -666,6 +700,9 @@
if (status)
goto done;
+ iommu->iommu_reg_list = kgsl_iommuv1_reg;
+ iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
+
/* A nop is required in an indirect buffer when switching
* pagetables in-stream */
kgsl_sharedmem_writel(&mmu->setstate_memory,
@@ -720,13 +757,14 @@
mmu->defaultpagetable;
/* Map the IOMMU regsiters to only defaultpagetable */
for (i = 0; i < iommu->unit_count; i++) {
- iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
+ iommu->iommu_units[i].reg_map.priv |=
+ KGSL_MEMFLAGS_GLOBAL;
status = kgsl_mmu_map(pagetable,
&(iommu->iommu_units[i].reg_map),
GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
if (status) {
iommu->iommu_units[i].reg_map.priv &=
- ~KGSL_MEMFLAGS_GLOBAL;
+ ~KGSL_MEMFLAGS_GLOBAL;
goto err;
}
}
@@ -799,9 +837,9 @@
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++)
- iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
- KGSL_IOMMU_GET_IOMMU_REG(
- iommu_unit->reg_map.hostptr,
+ iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
+ KGSL_IOMMU_GET_CTX_REG(iommu,
+ iommu_unit,
iommu_unit->dev[j].ctx_id,
TTBR0));
}
@@ -940,12 +978,13 @@
return 0;
/* Return the current pt base by reading IOMMU pt_base register */
kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
- pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
- (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
- KGSL_IOMMU_TTBR0);
+ pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
+ KGSL_IOMMU_CONTEXT_USER,
+ TTBR0);
kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
- return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT);
+ return pt_base &
+ (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
}
/*
@@ -966,8 +1005,8 @@
struct kgsl_iommu *iommu = mmu->priv;
int temp;
int i;
- unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
- mmu->hwpagetable);
+ unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
+ mmu->hwpagetable);
unsigned int pt_val;
if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
@@ -975,7 +1014,9 @@
return;
}
/* Mask off the lsb of the pt base address since lsb will not change */
- pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
+ pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
kgsl_idle(mmu->device);
for (i = 0; i < iommu->unit_count; i++) {
@@ -985,23 +1026,20 @@
KGSL_IOMMU_CONTEXT_USER);
pt_val += pt_base;
- KGSL_IOMMU_SET_IOMMU_REG(
- iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
mb();
- temp = KGSL_IOMMU_GET_IOMMU_REG(
- iommu->iommu_units[i].reg_map.hostptr,
+ temp = KGSL_IOMMU_GET_CTX_REG(iommu,
+ (&iommu->iommu_units[i]),
KGSL_IOMMU_CONTEXT_USER, TTBR0);
}
}
/* Flush tlb */
if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
for (i = 0; i < iommu->unit_count; i++) {
- KGSL_IOMMU_SET_IOMMU_REG(
- iommu->iommu_units[i].reg_map.hostptr,
- KGSL_IOMMU_CONTEXT_USER, CTX_TLBIALL,
- 1);
+ KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
+ KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
mb();
}
}
@@ -1010,40 +1048,32 @@
}
/*
- * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
- * the address of memory descriptors which map the IOMMU registers
+ * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
* @mmu - Pointer to mmu structure
- * @reg_map_desc - Out parameter in which the address of the array containing
- * pointers to register map descriptors is returned. The caller is supposed
- * to free this array
+ * @iommu_unit - The iommu unit for which base address is requested
+ * @ctx_id - The context ID of the IOMMU ctx
+ * @reg - The register for which address is required
*
* Return - The number of iommu units which is also the number of register
* mapped descriptor arrays which the out parameter will have
*/
-static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
- void **reg_map_desc)
+static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
+ int iommu_unit, int ctx_id, int reg)
{
struct kgsl_iommu *iommu = mmu->priv;
- void **reg_desc_ptr;
- int i;
- /*
- * Alocate array of pointers that will hold address of the register map
- * descriptors
- */
- reg_desc_ptr = kmalloc(iommu->unit_count *
- sizeof(struct kgsl_memdesc *), GFP_KERNEL);
- if (!reg_desc_ptr) {
- KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
- iommu->unit_count * sizeof(struct kgsl_memdesc *));
- return -ENOMEM;
- }
+ if (KGSL_IOMMU_GLOBAL_BASE == reg)
+ return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
+ else
+ return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
+ iommu->iommu_reg_list[reg].reg_offset +
+ (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
+}
- for (i = 0; i < iommu->unit_count; i++)
- reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
-
- *reg_map_desc = reg_desc_ptr;
- return i;
+static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ return iommu->unit_count;
}
struct kgsl_mmu_ops iommu_ops = {
@@ -1058,7 +1088,10 @@
.mmu_enable_clk = kgsl_iommu_enable_clk,
.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
.mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
- .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
+ .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
+ .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
+ .mmu_pt_equal = kgsl_iommu_pt_equal,
+ .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
};
struct kgsl_mmu_pt_ops iommu_pt_ops = {
@@ -1066,6 +1099,4 @@
.mmu_unmap = kgsl_iommu_unmap,
.mmu_create_pagetable = kgsl_iommu_create_pagetable,
.mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
- .mmu_pt_equal = kgsl_iommu_pt_equal,
- .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
};
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index f14db93..7dc222e 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -15,15 +15,23 @@
#include <mach/iommu.h>
-/* IOMMU registers and masks */
-#define KGSL_IOMMU_TTBR0 0x10
-#define KGSL_IOMMU_TTBR1 0x14
-#define KGSL_IOMMU_FSR 0x20
+#define KGSL_IOMMU_CTX_OFFSET_V1 0
+#define KGSL_IOMMU_CTX_SHIFT 12
-#define KGSL_IOMMU_TTBR0_PA_MASK 0x0003FFFF
-#define KGSL_IOMMU_TTBR0_PA_SHIFT 14
-#define KGSL_IOMMU_CTX_TLBIALL 0x800
-#define KGSL_IOMMU_CTX_SHIFT 12
+enum kgsl_iommu_reg_map {
+ KGSL_IOMMU_GLOBAL_BASE = 0,
+ KGSL_IOMMU_CTX_TTBR0,
+ KGSL_IOMMU_CTX_TTBR1,
+ KGSL_IOMMU_CTX_FSR,
+ KGSL_IOMMU_CTX_TLBIALL,
+ KGSL_IOMMU_REG_MAX
+};
+
+struct kgsl_iommu_register_list {
+ unsigned int reg_offset;
+ unsigned int reg_mask;
+ unsigned int reg_shift;
+};
/*
* Max number of iommu units that the gpu core can have
@@ -35,20 +43,25 @@
#define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
/* Macros to read/write IOMMU registers */
-#define KGSL_IOMMU_SET_IOMMU_REG(base_addr, ctx, REG, val) \
- writel_relaxed(val, base_addr + \
- (ctx << KGSL_IOMMU_CTX_SHIFT) + \
- KGSL_IOMMU_##REG)
+#define KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, ctx, REG, val) \
+ writel_relaxed(val, \
+ iommu_unit->reg_map.hostptr + \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ iommu->ctx_offset)
-#define KGSL_IOMMU_GET_IOMMU_REG(base_addr, ctx, REG) \
- readl_relaxed(base_addr + \
- (ctx << KGSL_IOMMU_CTX_SHIFT) + \
- KGSL_IOMMU_##REG)
+#define KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit, ctx, REG) \
+ readl_relaxed( \
+ iommu_unit->reg_map.hostptr + \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ iommu->ctx_offset)
/* Gets the lsb value of pagetable */
-#define KGSL_IOMMMU_PT_LSB(pt_val) \
- (pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK << \
- KGSL_IOMMU_TTBR0_PA_SHIFT))
+#define KGSL_IOMMMU_PT_LSB(iommu, pt_val) \
+ (pt_val & \
+ ~(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask << \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift))
/* offset at which a nop command is placed in setstate_memory */
#define KGSL_IOMMU_SETSTATE_NOP_OFFSET 1024
@@ -99,6 +112,9 @@
* @clk_event_queued: Indicates whether an event to disable clocks
* is already queued or not
* @device: Pointer to kgsl device
+ * @ctx_offset: The context offset to be added to base address when
+ * accessing IOMMU registers
+ * @iommu_reg_list: List of IOMMU registers { offset, map, shift } array
*/
struct kgsl_iommu {
struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS];
@@ -106,6 +122,8 @@
unsigned int iommu_last_cmd_ts;
bool clk_event_queued;
struct kgsl_device *device;
+ unsigned int ctx_offset;
+ struct kgsl_iommu_register_list *iommu_reg_list;
};
/*
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 0426339..3aea81f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/iommu.h>
+#include <mach/iommu.h>
#include <mach/socinfo.h>
#include "kgsl.h"
@@ -325,14 +326,16 @@
}
int
-kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base)
+kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, unsigned int pt_base)
{
struct kgsl_pagetable *pt;
int ptid = -1;
+ if (!mmu->mmu_ops || !mmu->mmu_ops->mmu_pt_equal)
+ return KGSL_MMU_GLOBAL_PT;
spin_lock(&kgsl_driver.ptlock);
list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
- if (pt->pt_ops->mmu_pt_equal(pt, pt_base)) {
+ if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
ptid = (int) pt->name;
break;
}
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 8221b80..234629b 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -139,8 +139,15 @@
int (*mmu_get_pt_lsb)(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id);
- int (*mmu_get_reg_map_desc)(struct kgsl_mmu *mmu,
- void **reg_map_desc);
+ unsigned int (*mmu_get_reg_gpuaddr)(struct kgsl_mmu *mmu,
+ int iommu_unit_num, int ctx_id, int reg);
+ int (*mmu_get_num_iommu_units)(struct kgsl_mmu *mmu);
+ int (*mmu_pt_equal) (struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt,
+ unsigned int pt_base);
+ unsigned int (*mmu_get_pt_base_addr)
+ (struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt);
};
struct kgsl_mmu_pt_ops {
@@ -153,10 +160,6 @@
unsigned int *tlb_flags);
void *(*mmu_create_pagetable) (void);
void (*mmu_destroy_pagetable) (void *pt);
- int (*mmu_pt_equal) (struct kgsl_pagetable *pt,
- unsigned int pt_base);
- unsigned int (*mmu_pt_get_base_addr)
- (struct kgsl_pagetable *pt);
};
struct kgsl_mmu {
@@ -196,7 +199,8 @@
unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
uint32_t flags);
-int kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base);
+int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
+ unsigned int pt_base);
int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
enum kgsl_deviceid id);
void kgsl_mmu_ptpool_destroy(void *ptpool);
@@ -242,28 +246,21 @@
mmu->mmu_ops->mmu_stop(mmu);
}
-static inline int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
+static inline int kgsl_mmu_pt_equal(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt,
unsigned int pt_base)
{
- if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_pt_equal)
+ return mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base);
+ else
return 1;
- else
- return pt->pt_ops->mmu_pt_equal(pt, pt_base);
}
-static inline unsigned int kgsl_mmu_pt_get_base_addr(struct kgsl_pagetable *pt)
+static inline unsigned int kgsl_mmu_get_pt_base_addr(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt)
{
- if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
- return 0;
- else
- return pt->pt_ops->mmu_pt_get_base_addr(pt);
-}
-
-static inline int kgsl_mmu_get_reg_map_desc(struct kgsl_mmu *mmu,
- void **reg_map_desc)
-{
- if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_map_desc)
- return mmu->mmu_ops->mmu_get_reg_map_desc(mmu, reg_map_desc);
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_base_addr)
+ return mmu->mmu_ops->mmu_get_pt_base_addr(mmu, pt);
else
return 0;
}
@@ -304,4 +301,23 @@
MH_INTERRUPT_MASK__AXI_WRITE_ERROR);
}
+static inline unsigned int kgsl_mmu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
+ int iommu_unit_num,
+ int ctx_id, int reg)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_gpuaddr)
+ return mmu->mmu_ops->mmu_get_reg_gpuaddr(mmu, iommu_unit_num,
+ ctx_id, reg);
+ else
+ return 0;
+}
+
+static inline int kgsl_mmu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_num_iommu_units)
+ return mmu->mmu_ops->mmu_get_num_iommu_units(mmu);
+ else
+ return 0;
+}
+
#endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 824d806..abaa8ce 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -175,7 +175,8 @@
/* Get the current PT base */
header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
/* And the PID for the task leader */
- pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
+ pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+ header->ptbase);
task = find_task_by_vpid(pid);
@@ -307,7 +308,7 @@
struct kgsl_snapshot_object *obj;
int offset;
- entry = kgsl_get_mem_entry(ptbase, gpuaddr, size);
+ entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
if (entry == NULL) {
KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index a9b0c50..7cf3799 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -152,7 +152,8 @@
ib_gpuptr = rb_hostptr[i+1];
- entry = kgsl_get_mem_entry(pt_base, ib_gpuptr, 1);
+ entry = kgsl_get_mem_entry(device, pt_base, ib_gpuptr,
+ 1);
if (entry == NULL) {
KGSL_LOG_DUMP(device,