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

Commit 6fef3054 authored by Shubhraprakash Das's avatar Shubhraprakash Das
Browse files

msm: kgsl: Add ringbuffer priority levels



Add priority levels to ringbuffers and since there are
multiple ringbuffers, place the index of memstore memory
for these ringbuffers after the indexes of contexts. Context id
0 is used to refer to ringbuffer memstore but since there are
multiple ringbuffers the priority level is also used to decide
the memstore index for a ringbuffer. This leaves index 0 of
memstore unused for now.

Change-Id: I922b98dedeb0392cc81095efc100d8c585ab5c17
Signed-off-by: default avatarShubhraprakash Das <sadas@codeaurora.org>
parent 15e3d7d4
Loading
Loading
Loading
Loading
+78 −25
Original line number Diff line number Diff line
@@ -1339,7 +1339,7 @@ static int adreno_iommu_setstate(struct kgsl_device *device,
	if (result)
		kgsl_mmu_disable_clk(&device->mmu, KGSL_IOMMU_MAX_UNITS);
	else
		kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts,
		adreno_ringbuffer_mmu_disable_clk_on_ts(device, rb,
						KGSL_IOMMU_MAX_UNITS);

done:
@@ -1811,7 +1811,7 @@ static int adreno_remove(struct platform_device *pdev)
static int adreno_init(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev;
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	int i;
	int ret;

@@ -1823,8 +1823,6 @@ static int adreno_init(struct kgsl_device *device)
	if (test_bit(ADRENO_DEVICE_INITIALIZED, &adreno_dev->priv))
		return 0;

	gpudev = ADRENO_GPU_DEVICE(adreno_dev);

	/* Power up the device */
	ret = kgsl_pwrctrl_enable(device);
	if (ret)
@@ -2079,6 +2077,8 @@ static int adreno_stop(struct kgsl_device *device)

	adreno_dispatcher_stop(adreno_dev);

	adreno_ringbuffer_stop(adreno_dev);

	kgsl_mmu_stop(&device->mmu);

	adreno_irqctrl(adreno_dev, 0);
@@ -3139,6 +3139,74 @@ static int adreno_waittimestamp(struct kgsl_device *device,
	return ret;
}

/**
 * __adreno_readtimestamp() - Reads the timestamp from memstore memory
 * @device: Pointer to device whose memstore is read
 * @index: Index into the memstore memory
 * @type: Type of timestamp to read
 * @timestamp: The out parameter where the timestamp is read
 */
int __adreno_readtimestamp(struct kgsl_device *device, int index, int type,
		unsigned int *timestamp)
{
	int status = 0;

	switch (type) {
	case KGSL_TIMESTAMP_CONSUMED:
		kgsl_sharedmem_readl(&device->memstore, timestamp,
			KGSL_MEMSTORE_OFFSET(index, soptimestamp));
		break;
	case KGSL_TIMESTAMP_RETIRED:
		kgsl_sharedmem_readl(&device->memstore, timestamp,
			KGSL_MEMSTORE_OFFSET(index, eoptimestamp));
		break;
	default:
		status = -EINVAL;
		*timestamp = 0;
		break;
	}
	return status;
}

/**
 * adreno_rb_readtimestamp(): Return the value of given type of timestamp
 * for a RB
 * @device: GPU device whose timestamp values are being queried
 * @priv: The object being queried for a timestamp (expected to be a rb pointer)
 * @type: The type of timestamp (one of 3) to be read
 * @timestamp: Pointer to where the read timestamp is to be written to
 *
 * CONSUMED and RETIRED type timestamps are sorted by id and are constantly
 * updated by the GPU through shared memstore memory. QUEUED type timestamps
 * are read directly from context struct.

 * The function returns 0 on success and timestamp value at the *timestamp
 * address and returns -EINVAL on any read error/invalid type and timestamp = 0.
 */
int adreno_rb_readtimestamp(struct kgsl_device *device,
		void *priv, enum kgsl_timestamp_type type,
		unsigned int *timestamp)
{
	int status = 0;
	struct adreno_ringbuffer *rb = priv;

	/*
	 * If user passed in a NULL pointer for timestamp, return without
	 * doing anything.
	 */
	if (!timestamp)
		return status;

	if (KGSL_TIMESTAMP_QUEUED == type)
		*timestamp = rb->timestamp;
	else
		status = __adreno_readtimestamp(device,
				rb->id + KGSL_MEMSTORE_MAX,
				type, timestamp);

	return status;
}

/**
 * adreno_readtimestamp(): Return the value of given type of timestamp
 * @device: GPU device whose timestamp values are being queried
@@ -3161,6 +3229,7 @@ static int adreno_readtimestamp(struct kgsl_device *device,
	struct kgsl_context *context = priv;
	unsigned int id = KGSL_CONTEXT_ID(context);

	BUG_ON(NULL == context || id >= KGSL_MEMSTORE_MAX);
	/*
	 * If user passed in a NULL pointer for timestamp, return without
	 * doing anything.
@@ -3168,27 +3237,11 @@ static int adreno_readtimestamp(struct kgsl_device *device,
	if (!timestamp)
		return status;

	switch (type) {
	case KGSL_TIMESTAMP_QUEUED: {
		struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

		*timestamp = adreno_context_timestamp(context,
				ADRENO_CURRENT_RINGBUFFER(adreno_dev));
		break;
	}
	case KGSL_TIMESTAMP_CONSUMED:
		kgsl_sharedmem_readl(&device->memstore, timestamp,
			KGSL_MEMSTORE_OFFSET(id, soptimestamp));
		break;
	case KGSL_TIMESTAMP_RETIRED:
		kgsl_sharedmem_readl(&device->memstore, timestamp,
			KGSL_MEMSTORE_OFFSET(id, eoptimestamp));
		break;
	default:
		status = -EINVAL;
		*timestamp = 0;
		break;
	}
	if (KGSL_TIMESTAMP_QUEUED == type)
		*timestamp = adreno_context_timestamp(context);
	else
		status = __adreno_readtimestamp(device,
				context->id, type, timestamp);

	return status;
}
+37 −8
Original line number Diff line number Diff line
@@ -600,6 +600,7 @@ struct adreno_gpudev {
	struct adreno_coresight *coresight;

	struct adreno_irq *irq;
	int num_prio_levels;
	/* GPU specific function hooks */
	irqreturn_t (*irq_handler)(struct adreno_device *);
	void (*irq_control)(struct adreno_device *, int);
@@ -774,6 +775,10 @@ void adreno_coresight_remove(struct kgsl_device *device);

bool adreno_hw_isidle(struct kgsl_device *device);

int adreno_rb_readtimestamp(struct kgsl_device *device,
	void *priv, enum kgsl_timestamp_type type,
	unsigned int *timestamp);

static inline int adreno_is_a3xx(struct adreno_device *adreno_dev)
{
	return ((ADRENO_GPUREV(adreno_dev) >= 300) &&
@@ -856,19 +861,14 @@ static inline int adreno_rb_ctxtswitch(unsigned int *cmd)
/**
 * adreno_context_timestamp() - Return the last queued timestamp for the context
 * @k_ctxt: Pointer to the KGSL context to query
 * @rb: Pointer to the ringbuffer structure for the GPU
 *
 * Return the last queued context for the given context. This is used to verify
 * that incoming requests are not using an invalid (unsubmitted) timestamp
 */
static inline int adreno_context_timestamp(struct kgsl_context *k_ctxt,
		struct adreno_ringbuffer *rb)
static inline int adreno_context_timestamp(struct kgsl_context *k_ctxt)
{
	if (k_ctxt) {
		struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
		return a_ctxt->timestamp;
	}
	return rb->global_ts;
	struct adreno_context *drawctxt = ADRENO_CONTEXT(k_ctxt);
	return drawctxt->timestamp;
}

static inline int __adreno_add_idle_indirect_cmds(unsigned int *cmds,
@@ -1287,4 +1287,33 @@ adreno_get_rptr(struct adreno_ringbuffer *rb)
	return rb->rptr;
}

/**
 * adreno_ctx_get_rb() - Return the ringbuffer that a context should
 * use based on priority
 * @adreno_dev: The adreno device that context is using
 * @drawctxt: The context pointer
 */
static inline struct adreno_ringbuffer *adreno_ctx_get_rb(
				struct adreno_device *adreno_dev,
				struct adreno_context *drawctxt)
{
	struct kgsl_context *context;
	int level;
	if (!drawctxt)
		return NULL;

	context = &(drawctxt->base);

	/*
	 * Math to convert the priority field in context structure to an RB ID.
	 * Divide up the context priority based on number of ringbuffer levels.
	 */
	level = context->priority / adreno_dev->num_ringbuffers;
	if (level < adreno_dev->num_ringbuffers)
		return &(adreno_dev->ringbuffers[level]);
	else
		return &(adreno_dev->ringbuffers[
				adreno_dev->num_ringbuffers - 1]);
}

#endif /*__ADRENO_H */
+1 −0
Original line number Diff line number Diff line
@@ -2487,6 +2487,7 @@ struct adreno_gpudev adreno_a3xx_gpudev = {
	.perfcounters = &a3xx_perfcounters,
	.irq = &a3xx_irq,
	.snapshot_data = &a3xx_snapshot_data,
	.num_prio_levels = 1,

	.rb_init = a3xx_rb_init,
	.perfcounter_init = a3xx_perfcounter_init,
+1 −0
Original line number Diff line number Diff line
@@ -1423,6 +1423,7 @@ struct adreno_gpudev adreno_a4xx_gpudev = {
	.perfcounters = &a4xx_perfcounters,
	.irq = &a4xx_irq,
	.snapshot_data = &a4xx_snapshot_data,
	.num_prio_levels = 1,

	.perfcounter_init = a3xx_perfcounter_init,
	.perfcounter_close = a3xx_perfcounter_close,
+28 −17
Original line number Diff line number Diff line
@@ -57,23 +57,25 @@ static unsigned int _fault_timer_interval = 200;
/* Local array for the current set of fault detect registers */
static unsigned int fault_detect_regs[FT_DETECT_REGS_COUNT];

/* The last retired global timestamp read during fault detect */
static unsigned int fault_detect_ts;

/**
 * fault_detect_read() - Read the set of fault detect registers
 * @device: Pointer to the KGSL device struct
 *
 * Read the set of fault detect registers and store them in the local array.
 * This is for the initial values that are compared later with
 * fault_detect_read_compare
 * fault_detect_read_compare. Also store the initial timestamp of each rb
 * to compare the timestamps with.
 */
static void fault_detect_read(struct kgsl_device *device)
{
	int i;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED,
		&fault_detect_ts);
	for (i = 0; i < adreno_dev->num_ringbuffers; i++) {
		struct adreno_ringbuffer *rb = &(adreno_dev->ringbuffers[i]);
		adreno_rb_readtimestamp(device, rb,
			KGSL_TIMESTAMP_RETIRED, &(rb->fault_detect_ts));
	}

	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
		if (ft_detect_regs[i] == 0)
@@ -99,12 +101,16 @@ static inline bool _isidle(struct kgsl_device *device)
	if (!adreno_hw_isidle(device))
		return false;

	for (i = 0; i < adreno_dev->num_ringbuffers; i++) {
		kgsl_readtimestamp(device, NULL,
				KGSL_TIMESTAMP_RETIRED, &ts);
		if (ts != adreno_dev->ringbuffers[i].global_ts)
	/*
	 * only compare the current RB timestamp because the device has gone
	 * idle and therefore only the current RB ts can be equal, the other
	 * RB's may not be scheduled by dispatcher yet
	 */
	if (adreno_rb_readtimestamp(device,
		adreno_dev->cur_rb, KGSL_TIMESTAMP_RETIRED, &ts))
		return false;
	if (ts != adreno_dev->cur_rb->timestamp)
		return false;
	}
ret:
	for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
		fault_detect_regs[i] = 0;
@@ -117,10 +123,13 @@ ret:
 * @device: Pointer to the KGSL device struct
 *
 * Read the set of fault detect registers and compare them to the current set
 * of registers.  Return 1 if any of the register values changed
 * of registers.  Return 1 if any of the register values changed. Also, compare
 * if the current RB's timstamp has changed or not.
 */
static int fault_detect_read_compare(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_ringbuffer *rb = ADRENO_CURRENT_RINGBUFFER(adreno_dev);
	int i, ret = 0;
	unsigned int ts;

@@ -139,11 +148,13 @@ static int fault_detect_read_compare(struct kgsl_device *device)
		fault_detect_regs[i] = val;
	}

	kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED, &ts);
	if (ts != fault_detect_ts)
	if (!adreno_rb_readtimestamp(device, adreno_dev->cur_rb,
				KGSL_TIMESTAMP_RETIRED, &ts)) {
		if (ts != rb->fault_detect_ts)
			ret = 1;

	fault_detect_ts = ts;
		rb->fault_detect_ts = ts;
	}

	return ret;
}
Loading