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

Commit ad6790ba authored by Jeremy Gebben's avatar Jeremy Gebben
Browse files

msm: kgsl: consolidate preamble based context switch code



Move logic for handling preamble based context switch
to the core adreno code. This makes it less burdensome
to implement support for newer GPU families that won't
ever support legacy context switching.

Change-Id: Id9ad5936ff91dcdbc9de869baf0d0b9fcf1b5170
Signed-off-by: default avatarJeremy Gebben <jgebben@codeaurora.org>
parent dc077d46
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -362,10 +362,6 @@ struct adreno_gpudev {

	/* GPU specific function hooks */
	int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
	int (*ctxt_save)(struct adreno_device *, struct adreno_context *);
	int (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
	int (*ctxt_draw_workaround)(struct adreno_device *,
					struct adreno_context *);
	irqreturn_t (*irq_handler)(struct adreno_device *);
	void (*irq_control)(struct adreno_device *, int);
	unsigned int (*irq_pending)(struct adreno_device *);
+50 −39
Original line number Diff line number Diff line
@@ -1398,11 +1398,56 @@ static int a2xx_create_gmem_shadow(struct adreno_device *adreno_dev,
	return 0;
}

static void a2xx_drawctxt_detach(struct adreno_context *drawctxt)
{
	kgsl_sharedmem_free(&drawctxt->gpustate);
	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
}

static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
			struct adreno_context *context);

static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
			struct adreno_context *context);

static int a2xx_drawctxt_draw_workaround(struct adreno_device *adreno_dev,
					struct adreno_context *context);

static const struct adreno_context_ops a225_preamble_ctx_ops = {
	.restore = adreno_context_restore,
	.draw_workaround = a2xx_drawctxt_draw_workaround,
};

static const struct adreno_context_ops a225_legacy_ctx_ops = {
	.save = a2xx_drawctxt_save,
	.restore = a2xx_drawctxt_restore,
	.draw_workaround = a2xx_drawctxt_draw_workaround,
	.detach = a2xx_drawctxt_detach,
};

static const struct adreno_context_ops a2xx_legacy_ctx_ops = {
	.save = a2xx_drawctxt_save,
	.restore = a2xx_drawctxt_restore,
	.detach = a2xx_drawctxt_detach,
};


static int a2xx_drawctxt_create(struct adreno_device *adreno_dev,
	struct adreno_context *drawctxt)
{
	int ret;

	if (drawctxt->flags & CTXT_FLAGS_PREAMBLE
	   && drawctxt->flags & CTXT_FLAGS_NOGMEMALLOC) {
		drawctxt->ops = (adreno_is_a225(adreno_dev))
			?  &a225_preamble_ctx_ops : &adreno_preamble_ctx_ops;

		return 0;
	}

	drawctxt->ops = (adreno_is_a225(adreno_dev))
			?  &a225_legacy_ctx_ops : &a2xx_legacy_ctx_ops;

	/*
	 * Allocate memory for the GPU state and the context commands.
	 * Despite the name, this is much more then just storage for
@@ -1510,12 +1555,6 @@ static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
	struct kgsl_device *device = &adreno_dev->dev;
	int ret;

	if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTROYED))
		return 0;

	if (context->state == ADRENO_CONTEXT_STATE_INVALID)
		return 0;

	if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
		kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
			context->reg_save[1],
@@ -1600,40 +1639,14 @@ static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
			struct adreno_context *context)
{
	struct kgsl_device *device = &adreno_dev->dev;
	unsigned int cmds[5];
	int ret = 0;

	if (context == NULL) {
		/* No context - set the default pagetable and thats it */
		unsigned int id;
		/*
		 * 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.
		 */
		id = (adreno_dev->drawctxt_active != NULL)
			? adreno_dev->drawctxt_active->base.id
			: KGSL_CONTEXT_INVALID;
		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
				  id);
		return 0;
	}
	int ret;

	cmds[0] = cp_nop_packet(1);
	cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
	cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
	cmds[3] = device->memstore.gpuaddr +
		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
	cmds[4] = context->base.id;
	ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
					cmds, 5);
	ret = adreno_context_restore(adreno_dev, context);
	if (ret)
		return ret;

	kgsl_mmu_setstate(&device->mmu, context->base.proc_priv->pagetable,
			context->base.id);

	/* restore gmem.
	/*
	 *  restore gmem.
	 *  (note: changes shader. shader must not already be restored.)
	 */
	if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
@@ -1692,6 +1705,7 @@ static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
	}

	if (adreno_is_a20x(adreno_dev)) {
		unsigned int cmds[2];
		cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
		cmds[1] = context->bin_base_offset;
		ret = adreno_ringbuffer_issuecmds(device, context,
@@ -2296,9 +2310,6 @@ struct adreno_gpudev adreno_a2xx_gpudev = {
	.reg_offsets = &a2xx_reg_offsets,

	.ctxt_create = a2xx_drawctxt_create,
	.ctxt_save = a2xx_drawctxt_save,
	.ctxt_restore = a2xx_drawctxt_restore,
	.ctxt_draw_workaround = a2xx_drawctxt_draw_workaround,
	.irq_handler = a2xx_irq_handler,
	.irq_control = a2xx_irq_control,
	.irq_pending = a2xx_irq_pending,
+30 −39
Original line number Diff line number Diff line
@@ -2345,17 +2345,40 @@ static int a3xx_create_gmem_shadow(struct adreno_device *adreno_dev,
	return 0;
}

static void a3xx_drawctxt_detach(struct adreno_context *drawctxt)
{
	kgsl_sharedmem_free(&drawctxt->gpustate);
	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
}

static int a3xx_drawctxt_save(struct adreno_device *adreno_dev,
			   struct adreno_context *context);

static int a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
			      struct adreno_context *context);

static const struct adreno_context_ops a3xx_legacy_ctx_ops = {
	.save = a3xx_drawctxt_save,
	.restore = a3xx_drawctxt_restore,
	.detach = a3xx_drawctxt_detach,
};


static int a3xx_drawctxt_create(struct adreno_device *adreno_dev,
	struct adreno_context *drawctxt)
{
	int ret;

	/*
	 * Allocate memory for the GPU state and the context commands.
	 * Despite the name, this is much more then just storage for
	 * the gpustate.  This contains command space for gmem save
	 * and texture and vertex buffer storage too
	 * Nothing to do here if the context is using preambles and doesn't need
	 * GMEM save/restore
	 */
	if ((drawctxt->flags & CTXT_FLAGS_PREAMBLE) &&
		(drawctxt->flags & CTXT_FLAGS_NOGMEMALLOC)) {
		drawctxt->ops = &adreno_preamble_ctx_ops;
		return 0;
	}
	drawctxt->ops = &a3xx_legacy_ctx_ops;

	ret = kgsl_allocate(&drawctxt->gpustate,
		drawctxt->base.proc_priv->pagetable, CONTEXT_SIZE);
@@ -2391,9 +2414,6 @@ static int a3xx_drawctxt_save(struct adreno_device *adreno_dev,
	struct kgsl_device *device = &adreno_dev->dev;
	int ret;

	if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTROYED))
		return 0;

	if (context->state == ADRENO_CONTEXT_STATE_INVALID)
		return 0;

@@ -2451,39 +2471,13 @@ static int a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
			      struct adreno_context *context)
{
	struct kgsl_device *device = &adreno_dev->dev;
	unsigned int cmds[5];
	int ret = 0;

	if (context == NULL) {
		/* No context - set the default pagetable and thats it */
		unsigned int id;
		/*
		 * 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.
		 */
		id = (adreno_dev->drawctxt_active != NULL)
			? adreno_dev->drawctxt_active->base.id
			: KGSL_CONTEXT_INVALID;
		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
				  id);
		return 0;
	}
	int ret;

	cmds[0] = cp_nop_packet(1);
	cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
	cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
	cmds[3] = device->memstore.gpuaddr +
		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
	cmds[4] = context->base.id;
	ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
					cmds, 5);
	/* do the common part */
	ret = adreno_context_restore(adreno_dev, context);
	if (ret)
		return ret;

	kgsl_mmu_setstate(&device->mmu, context->base.proc_priv->pagetable,
			context->base.id);

	/*
	 * Restore GMEM.  (note: changes shader.
	 * Shader must not already be restored.)
@@ -4401,9 +4395,6 @@ struct adreno_gpudev adreno_a3xx_gpudev = {
	.perfcounters = &a3xx_perfcounters,

	.ctxt_create = a3xx_drawctxt_create,
	.ctxt_save = a3xx_drawctxt_save,
	.ctxt_restore = a3xx_drawctxt_restore,
	.ctxt_draw_workaround = NULL,
	.rb_init = a3xx_rb_init,
	.perfcounter_init = a3xx_perfcounter_init,
	.perfcounter_close = a3xx_perfcounter_close,
+0 −66
Original line number Diff line number Diff line
@@ -106,70 +106,6 @@ const unsigned int a4xx_registers[] = {

const unsigned int a4xx_registers_count = ARRAY_SIZE(a4xx_registers) / 2;

static int a4xx_drawctxt_create(struct adreno_device *adreno_dev,
	struct adreno_context *drawctxt)
{
	int ret = 0;
	struct kgsl_device *device = &adreno_dev->dev;

	if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
		/* This option is not supported on a4xx */
		KGSL_DRV_ERR(device,
			"Preambles required for A4XX draw contexts\n");
		ret = -EPERM;
		goto done;
	}

	if (!(drawctxt->flags & CTXT_FLAGS_NOGMEMALLOC)) {
		/* This option is not supported on a4xx */
		KGSL_DRV_ERR(device,
			"Cannot create context with gmemalloc\n");
		ret = -EPERM;
	}

done:
	return ret;
}

static int a4xx_drawctxt_restore(struct adreno_device *adreno_dev,
			      struct adreno_context *context)
{
	struct kgsl_device *device = &adreno_dev->dev;
	unsigned int cmds[5];
	int ret;

	if (context == NULL) {
		/* No context - set the default pagetable and thats it */
		unsigned int id;
		/*
		 * 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.
		 */
		id = (adreno_dev->drawctxt_active != NULL)
			? adreno_dev->drawctxt_active->base.id
			: KGSL_CONTEXT_INVALID;
		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
				  id);
		return 0;
	}

	cmds[0] = cp_nop_packet(1);
	cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
	cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
	cmds[3] = device->memstore.gpuaddr +
		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
	cmds[4] = context->base.id;
	ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
					cmds, 5);
	if (ret)
		return ret;
	ret = kgsl_mmu_setstate(&device->mmu,
			context->base.proc_priv->pagetable,
			context->base.id);
	return ret;
}

static const struct adreno_vbif_data a420_vbif[] = {
	{ A4XX_VBIF_ABIT_SORT, 0x0001001F },
	{ A4XX_VBIF_ABIT_SORT_CONF, 0x000000A4 },
@@ -294,8 +230,6 @@ const struct adreno_reg_offsets a4xx_reg_offsets = {
struct adreno_gpudev adreno_a4xx_gpudev = {
	.reg_offsets = &a4xx_reg_offsets,

	.ctxt_create = a4xx_drawctxt_create,
	.ctxt_restore = a4xx_drawctxt_restore,
	.rb_init = a3xx_rb_init,
	.irq_control = a3xx_irq_control,
	.irq_handler = a3xx_irq_handler,
+109 −36
Original line number Diff line number Diff line
@@ -458,9 +458,20 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
	drawctxt->type =
		(*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT;

	if (adreno_dev->gpudev->ctxt_create) {
		ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
		if (ret)
			goto err;
	} else if ((*flags & KGSL_CONTEXT_PREAMBLE) == 0 ||
		  (*flags & KGSL_CONTEXT_NO_GMEM_ALLOC) == 0) {
		KGSL_DEV_ERR_ONCE(device,
				"legacy context switch not supported\n");
		ret = -EINVAL;
		goto err;

	} else {
		drawctxt->ops = &adreno_preamble_ctx_ops;
	}

	kgsl_sharedmem_writel(device, &device->memstore,
			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
@@ -510,19 +521,8 @@ int adreno_drawctxt_detach(struct kgsl_context *context)
	drawctxt = ADRENO_CONTEXT(context);

	/* deactivate context */
	if (adreno_dev->drawctxt_active == drawctxt) {
		/* no need to save GMEM or shader, the context is
		 * being destroyed.
		 */
		drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
				     CTXT_FLAGS_SHADER_SAVE |
				     CTXT_FLAGS_GMEM_SHADOW |
				     CTXT_FLAGS_STATE_SHADOW);

		drawctxt->flags |= CTXT_FLAGS_BEING_DESTROYED;

	if (adreno_dev->drawctxt_active == drawctxt)
		adreno_drawctxt_switch(adreno_dev, NULL, 0);
	}

	mutex_lock(&drawctxt->mutex);

@@ -568,8 +568,8 @@ int adreno_drawctxt_detach(struct kgsl_context *context)

	adreno_profile_process_results(device);

	kgsl_sharedmem_free(&drawctxt->gpustate);
	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
	if (drawctxt->ops->detach)
		drawctxt->ops->detach(drawctxt);

	/* wake threads waiting to submit commands from this context */
	wake_up_interruptible_all(&drawctxt->waiting);
@@ -589,6 +589,69 @@ void adreno_drawctxt_destroy(struct kgsl_context *context)
	kfree(drawctxt);
}


/**
 * adreno_context_restore() - generic context restore handler
 * @adreno_dev: the device
 * @context: the context
 *
 * Basic context restore handler that writes the context identifier
 * to the ringbuffer and issues pagetable switch commands if necessary.
 * May be called directly from the adreno_context_ops.restore function
 * pointer or as the first action in a hardware specific restore
 * function.
 */
int adreno_context_restore(struct adreno_device *adreno_dev,
				  struct adreno_context *context)
{
	int ret;
	struct kgsl_device *device;
	unsigned int cmds[5];

	if (adreno_dev == NULL || context == NULL)
		return -EINVAL;

	device = &adreno_dev->dev;
	/* write the context identifier to the ringbuffer */
	cmds[0] = cp_nop_packet(1);
	cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
	cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
	cmds[3] = device->memstore.gpuaddr +
		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
	cmds[4] = context->base.id;
	ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
					cmds, 5);
	if (ret)
		return ret;

	return kgsl_mmu_setstate(&device->mmu,
			context->base.proc_priv->pagetable,
			context->base.id);
}


const struct adreno_context_ops adreno_preamble_ctx_ops = {
	.restore = adreno_context_restore,
};

/**
 * context_save() - save old context when necessary
 * @drawctxt - the old context
 *
 * For legacy context switching, we need to issue save
 * commands unless the context is being destroyed.
 */
static inline int context_save(struct adreno_device *adreno_dev,
				struct adreno_context *context)
{
	if (context->ops->save == NULL
		|| kgsl_context_detached(&context->base)
		|| context->state == ADRENO_CONTEXT_STATE_INVALID)
		return 0;

	return context->ops->save(adreno_dev, context);
}

/**
 * adreno_drawctxt_set_bin_base_offset - set bin base offset for the context
 * @device - KGSL device that owns the context
@@ -627,6 +690,12 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_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. */
@@ -638,31 +707,25 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,

	/* already current? */
	if (adreno_dev->drawctxt_active == drawctxt) {
		if (adreno_dev->gpudev->ctxt_draw_workaround &&
			adreno_is_a225(adreno_dev))
				ret = adreno_dev->gpudev->ctxt_draw_workaround(
					adreno_dev, 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);

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

	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;
		}
	}

		/* 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;
	}
@@ -671,16 +734,26 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
	if (drawctxt) {
		if (!_kgsl_context_get(&drawctxt->base))
			return -EINVAL;
	}

		/* Set the new context */
	ret = adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
		ret = drawctxt->ops->restore(adreno_dev, drawctxt);
		if (ret) {
			KGSL_DRV_ERR(device,
					"Error in GPU context %d restore: %d\n",
			drawctxt ? drawctxt->base.id : 0, ret);
					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,
					 KGSL_CONTEXT_INVALID);
	}

	adreno_dev->drawctxt_active = drawctxt;
	return 0;
Loading