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

Commit e239c703 authored by Shubhraprakash Das's avatar Shubhraprakash Das
Browse files

msm: kgsl: Wait for dispatcher on adreno idle



When waiting for the adreno device to become idle wait for
the dispatcher to complete processing commands that are
already submitted to the ringbuffer and prevent dispatcher
from submitting more commands while a thread is waiting for
dispatcher to become idle. This is required to support mutiple
ringbuffers where it is not sufficient to just wait for current
ringbuffer to become idle. All ringbuffers need to be idle and
to do that dispatcher needs to run without submitting more
commands but retiring commands that have been submitted.

Change-Id: Idd36a8da3c230981476348682cd22aed6dab113c
Signed-off-by: default avatarShubhraprakash Das <sadas@codeaurora.org>
parent 5f318d6e
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -2787,6 +2787,7 @@ int adreno_idle(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	unsigned long wait = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
	int ret;

	/*
	 * Make sure the device mutex is held so the dispatcher can't send any
@@ -2799,6 +2800,17 @@ int adreno_idle(struct kgsl_device *device)
		adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
		0x00000000, 0x80000000);

	/* Check if we are already idle before idling dispatcher */
	if (adreno_isidle(device))
		return 0;
	/*
	 * Wait for dispatcher to finish completing commands
	 * already submitted
	 */
	ret = adreno_dispatcher_idle(adreno_dev);
	if (ret)
		return ret;

	while (time_before(jiffies, wait)) {
		/*
		 * If we fault, stop waiting and return an error. The dispatcher
+29 −3
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ enum adreno_gpurev {
 * submitted operation
 * @work: work_struct to put the dispatcher in a work queue
 * @kobj: kobject for the dispatcher directory in the device sysfs node
 * @idle_gate: Gate to wait on for dispatcher to idle
 */
struct adreno_dispatcher {
	struct mutex mutex;
@@ -135,6 +136,7 @@ struct adreno_dispatcher {
	unsigned int tail;
	struct work_struct work;
	struct kobject kobj;
	struct completion idle_gate;
};

enum adreno_dispatcher_flags {
@@ -192,6 +194,7 @@ struct adreno_device {
	struct adreno_busy_data busy_data;
	unsigned int ram_cycles_lo;
	unsigned int starved_ram_lo;
	atomic_t halt;
};

/**
@@ -621,8 +624,7 @@ void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
void adreno_dispatcher_start(struct kgsl_device *device);
int adreno_dispatcher_init(struct adreno_device *adreno_dev);
void adreno_dispatcher_close(struct adreno_device *adreno_dev);
int adreno_dispatcher_idle(struct adreno_device *adreno_dev,
		unsigned int timeout);
int adreno_dispatcher_idle(struct adreno_device *adreno_dev);
void adreno_dispatcher_irq_fault(struct kgsl_device *device);
void adreno_dispatcher_stop(struct adreno_device *adreno_dev);

@@ -925,7 +927,7 @@ static inline unsigned int adreno_getreg(struct adreno_device *adreno_dev,

/**
 * adreno_gpu_fault() - Return the current state of the GPU
 * @adreno_dev: A ponter to the adreno_device to query
 * @adreno_dev: A pointer to the adreno_device to query
 *
 * Return 0 if there is no fault or positive with the last type of fault that
 * occurred
@@ -936,6 +938,18 @@ static inline unsigned int adreno_gpu_fault(struct adreno_device *adreno_dev)
	return atomic_read(&adreno_dev->dispatcher.fault);
}

/**
 * adreno_gpu_halt() - Return the halt status of GPU
 * @adreno_dev: A pointer to the adreno_device to query
 *
 * Return the halt request value
 */
static inline unsigned int adreno_gpu_halt(struct adreno_device *adreno_dev)
{
	smp_rmb();
	return atomic_read(&adreno_dev->halt);
}

/**
 * adreno_set_gpu_fault() - Set the current fault status of the GPU
 * @adreno_dev: A pointer to the adreno_device to set
@@ -950,6 +964,18 @@ static inline void adreno_set_gpu_fault(struct adreno_device *adreno_dev,
	smp_wmb();
}

/**
 * adreno_set_gpu_halt() - Set the halt request
 * @adreno_dev: A pointer to the adreno_device to set
 * @state: Value to set
 */
static inline void adreno_set_gpu_halt(struct adreno_device *adreno_dev,
	int state)
{
	atomic_set(&adreno_dev->halt, state);
	smp_wmb();
}

/**
 * adreno_clear_gpu_fault() - Clear the GPU fault register
 * @adreno_dev: A pointer to an adreno_device structure
+73 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/err.h>

#include "kgsl.h"
#include "kgsl_cffdump.h"
#include "adreno.h"
#include "adreno_ringbuffer.h"
#include "adreno_trace.h"
@@ -283,6 +284,9 @@ static int sendcmd(struct adreno_device *adreno_dev,
	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
	int ret;

	if (0 != adreno_gpu_halt(adreno_dev))
		return -EINVAL;

	dispatcher->inflight++;

	mutex_lock(&device->mutex);
@@ -308,9 +312,10 @@ static int sendcmd(struct adreno_device *adreno_dev,
	 */

	if (dispatcher->inflight == 1) {
		if (ret == 0)
		if (ret == 0) {
			fault_detect_read(device);
		else {
			init_completion(&dispatcher->idle_gate);
		} else {
			kgsl_active_count_put(device);
			clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
		}
@@ -468,6 +473,9 @@ static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
		if (adreno_gpu_fault(adreno_dev) != 0)
			break;

		if (0 != adreno_gpu_halt(adreno_dev))
			break;

		spin_lock(&dispatcher->plist_lock);

		if (plist_head_empty(&dispatcher->pending)) {
@@ -962,6 +970,7 @@ static int dispatcher_do_fault(struct kgsl_device *device)
	int fault, first = 0;
	bool pagefault = false;
	char *state = "failed";
	int halt;

	fault = atomic_xchg(&dispatcher->fault, 0);
	if (fault == 0)
@@ -988,6 +997,9 @@ static int dispatcher_do_fault(struct kgsl_device *device)

	mutex_lock(&device->mutex);

	/* hang opcode */
	kgsl_cffdump_hang(device);

	cmdbatch = dispatcher->cmdqueue[dispatcher->head];

	trace_adreno_cmdbatch_fault(cmdbatch, fault);
@@ -1211,7 +1223,9 @@ replay:

	/* Reset the GPU */
	mutex_lock(&device->mutex);

	/* make sure halt is not set during recovery */
	halt = adreno_gpu_halt(adreno_dev);
	adreno_set_gpu_halt(adreno_dev, 0);
	ret = adreno_reset(device);
	mutex_unlock(&device->mutex);
	/* if any other fault got in until reset then ignore */
@@ -1270,6 +1284,8 @@ replay:
	}

	kfree(replay);
	/* restore halt indicator */
	adreno_set_gpu_halt(adreno_dev, halt);

	return 1;
}
@@ -1471,6 +1487,7 @@ done:
	} else {
		/* There is nothing left in the pipeline.  Shut 'er down boys */
		mutex_lock(&device->mutex);
		complete_all(&dispatcher->idle_gate);
		/*
		 * Stop the fault timer before decrementing the active count to
		 * avoid reading the hardware registers while we are trying to
@@ -1782,6 +1799,9 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev)

	INIT_WORK(&dispatcher->work, adreno_dispatcher_work);

	init_completion(&dispatcher->idle_gate);
	complete_all(&dispatcher->idle_gate);

	plist_head_init(&dispatcher->pending);
	spin_lock_init(&dispatcher->plist_lock);

@@ -1790,3 +1810,53 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev)

	return ret;
}

/*
 * adreno_dispatcher_idle() - Wait for dispatcher to idle
 * @adreno_dev: Adreno device whose dispatcher needs to idle
 *
 * Signal dispatcher to stop sending more commands and complete
 * the commands that have already been submitted. This function
 * should not be called when dispatcher mutex is held.
 */
int adreno_dispatcher_idle(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = &adreno_dev->dev;
	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
	int ret;

	BUG_ON(!mutex_is_locked(&device->mutex));
	if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv))
		return 0;

	/*
	 * Ensure that this function is not called when dispatcher
	 * mutex is held and device is started
	 */
	if (mutex_is_locked(&dispatcher->mutex) &&
		dispatcher->mutex.owner == current)
		BUG_ON(1);

	adreno_set_gpu_halt(adreno_dev, 1);

	mutex_unlock(&device->mutex);

	ret = wait_for_completion_timeout(&dispatcher->idle_gate,
			msecs_to_jiffies(ADRENO_IDLE_TIMEOUT));
	if (ret <= 0) {
		if (!ret)
			ret = -ETIMEDOUT;
		KGSL_DRV_ERR(device, "Dispatcher halt failed %d\n", ret);
	} else {
		ret = 0;
	}

	mutex_lock(&device->mutex);
	adreno_set_gpu_halt(adreno_dev, 0);
	/*
	 * requeue dispatcher work to resubmit pending commands
	 * that may have been blocked due to this idling request
	 */
	adreno_dispatcher_schedule(device);
	return ret;
}
+6 −4
Original line number Diff line number Diff line
@@ -1277,16 +1277,18 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
	/* Set the constraints before adding to ringbuffer */
	adreno_ringbuffer_set_constraint(device, cmdbatch);

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

	ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
					drawctxt,
					flags,
					&link[0], (cmds - link),
					cmdbatch->timestamp);

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

	kgsl_cffdump_regpoll(device,
		adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
		0x00000000, 0x80000000);
done:
	device->pwrctrl.irq_last = 0;
	trace_kgsl_issueibcmds(device, context->id, cmdbatch,
+1 −12
Original line number Diff line number Diff line
/* Copyright (c) 2010-2011,2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2011,2013-2014, 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
@@ -149,15 +149,4 @@ static inline int kgsl_cff_dump_enable_get(void *data, u64 *val)
}

#endif /* CONFIG_MSM_KGSL_CFF_DUMP */

/*
 * kgsl_cff_core_idle() - Idle the device if CFF is on
 * @device: Device whose idle fuunction is called
 */
static inline void kgsl_cff_core_idle(struct kgsl_device *device)
{
	if (device->cff_dump_enable)
		device->ftbl->idle(device);
}

#endif /* __KGSL_CFFDUMP_H */