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

Commit 1f3d748d 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: Wait for dispatcher on adreno idle"

parents 67732f97 e239c703
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -2794,6 +2794,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
@@ -2806,6 +2807,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;
};

/**
@@ -623,8 +626,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);

@@ -929,7 +931,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
@@ -940,6 +942,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
@@ -954,6 +968,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"
@@ -292,6 +293,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);
@@ -317,9 +321,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);
		}
@@ -477,6 +482,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)) {
@@ -971,6 +979,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)
@@ -997,6 +1006,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);
@@ -1220,7 +1232,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 */
@@ -1279,6 +1293,8 @@ replay:
	}

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

	return 1;
}
@@ -1480,6 +1496,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
@@ -1791,6 +1808,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);

@@ -1799,3 +1819,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 */