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

Commit 6fadf462 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Allow memory lists along with command submission"

parents 4ba0e33b 1df7d244
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@
#define KGSL_CMD_FLAGS_WFI              BIT(2)
#define KGSL_CMD_FLAGS_PROFILE		BIT(3)
#define KGSL_CMD_FLAGS_PWRON_FIXUP      BIT(4)
#define KGSL_CMD_FLAGS_MEMLIST          BIT(5)

/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER	0x2EADBEEF
+4 −4
Original line number Diff line number Diff line
@@ -825,11 +825,11 @@ static void mark_guilty_context(struct kgsl_device *device, unsigned int id)
static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch,
				unsigned int base)
{
	int i;
	struct kgsl_memobj_node *ib;

	for (i = 0; i < cmdbatch->ibcount; i++) {
		if (cmdbatch->ibdesc[i].gpuaddr == base) {
			cmdbatch->ibdesc[i].sizedwords = 0;
	list_for_each_entry(ib, &cmdbatch->cmdlist, node) {
		if (ib->gpuaddr == base) {
			ib->priv |= MEMOBJ_SKIP;
			if (base)
				return;
		}
+49 −46
Original line number Diff line number Diff line
@@ -1078,20 +1078,20 @@ done:
 * core does
 */
static inline bool _ringbuffer_verify_ib(struct kgsl_device_private *dev_priv,
		struct kgsl_ibdesc *ibdesc)
		struct kgsl_memobj_node *ib)
{
	struct kgsl_device *device = dev_priv->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	/* Check that the size of the IBs is under the allowable limit */
	if (ibdesc->sizedwords == 0 || ibdesc->sizedwords > 0xFFFFF) {
	if (ib->sizedwords == 0 || ib->sizedwords > 0xFFFFF) {
		KGSL_DRV_ERR(device, "Invalid IB size 0x%zX\n",
				ibdesc->sizedwords);
				ib->sizedwords);
		return false;
	}

	if (unlikely(adreno_dev->ib_check_level >= 1) &&
		!_parse_ibs(dev_priv, ibdesc->gpuaddr, ibdesc->sizedwords)) {
		!_parse_ibs(dev_priv, ib->gpuaddr, ib->sizedwords)) {
		KGSL_DRV_ERR(device, "Could not verify the IBs\n");
		return false;
	}
@@ -1108,17 +1108,16 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
	struct kgsl_device *device = dev_priv->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
	int i, ret;
	struct kgsl_memobj_node *ib;
	int ret;

	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
		return -EDEADLK;

	/* Verify the IBs before they get queued */

	for (i = 0; i < cmdbatch->ibcount; i++) {
		if (!_ringbuffer_verify_ib(dev_priv, &cmdbatch->ibdesc[i]))
	list_for_each_entry(ib, &cmdbatch->cmdlist, node)
		if (!_ringbuffer_verify_ib(dev_priv, ib))
			return -EINVAL;
	}

	/* wait for the suspend gate */
	wait_for_completion(&device->cmdbatch_gate);
@@ -1210,22 +1209,22 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
		struct kgsl_cmdbatch *cmdbatch)
{
	struct kgsl_device *device = &adreno_dev->dev;
	struct kgsl_ibdesc *ibdesc;
	unsigned int numibs;
	struct kgsl_memobj_node *ib;
	unsigned int numibs = 0;
	unsigned int *link;
	unsigned int *cmds;
	unsigned int i;
	struct kgsl_context *context;
	struct adreno_context *drawctxt;
	unsigned int start_index = 0;
	bool use_preamble = true;
	int flags = KGSL_CMD_FLAGS_NONE;
	int ret;

	context = cmdbatch->context;
	drawctxt = ADRENO_CONTEXT(context);

	ibdesc = cmdbatch->ibdesc;
	numibs = cmdbatch->ibcount;
	/* Get the total IBs in the list */
	list_for_each_entry(ib, &cmdbatch->cmdlist, node)
		numibs++;

	/* process any profiling results that are available into the log_buf */
	adreno_profile_process_results(device);
@@ -1260,7 +1259,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
	if ((drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE) &&
		!test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) &&
		(adreno_dev->drawctxt_active == drawctxt))
		start_index = 1;
		use_preamble = false;

	/*
	 * In skip mode don't issue the draw IBs but keep all the other
@@ -1268,43 +1267,47 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
	 * the accounting sane. Set start_index and numibs to 0 to just
	 * generate the start and end markers and skip everything else
	 */

	if (test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv)) {
		start_index = 0;
		use_preamble = false;
		numibs = 0;
	}

	cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
	/*
	 * Worst case size:
	 * 2 - start of IB identifier
	 * 1 - skip preamble
	 * 3 * numibs - 3 per IB
	 * 2 - end of IB identifier
	 */
	cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 5),
				GFP_KERNEL);
	if (!link) {
		ret = -ENOMEM;
		goto done;
	}

	if (!start_index) {
	*cmds++ = cp_nop_packet(1);
	*cmds++ = KGSL_START_OF_IB_IDENTIFIER;
	} else {
		*cmds++ = cp_nop_packet(4);
		*cmds++ = KGSL_START_OF_IB_IDENTIFIER;
		*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
		*cmds++ = ibdesc[0].gpuaddr;
		*cmds++ = ibdesc[0].sizedwords;
	}
	for (i = start_index; i < numibs; i++) {

	if (numibs) {
		list_for_each_entry(ib, &cmdbatch->cmdlist, node) {
			/* use the preamble? */
			if ((ib->priv & MEMOBJ_PREAMBLE) &&
					(use_preamble == false))
				*cmds++ = cp_nop_packet(3);
			/*
		 * Skip 0 sized IBs - these are presumed to have been removed
		 * from consideration by the FT policy
			 * Skip 0 sized IBs - these are presumed to have been
			 * removed from consideration by the FT policy
			 */

		if (ibdesc[i].sizedwords == 0)
			if (ib->priv & MEMOBJ_SKIP)
				*cmds++ = cp_nop_packet(2);
			else
				*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;

		*cmds++ = ibdesc[i].gpuaddr;
		*cmds++ = ibdesc[i].sizedwords;
			*cmds++ = ib->gpuaddr;
			*cmds++ = ib->sizedwords;
		}
	}

	*cmds++ = cp_nop_packet(1);
@@ -1342,7 +1345,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
	adreno_ringbuffer_set_constraint(device, cmdbatch);

	/* CFF stuff executed only if CFF is enabled */
	kgsl_cffdump_capture_ib_desc(device, context, ibdesc, numibs);
	kgsl_cffdump_capture_ib_desc(device, context, cmdbatch);

	ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
					drawctxt,
@@ -1355,8 +1358,8 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
		0x00000000, 0x80000000);
done:
	trace_kgsl_issueibcmds(device, context->id, cmdbatch,
		cmdbatch->timestamp, cmdbatch->flags, ret,
		drawctxt->type);
			numibs, cmdbatch->timestamp,
			cmdbatch->flags, ret, drawctxt->type);

	kfree(link);
	return ret;
+129 −46
Original line number Diff line number Diff line
@@ -63,6 +63,12 @@
#define KGSL_DMA_BIT_MASK	DMA_BIT_MASK(32)
#endif

/*
 * Define an kmem cache for the memobj structures since we allocate and free
 * them so frequently
 */
static struct kmem_cache *memobjs_cache;

static char *ksgl_mmu_type;
module_param_named(mmutype, ksgl_mmu_type, charp, 0);
MODULE_PARM_DESC(ksgl_mmu_type,
@@ -1461,7 +1467,6 @@ void kgsl_cmdbatch_destroy_object(struct kref *kref)
		struct kgsl_cmdbatch, refcount);

	kgsl_context_put(cmdbatch->context);
	kfree(cmdbatch->ibdesc);

	kfree(cmdbatch);
}
@@ -1533,6 +1538,17 @@ static void kgsl_cmdbatch_sync_func(struct kgsl_device *device,
	kgsl_cmdbatch_sync_event_put(event);
}

static inline void _free_memobj_list(struct list_head *list)
{
	struct kgsl_memobj_node *mem, *tmpmem;

	/* Free the cmd mem here */
	list_for_each_entry_safe(mem, tmpmem, list, node) {
		list_del_init(&mem->node);
		kmem_cache_free(memobjs_cache, mem);
	}
}

/**
 * kgsl_cmdbatch_destroy() - Destroy a cmdbatch structure
 * @cmdbatch: Pointer to the command batch object to destroy
@@ -1543,7 +1559,7 @@ static void kgsl_cmdbatch_sync_func(struct kgsl_device *device,
 */
void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
{
	struct kgsl_cmdbatch_sync_event *event, *tmp;
	struct kgsl_cmdbatch_sync_event *event, *tmpsync;
	LIST_HEAD(cancel_synclist);
	int sched = 0;

@@ -1563,7 +1579,7 @@ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
	 * not to signal the callback. This guarantee ensures that
	 * the reference count for the event and cmdbatch is correct.
	 */
	list_for_each_entry_safe(event, tmp, &cancel_synclist, node) {
	list_for_each_entry_safe(event, tmpsync, &cancel_synclist, node) {

		sched = 1;
		if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) {
@@ -1585,6 +1601,12 @@ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
		kgsl_cmdbatch_sync_event_put(event);
	}

	/* Destroy the cmdlist we created */
	_free_memobj_list(&cmdbatch->cmdlist);

	/* Destroy the memlist we created */
	_free_memobj_list(&cmdbatch->memlist);

	/*
	 * If we cancelled an event, there's a good chance that the context is
	 * on a dispatcher queue, so schedule to get it removed.
@@ -1830,18 +1852,58 @@ int kgsl_cmdbatch_add_sync(struct kgsl_device *device,
	return ret;
}

/**
 * kgsl_cmdbatch_add_memobj() - Add an entry to a command batch
 * @cmdbatch: Pointer to the cmdbatch
 * @ibdesc: Pointer to the user-specified struct defining the memory or IB
 * @preamble: Flag to mark this ibdesc as a preamble (if known)
 *
 * Create a new memory entry in the cmdbatch based on the user specified
 * parameters
 */
int kgsl_cmdbatch_add_memobj(struct kgsl_cmdbatch *cmdbatch,
	struct kgsl_ibdesc *ibdesc)
{
	struct kgsl_memobj_node *mem;

	mem = kmem_cache_alloc(memobjs_cache, GFP_KERNEL);
	if (mem == NULL)
		return -ENOMEM;

	mem->gpuaddr = ibdesc->gpuaddr;
	mem->sizedwords = ibdesc->sizedwords;
	mem->priv = 0;

	/* sanitize the ibdesc ctrl flags */
	ibdesc->ctrl &= KGSL_IBDESC_MEMLIST;

	if (cmdbatch->flags & KGSL_CMDBATCH_MEMLIST &&
			ibdesc->ctrl & KGSL_IBDESC_MEMLIST) {
		/* add to the memlist */
		list_add_tail(&mem->node, &cmdbatch->memlist);
	} else {
		/* set the preamble flag if directed to */
		if (cmdbatch->context->flags & KGSL_CONTEXT_PREAMBLE &&
			list_empty(&cmdbatch->cmdlist))
			mem->priv = MEMOBJ_PREAMBLE;

		/* add to the cmd list */
		list_add_tail(&mem->node, &cmdbatch->cmdlist);
	}

	return 0;
}

/**
 * kgsl_cmdbatch_create() - Create a new cmdbatch structure
 * @device: Pointer to a KGSL device struct
 * @context: Pointer to a KGSL context struct
 * @numibs: Number of indirect buffers to make room for in the cmdbatch
 * @flags: Flags for the cmdbatch
 *
 * Allocate an new cmdbatch structure and add enough room to store the list of
 * indirect buffers
 * Allocate an new cmdbatch structure
 */
static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device,
		struct kgsl_context *context, unsigned int flags,
		unsigned int numibs)
		struct kgsl_context *context, unsigned int flags)
{
	struct kgsl_cmdbatch *cmdbatch = kzalloc(sizeof(*cmdbatch), GFP_KERNEL);
	if (cmdbatch == NULL)
@@ -1857,22 +1919,13 @@ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device,
		return ERR_PTR(-EINVAL);
	}

	if (!(flags & KGSL_CONTEXT_SYNC)) {
		cmdbatch->ibdesc = kzalloc(sizeof(*cmdbatch->ibdesc) * numibs,
			GFP_KERNEL);
		if (cmdbatch->ibdesc == NULL) {
			kgsl_context_put(context);
			kfree(cmdbatch);
			return ERR_PTR(-ENOMEM);
		}
	}

	kref_init(&cmdbatch->refcount);
	INIT_LIST_HEAD(&cmdbatch->cmdlist);
	INIT_LIST_HEAD(&cmdbatch->synclist);
	INIT_LIST_HEAD(&cmdbatch->memlist);
	spin_lock_init(&cmdbatch->lock);

	cmdbatch->device = device;
	cmdbatch->ibcount = (flags & KGSL_CONTEXT_SYNC) ? 0 : numibs;
	cmdbatch->context = context;
	cmdbatch->flags = flags & ~KGSL_CMDBATCH_SUBMIT_IB_LIST;

@@ -1895,27 +1948,27 @@ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device,
static bool _kgsl_cmdbatch_verify(struct kgsl_device_private *dev_priv,
	struct kgsl_cmdbatch *cmdbatch)
{
	int i;
	struct kgsl_process_private *private = dev_priv->process_priv;
	struct kgsl_memobj_node *ib;

	for (i = 0; i < cmdbatch->ibcount; i++) {
		if (cmdbatch->ibdesc[i].sizedwords == 0) {
	list_for_each_entry(ib, &cmdbatch->cmdlist, node) {
		if (ib->sizedwords == 0) {
			KGSL_DRV_ERR(dev_priv->device,
				"invalid size ctx %d ib(%d) %lX/%zX\n",
				cmdbatch->context->id, i,
				cmdbatch->ibdesc[i].gpuaddr,
				cmdbatch->ibdesc[i].sizedwords);
				"invalid size ctx %d %lX/%zX\n",
				cmdbatch->context->id,
				ib->gpuaddr,
				ib->sizedwords);

			return false;
		}

		if (!kgsl_mmu_gpuaddr_in_range(private->pagetable,
			cmdbatch->ibdesc[i].gpuaddr)) {
			ib->gpuaddr)) {
			KGSL_DRV_ERR(dev_priv->device,
				"Invalid address ctx %d ib(%d) %lX/%zX\n",
				cmdbatch->context->id, i,
				cmdbatch->ibdesc[i].gpuaddr,
				cmdbatch->ibdesc[i].sizedwords);
				"Invalid address ctx %d %lX/%zX\n",
				cmdbatch->context->id,
				ib->gpuaddr,
				ib->sizedwords);

			return false;
		}
@@ -1937,16 +1990,24 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create_legacy(
		struct kgsl_context *context,
		struct kgsl_ringbuffer_issueibcmds *param)
{
	struct kgsl_memobj_node *mem;
	struct kgsl_cmdbatch *cmdbatch =
		kgsl_cmdbatch_create(device, context, param->flags, 1);
		kgsl_cmdbatch_create(device, context, param->flags);

	if (IS_ERR(cmdbatch))
		return cmdbatch;

	cmdbatch->ibdesc[0].gpuaddr = param->ibdesc_addr;
	cmdbatch->ibdesc[0].sizedwords = param->numibs;
	cmdbatch->ibcount = 1;
	cmdbatch->flags = param->flags;
	mem = kmem_cache_alloc(memobjs_cache, GFP_KERNEL);
	if (mem == NULL) {
		kgsl_cmdbatch_destroy(cmdbatch);
		return NULL;
	}

	mem->gpuaddr = param->ibdesc_addr;
	mem->sizedwords = param->numibs;
	mem->priv = 0;

	list_add_tail(&mem->node, &cmdbatch->cmdlist);

	return cmdbatch;
}
@@ -1969,8 +2030,8 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device,
		void __user *synclist, unsigned int numsyncs)
{
	struct kgsl_cmdbatch *cmdbatch =
		kgsl_cmdbatch_create(device, context, flags, numcmds);
	int ret = 0;
		kgsl_cmdbatch_create(device, context, flags);
	int ret = 0, i;

	if (IS_ERR(cmdbatch))
		return cmdbatch;
@@ -1982,30 +2043,40 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device,
	}

	if (!(flags & KGSL_CMDBATCH_SYNC)) {
		if (copy_from_user(cmdbatch->ibdesc, cmdlist,
			sizeof(struct kgsl_ibdesc) * numcmds)) {
		struct kgsl_ibdesc ibdesc;
		void  __user *uptr = cmdlist;

		for (i = 0; i < numcmds; i++) {
			memset(&ibdesc, 0, sizeof(ibdesc));

			if (copy_from_user(&ibdesc, uptr, sizeof(ibdesc))) {
				ret = -EFAULT;
				goto done;
			}

			ret = kgsl_cmdbatch_add_memobj(cmdbatch, &ibdesc);
			if (ret)
				goto done;

			uptr += sizeof(ibdesc);
		}
	}

	if (synclist && numsyncs) {
		struct kgsl_cmd_syncpoint sync;
		void  __user *uptr = synclist;
		int i;

		for (i = 0; i < numsyncs; i++) {
			memset(&sync, 0, sizeof(sync));

			if (copy_from_user(&sync, uptr, sizeof(sync))) {
				ret = -EFAULT;
				break;
				goto done;
			}

			ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync);

			if (ret)
				break;
				goto done;

			uptr += sizeof(sync);
		}
@@ -4282,6 +4353,10 @@ static void kgsl_core_exit(void)
		kgsl_driver.class = NULL;
	}

	/* free the memobject cache */
	if (memobjs_cache)
		kmem_cache_destroy(memobjs_cache);

	kgsl_memfree_hist_exit();
	unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
}
@@ -4352,6 +4427,14 @@ static int __init kgsl_core_init(void)

	kgsl_events_init();

	/* create the memobjs kmem cache */
	memobjs_cache = KMEM_CACHE(kgsl_memobj_node, 0);
	if (memobjs_cache == NULL) {
		KGSL_CORE_ERR("failed to create memobjs_cache");
		result = -ENOMEM;
		goto err;
	}

	if (kgsl_memfree_hist_init())
		KGSL_CORE_ERR("failed to init memfree_hist");

+3 −0
Original line number Diff line number Diff line
@@ -243,6 +243,9 @@ long kgsl_ioctl_cff_user_event(struct kgsl_device_private *dev_priv,
long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data);

int kgsl_cmdbatch_add_memobj(struct kgsl_cmdbatch *cmdbatch,
			struct kgsl_ibdesc *ibdesc);

int kgsl_cmdbatch_add_sync(struct kgsl_device *device,
			struct kgsl_cmdbatch *cmdbatch,
			struct kgsl_cmd_syncpoint *sync);
Loading