Loading drivers/gpu/msm/adreno_iommu.c +4 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading drivers/gpu/msm/kgsl_iommu.c +56 −8 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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) { Loading drivers/gpu/msm/kgsl_iommu.h +4 −1 Original line number Diff line number Diff line /* 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 Loading Loading @@ -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]; Loading @@ -150,6 +152,7 @@ struct kgsl_iommu { struct kgsl_memdesc smmu_info; unsigned int version; struct kgsl_protected_registers protect; u32 pagefault_suppression_count; }; /* Loading Loading
drivers/gpu/msm/adreno_iommu.c +4 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading
drivers/gpu/msm/kgsl_iommu.c +56 −8 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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) { Loading
drivers/gpu/msm/kgsl_iommu.h +4 −1 Original line number Diff line number Diff line /* 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 Loading Loading @@ -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]; Loading @@ -150,6 +152,7 @@ struct kgsl_iommu { struct kgsl_memdesc smmu_info; unsigned int version; struct kgsl_protected_registers protect; u32 pagefault_suppression_count; }; /* Loading