Loading drivers/gpu/msm/kgsl_iommu.c +43 −62 Original line number Diff line number Diff line Loading @@ -647,10 +647,8 @@ static void _get_entries(struct kgsl_process_private *private, static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, struct _mem_entry *preventry, struct _mem_entry *nextentry, struct kgsl_context *context) struct kgsl_process_private *private) { struct kgsl_process_private *private; memset(preventry, 0, sizeof(*preventry)); memset(nextentry, 0, sizeof(*nextentry)); Loading @@ -659,8 +657,7 @@ static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, if (ADDR_IN_GLOBAL(mmu, faultaddr)) { _get_global_entries(faultaddr, preventry, nextentry); } else if (context) { private = context->proc_priv; } else if (private) { spin_lock(&private->mem_lock); _get_entries(private, faultaddr, preventry, nextentry); spin_unlock(&private->mem_lock); Loading Loading @@ -727,7 +724,7 @@ kgsl_iommu_uche_overfetch(struct kgsl_process_private *private, */ static bool kgsl_iommu_suppress_pagefault(uint64_t faultaddr, int write, struct kgsl_context *context) struct kgsl_process_private *private) { /* * If there is no context associated with the pagefault then this Loading @@ -735,10 +732,28 @@ static bool kgsl_iommu_suppress_pagefault(uint64_t faultaddr, int write, * on global buffers as they are mainly accessed by the CP bypassing * the UCHE. Also, write pagefaults are never suppressed. */ if (!context || write) if (!private || write) return false; return kgsl_iommu_uche_overfetch(context->proc_priv, faultaddr); return kgsl_iommu_uche_overfetch(private, faultaddr); } static struct kgsl_process_private *kgsl_iommu_identify_process(u64 ptbase) { struct kgsl_process_private *p = NULL; struct kgsl_iommu_pt *iommu_pt; mutex_lock(&kgsl_driver.process_mutex); list_for_each_entry(p, &kgsl_driver.process_list, list) { iommu_pt = p->pagetable->priv; if (iommu_pt->ttbr0 == ptbase) { mutex_unlock(&kgsl_driver.process_mutex); return p; } } mutex_unlock(&kgsl_driver.process_mutex); return p; } static int kgsl_iommu_fault_handler(struct iommu_domain *domain, Loading @@ -749,7 +764,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, struct kgsl_mmu *mmu = pt->mmu; struct kgsl_iommu *iommu; struct kgsl_iommu_context *ctx; u64 ptbase, proc_ptbase; u64 ptbase; u32 contextidr; pid_t pid = 0; pid_t ptname; Loading @@ -759,9 +774,8 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, struct adreno_device *adreno_dev; struct adreno_gpudev *gpudev; unsigned int no_page_fault_log = 0; unsigned int curr_context_id = 0; struct kgsl_context *context; char *fault_type = "unknown"; struct kgsl_process_private *private; static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, Loading @@ -776,21 +790,6 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, adreno_dev = ADRENO_DEVICE(device); gpudev = ADRENO_GPU_DEVICE(adreno_dev); if (pt->name == KGSL_MMU_SECURE_PT) ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE]; /* * set the fault bits and stuff before any printks so that if fault * handler runs then it will know it's dealing with a pagefault. * Read the global current timestamp because we could be in middle of * RB switch and hence the cur RB may not be reliable but global * one will always be reliable */ kgsl_sharedmem_readl(&device->memstore, &curr_context_id, KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context)); context = kgsl_context_get(device, curr_context_id); write = (flags & IOMMU_FAULT_WRITE) ? 1 : 0; if (flags & IOMMU_FAULT_TRANSLATION) fault_type = "translation"; Loading @@ -801,17 +800,21 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, else if (flags & IOMMU_FAULT_TRANSACTION_STALLED) fault_type = "transaction stalled"; if (kgsl_iommu_suppress_pagefault(addr, write, context)) { ptbase = KGSL_IOMMU_GET_CTX_REG_Q(ctx, TTBR0); private = kgsl_iommu_identify_process(ptbase); if (!kgsl_process_private_get(private)) private = NULL; else pid = private->pid; if (kgsl_iommu_suppress_pagefault(addr, write, private)) { 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); pid = context->proc_priv->pid; } if (pt->name == KGSL_MMU_SECURE_PT) ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE]; ctx->fault = 1; Loading @@ -827,9 +830,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, mutex_unlock(&device->mutex); } ptbase = KGSL_IOMMU_GET_CTX_REG_Q(ctx, TTBR0); contextidr = KGSL_IOMMU_GET_CTX_REG(ctx, CONTEXTIDR); ptname = MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE) ? KGSL_MMU_GLOBAL_PT : pid; /* Loading @@ -839,7 +840,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, */ trace_kgsl_mmu_pagefault(ctx->kgsldev, addr, ptname, context != NULL ? context->proc_priv->comm : "unknown", private != NULL ? private->comm : "unknown", write ? "write" : "read"); if (test_bit(KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE, Loading @@ -847,34 +848,13 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr); if (!no_page_fault_log && __ratelimit(&_rs)) { const char *api_str; if (context != NULL) { struct adreno_context *drawctxt = ADRENO_CONTEXT(context); api_str = get_api_type_str(drawctxt->type); } else api_str = "UNKNOWN"; KGSL_MEM_CRIT(ctx->kgsldev, "GPU PAGE FAULT: addr = %lX pid= %d name=%s\n", addr, ptname, context != NULL ? context->proc_priv->comm : "unknown"); if (context != NULL) { proc_ptbase = kgsl_mmu_pagetable_get_ttbr0( context->proc_priv->pagetable); if (ptbase != proc_ptbase) private != NULL ? private->comm : "unknown"); KGSL_MEM_CRIT(ctx->kgsldev, "Pagetable address mismatch: HW address is 0x%llx but SW expected 0x%llx\n", ptbase, proc_ptbase); } KGSL_MEM_CRIT(ctx->kgsldev, "context=%s ctx_type=%s TTBR0=0x%llx CIDR=0x%x (%s %s fault)\n", ctx->name, api_str, ptbase, contextidr, "context=%s TTBR0=0x%llx CIDR=0x%x (%s %s fault)\n", ctx->name, ptbase, contextidr, write ? "write" : "read", fault_type); if (gpudev->iommu_fault_block) { Loading @@ -893,7 +873,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, KGSL_LOG_DUMP(ctx->kgsldev, "---- nearby memory ----\n"); _find_mem_entries(mmu, addr, &prev, &next, context); _find_mem_entries(mmu, addr, &prev, &next, private); if (prev.gpuaddr) _print_entry(ctx->kgsldev, &prev); else Loading Loading @@ -935,7 +915,8 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, adreno_dispatcher_schedule(device); } kgsl_context_put(context); kgsl_process_private_put(private); return ret; } Loading Loading
drivers/gpu/msm/kgsl_iommu.c +43 −62 Original line number Diff line number Diff line Loading @@ -647,10 +647,8 @@ static void _get_entries(struct kgsl_process_private *private, static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, struct _mem_entry *preventry, struct _mem_entry *nextentry, struct kgsl_context *context) struct kgsl_process_private *private) { struct kgsl_process_private *private; memset(preventry, 0, sizeof(*preventry)); memset(nextentry, 0, sizeof(*nextentry)); Loading @@ -659,8 +657,7 @@ static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, if (ADDR_IN_GLOBAL(mmu, faultaddr)) { _get_global_entries(faultaddr, preventry, nextentry); } else if (context) { private = context->proc_priv; } else if (private) { spin_lock(&private->mem_lock); _get_entries(private, faultaddr, preventry, nextentry); spin_unlock(&private->mem_lock); Loading Loading @@ -727,7 +724,7 @@ kgsl_iommu_uche_overfetch(struct kgsl_process_private *private, */ static bool kgsl_iommu_suppress_pagefault(uint64_t faultaddr, int write, struct kgsl_context *context) struct kgsl_process_private *private) { /* * If there is no context associated with the pagefault then this Loading @@ -735,10 +732,28 @@ static bool kgsl_iommu_suppress_pagefault(uint64_t faultaddr, int write, * on global buffers as they are mainly accessed by the CP bypassing * the UCHE. Also, write pagefaults are never suppressed. */ if (!context || write) if (!private || write) return false; return kgsl_iommu_uche_overfetch(context->proc_priv, faultaddr); return kgsl_iommu_uche_overfetch(private, faultaddr); } static struct kgsl_process_private *kgsl_iommu_identify_process(u64 ptbase) { struct kgsl_process_private *p = NULL; struct kgsl_iommu_pt *iommu_pt; mutex_lock(&kgsl_driver.process_mutex); list_for_each_entry(p, &kgsl_driver.process_list, list) { iommu_pt = p->pagetable->priv; if (iommu_pt->ttbr0 == ptbase) { mutex_unlock(&kgsl_driver.process_mutex); return p; } } mutex_unlock(&kgsl_driver.process_mutex); return p; } static int kgsl_iommu_fault_handler(struct iommu_domain *domain, Loading @@ -749,7 +764,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, struct kgsl_mmu *mmu = pt->mmu; struct kgsl_iommu *iommu; struct kgsl_iommu_context *ctx; u64 ptbase, proc_ptbase; u64 ptbase; u32 contextidr; pid_t pid = 0; pid_t ptname; Loading @@ -759,9 +774,8 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, struct adreno_device *adreno_dev; struct adreno_gpudev *gpudev; unsigned int no_page_fault_log = 0; unsigned int curr_context_id = 0; struct kgsl_context *context; char *fault_type = "unknown"; struct kgsl_process_private *private; static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, Loading @@ -776,21 +790,6 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, adreno_dev = ADRENO_DEVICE(device); gpudev = ADRENO_GPU_DEVICE(adreno_dev); if (pt->name == KGSL_MMU_SECURE_PT) ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE]; /* * set the fault bits and stuff before any printks so that if fault * handler runs then it will know it's dealing with a pagefault. * Read the global current timestamp because we could be in middle of * RB switch and hence the cur RB may not be reliable but global * one will always be reliable */ kgsl_sharedmem_readl(&device->memstore, &curr_context_id, KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context)); context = kgsl_context_get(device, curr_context_id); write = (flags & IOMMU_FAULT_WRITE) ? 1 : 0; if (flags & IOMMU_FAULT_TRANSLATION) fault_type = "translation"; Loading @@ -801,17 +800,21 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, else if (flags & IOMMU_FAULT_TRANSACTION_STALLED) fault_type = "transaction stalled"; if (kgsl_iommu_suppress_pagefault(addr, write, context)) { ptbase = KGSL_IOMMU_GET_CTX_REG_Q(ctx, TTBR0); private = kgsl_iommu_identify_process(ptbase); if (!kgsl_process_private_get(private)) private = NULL; else pid = private->pid; if (kgsl_iommu_suppress_pagefault(addr, write, private)) { 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); pid = context->proc_priv->pid; } if (pt->name == KGSL_MMU_SECURE_PT) ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE]; ctx->fault = 1; Loading @@ -827,9 +830,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, mutex_unlock(&device->mutex); } ptbase = KGSL_IOMMU_GET_CTX_REG_Q(ctx, TTBR0); contextidr = KGSL_IOMMU_GET_CTX_REG(ctx, CONTEXTIDR); ptname = MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE) ? KGSL_MMU_GLOBAL_PT : pid; /* Loading @@ -839,7 +840,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, */ trace_kgsl_mmu_pagefault(ctx->kgsldev, addr, ptname, context != NULL ? context->proc_priv->comm : "unknown", private != NULL ? private->comm : "unknown", write ? "write" : "read"); if (test_bit(KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE, Loading @@ -847,34 +848,13 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr); if (!no_page_fault_log && __ratelimit(&_rs)) { const char *api_str; if (context != NULL) { struct adreno_context *drawctxt = ADRENO_CONTEXT(context); api_str = get_api_type_str(drawctxt->type); } else api_str = "UNKNOWN"; KGSL_MEM_CRIT(ctx->kgsldev, "GPU PAGE FAULT: addr = %lX pid= %d name=%s\n", addr, ptname, context != NULL ? context->proc_priv->comm : "unknown"); if (context != NULL) { proc_ptbase = kgsl_mmu_pagetable_get_ttbr0( context->proc_priv->pagetable); if (ptbase != proc_ptbase) private != NULL ? private->comm : "unknown"); KGSL_MEM_CRIT(ctx->kgsldev, "Pagetable address mismatch: HW address is 0x%llx but SW expected 0x%llx\n", ptbase, proc_ptbase); } KGSL_MEM_CRIT(ctx->kgsldev, "context=%s ctx_type=%s TTBR0=0x%llx CIDR=0x%x (%s %s fault)\n", ctx->name, api_str, ptbase, contextidr, "context=%s TTBR0=0x%llx CIDR=0x%x (%s %s fault)\n", ctx->name, ptbase, contextidr, write ? "write" : "read", fault_type); if (gpudev->iommu_fault_block) { Loading @@ -893,7 +873,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, KGSL_LOG_DUMP(ctx->kgsldev, "---- nearby memory ----\n"); _find_mem_entries(mmu, addr, &prev, &next, context); _find_mem_entries(mmu, addr, &prev, &next, private); if (prev.gpuaddr) _print_entry(ctx->kgsldev, &prev); else Loading Loading @@ -935,7 +915,8 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, adreno_dispatcher_schedule(device); } kgsl_context_put(context); kgsl_process_private_put(private); return ret; } Loading