Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3cc7764f authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Correctly identify page faulting process"

parents 77c559a8 c8216586
Loading
Loading
Loading
Loading
+43 −62
Original line number Diff line number Diff line
@@ -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));

@@ -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);
@@ -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
@@ -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,
@@ -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;
@@ -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,
@@ -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";
@@ -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;

@@ -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;
	/*
@@ -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,
@@ -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) {
@@ -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
@@ -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;
}