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

Commit f4c9ffd6 authored by Jordan Crouse's avatar Jordan Crouse Committed by Sudeep Yedalapure
Browse files

msm: kgsl: Fix pagetable member of struct kgsl_memdesc



memdesc->pagetable is supposed to help ensure that memory gets
unmapped before it is freed, but the pagetable member is being
populated at create time not when the buffer gets mapped. This
forces the developer to ensure that the same pagetable is
used for both the create and map step. Instead, assign the
pagetable member when it is first used (to get a GPU address)
and put it away when the GPU address is released.

Change-Id: Ic0dedbad372fd9029b932dd99633a650049751ed
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: default avatarSudeep Yedalapure <sudeepy@codeaurora.org>
parent 2c6d35a2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2017, 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
@@ -250,7 +250,7 @@ static int a5xx_critical_packet_construct(struct adreno_device *adreno_dev)
		return ret;

	ret = kgsl_allocate_user(&adreno_dev->dev, &crit_pkts_refbuf0,
					NULL, PAGE_SIZE, KGSL_MEMFLAGS_SECURE);
		PAGE_SIZE, KGSL_MEMFLAGS_SECURE);
	if (ret)
		return ret;

+7 −26
Original line number Diff line number Diff line
/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2017, 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
@@ -370,24 +370,6 @@ kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process,
	return kgsl_mmu_get_gpuaddr(pagetable, &entry->memdesc);
}

/**
 * kgsl_mem_entry_untrack_gpuaddr() - Untrack memory that is previously tracked
 * process - Pointer to process private to which memory belongs
 * entry - Memory entry to untrack
 *
 * Function just does the opposite of kgsl_mem_entry_track_gpuaddr. Needs to be
 * called with processes spin lock held
 */
static void
kgsl_mem_entry_untrack_gpuaddr(struct kgsl_process_private *process,
				struct kgsl_mem_entry *entry)
{
	struct kgsl_pagetable *pagetable = entry->memdesc.pagetable;

	if (entry->memdesc.gpuaddr)
		kgsl_mmu_put_gpuaddr(pagetable, &entry->memdesc);
}

/* Commit the entry to the process so it can be accessed by other operations */
static void kgsl_mem_entry_commit_process(struct kgsl_mem_entry *entry)
{
@@ -436,7 +418,7 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,

	if (id < 0) {
		ret = id;
		kgsl_mem_entry_untrack_gpuaddr(process, entry);
		kgsl_mmu_put_gpuaddr(&entry->memdesc);
		goto err_put_proc_priv;
	}

@@ -472,6 +454,7 @@ err_put_proc_priv:
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
{
	unsigned int type;

	if (entry == NULL)
		return;

@@ -488,9 +471,7 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
	entry->priv->stats[type].cur -= entry->memdesc.size;
	spin_unlock(&entry->priv->mem_lock);

	kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);

	kgsl_mem_entry_untrack_gpuaddr(entry->priv, entry);
	kgsl_mmu_put_gpuaddr(&entry->memdesc);

	kgsl_process_private_put(entry->priv);

@@ -3021,7 +3002,7 @@ static struct kgsl_mem_entry *gpumem_alloc_entry(
		entry->memdesc.priv |= KGSL_MEMDESC_SECURE;

	ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc,
				private->pagetable, size, flags);
		size, flags);
	if (ret != 0)
		goto err;

@@ -3442,11 +3423,11 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private,
		return ret;

	entry->memdesc.gpuaddr = (uint64_t) addr;
	entry->memdesc.pagetable = private->pagetable;

	ret = kgsl_mmu_map(private->pagetable, &entry->memdesc);
	if (ret) {
		kgsl_mmu_put_gpuaddr(private->pagetable,
				&entry->memdesc);
		kgsl_mmu_put_gpuaddr(&entry->memdesc);
		return ret;
	}

+19 −16
Original line number Diff line number Diff line
/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2017, 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
@@ -1402,17 +1402,16 @@ static int _setstate_alloc(struct kgsl_device *device,
{
	int ret;

	ret = kgsl_sharedmem_alloc_contig(device, &iommu->setstate, NULL,
		PAGE_SIZE);
	if (ret)
		return ret;
	ret = kgsl_sharedmem_alloc_contig(device, &iommu->setstate, PAGE_SIZE);

	if (!ret) {
		/* Mark the setstate memory as read only */
		iommu->setstate.flags |= KGSL_MEMFLAGS_GPUREADONLY;

		kgsl_sharedmem_set(device, &iommu->setstate, 0, 0, PAGE_SIZE);
	}

	return 0;
	return ret;
}

static int kgsl_iommu_init(struct kgsl_mmu *mmu)
@@ -1663,7 +1662,7 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt,

		if (!kgsl_secure_guard_page_memdesc.sgt) {
			if (kgsl_allocate_user(KGSL_MMU_DEVICE(pt->mmu),
					&kgsl_secure_guard_page_memdesc, pt,
					&kgsl_secure_guard_page_memdesc,
					sgp_size, KGSL_MEMFLAGS_SECURE)) {
				KGSL_CORE_ERR(
					"Secure guard page alloc failed\n");
@@ -2264,23 +2263,27 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable,
	}

	ret = _insert_gpuaddr(pagetable, addr, size);
	if (ret == 0)
	if (ret == 0) {
		memdesc->gpuaddr = addr;
		memdesc->pagetable = pagetable;
	}

out:
	spin_unlock(&pagetable->lock);
	return ret;
}

static void kgsl_iommu_put_gpuaddr(struct kgsl_pagetable *pagetable,
		struct kgsl_memdesc *memdesc)
static void kgsl_iommu_put_gpuaddr(struct kgsl_memdesc *memdesc)
{
	spin_lock(&pagetable->lock);
	if (memdesc->pagetable == NULL)
		return;

	spin_lock(&memdesc->pagetable->lock);

	if (_remove_gpuaddr(pagetable, memdesc->gpuaddr))
	if (_remove_gpuaddr(memdesc->pagetable, memdesc->gpuaddr))
		BUG();

	spin_unlock(&pagetable->lock);
	spin_unlock(&memdesc->pagetable->lock);
}

static int kgsl_iommu_svm_range(struct kgsl_pagetable *pagetable,
+23 −6
Original line number Diff line number Diff line
/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2002,2007-2017, 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
@@ -419,17 +419,29 @@ EXPORT_SYMBOL(kgsl_mmu_map);
 * @pagetable: Pagetable to release the memory from
 * @memdesc: Memory descriptor containing the GPU address to free
 */
void kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable,
		struct kgsl_memdesc *memdesc)
void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc)
{
	struct kgsl_pagetable *pagetable = memdesc->pagetable;
	int unmap_fail = 0;

	if (memdesc->size == 0 || memdesc->gpuaddr == 0)
		return;

	if (PT_OP_VALID(pagetable, put_gpuaddr))
		pagetable->pt_ops->put_gpuaddr(pagetable, memdesc);
	if (!kgsl_memdesc_is_global(memdesc))
		unmap_fail = kgsl_mmu_unmap(pagetable, memdesc);

	/*
	 * Do not free the gpuaddr/size if unmap fails. Because if we
	 * try to map this range in future, the iommu driver will throw
	 * a BUG_ON() because it feels we are overwriting a mapping.
	*/
	if (PT_OP_VALID(pagetable, put_gpuaddr) && (unmap_fail == 0))
		pagetable->pt_ops->put_gpuaddr(memdesc);

	if (!kgsl_memdesc_is_global(memdesc))
		memdesc->gpuaddr = 0;

	memdesc->pagetable = NULL;
}
EXPORT_SYMBOL(kgsl_mmu_put_gpuaddr);

@@ -580,7 +592,12 @@ static int nommu_get_gpuaddr(struct kgsl_pagetable *pagetable,

	memdesc->gpuaddr = (uint64_t) sg_phys(memdesc->sgt->sgl);

	return memdesc->gpuaddr != 0 ? 0 : -ENOMEM;
	if (memdesc->gpuaddr) {
		memdesc->pagetable = pagetable;
		return 0;
	}

	return -ENOMEM;
}

static struct kgsl_mmu_pt_ops nommu_pt_ops = {
+3 −4
Original line number Diff line number Diff line
/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2002,2007-2017, 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
@@ -92,7 +92,7 @@ struct kgsl_mmu_pt_ops {
	u64 (*get_ttbr0)(struct kgsl_pagetable *);
	u32 (*get_contextidr)(struct kgsl_pagetable *);
	int (*get_gpuaddr)(struct kgsl_pagetable *, struct kgsl_memdesc *);
	void (*put_gpuaddr)(struct kgsl_pagetable *, struct kgsl_memdesc *);
	void (*put_gpuaddr)(struct kgsl_memdesc *);
	uint64_t (*find_svm_region)(struct kgsl_pagetable *, uint64_t, uint64_t,
		uint64_t, uint64_t);
	int (*set_svm_region)(struct kgsl_pagetable *, uint64_t, uint64_t);
@@ -180,8 +180,7 @@ int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
		 struct kgsl_memdesc *memdesc);
int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
		    struct kgsl_memdesc *memdesc);
void kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable,
		 struct kgsl_memdesc *memdesc);
void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc);
unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
unsigned int kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu,
		u64 ttbr0, uint64_t addr);
Loading