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

Commit bd411b48 authored by Tarun Karra's avatar Tarun Karra
Browse files

msm: kgsl: Make fast hang detect generic



Code to get performance counters for fast hang detection is not
specific to adreno device, we use the same performance counter
countables on all adreno devices, so this code should be generic.

Change-Id: I317bd38f8e733c05b5d52571ddede433b12bec02
Signed-off-by: default avatarTarun Karra <tkarra@codeaurora.org>
parent dcb37eee
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -883,7 +883,6 @@
#define A310_RBBM_GPR0_CTL_DEFAULT    0x000000AA

/* COUNTABLE FOR SP PERFCOUNTER */
#define SP_FS_FULL_ALU_INSTRUCTIONS    0x0E
#define SP_ALU_ACTIVE_CYCLES           0x1D
#define SP0_ICL1_MISSES                0x1A
#define SP_FS_CFLOW_INSTRUCTIONS       0x0C
+116 −29
Original line number Diff line number Diff line
@@ -94,7 +94,21 @@ static struct adreno_device device_3d0 = {
		adreno_input_work),
};

unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
/* Ptr to array for the current set of fault detect registers */
unsigned int *adreno_ft_regs;
/* Total number of fault detect registers */
unsigned int adreno_ft_regs_num;
/* Ptr to array for the current fault detect registers values */
unsigned int *adreno_ft_regs_val;
/* Array of default fault detect registers */
static unsigned int adreno_ft_regs_default[] = {
	ADRENO_REG_RBBM_STATUS,
	ADRENO_REG_CP_RB_RPTR,
	ADRENO_REG_CP_IB1_BASE,
	ADRENO_REG_CP_IB1_BUFSZ,
	ADRENO_REG_CP_IB2_BASE,
	ADRENO_REG_CP_IB2_BUFSZ
};

static struct workqueue_struct *adreno_wq;

@@ -104,6 +118,86 @@ static unsigned int _wake_nice = -7;
/* Number of milliseconds to stay active active after a wake on touch */
static unsigned int _wake_timeout = 100;


static int _get_counter(struct adreno_device *adreno_dev,
		int group, int countable, unsigned int *lo,
		unsigned int *hi)
{
	int ret = 0;

	if (*lo == 0) {

		ret = adreno_perfcounter_get(adreno_dev, group, countable,
			lo, hi, PERFCOUNTER_FLAG_KERNEL);

		if (ret) {
			struct kgsl_device *device = &adreno_dev->dev;

			KGSL_DRV_ERR(device,
				"Unable to allocate fault detect performance counter %d/%d\n",
				group, countable);
			KGSL_DRV_ERR(device,
				"GPU fault detect will be less reliable\n");
		}
	}

	return ret;
}

static inline void _put_counter(struct adreno_device *adreno_dev,
		int group, int countable, unsigned int *lo,
		unsigned int *hi)
{
	if (*lo != 0)
		adreno_perfcounter_put(adreno_dev, group, countable,
			PERFCOUNTER_FLAG_KERNEL);

	*lo = 0;
	*hi = 0;
}

/**
 * adreno_fault_detect_start() - Allocate performance counters
 * used for fast fault detection
 * @adreno_dev: Pointer to an adreno_device structure
 *
 * Allocate the series of performance counters that should be periodically
 * checked to verify that the GPU is still moving
 */
void adreno_fault_detect_start(struct adreno_device *adreno_dev)
{
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	unsigned int i, j = ARRAY_SIZE(adreno_ft_regs_default);

	for (i = 0; i < gpudev->ft_perf_counters_count; i++) {
		_get_counter(adreno_dev, gpudev->ft_perf_counters[i].counter,
			 gpudev->ft_perf_counters[i].countable,
			 &adreno_ft_regs[j + (i * 2)],
			 &adreno_ft_regs[j + ((i * 2) + 1)]);
	}
}

/**
 * adreno_fault_detect_stop() - Release performance counters
 * used for fast fault detection
 * @adreno_dev: Pointer to an adreno_device structure
 *
 * Release the counters allocated in adreno_fault_detect_start
 */
void adreno_fault_detect_stop(struct adreno_device *adreno_dev)
{
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	unsigned int i, j = ARRAY_SIZE(adreno_ft_regs_default);

	for (i = 0; i < gpudev->ft_perf_counters_count; i++) {
		_put_counter(adreno_dev, gpudev->ft_perf_counters[i].counter,
			 gpudev->ft_perf_counters[i].countable,
			 &adreno_ft_regs[j + (i * 2)],
			 &adreno_ft_regs[j + ((i * 2) + 1)]);

	}
}

/*
 * A workqueue callback responsible for actually turning on the GPU after a
 * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any
@@ -1269,21 +1363,20 @@ static int adreno_init(struct kgsl_device *device)
			adreno_dev->gpucore->sync_lock_pfp_ver) >= 0))
		device->mmu.flags |= KGSL_MMU_FLAGS_IOMMU_SYNC;

	/* Initialize ft detection register offsets */
	ft_detect_regs[0] = adreno_getreg(adreno_dev,
						ADRENO_REG_RBBM_STATUS);
	ft_detect_regs[1] = adreno_getreg(adreno_dev,
						ADRENO_REG_CP_RB_RPTR);
	ft_detect_regs[2] = adreno_getreg(adreno_dev,
						ADRENO_REG_CP_IB1_BASE);
	ft_detect_regs[3] = adreno_getreg(adreno_dev,
						ADRENO_REG_CP_IB1_BUFSZ);
	ft_detect_regs[4] = adreno_getreg(adreno_dev,
						ADRENO_REG_CP_IB2_BASE);
	ft_detect_regs[5] = adreno_getreg(adreno_dev,
						ADRENO_REG_CP_IB2_BUFSZ);
	for (i = 6; i < FT_DETECT_REGS_COUNT; i++)
		ft_detect_regs[i] = 0;
	adreno_ft_regs_num = (ARRAY_SIZE(adreno_ft_regs_default) +
				   gpudev->ft_perf_counters_count*2);

	adreno_ft_regs = kzalloc(adreno_ft_regs_num, GFP_KERNEL);
	if (!adreno_ft_regs)
		return -ENOMEM;

	adreno_ft_regs_val = kzalloc(adreno_ft_regs_num, GFP_KERNEL);
	if (!adreno_ft_regs_val)
		return -ENOMEM;

	for (i = 0; i < ARRAY_SIZE(adreno_ft_regs_default); i++)
		adreno_ft_regs[i] = adreno_getreg(adreno_dev,
					adreno_ft_regs_default[i]);

	/* turn on hang interrupt for A4XX and a330v2 by default */
	if ((adreno_is_a4xx(adreno_dev)) || (adreno_is_a330v2(adreno_dev)))
@@ -1760,15 +1853,12 @@ static ssize_t _ft_fast_hang_detect_store(struct device *dev,

	if (tmp != adreno_dev->fast_hang_detect) {
		if (adreno_dev->fast_hang_detect) {
			if (gpudev->fault_detect_start &&
				!kgsl_active_count_get(&adreno_dev->dev)) {
				gpudev->fault_detect_start(adreno_dev);
			if (kgsl_active_count_get(&adreno_dev->dev)) {
				adreno_fault_detect_start(adreno_dev);
				kgsl_active_count_put(&adreno_dev->dev);
			}
		} else {
			if (gpudev->fault_detect_stop)
				gpudev->fault_detect_stop(adreno_dev);
		}
		} else
			adreno_fault_detect_stop(adreno_dev);
	}

	mutex_unlock(&adreno_dev->dev.mutex);
@@ -2345,7 +2435,6 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
	int status = -EINVAL;
	struct kgsl_device *device = dev_priv->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);

	switch (type) {
	case KGSL_PROP_PWRCTRL: {
@@ -2365,9 +2454,8 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
				device->pwrctrl.ctrl_flags = 0;
				adreno_dev->fast_hang_detect = 1;

				if (gpudev->fault_detect_start &&
				!kgsl_active_count_get(&adreno_dev->dev)) {
					gpudev->fault_detect_start(adreno_dev);
				if (!kgsl_active_count_get(&adreno_dev->dev)) {
					adreno_fault_detect_start(adreno_dev);
					kgsl_active_count_put(&adreno_dev->dev);
				}

@@ -2377,8 +2465,7 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
							KGSL_STATE_ACTIVE);
				device->pwrctrl.ctrl_flags = KGSL_PWR_ON;
				adreno_dev->fast_hang_detect = 0;
				if (gpudev->fault_detect_stop)
					gpudev->fault_detect_stop(adreno_dev);
				adreno_fault_detect_stop(adreno_dev);
				kgsl_pwrscale_disable(device);
			}

+14 −6
Original line number Diff line number Diff line
@@ -591,6 +591,8 @@ struct adreno_gpudev {
	 * so define them in the structure and use them as variables.
	 */
	const struct adreno_reg_offsets *reg_offsets;
	const struct adreno_ft_perf_counters *ft_perf_counters;
	unsigned int ft_perf_counters_count;

	struct adreno_perfcounters *perfcounters;
	const struct adreno_invalid_countables
@@ -612,8 +614,6 @@ struct adreno_gpudev {
	void (*perfcounter_close)(struct adreno_device *);
	void (*perfcounter_save)(struct adreno_device *);
	void (*perfcounter_restore)(struct adreno_device *);
	void (*fault_detect_start)(struct adreno_device *);
	void (*fault_detect_stop)(struct adreno_device *);
	void (*start)(struct adreno_device *);
	void (*busy_cycles)(struct adreno_device *, struct adreno_busy_data *);
	int (*perfcounter_enable)(struct adreno_device *, unsigned int group,
@@ -629,8 +629,6 @@ struct adreno_gpudev {
	void (*regulator_disable)(struct adreno_device *);
};

#define FT_DETECT_REGS_COUNT 14

struct log_field {
	bool show;
	const char *display;
@@ -678,6 +676,15 @@ struct log_field {
		(_i) < (_dev)->num_ringbuffers;			\
		(_i)++, (_rb)++)

struct adreno_ft_perf_counters {
	unsigned int counter;
	unsigned int countable;
};

extern unsigned int *adreno_ft_regs;
extern unsigned int adreno_ft_regs_num;
extern unsigned int *adreno_ft_regs_val;

extern struct adreno_gpudev adreno_a3xx_gpudev;
extern struct adreno_gpudev adreno_a4xx_gpudev;

@@ -705,8 +712,6 @@ extern const struct adreno_vbif_snapshot_registers
				a4xx_vbif_snapshot_registers[];
extern const unsigned int a4xx_vbif_snapshot_reg_cnt;

extern unsigned int ft_detect_regs[];

int adreno_spin_idle(struct kgsl_device *device);
int adreno_idle(struct kgsl_device *device);
bool adreno_isidle(struct kgsl_device *device);
@@ -788,6 +793,9 @@ int adreno_iommu_set_pt(struct adreno_ringbuffer *rb,
void adreno_iommu_set_pt_generate_rb_cmds(struct adreno_ringbuffer *rb,
					struct kgsl_pagetable *pt);

void adreno_fault_detect_start(struct adreno_device *adreno_dev);
void adreno_fault_detect_stop(struct adreno_device *adreno_dev);

static inline int adreno_is_a3xx(struct adreno_device *adreno_dev)
{
	return ((ADRENO_GPUREV(adreno_dev) >= 300) &&
+11 −93
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@

#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/msm_kgsl.h>

#include "kgsl.h"
#include "adreno.h"
@@ -2074,95 +2075,12 @@ static struct adreno_perfcounters a3xx_perfcounters = {
	ARRAY_SIZE(a3xx_perfcounter_groups),
};

static inline int _get_counter(struct adreno_device *adreno_dev,
		int group, int countable, unsigned int *lo,
		unsigned int *hi)
{
	int ret = 0;

	if (*lo == 0) {

		ret = adreno_perfcounter_get(adreno_dev, group, countable,
			lo, hi, PERFCOUNTER_FLAG_KERNEL);

		if (ret) {
			struct kgsl_device *device = &adreno_dev->dev;

			KGSL_DRV_ERR(device,
				"Unable to allocate fault detect performance counter %d/%d\n",
				group, countable);
			KGSL_DRV_ERR(device,
				"GPU fault detect will be less reliable\n");
		}
	}

	return ret;
}

static inline void _put_counter(struct adreno_device *adreno_dev,
		int group, int countable, unsigned int *lo,
		unsigned int *hi)
{
	if (*lo != 0) {
		adreno_perfcounter_put(adreno_dev, group, countable,
			PERFCOUNTER_FLAG_KERNEL);
	}

	*lo = 0;
	*hi = 0;
}

/**
 * a3xx_fault_detect_start() - Allocate performance counters used for fast fault
 * detection
 * @adreno_dev: Pointer to an adreno_device structure
 *
 * Allocate the series of performance counters that should be periodically
 * checked to verify that the GPU is still moving
 */
void a3xx_fault_detect_start(struct adreno_device *adreno_dev)
{
	_get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
		SP_ALU_ACTIVE_CYCLES,
		&ft_detect_regs[6], &ft_detect_regs[7]);

	_get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
		SP0_ICL1_MISSES,
		&ft_detect_regs[8], &ft_detect_regs[9]);

	_get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
		SP_FS_CFLOW_INSTRUCTIONS,
		&ft_detect_regs[10], &ft_detect_regs[11]);

	_get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_TSE,
		TSE_INPUT_PRIM_NUM,
		&ft_detect_regs[12], &ft_detect_regs[13]);
}
/**
 * a3xx_fault_detect_stop() - Release performance counters used for fast fault
 * detection
 * @adreno_dev: Pointer to an adreno_device structure
 *
 * Release the counters allocated in a3xx_fault_detect_start
 */
void a3xx_fault_detect_stop(struct adreno_device *adreno_dev)
{
	_put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
		SP_ALU_ACTIVE_CYCLES,
		&ft_detect_regs[6], &ft_detect_regs[7]);

	_put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
		SP0_ICL1_MISSES,
		&ft_detect_regs[8], &ft_detect_regs[9]);

	_put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
		SP_FS_CFLOW_INSTRUCTIONS,
		&ft_detect_regs[10], &ft_detect_regs[11]);

	_put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_TSE,
		TSE_INPUT_PRIM_NUM,
		&ft_detect_regs[12], &ft_detect_regs[13]);
}
struct adreno_ft_perf_counters a3xx_ft_perf_counters[] = {
	{KGSL_PERFCOUNTER_GROUP_SP, SP_ALU_ACTIVE_CYCLES},
	{KGSL_PERFCOUNTER_GROUP_SP, SP0_ICL1_MISSES},
	{KGSL_PERFCOUNTER_GROUP_SP, SP_FS_CFLOW_INSTRUCTIONS},
	{KGSL_PERFCOUNTER_GROUP_TSE, TSE_INPUT_PRIM_NUM},
};

/**
 * a3xx_perfcounter_close() - Put counters that were initialized in
@@ -2175,7 +2093,7 @@ void a3xx_perfcounter_close(struct adreno_device *adreno_dev)
		PERFCOUNTER_FLAG_KERNEL);

	if (adreno_dev->fast_hang_detect)
		a3xx_fault_detect_stop(adreno_dev);
		adreno_fault_detect_stop(adreno_dev);
}

/**
@@ -2203,7 +2121,7 @@ int a3xx_perfcounter_init(struct adreno_device *adreno_dev)
	}

	if (adreno_dev->fast_hang_detect)
		a3xx_fault_detect_start(adreno_dev);
		adreno_fault_detect_start(adreno_dev);

	/* Turn on the GPU busy counter(s) and let them run free */
	/* GPU busy counts */
@@ -2483,6 +2401,8 @@ static struct adreno_snapshot_data a3xx_snapshot_data = {

struct adreno_gpudev adreno_a3xx_gpudev = {
	.reg_offsets = &a3xx_reg_offsets,
	.ft_perf_counters = a3xx_ft_perf_counters,
	.ft_perf_counters_count = ARRAY_SIZE(a3xx_ft_perf_counters),
	.perfcounters = &a3xx_perfcounters,
	.irq = &a3xx_irq,
	.snapshot_data = &a3xx_snapshot_data,
@@ -2503,7 +2423,5 @@ struct adreno_gpudev adreno_a3xx_gpudev = {
	.perfcounter_enable = a3xx_perfcounter_enable,
	.perfcounter_read = a3xx_perfcounter_read,
	.perfcounter_write = a3xx_perfcounter_write,
	.fault_detect_start = a3xx_fault_detect_start,
	.fault_detect_stop = a3xx_fault_detect_stop,
	.coresight = &a3xx_coresight,
};
+0 −3
Original line number Diff line number Diff line
@@ -34,9 +34,6 @@ void a3xx_a4xx_err_callback(struct adreno_device *adreno_dev, int bit);
void a3xx_fatal_err_callback(struct adreno_device *adreno_dev, int bit);
void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq);

void a3xx_fault_detect_start(struct adreno_device *adreno_dev);
void a3xx_fault_detect_stop(struct adreno_device *adreno_dev);

void a3xx_snapshot(struct adreno_device *adreno_dev,
		struct kgsl_snapshot *snapshot);
#endif /*__A3XX_H */
Loading