summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorSushmita Susheelendra <ssusheel@codeaurora.org>2015-04-28 17:30:34 -0600
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-25 16:02:48 -0700
commit82dd02436d2fe9964f32b08583e40b013d138e8d (patch)
tree237e0d4df05f13a29282bce2f4228e38e1be1ae8 /drivers/gpu
parent1d7b7494274e98488c4add1d238f2e55ab6f7f2a (diff)
msm: kgsl: Disable guardpage for A5x and suppress pagefaults
Disable the guardpage workaround for A5x and instead selectively suppress pagefaults. Suppress read pagefaults that are likely caused due to UCHE overfetches. For this, the fault address must be within the first 64 bytes of a page and the fault page must be preceded by a valid allocation. CRs-Fixed: 975293 Change-Id: I6a0995af3ab4129c6923726043c5f34c747641f9 Signed-off-by: Sushmita Susheelendra <ssusheel@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/msm/adreno_iommu.c4
-rw-r--r--drivers/gpu/msm/kgsl_iommu.c64
-rw-r--r--drivers/gpu/msm/kgsl_iommu.h5
3 files changed, 64 insertions, 9 deletions
diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c
index f1168d96b5de..2eeda01b3c4d 100644
--- a/drivers/gpu/msm/adreno_iommu.c
+++ b/drivers/gpu/msm/adreno_iommu.c
@@ -867,6 +867,10 @@ int adreno_iommu_init(struct adreno_device *adreno_dev)
}
}
+ /* Enable guard page MMU feature for A3xx and A4xx targets only */
+ if (adreno_is_a3xx(adreno_dev) || adreno_is_a4xx(adreno_dev))
+ device->mmu.features |= KGSL_MMU_NEED_GUARD_PAGE;
+
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 978d7ac405aa..95ebe628f823 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -476,6 +476,48 @@ static void _check_if_freed(struct kgsl_iommu_context *ctx,
}
}
+static bool
+kgsl_iommu_uche_overfetch(struct kgsl_process_private *private,
+ uint64_t faultaddr)
+{
+ int id;
+ struct kgsl_mem_entry *entry = NULL;
+
+ spin_lock(&private->mem_lock);
+ idr_for_each_entry(&private->mem_idr, entry, id) {
+ struct kgsl_memdesc *m = &entry->memdesc;
+
+ if ((faultaddr >= (m->gpuaddr + m->size))
+ && (faultaddr < (m->gpuaddr + m->size + 64))) {
+ spin_unlock(&private->mem_lock);
+ return true;
+ }
+ }
+ spin_unlock(&private->mem_lock);
+ return false;
+}
+
+/*
+ * Read pagefaults where the faulting address lies within the first 64 bytes
+ * of a page (UCHE line size is 64 bytes) and the fault page is preceded by a
+ * valid allocation are considered likely due to UCHE overfetch and suppressed.
+ */
+
+static bool kgsl_iommu_suppress_pagefault(uint64_t faultaddr, int write,
+ struct kgsl_context *context)
+{
+ /*
+ * If there is no context associated with the pagefault then this
+ * could be a fault on a global buffer. We do not suppress faults
+ * on global buffers as they are mainly accessed by the CP bypassing
+ * the UCHE. Also, write pagefaults are never suppressed.
+ */
+ if (!context || write)
+ return false;
+
+ return kgsl_iommu_uche_overfetch(context->proc_priv, faultaddr);
+}
+
static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
struct device *dev, unsigned long addr, int flags, void *token)
{
@@ -524,6 +566,18 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
context = kgsl_context_get(device, curr_context_id);
+ write = (flags & IOMMU_FAULT_WRITE) ? 1 : 0;
+ if (flags & IOMMU_FAULT_TRANSLATION)
+ fault_type = "translation";
+ else if (flags & IOMMU_FAULT_PERMISSION)
+ fault_type = "permission";
+
+ if (kgsl_iommu_suppress_pagefault(addr, write, context)) {
+ iommu->pagefault_suppression_count++;
+ kgsl_context_put(context);
+ return ret;
+ }
+
if (context != NULL) {
/* save pagefault timestamp for GFT */
set_bit(KGSL_CONTEXT_PRIV_PAGEFAULT, &context->priv);
@@ -544,12 +598,6 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
mutex_unlock(&device->mutex);
}
- write = (flags & IOMMU_FAULT_WRITE) ? 1 : 0;
- if (flags & IOMMU_FAULT_TRANSLATION)
- fault_type = "translation";
- else if (flags & IOMMU_FAULT_PERMISSION)
- fault_type = "permission";
-
ptbase = KGSL_IOMMU_GET_CTX_REG_Q(ctx, TTBR0);
contextidr = KGSL_IOMMU_GET_CTX_REG(ctx, CONTEXTIDR);
@@ -1178,7 +1226,6 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu)
int status;
mmu->features |= KGSL_MMU_PAGED;
- mmu->features |= KGSL_MMU_NEED_GUARD_PAGE;
if (ctx->name == NULL) {
KGSL_CORE_ERR("dt: gfx3d0_user context bank not found\n");
@@ -1221,7 +1268,8 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu)
}
}
- if (kgsl_guard_page == NULL) {
+ if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)
+ && (kgsl_guard_page == NULL)) {
kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
__GFP_HIGHMEM);
if (kgsl_guard_page == NULL) {
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index c8875bb975a9..f82452dd6080 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -137,6 +137,8 @@ struct kgsl_iommu_context {
* @micro_mmu_ctrl: GPU register offset of this glob al register
* @smmu_info: smmu info used in a5xx preemption
* @protect: register protection settings for the iommu.
+ * @pagefault_suppression_count: Total number of pagefaults
+ * suppressed since boot.
*/
struct kgsl_iommu {
struct kgsl_iommu_context ctx[KGSL_IOMMU_CONTEXT_MAX];
@@ -150,6 +152,7 @@ struct kgsl_iommu {
struct kgsl_memdesc smmu_info;
unsigned int version;
struct kgsl_protected_registers protect;
+ u32 pagefault_suppression_count;
};
/*