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

Commit 443438e6 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 c285814c 4a1b1549
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -738,7 +738,7 @@ static void setup_fault_process(struct kgsl_device *device,
	if (kgsl_mmu_is_perprocess(&device->mmu)) {
		struct kgsl_process_private *tmp;

		mutex_lock(&kgsl_driver.process_mutex);
		spin_lock(&kgsl_driver.proclist_lock);
		list_for_each_entry(tmp, &kgsl_driver.process_list, list) {
			u64 pt_ttbr0;

@@ -749,7 +749,7 @@ static void setup_fault_process(struct kgsl_device *device,
				break;
			}
		}
		mutex_unlock(&kgsl_driver.process_mutex);
		spin_unlock(&kgsl_driver.proclist_lock);
	}
done:
	snapshot->process = process;
+8 −2
Original line number Diff line number Diff line
@@ -921,7 +921,7 @@ struct kgsl_process_private *kgsl_process_private_find(pid_t pid)
{
	struct kgsl_process_private *p, *private = NULL;

	mutex_lock(&kgsl_driver.process_mutex);
	spin_lock(&kgsl_driver.proclist_lock);
	list_for_each_entry(p, &kgsl_driver.process_list, list) {
		if (p->pid == pid) {
			if (kgsl_process_private_get(p))
@@ -929,7 +929,8 @@ struct kgsl_process_private *kgsl_process_private_find(pid_t pid)
			break;
		}
	}
	mutex_unlock(&kgsl_driver.process_mutex);
	spin_unlock(&kgsl_driver.proclist_lock);

	return private;
}

@@ -1035,7 +1036,9 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv,
		kgsl_mmu_detach_pagetable(private->pagetable);

	/* Remove the process struct from the master list */
	spin_lock(&kgsl_driver.proclist_lock);
	list_del(&private->list);
	spin_unlock(&kgsl_driver.proclist_lock);

	/*
	 * Unlock the mutex before releasing the memory and the debugfs
@@ -1071,7 +1074,9 @@ static struct kgsl_process_private *kgsl_process_private_open(
		kgsl_process_init_sysfs(device, private);
		kgsl_process_init_debugfs(private);

		spin_lock(&kgsl_driver.proclist_lock);
		list_add(&private->list, &kgsl_driver.process_list);
		spin_unlock(&kgsl_driver.proclist_lock);
	}

done:
@@ -4870,6 +4875,7 @@ static const struct file_operations kgsl_fops = {

struct kgsl_driver kgsl_driver  = {
	.process_mutex = __MUTEX_INITIALIZER(kgsl_driver.process_mutex),
	.proclist_lock = __SPIN_LOCK_UNLOCKED(kgsl_driver.proclist_lock),
	.ptlock = __SPIN_LOCK_UNLOCKED(kgsl_driver.ptlock),
	.devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock),
	/*
+2 −0
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ struct kgsl_context;
 * @pagetable_list: LIst of open pagetables
 * @ptlock: Lock for accessing the pagetable list
 * @process_mutex: Mutex for accessing the process list
 * @proclist_lock: Lock for accessing the process list
 * @devlock: Mutex protecting the device list
 * @stats: Struct containing atomic memory statistics
 * @full_cache_threshold: the threshold that triggers a full cache flush
@@ -131,6 +132,7 @@ struct kgsl_driver {
	struct list_head pagetable_list;
	spinlock_t ptlock;
	struct mutex process_mutex;
	spinlock_t proclist_lock;
	struct mutex devlock;
	struct {
		atomic_long_t vmalloc;
+44 −59
Original line number Diff line number Diff line
@@ -635,10 +635,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));

@@ -647,8 +645,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);
@@ -687,6 +684,29 @@ static void _check_if_freed(struct kgsl_iommu_context *ctx,
	}
}

static struct kgsl_process_private *kgsl_iommu_get_process(u64 ptbase)
{
	struct kgsl_process_private *p;
	struct kgsl_iommu_pt *iommu_pt;

	spin_lock(&kgsl_driver.proclist_lock);

	list_for_each_entry(p, &kgsl_driver.process_list, list) {
		iommu_pt = p->pagetable->priv;
		if (iommu_pt->ttbr0 == ptbase) {
			if (!kgsl_process_private_get(p))
				p = NULL;

			spin_unlock(&kgsl_driver.proclist_lock);
			return p;
		}
	}

	spin_unlock(&kgsl_driver.proclist_lock);

	return NULL;
}

static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
	struct device *dev, unsigned long addr, int flags, void *token)
{
@@ -695,7 +715,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;
@@ -705,9 +725,9 @@ 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";
	char *comm = "unknown";
	struct kgsl_process_private *private;

	static DEFINE_RATELIMIT_STATE(_rs,
					DEFAULT_RATELIMIT_INTERVAL,
@@ -722,21 +742,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";
@@ -747,12 +752,17 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
	else if (flags & IOMMU_FAULT_TRANSACTION_STALLED)
		fault_type = "transaction stalled";

	if (context != NULL) {
		/* save pagefault timestamp for GFT */
		set_bit(KGSL_CONTEXT_PRIV_PAGEFAULT, &context->priv);
		pid = context->proc_priv->pid;
	ptbase = KGSL_IOMMU_GET_CTX_REG_Q(ctx, TTBR0);
	private = kgsl_iommu_get_process(ptbase);

	if (private) {
		pid = private->pid;
		comm = private->comm;
	}

	if (pt->name == KGSL_MMU_SECURE_PT)
		ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE];

	ctx->fault = 1;

	if (test_bit(KGSL_FT_PAGEFAULT_GPUHALT_ENABLE,
@@ -767,9 +777,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;
	/*
@@ -778,43 +786,19 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
	 * search and delays the trace unnecessarily.
	 */
	trace_kgsl_mmu_pagefault(ctx->kgsldev, addr,
			ptname,
			context != NULL ? context->proc_priv->comm : "unknown",
			write ? "write" : "read");
			ptname, comm, write ? "write" : "read");

	if (test_bit(KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE,
		&adreno_dev->ft_pf_policy))
		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";

		dev_crit(ctx->kgsldev->dev,
			"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)
			ptname, comm);
		dev_crit(ctx->kgsldev->dev,
				"Pagetable address mismatch: HW address is 0x%llx but SW expected 0x%llx\n",
				ptbase, proc_ptbase);
		}

		dev_crit(ctx->kgsldev->dev,
			"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) {
@@ -834,7 +818,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
			dev_err(ctx->kgsldev->dev,
				      "---- 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
@@ -877,7 +861,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;
}