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

Commit f18011bd 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: Update GPU HARD RESET processing" into msm-4.9

parents fffa439a d0fe7463
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -783,6 +783,7 @@
#define A6XX_GMU_GX_SPTPRAC_POWER_CONTROL	0x1A881
#define A6XX_GMU_CM3_ITCM_START			0x1B400
#define A6XX_GMU_CM3_DTCM_START			0x1C400
#define A6XX_GMU_NMI_CONTROL_STATUS		0x1CBF0
#define A6XX_GMU_BOOT_SLUMBER_OPTION		0x1CBF8
#define A6XX_GMU_GX_VOTE_IDX			0x1CBF9
#define A6XX_GMU_MX_VOTE_IDX			0x1CBFA
@@ -794,6 +795,7 @@
#define A6XX_GMU_CM3_BOOT_CONFIG		0x1F801
#define A6XX_GMU_CM3_FW_BUSY			0x1F81A
#define A6XX_GMU_CM3_FW_INIT_RESULT		0x1F81C
#define A6XX_GMU_CM3_CFG			0x1F82D
#define A6XX_GMU_PWR_COL_INTER_FRAME_CTRL	0x1F8C0
#define A6XX_GMU_PWR_COL_INTER_FRAME_HYST	0x1F8C1
#define A6XX_GMU_PWR_COL_SPTPRAC_HYST		0x1F8C2
+2 −7
Original line number Diff line number Diff line
@@ -56,9 +56,6 @@ MODULE_PARM_DESC(swfdetect, "Enable soft fault detection");
#define DRIVER_VERSION_MAJOR   3
#define DRIVER_VERSION_MINOR   1

/* Number of times to try hard reset */
#define NUM_TIMES_RESET_RETRY 5

#define KGSL_LOG_LEVEL_DEFAULT 3

static void adreno_input_work(struct work_struct *work);
@@ -514,8 +511,6 @@ static struct input_handler adreno_input_handler = {
	.id_table = adreno_input_ids,
};

static int adreno_soft_reset(struct kgsl_device *device);

/*
 * _soft_reset() - Soft reset GPU
 * @adreno_dev: Pointer to adreno device
@@ -1625,7 +1620,7 @@ static int _adreno_start(struct adreno_device *adreno_dev)
 * Power up the GPU and initialize it.  If priority is specified then elevate
 * the thread priority for the duration of the start operation
 */
static int adreno_start(struct kgsl_device *device, int priority)
int adreno_start(struct kgsl_device *device, int priority)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int nice = task_nice(current);
@@ -2310,7 +2305,7 @@ bool adreno_hw_isidle(struct adreno_device *adreno_dev)
 * The GPU hardware is reset but we never pull power so we can skip
 * a lot of the standard adreno_stop/adreno_start sequence
 */
static int adreno_soft_reset(struct kgsl_device *device)
int adreno_soft_reset(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+7 −1
Original line number Diff line number Diff line
@@ -159,10 +159,12 @@
#define KGSL_END_OF_PROFILE_IDENTIFIER	0x2DEFADE2
#define KGSL_PWRON_FIXUP_IDENTIFIER	0x2AFAFAFA

/* Number of times to try hard reset */
#define NUM_TIMES_RESET_RETRY 5

/* One cannot wait forever for the core to idle, so set an upper limit to the
 * amount of time to wait for the core to go idle
 */

#define ADRENO_IDLE_TIMEOUT (20 * 1000)

#define ADRENO_UCHE_GMEM_BASE	0x100000
@@ -204,6 +206,7 @@ enum adreno_gpurev {
#define ADRENO_TIMEOUT_FAULT BIT(2)
#define ADRENO_IOMMU_PAGE_FAULT BIT(3)
#define ADRENO_PREEMPT_FAULT BIT(4)
#define ADRENO_GMU_FAULT BIT(5)

#define ADRENO_SPTP_PC_CTRL 0
#define ADRENO_PPD_CTRL     1
@@ -866,6 +869,7 @@ struct adreno_gpudev {
	int (*wait_for_gmu_idle)(struct adreno_device *);
	const char *(*iommu_fault_block)(struct adreno_device *adreno_dev,
				unsigned int fsynr1);
	int (*reset)(struct kgsl_device *, int fault);
	int (*soft_reset)(struct adreno_device *);
};

@@ -955,6 +959,8 @@ extern struct adreno_gpudev adreno_a6xx_gpudev;
extern int adreno_wake_nice;
extern unsigned int adreno_wake_timeout;

int adreno_start(struct kgsl_device *device, int priority);
int adreno_soft_reset(struct kgsl_device *device);
long adreno_ioctl(struct kgsl_device_private *dev_priv,
		unsigned int cmd, unsigned long arg);

+86 −1
Original line number Diff line number Diff line
@@ -1562,7 +1562,8 @@ static int a6xx_soft_reset(struct adreno_device *adreno_dev)
	 * For the soft reset case with GMU enabled this part is done
	 * by the GMU firmware
	 */
	if (kgsl_gmu_isenabled(device))
	if (kgsl_gmu_isenabled(device) &&
		!test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv))
		return 0;


@@ -1750,6 +1751,89 @@ static int a6xx_rpmh_gpu_pwrctrl(struct adreno_device *adreno_dev,
	return ret;
}

/**
 * a6xx_reset() - Helper function to reset the GPU
 * @device: Pointer to the KGSL device structure for the GPU
 * @fault: Type of fault. Needed to skip soft reset for MMU fault
 *
 * Try to reset the GPU to recover from a fault.  First, try to do a low latency
 * soft reset.  If the soft reset fails for some reason, then bring out the big
 * guns and toggle the footswitch.
 */
static int a6xx_reset(struct kgsl_device *device, int fault)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int ret = -EINVAL;
	int i = 0;

	/* Use the regular reset sequence for No GMU */
	if (!kgsl_gmu_isenabled(device))
		return adreno_reset(device, fault);

	/* Transition from ACTIVE to RESET state */
	kgsl_pwrctrl_change_state(device, KGSL_STATE_RESET);

	/* Try soft reset first */
	if (!(fault & ADRENO_IOMMU_PAGE_FAULT)) {
		int acked;

		/* NMI */
		kgsl_gmu_regwrite(device, A6XX_GMU_NMI_CONTROL_STATUS, 0);
		kgsl_gmu_regwrite(device, A6XX_GMU_CM3_CFG, (1 << 9));

		for (i = 0; i < 10; i++) {
			kgsl_gmu_regread(device,
					A6XX_GMU_NMI_CONTROL_STATUS, &acked);

			/* NMI FW ACK recevied */
			if (acked == 0x1)
				break;

			udelay(100);
		}

		if (acked)
			ret = adreno_soft_reset(device);
		if (ret)
			KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
	}
	if (ret) {
		/* If soft reset failed/skipped, then pull the power */
		set_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv);
		/* since device is officially off now clear start bit */
		clear_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);

		/* Keep trying to start the device until it works */
		for (i = 0; i < NUM_TIMES_RESET_RETRY; i++) {
			ret = adreno_start(device, 0);
			if (!ret)
				break;

			msleep(20);
		}
	}

	clear_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv);

	if (ret)
		return ret;

	if (i != 0)
		KGSL_DRV_WARN(device, "Device hard reset tried %d tries\n", i);

	/*
	 * If active_cnt is non-zero then the system was active before
	 * going into a reset - put it back in that state
	 */

	if (atomic_read(&device->active_cnt))
		kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE);
	else
		kgsl_pwrctrl_change_state(device, KGSL_STATE_NAP);

	return ret;
}

static void a6xx_cp_hw_err_callback(struct adreno_device *adreno_dev, int bit)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
@@ -2500,5 +2584,6 @@ struct adreno_gpudev adreno_a6xx_gpudev = {
	.hw_isidle = a6xx_hw_isidle, /* Replaced by NULL if GMU is disabled */
	.wait_for_gmu_idle = a6xx_wait_for_gmu_idle,
	.iommu_fault_block = a6xx_iommu_fault_block,
	.reset = a6xx_reset,
	.soft_reset = a6xx_soft_reset,
};
+5 −1
Original line number Diff line number Diff line
@@ -2183,7 +2183,11 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev)
		kgsl_process_event_group(device, &hung_rb->events);
	}

	if (gpudev->reset)
		ret = gpudev->reset(device, fault);
	else
		ret = adreno_reset(device, fault);

	mutex_unlock(&device->mutex);
	/* if any other fault got in until reset then ignore */
	atomic_set(&dispatcher->fault, 0);
Loading