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

Commit efc44dfe 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: Use spinlock for A6xx perfcounter updates"

parents fbf9b0bb 1382e511
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -943,6 +943,9 @@ struct adreno_gpudev {
	bool (*sptprac_is_on)(struct adreno_device *);
	bool (*sptprac_is_on)(struct adreno_device *);
	unsigned int (*ccu_invalidate)(struct adreno_device *adreno_dev,
	unsigned int (*ccu_invalidate)(struct adreno_device *adreno_dev,
				unsigned int *cmds);
				unsigned int *cmds);
	int (*perfcounter_update)(struct adreno_device *adreno_dev,
				struct adreno_perfcount_register *reg,
				bool update_reg);
};
};


/**
/**
+76 −3
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/firmware.h>
#include <linux/firmware.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/subsystem_restart.h>
#include <linux/pm_opp.h>
#include <linux/pm_opp.h>
#include <linux/jiffies.h>


#include "adreno.h"
#include "adreno.h"
#include "a6xx_reg.h"
#include "a6xx_reg.h"
@@ -3010,8 +3011,16 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = {
		A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, },
		A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, },
};
};


/*
 * ADRENO_PERFCOUNTER_GROUP_RESTORE flag is enabled by default
 * because most of the perfcounter groups need to be restored
 * as part of preemption and IFPC. Perfcounter groups that are
 * not restored as part of preemption and IFPC should be defined
 * using A6XX_PERFCOUNTER_GROUP_FLAGS macro
 */
#define A6XX_PERFCOUNTER_GROUP(offset, name) \
#define A6XX_PERFCOUNTER_GROUP(offset, name) \
	ADRENO_PERFCOUNTER_GROUP(a6xx, offset, name)
	ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, \
	ADRENO_PERFCOUNTER_GROUP_RESTORE)


#define A6XX_PERFCOUNTER_GROUP_FLAGS(offset, name, flags) \
#define A6XX_PERFCOUNTER_GROUP_FLAGS(offset, name, flags) \
	ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, flags)
	ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, flags)
@@ -3022,7 +3031,7 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = {
static struct adreno_perfcount_group a6xx_perfcounter_groups
static struct adreno_perfcount_group a6xx_perfcounter_groups
				[KGSL_PERFCOUNTER_GROUP_MAX] = {
				[KGSL_PERFCOUNTER_GROUP_MAX] = {
	A6XX_PERFCOUNTER_GROUP(CP, cp),
	A6XX_PERFCOUNTER_GROUP(CP, cp),
	A6XX_PERFCOUNTER_GROUP(RBBM, rbbm),
	A6XX_PERFCOUNTER_GROUP_FLAGS(RBBM, rbbm, 0),
	A6XX_PERFCOUNTER_GROUP(PC, pc),
	A6XX_PERFCOUNTER_GROUP(PC, pc),
	A6XX_PERFCOUNTER_GROUP(VFD, vfd),
	A6XX_PERFCOUNTER_GROUP(VFD, vfd),
	A6XX_PERFCOUNTER_GROUP(HLSQ, hlsq),
	A6XX_PERFCOUNTER_GROUP(HLSQ, hlsq),
@@ -3037,7 +3046,7 @@ static struct adreno_perfcount_group a6xx_perfcounter_groups
	A6XX_PERFCOUNTER_GROUP(SP, sp),
	A6XX_PERFCOUNTER_GROUP(SP, sp),
	A6XX_PERFCOUNTER_GROUP(RB, rb),
	A6XX_PERFCOUNTER_GROUP(RB, rb),
	A6XX_PERFCOUNTER_GROUP(VSC, vsc),
	A6XX_PERFCOUNTER_GROUP(VSC, vsc),
	A6XX_PERFCOUNTER_GROUP(VBIF, vbif),
	A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF, vbif, 0),
	A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF_PWR, vbif_pwr,
	A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF_PWR, vbif_pwr,
		ADRENO_PERFCOUNTER_GROUP_FIXED),
		ADRENO_PERFCOUNTER_GROUP_FIXED),
	A6XX_PERFCOUNTER_GROUP_FLAGS(PWR, pwr,
	A6XX_PERFCOUNTER_GROUP_FLAGS(PWR, pwr,
@@ -3294,6 +3303,69 @@ static const struct adreno_reg_offsets a6xx_reg_offsets = {
	.offset_0 = ADRENO_REG_REGISTER_MAX,
	.offset_0 = ADRENO_REG_REGISTER_MAX,
};
};


static int a6xx_perfcounter_update(struct adreno_device *adreno_dev,
	struct adreno_perfcount_register *reg, bool update_reg)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct cpu_gpu_lock *lock = adreno_dev->pwrup_reglist.hostptr;
	struct reg_list_pair *reg_pair = (struct reg_list_pair *)(lock + 1);
	unsigned int i;
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	int ret = 0;

	lock->flag_kmd = 1;
	/* Write flag_kmd before turn */
	wmb();
	lock->turn = 0;
	/* Write these fields before looping */
	mb();

	/*
	 * Spin here while GPU ucode holds the lock, lock->flag_ucode will
	 * be set to 0 after GPU ucode releases the lock. Minimum wait time
	 * is 1 second and this should be enough for GPU to release the lock
	 */
	while (lock->flag_ucode == 1 && lock->turn == 0) {
		cpu_relax();
		/* Get the latest updates from GPU */
		rmb();
		/*
		 * Make sure we wait at least 1sec for the lock,
		 * if we did not get it after 1sec return an error.
		 */
		if (time_after(jiffies, timeout) &&
			(lock->flag_ucode == 1 && lock->turn == 0)) {
			ret = -EBUSY;
			goto unlock;
		}
	}

	/* Read flag_ucode and turn before list_length */
	rmb();
	/*
	 * If the perfcounter select register is already present in reglist
	 * update it, otherwise append the <select register, value> pair to
	 * the end of the list.
	 */
	for (i = 0; i < lock->list_length >> 1; i++)
		if (reg_pair[i].offset == reg->select)
			break;

	reg_pair[i].offset = reg->select;
	reg_pair[i].val = reg->countable;
	if (i == lock->list_length >> 1)
		lock->list_length += 2;

	if (update_reg)
		kgsl_regwrite(device, reg->select, reg->countable);

unlock:
	/* All writes done before releasing the lock */
	wmb();
	lock->flag_kmd = 0;
	return ret;
}

struct adreno_gpudev adreno_a6xx_gpudev = {
struct adreno_gpudev adreno_a6xx_gpudev = {
	.reg_offsets = &a6xx_reg_offsets,
	.reg_offsets = &a6xx_reg_offsets,
	.start = a6xx_start,
	.start = a6xx_start,
@@ -3336,4 +3408,5 @@ struct adreno_gpudev adreno_a6xx_gpudev = {
	.gx_is_on = a6xx_gx_is_on,
	.gx_is_on = a6xx_gx_is_on,
	.sptprac_is_on = a6xx_sptprac_is_on,
	.sptprac_is_on = a6xx_sptprac_is_on,
	.ccu_invalidate = a6xx_ccu_invalidate,
	.ccu_invalidate = a6xx_ccu_invalidate,
	.perfcounter_update = a6xx_perfcounter_update,
};
};
+9 −3
Original line number Original line Diff line number Diff line
@@ -775,6 +775,7 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev,
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	struct adreno_perfcount_register *reg;
	struct adreno_perfcount_register *reg;
	struct adreno_perfcount_group *grp;
	int i;
	int i;
	int ret = 0;
	int ret = 0;


@@ -789,7 +790,8 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev,
			if (countable == invalid_countable.countables[i])
			if (countable == invalid_countable.countables[i])
				return -EACCES;
				return -EACCES;
	}
	}
	reg = &(counters->groups[group].regs[counter]);
	grp = &(counters->groups[group]);
	reg = &(grp->regs[counter]);


	if (!adreno_is_a6xx(adreno_dev) &&
	if (!adreno_is_a6xx(adreno_dev) &&
			test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) {
			test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) {
@@ -834,12 +836,16 @@ static int _perfcounter_enable_default(struct adreno_device *adreno_dev,
		}
		}
	} else {
	} else {
		/* Select the desired perfcounter */
		/* Select the desired perfcounter */
		if (gpudev->perfcounter_update && (grp->flags &
				ADRENO_PERFCOUNTER_GROUP_RESTORE))
			ret = gpudev->perfcounter_update(adreno_dev, reg, true);
		else
			kgsl_regwrite(device, reg->select, countable);
			kgsl_regwrite(device, reg->select, countable);
	}
	}


	if (!ret)
	if (!ret)
		reg->value = 0;
		reg->value = 0;
	return 0;
	return ret;
}
}


/**
/**
+8 −1
Original line number Original line Diff line number Diff line
/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2015, 2017 The Linux Foundation. All rights reserved.
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * 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
 * it under the terms of the GNU General Public License version 2 and
@@ -70,6 +70,13 @@ struct adreno_perfcount_group {


#define ADRENO_PERFCOUNTER_GROUP_FIXED BIT(0)
#define ADRENO_PERFCOUNTER_GROUP_FIXED BIT(0)


/*
 * ADRENO_PERFCOUNTER_GROUP_RESTORE indicates CP needs to restore the select
 * registers of this perfcounter group as part of preemption and IFPC
 */
#define ADRENO_PERFCOUNTER_GROUP_RESTORE BIT(1)


/**
/**
 * adreno_perfcounts: all available perfcounter groups
 * adreno_perfcounts: all available perfcounter groups
 * @groups: available groups for this device
 * @groups: available groups for this device