static int adreno_drawctxt_wait_global(struct adreno_device *adreno_dev,
		struct kgsl_context *context,
		uint32_t timestamp, unsigned int timeout)
{
	struct kgsl_device *device = &adreno_dev->dev;
	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
	int ret = 0;

	/* Needs to hold the device mutex */
	BUG_ON(!mutex_is_locked(&device->mutex));

	if (!_kgsl_context_get(context)) {
		ret = -EINVAL;
		goto done;
	}

	/*
	 * If the context is invalid then return immediately - we may end up
	 * waiting for a timestamp that will never come
	 */
	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
		kgsl_context_put(context);
		goto done;
	}

	trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp);

	ret = kgsl_add_event(device, &device->global_events, timestamp,
		global_wait_callback, (void *) drawctxt);
	if (ret) {
		kgsl_context_put(context);
		goto done;
	}

	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);

	if (timeout) {
		ret = (int) wait_event_timeout(drawctxt->waiting,
			_check_global_timestamp(device, drawctxt, timestamp),
			msecs_to_jiffies(timeout));

		if (ret == 0)
			ret = -ETIMEDOUT;
		else if (ret > 0)
			ret = 0;
	} else {
		wait_event(drawctxt->waiting,
			_check_global_timestamp(device, drawctxt, timestamp));
	}

	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);

	if (ret)
		kgsl_cancel_events_timestamp(device, &device->global_events,
			timestamp);

done:
	trace_adreno_drawctxt_wait_done(KGSL_MEMSTORE_GLOBAL, timestamp, ret);
	return ret;
}
int adreno_drawctxt_wait_global(struct adreno_device *adreno_dev,
		struct kgsl_context *context,
		uint32_t timestamp, unsigned int timeout)
{
	struct kgsl_device *device = &adreno_dev->dev;
	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
	int ret = 0;

	
	BUG_ON(!mutex_is_locked(&device->mutex));

	if (!_kgsl_context_get(context)) {
		ret = -EINVAL;
		goto done;
	}

	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
		kgsl_context_put(context);
		goto done;
	}

	trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp);

	ret = kgsl_add_event(device, KGSL_MEMSTORE_GLOBAL, timestamp,
		global_wait_callback, drawctxt, NULL);
	if (ret) {
		kgsl_context_put(context);
		goto done;
	}

	mutex_unlock(&device->mutex);

	if (timeout) {
		ret = (int) wait_event_timeout(drawctxt->waiting,
			_check_global_timestamp(device, drawctxt, timestamp),
			msecs_to_jiffies(timeout));

		if (ret == 0)
			ret = -ETIMEDOUT;
		else if (ret > 0)
			ret = 0;
	} else {
		wait_event(drawctxt->waiting,
			_check_global_timestamp(device, drawctxt, timestamp));
	}

	mutex_lock(&device->mutex);

	if (ret)
		kgsl_cancel_events_timestamp(device, NULL, timestamp);

done:
	trace_adreno_drawctxt_wait_done(KGSL_MEMSTORE_GLOBAL, timestamp, ret);
	return ret;
}
static int _add_fence_event(struct kgsl_device *device,
	struct kgsl_context *context, unsigned int timestamp)
{
	struct kgsl_fence_event_priv *event;
	int ret;

	event = kmalloc(sizeof(*event), GFP_KERNEL);
	if (event == NULL)
		return -ENOMEM;

	/*
	 * Increase the refcount for the context to keep it through the
	 * callback
	 */

	_kgsl_context_get(context);

	event->context = context;
	event->timestamp = timestamp;
	event->context = context;

	ret = kgsl_add_event(device, context->id, timestamp,
		kgsl_fence_event_cb, event, context->dev_priv);

	if (ret) {
		kgsl_context_put(context);
		kfree(event);
	}

	return ret;
}
static void global_wait_callback(struct kgsl_device *device, void *priv, u32 id,
		u32 timestamp, u32 type)
{
	struct adreno_context *drawctxt = priv;

	wake_up_all(&drawctxt->waiting);
	kgsl_context_put(&drawctxt->base);
}
Ejemplo n.º 5
0
static inline void kgsl_fence_event_cb(struct kgsl_device *device,
	void *priv, u32 context_id, u32 timestamp)
{
	struct kgsl_fence_event_priv *ev = priv;
	kgsl_sync_timeline_signal(ev->context->timeline, ev->timestamp);
	kgsl_context_put(ev->context);
	kfree(ev);
}
Ejemplo n.º 6
0
static void kgsl_fence_event_cb(struct kgsl_device *device,
		struct kgsl_context *context, void *priv, int result)
{
	struct kgsl_fence_event_priv *ev = priv;
	kgsl_sync_timeline_signal(ev->context->timeline, ev->timestamp);
	kgsl_context_put(ev->context);
	kfree(ev);
}
static void global_wait_callback(struct kgsl_device *device,
		struct kgsl_context *context, void *priv, int result)
{
	struct adreno_context *drawctxt = priv;

	wake_up_all(&drawctxt->waiting);
	kgsl_context_put(&drawctxt->base);
}
Ejemplo n.º 8
0
static inline void kgsl_fence_event_cb(struct kgsl_device *device,
	void *priv, u32 context_id, u32 timestamp, u32 type)
{
	struct kgsl_fence_event_priv *ev = priv;

	/* Signal time timeline for every event type */
	kgsl_sync_timeline_signal(ev->context->timeline, timestamp);
	kgsl_context_put(ev->context);
	kfree(ev);
}
Ejemplo n.º 9
0
static unsigned int kgsl_sync_get_timestamp(
	struct kgsl_sync_timeline *ktimeline, enum kgsl_timestamp_type type)
{
	unsigned int ret = 0;

	struct kgsl_context *context = kgsl_context_get(ktimeline->device,
			ktimeline->context_id);

	if (context)
		ret = kgsl_readtimestamp(ktimeline->device, context, type);

	kgsl_context_put(context);
	return ret;
}
int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
				struct adreno_context *drawctxt,
				unsigned int flags)
{
	struct kgsl_device *device = &adreno_dev->dev;
	int ret = 0;

	/* already current? */
	if (adreno_dev->drawctxt_active == drawctxt)
		return ret;

	trace_adreno_drawctxt_switch(adreno_dev->drawctxt_active,
		drawctxt, flags);

	/* Get a refcount to the new instance */
	if (drawctxt) {
		if (!_kgsl_context_get(&drawctxt->base))
			return -EINVAL;

		ret = kgsl_mmu_setstate(&device->mmu,
			drawctxt->base.proc_priv->pagetable,
			adreno_dev->drawctxt_active ?
			adreno_dev->drawctxt_active->base.id :
			KGSL_CONTEXT_INVALID);
		/* Set the new context */
		ret = adreno_context_restore(adreno_dev, drawctxt);
		if (ret) {
			KGSL_DRV_ERR(device,
					"Error in GPU context %d restore: %d\n",
					drawctxt->base.id, ret);
			return ret;
		}
	} else {
		/*
		 * No context - set the default pagetable and thats it.
		 * If there isn't a current context, the kgsl_mmu_setstate
		 * will use the CPU path so we don't need to give
		 * it a valid context id.
		 */
		ret = kgsl_mmu_setstate(&device->mmu,
					 device->mmu.defaultpagetable,
					adreno_dev->drawctxt_active->base.id);
	}
	/* Put the old instance of the active drawctxt */
	if (adreno_dev->drawctxt_active)
		kgsl_context_put(&adreno_dev->drawctxt_active->base);
	adreno_dev->drawctxt_active = drawctxt;
	return 0;
}
int adreno_setproperty_compat(struct kgsl_device_private *dev_priv,
				enum kgsl_property_type type,
				void __user *value,
				unsigned int sizebytes)
{
	int status = -EINVAL;
	struct kgsl_device *device = dev_priv->device;

	switch (type) {
	case KGSL_PROP_PWR_CONSTRAINT: {
			struct kgsl_device_constraint_compat constraint32;
			struct kgsl_device_constraint constraint;
			struct kgsl_context *context;

			if (sizebytes != sizeof(constraint32))
				break;

			if (copy_from_user(&constraint32, value,
				sizeof(constraint32))) {
				status = -EFAULT;
				break;
			}

			/* Populate the real constraint type from the compat */
			constraint.type = constraint32.type;
			constraint.context_id = constraint32.context_id;
			constraint.data = compat_ptr(constraint32.data);
			constraint.size = (size_t)constraint32.size;

			context = kgsl_context_get_owner(dev_priv,
							constraint.context_id);
			if (context == NULL)
				break;
			status = adreno_set_constraint(device, context,
								&constraint);
			kgsl_context_put(context);
		}
		break;
	default:
		/*
		 * Call adreno_setproperty in case the property type was
		 * KGSL_PROP_PWRCTRL
		 */
		status = device->ftbl->setproperty(dev_priv, type, value,
						sizebytes);
	}

	return status;
}
void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
				struct adreno_context *drawctxt,
				unsigned int flags)
{
	struct kgsl_device *device = &adreno_dev->dev;

	if (drawctxt) {
		if (flags & KGSL_CONTEXT_SAVE_GMEM)
			/* Set the flag in context so that the save is done
			* when this context is switched out. */
			drawctxt->flags |= CTXT_FLAGS_GMEM_SAVE;
		else
			/* Remove GMEM saving flag from the context */
			drawctxt->flags &= ~CTXT_FLAGS_GMEM_SAVE;
	}

	/* already current? */
	if (adreno_dev->drawctxt_active == drawctxt) {
		if (adreno_dev->gpudev->ctxt_draw_workaround &&
			adreno_is_a225(adreno_dev))
				adreno_dev->gpudev->ctxt_draw_workaround(
					adreno_dev, drawctxt);
		return;
	}

	KGSL_CTXT_INFO(device, "from %d to %d flags %d\n",
		adreno_dev->drawctxt_active ?
		adreno_dev->drawctxt_active->base.id : 0,
		drawctxt ? drawctxt->base.id : 0, flags);

	/* Save the old context */
	adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);

	/* Put the old instance of the active drawctxt */
	if (adreno_dev->drawctxt_active) {
		kgsl_context_put(&adreno_dev->drawctxt_active->base);
		adreno_dev->drawctxt_active = NULL;
	}

	/* Get a refcount to the new instance */
	if (drawctxt)
		_kgsl_context_get(&drawctxt->base);

	/* Set the new context */
	adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
	adreno_dev->drawctxt_active = drawctxt;
}
int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
				struct adreno_ringbuffer *rb,
				struct adreno_context *drawctxt,
				unsigned int flags)
{
	struct kgsl_device *device = &adreno_dev->dev;
	struct kgsl_pagetable *new_pt;
	int ret = 0;

	/* We always expect a valid rb */
	BUG_ON(!rb);

	/* already current? */
	if (rb->drawctxt_active == drawctxt)
		return ret;

	trace_adreno_drawctxt_switch(rb,
		drawctxt, flags);

	/* Get a refcount to the new instance */
	if (drawctxt) {
		if (!_kgsl_context_get(&drawctxt->base))
			return -EINVAL;

		new_pt = drawctxt->base.proc_priv->pagetable;
	} else {
		 /* No context - set the default pagetable and thats it. */
		new_pt = device->mmu.defaultpagetable;
	}
	ret = adreno_iommu_set_pt(rb, new_pt);
	if (ret) {
		KGSL_DRV_ERR(device,
			"Failed to set pagetable on rb %d\n", rb->id);
		return ret;
	}

	/* Put the old instance of the active drawctxt */
	if (rb->drawctxt_active)
		kgsl_context_put(&rb->drawctxt_active->base);

	rb->drawctxt_active = drawctxt;
	/* Set the new context */
	adreno_context_restore(rb);

	return 0;
}
Ejemplo n.º 14
0
int kgsl_add_fence_event(struct kgsl_device *device,
	u32 context_id, u32 timestamp, void __user *data, int len,
	struct kgsl_device_private *owner)
{
	struct kgsl_timestamp_event_fence priv;
	struct kgsl_context *context;
	struct sync_pt *pt;
	struct sync_fence *fence = NULL;
	int ret = -EINVAL;
	char fence_name[sizeof(fence->name)] = {};
	unsigned int cur;

	priv.fence_fd = -1;

	if (len != sizeof(priv))
		return -EINVAL;

	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);

	context = kgsl_context_get_owner(owner, context_id);

	if (context == NULL)
		goto unlock;

	pt = kgsl_sync_pt_create(context->timeline, context, timestamp);

	if (pt == NULL) {
		KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n");
		ret = -ENOMEM;
		goto unlock;
	}
	snprintf(fence_name, sizeof(fence_name),
		"%s-pid-%d-ctx-%d-ts-%d",
		device->name, current->group_leader->pid,
		context_id, timestamp);


	fence = sync_fence_create(fence_name, pt);
	if (fence == NULL) {
		/* only destroy pt when not added to fence */
		kgsl_sync_pt_destroy(pt);
		KGSL_DRV_ERR(device, "sync_fence_create failed\n");
		ret = -ENOMEM;
		goto unlock;
	}

	priv.fence_fd = get_unused_fd_flags(0);
	if (priv.fence_fd < 0) {
		KGSL_DRV_ERR(device, "Unable to get a file descriptor: %d\n",
			priv.fence_fd);
		ret = priv.fence_fd;
		goto unlock;
	}
	sync_fence_install(fence, priv.fence_fd);

	/*
	 * If the timestamp hasn't expired yet create an event to trigger it.
	 * Otherwise, just signal the fence - there is no reason to go through
	 * the effort of creating a fence we don't need.
	 */

	cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);

	if (timestamp_cmp(cur, timestamp) >= 0)
		kgsl_sync_timeline_signal(context->timeline, cur);
	else {
		ret = _add_fence_event(device, context, timestamp);
		if (ret)
			goto unlock;
	}

	kgsl_context_put(context);

	/* Unlock the mutex before copying to user */
	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);

	if (copy_to_user(data, &priv, sizeof(priv))) {
		ret = -EFAULT;
		goto out;
	}

	return 0;

unlock:
	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);

out:
	if (priv.fence_fd >= 0)
		put_unused_fd(priv.fence_fd);

	if (fence)
		sync_fence_put(fence);

	kgsl_context_put(context);
	return ret;
}
Ejemplo n.º 15
0
int kgsl_add_fence_event(struct kgsl_device *device,
	u32 context_id, u32 timestamp, void __user *data, int len,
	struct kgsl_device_private *owner)
{
	struct kgsl_fence_event_priv *event;
	struct kgsl_timestamp_event_fence priv;
	struct kgsl_context *context;
	struct sync_pt *pt;
	struct sync_fence *fence = NULL;
	int ret = -EINVAL;
	char fence_name[sizeof(fence->name)] = {};

	priv.fence_fd = -1;

	if (len != sizeof(priv))
		return -EINVAL;

	event = kzalloc(sizeof(*event), GFP_KERNEL);
	if (event == NULL)
		return -ENOMEM;

	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);

	context = kgsl_context_get_owner(owner, context_id);

	if (context == NULL)
		goto unlock;

	event->context = context;
	event->timestamp = timestamp;

	pt = kgsl_sync_pt_create(context->timeline, timestamp);
	if (pt == NULL) {
		KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n");
		ret = -ENOMEM;
		goto unlock;
	}
	snprintf(fence_name, sizeof(fence_name),
		"%s-pid-%d-ctx-%d-ts-%d",
		device->name, current->group_leader->pid,
		context_id, timestamp);


	fence = sync_fence_create(fence_name, pt);
	if (fence == NULL) {
		/* only destroy pt when not added to fence */
		kgsl_sync_pt_destroy(pt);
		KGSL_DRV_ERR(device, "sync_fence_create failed\n");
		ret = -ENOMEM;
		goto unlock;
	}

	priv.fence_fd = get_unused_fd_flags(0);
	if (priv.fence_fd < 0) {
		KGSL_DRV_ERR(device, "Unable to get a file descriptor: %d\n",
			priv.fence_fd);
		ret = priv.fence_fd;
		goto unlock;
	}

	/* Unlock the mutex before copying to user */
	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);

	if (copy_to_user(data, &priv, sizeof(priv))) {
		ret = -EFAULT;
		goto out;
	}

	/*
	 * Hold the context ref-count for the event - it will get released in
	 * the callback
	 */
	ret = kgsl_add_event(device, &context->events, timestamp,
		kgsl_fence_event_cb, event);

	if (ret)
		goto out;

	sync_fence_install(fence, priv.fence_fd);

	return 0;

unlock:
	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);

out:
	if (priv.fence_fd >= 0)
		put_unused_fd(priv.fence_fd);

	if (fence)
		sync_fence_put(fence);

	kgsl_context_put(context);
	kfree(event);
	return ret;
}
Ejemplo n.º 16
0
int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
				struct adreno_context *drawctxt,
				unsigned int flags)
{
	struct kgsl_device *device = &adreno_dev->dev;
	int ret = 0;

	if (drawctxt) {
		/*
		* Handle legacy gmem / save restore flag on each IB.
		* Userspace sets to guard IB sequences that require
		* gmem to be saved and clears it at the end of the
		* sequence.
		*/
		if (flags & KGSL_CONTEXT_SAVE_GMEM)
			/* Set the flag in context so that the save is done
			* when this context is switched out. */
			set_bit(ADRENO_CONTEXT_GMEM_SAVE, &drawctxt->priv);
		else
			/* Remove GMEM saving flag from the context */
			clear_bit(ADRENO_CONTEXT_GMEM_SAVE, &drawctxt->priv);
	}

	/* already current? */
	if (adreno_dev->drawctxt_active == drawctxt) {
		if (drawctxt && drawctxt->ops->draw_workaround)
			ret = drawctxt->ops->draw_workaround(adreno_dev,
							 drawctxt);
		return ret;
	}

	trace_adreno_drawctxt_switch(adreno_dev->drawctxt_active,
		drawctxt, flags);

	/* Get a refcount to the new instance */
	if (drawctxt) {
		if (!_kgsl_context_get(&drawctxt->base))
			return -EINVAL;

		ret = kgsl_mmu_setstate(&device->mmu,
			drawctxt->base.proc_priv->pagetable,
			adreno_dev->drawctxt_active ?
			adreno_dev->drawctxt_active->base.id :
			KGSL_CONTEXT_INVALID);
		/* Set the new context */
		ret = drawctxt->ops->restore(adreno_dev, drawctxt);
		if (ret) {
			KGSL_DRV_ERR(device,
					"Error in GPU context %d restore: %d\n",
					drawctxt->base.id, ret);
			return ret;
		}
	} else {
		/*
		 * No context - set the default pagetable and thats it.
		 * If there isn't a current context, the kgsl_mmu_setstate
		 * will use the CPU path so we don't need to give
		 * it a valid context id.
		 */
		ret = kgsl_mmu_setstate(&device->mmu,
					 device->mmu.defaultpagetable,
					adreno_dev->drawctxt_active->base.id);
	}
	/* Put the old instance of the active drawctxt */
	if (adreno_dev->drawctxt_active)
		kgsl_context_put(&adreno_dev->drawctxt_active->base);
	adreno_dev->drawctxt_active = drawctxt;
	return 0;
}
Ejemplo n.º 17
0
int kgsl_add_fence_event(struct kgsl_device *device,
	u32 context_id, u32 timestamp, void __user *data, int len,
	struct kgsl_device_private *owner)
{
	struct kgsl_fence_event_priv *event;
	struct kgsl_timestamp_event_fence priv;
	struct kgsl_context *context;
	struct sync_pt *pt;
	struct sync_fence *fence = NULL;
	int ret = -EINVAL;

	if (len != sizeof(priv))
		return -EINVAL;

	context = kgsl_find_context(owner, context_id);
	if (context == NULL)
		return -EINVAL;

	event = kzalloc(sizeof(*event), GFP_KERNEL);
	if (event == NULL)
		return -ENOMEM;
	event->context = context;
	event->timestamp = timestamp;
	kgsl_context_get(context);

	pt = kgsl_sync_pt_create(context->timeline, timestamp);
	if (pt == NULL) {
		KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n");
		ret = -ENOMEM;
		goto fail_pt;
	}

	fence = sync_fence_create("kgsl-fence", pt);
	if (fence == NULL) {
		/* only destroy pt when not added to fence */
		kgsl_sync_pt_destroy(pt);
		KGSL_DRV_ERR(device, "sync_fence_create failed\n");
		ret = -ENOMEM;
		goto fail_fence;
	}

	priv.fence_fd = get_unused_fd_flags(0);
	if (priv.fence_fd < 0) {
		KGSL_DRV_ERR(device, "invalid fence fd\n");
		ret = -EINVAL;
		goto fail_fd;
	}
	sync_fence_install(fence, priv.fence_fd);

	if (copy_to_user(data, &priv, sizeof(priv))) {
		ret = -EFAULT;
		goto fail_copy_fd;
	}

	ret = kgsl_add_event(device, context_id, timestamp,
			kgsl_fence_event_cb, event, owner);
	if (ret)
		goto fail_event;

	return 0;

fail_event:
fail_copy_fd:
	/* clean up sync_fence_install */
	put_unused_fd(priv.fence_fd);
fail_fd:
	/* clean up sync_fence_create */
	sync_fence_put(fence);
fail_fence:
fail_pt:
	kgsl_context_put(context);
	kfree(event);
	return ret;
}
/**
 * adreno_drawctxt_create - create a new adreno draw context
 * @dev_priv: the owner of the context
 * @flags: flags for the context (passed from user space)
 *
 * Create and return a new draw context for the 3D core.
 */
struct kgsl_context *
adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
			uint32_t *flags)
{
	struct adreno_context *drawctxt;
	struct kgsl_device *device = dev_priv->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int ret;

	drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
	if (drawctxt == NULL)
		return ERR_PTR(-ENOMEM);

	ret = kgsl_context_init(dev_priv, &drawctxt->base);
	if (ret != 0) {
		kfree(drawctxt);
		return ERR_PTR(ret);
	}

	drawctxt->bin_base_offset = 0;
	drawctxt->timestamp = 0;

	*flags &= (KGSL_CONTEXT_PREAMBLE |
		KGSL_CONTEXT_NO_GMEM_ALLOC |
		KGSL_CONTEXT_PER_CONTEXT_TS |
		KGSL_CONTEXT_USER_GENERATED_TS |
		KGSL_CONTEXT_NO_FAULT_TOLERANCE |
		KGSL_CONTEXT_TYPE_MASK);

	if (*flags & KGSL_CONTEXT_PREAMBLE)
		drawctxt->flags |= CTXT_FLAGS_PREAMBLE;

	if (*flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
		drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;

	if (*flags & KGSL_CONTEXT_PER_CONTEXT_TS)
		drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;

	if (*flags & KGSL_CONTEXT_USER_GENERATED_TS) {
		if (!(*flags & KGSL_CONTEXT_PER_CONTEXT_TS)) {
			ret = -EINVAL;
			goto err;
		}
		drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
	}

	if (*flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
		drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE;

	drawctxt->type =
		(*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT;

	ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
	if (ret)
		goto err;

	kgsl_sharedmem_writel(device, &device->memstore,
			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ref_wait_ts),
			KGSL_INIT_REFTIMESTAMP);
	kgsl_sharedmem_writel(device, &device->memstore,
			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ts_cmp_enable),
			0);
	kgsl_sharedmem_writel(device, &device->memstore,
			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
			0);
	kgsl_sharedmem_writel(device, &device->memstore,
			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, eoptimestamp),
			0);

	return &drawctxt->base;
err:
	kgsl_context_put(&drawctxt->base);
	return ERR_PTR(ret);
}
int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
				struct adreno_context *drawctxt,
				unsigned int flags)
{
	struct kgsl_device *device = &adreno_dev->dev;
	int ret = 0;

	if (drawctxt) {
		if (flags & KGSL_CONTEXT_SAVE_GMEM)
			set_bit(ADRENO_CONTEXT_GMEM_SAVE, &drawctxt->priv);
		else
			
			clear_bit(ADRENO_CONTEXT_GMEM_SAVE, &drawctxt->priv);
	}

	
	if (adreno_dev->drawctxt_active == drawctxt) {
		if (drawctxt && drawctxt->ops->draw_workaround)
			ret = drawctxt->ops->draw_workaround(adreno_dev,
							 drawctxt);
		return ret;
	}

	trace_adreno_drawctxt_switch(adreno_dev->drawctxt_active,
		drawctxt, flags);

	if (adreno_dev->drawctxt_active) {
		ret = context_save(adreno_dev, adreno_dev->drawctxt_active);
		if (ret) {
			KGSL_DRV_ERR(device,
				"Error in GPU context %d save: %d\n",
				adreno_dev->drawctxt_active->base.id, ret);
			return ret;
		}

	}

	
	if (drawctxt) {
		if (!_kgsl_context_get(&drawctxt->base))
			return -EINVAL;

		ret = kgsl_mmu_setstate(&device->mmu,
			drawctxt->base.proc_priv->pagetable,
			adreno_dev->drawctxt_active ?
			adreno_dev->drawctxt_active->base.id :
			KGSL_CONTEXT_INVALID);
		
		ret = drawctxt->ops->restore(adreno_dev, drawctxt);
		if (ret) {
			KGSL_DRV_ERR(device,
					"Error in GPU context %d restore: %d\n",
					drawctxt->base.id, ret);
			return ret;
		}
	} else {
		ret = kgsl_mmu_setstate(&device->mmu,
					 device->mmu.defaultpagetable,
					adreno_dev->drawctxt_active->base.id);
	}
	
	if (adreno_dev->drawctxt_active)
		kgsl_context_put(&adreno_dev->drawctxt_active->base);
	adreno_dev->drawctxt_active = drawctxt;
	return 0;
}