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

Commit 2cc8c168 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: Surround RBBM interrupt mask writes with OOBs"

parents 2af522e4 8fe58df0
Loading
Loading
Loading
Loading
+62 −8
Original line number Diff line number Diff line
@@ -554,7 +554,13 @@ static int _soft_reset(struct adreno_device *adreno_dev)
	return 0;
}


/**
 * adreno_irqctrl() - Enables/disables the RBBM interrupt mask
 * @adreno_dev: Pointer to an adreno_device
 * @state: 1 for masked or 0 for unmasked
 * Power: The caller of this function must make sure to use OOBs
 * so that we know that the GPU is powered on
 */
void adreno_irqctrl(struct adreno_device *adreno_dev, int state)
{
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
@@ -599,7 +605,7 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	struct adreno_irq *irq_params = gpudev->irq;
	irqreturn_t ret = IRQ_NONE;
	unsigned int status = 0, tmp, int_bit;
	unsigned int status = 0, fence = 0, tmp, int_bit;
	int i;

	atomic_inc(&adreno_dev->pending_irq_refcnt);
@@ -614,6 +620,17 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
	if (gpudev->gpu_keepalive)
		gpudev->gpu_keepalive(adreno_dev, true);

	/*
	 * If the AHB fence is not in ALLOW mode when we receive an RBBM
	 * interrupt, something went wrong. Set a fault and change the
	 * fence to ALLOW so we can clear the interrupt.
	 */
	adreno_readreg(adreno_dev, ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, &fence);
	if (fence != 0) {
		KGSL_DRV_CRIT_RATELIMIT(device, "AHB fence is stuck in ISR\n");
		return ret;
	}

	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);

	/*
@@ -1498,9 +1515,9 @@ static int _adreno_start(struct adreno_device *adreno_dev)

	/* Send OOB request to turn on the GX */
	if (gpudev->oob_set) {
		status = gpudev->oob_set(adreno_dev, OOB_GPUSTART_SET_MASK,
				OOB_GPUSTART_CHECK_MASK,
				OOB_GPUSTART_CLEAR_MASK);
		status = gpudev->oob_set(adreno_dev, OOB_GPU_SET_MASK,
				OOB_GPU_CHECK_MASK,
				OOB_GPU_CLEAR_MASK);
		if (status)
			goto error_mmu_off;
	}
@@ -1599,17 +1616,28 @@ static int _adreno_start(struct adreno_device *adreno_dev)
				pmqos_active_vote);

	/* Send OOB request to allow IFPC */
	if (gpudev->oob_clear)
		gpudev->oob_clear(adreno_dev, OOB_GPUSTART_CLEAR_MASK);
	if (gpudev->oob_clear) {
		gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK);

		/* If we made it this far, the BOOT OOB was sent to the GMU */
		if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
			gpudev->oob_clear(adreno_dev,
					OOB_BOOT_SLUMBER_CLEAR_MASK);
	}

	return 0;

error_oob_clear:
	if (gpudev->oob_clear)
		gpudev->oob_clear(adreno_dev, OOB_GPUSTART_CLEAR_MASK);
		gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK);

error_mmu_off:
	kgsl_mmu_stop(&device->mmu);
	if (gpudev->oob_clear &&
			ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
		gpudev->oob_clear(adreno_dev,
				OOB_BOOT_SLUMBER_CLEAR_MASK);
	}

error_pwr_off:
	/* set the state back to original state */
@@ -1667,10 +1695,23 @@ static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev)
static int adreno_stop(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	int error = 0;

	if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv))
		return 0;

	/* Turn the power on one last time before stopping */
	if (gpudev->oob_set) {
		error = gpudev->oob_set(adreno_dev, OOB_GPU_SET_MASK,
				OOB_GPU_CHECK_MASK,
				OOB_GPU_CLEAR_MASK);
		if (error) {
			gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK);
			return error;
		}
	}

	adreno_set_active_ctxs_null(adreno_dev);

	adreno_dispatcher_stop(adreno_dev);
@@ -1694,6 +1735,19 @@ static int adreno_stop(struct kgsl_device *device)
	/* Save physical performance counter values before GPU power down*/
	adreno_perfcounter_save(adreno_dev);

	if (gpudev->oob_clear)
		gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK);

	/*
	 * Saving perfcounters will use an OOB to put the GMU into
	 * active state. Before continuing, we should wait for the
	 * GMU to return to the lowest idle level. This is
	 * because some idle level transitions require VBIF and MMU.
	 */
	if (gpudev->wait_for_lowest_idle &&
			gpudev->wait_for_lowest_idle(adreno_dev))
		return -EINVAL;

	adreno_vbif_clear_pending_transactions(device);

	kgsl_mmu_stop(&device->mmu);
+2 −0
Original line number Diff line number Diff line
@@ -638,6 +638,7 @@ enum adreno_regs {
	ADRENO_REG_VBIF_VERSION,
	ADRENO_REG_GBIF_HALT,
	ADRENO_REG_GBIF_HALT_ACK,
	ADRENO_REG_GMU_AO_AHB_FENCE_CTRL,
	ADRENO_REG_GMU_AO_INTERRUPT_EN,
	ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
	ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
@@ -886,6 +887,7 @@ struct adreno_gpudev {
	int (*rpmh_gpu_pwrctrl)(struct adreno_device *, unsigned int ops,
				unsigned int arg1, unsigned int arg2);
	bool (*hw_isidle)(struct adreno_device *);
	int (*wait_for_lowest_idle)(struct adreno_device *);
	int (*wait_for_gmu_idle)(struct adreno_device *);
	const char *(*iommu_fault_block)(struct adreno_device *adreno_dev,
				unsigned int fsynr1);
+69 −15
Original line number Diff line number Diff line
@@ -1025,6 +1025,15 @@ static int timed_poll_check(struct kgsl_device *device,
	return -EINVAL;
}

/*
 * The lowest 16 bits of this value are the number of XO clock cycles
 * for main hysteresis. This is the first hysteresis. Here we set it
 * to 0x5DC cycles, or 78.1 us. The highest 16 bits of this value are
 * the number of XO clock cycles for short hysteresis. This happens
 * after main hysteresis. Here we set it to 0xA cycles, or 0.5 us.
 */
#define GMU_PWR_COL_HYST 0x000A05DC

/*
 * a6xx_gmu_power_config() - Configure and enable GMU's low power mode
 * setting based on ADRENO feature flags.
@@ -1056,13 +1065,13 @@ static void a6xx_gmu_power_config(struct kgsl_device *device)
		/* fall through */
	case GPU_HW_IFPC:
		kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_HYST,
				0x000A0080);
				GMU_PWR_COL_HYST);
		kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0,
				IFPC_ENABLE_MASK);
		/* fall through */
	case GPU_HW_SPTP_PC:
		kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_SPTPRAC_HYST,
				0x000A0080);
				GMU_PWR_COL_HYST);
		kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0,
				SPTP_ENABLE_MASK);
		/* fall through */
@@ -1281,21 +1290,12 @@ static bool a6xx_gx_is_on(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	unsigned int val;
	bool state;

	if (!kgsl_gmu_isenabled(device))
		return true;

	kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val);
	state = !(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF));

	/* If GMU is holding on to the fence then we cannot dump any GX stuff */
	kgsl_gmu_regread(device, A6XX_GMU_AO_AHB_FENCE_CTRL, &val);
	if (val)
		return false;

	return state;

	return !(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF));
}

/*
@@ -1366,12 +1366,13 @@ static int a6xx_notify_slumber(struct kgsl_device *device)
	/* Disable the power counter so that the GMU is not busy */
	kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0);

	/* Turn off SPTPRAC before GMU turns off GX */
	/* Turn off SPTPRAC if we own it */
	if (gmu->idle_level < GPU_HW_SPTP_PC)
		a6xx_sptprac_disable(adreno_dev);

	if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
		ret = hfi_notify_slumber(gmu, perf_idx, bus_level);
		return ret;
		goto out;
	}

	kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION,
@@ -1397,6 +1398,9 @@ static int a6xx_notify_slumber(struct kgsl_device *device)
		}
	}

out:
	/* Make sure the fence is in ALLOW mode */
	kgsl_gmu_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0);
	return ret;
}

@@ -1744,6 +1748,53 @@ static bool a6xx_hw_isidle(struct adreno_device *adreno_dev)
	return true;
}

static int a6xx_wait_for_lowest_idle(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct gmu_device *gmu = &device->gmu;
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	unsigned int reg;
	unsigned long t;

	if (!kgsl_gmu_isenabled(device))
		return 0;

	t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT);
	while (!time_after(jiffies, t)) {
		adreno_read_gmureg(ADRENO_DEVICE(device),
				ADRENO_REG_GMU_RPMH_POWER_STATE, &reg);

		/* SPTPRAC PC has the same idle level as IFPC */
		if ((reg == gmu->idle_level) ||
				(gmu->idle_level == GPU_HW_SPTP_PC &&
				reg == GPU_HW_IFPC)) {
			/* IFPC is not complete until GX is off */
			if (gmu->idle_level != GPU_HW_IFPC ||
					!gpudev->gx_is_on(adreno_dev))
				return 0;
		}

		/* Wait 100us to reduce unnecessary AHB bus traffic */
		udelay(100);
		cond_resched();
	}

	/* Check one last time */
	adreno_read_gmureg(ADRENO_DEVICE(device),
			ADRENO_REG_GMU_RPMH_POWER_STATE, &reg);
	if ((reg == gmu->idle_level) ||
			(gmu->idle_level == GPU_HW_SPTP_PC &&
			reg == GPU_HW_IFPC)) {
		if (gmu->idle_level != GPU_HW_IFPC ||
				!gpudev->gx_is_on(adreno_dev))
			return 0;
	}

	dev_err(&gmu->pdev->dev,
			"Timeout waiting for lowest idle level: %d\n", reg);
	return -ETIMEDOUT;
}

static int a6xx_wait_for_gmu_idle(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
@@ -2939,6 +2990,8 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
				A6XX_GMU_ALWAYS_ON_COUNTER_L),
	ADRENO_REG_DEFINE(ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
				A6XX_GMU_ALWAYS_ON_COUNTER_H),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_AHB_FENCE_CTRL,
				A6XX_GMU_AO_AHB_FENCE_CTRL),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_INTERRUPT_EN,
				A6XX_GMU_AO_INTERRUPT_EN),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
@@ -3019,6 +3072,7 @@ struct adreno_gpudev adreno_a6xx_gpudev = {
	.gpu_keepalive = a6xx_gpu_keepalive,
	.rpmh_gpu_pwrctrl = a6xx_rpmh_gpu_pwrctrl,
	.hw_isidle = a6xx_hw_isidle, /* Replaced by NULL if GMU is disabled */
	.wait_for_lowest_idle = a6xx_wait_for_lowest_idle,
	.wait_for_gmu_idle = a6xx_wait_for_gmu_idle,
	.iommu_fault_block = a6xx_iommu_fault_block,
	.reset = a6xx_reset,
+6 −0
Original line number Diff line number Diff line
@@ -1577,6 +1577,12 @@ void a6xx_snapshot(struct adreno_device *adreno_dev,
	bool sptprac_on;
	unsigned int i;

	/* Make sure the fence is in ALLOW mode so registers can be read */
	kgsl_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0);

	/* GMU TCM data dumped through AHB */
	a6xx_snapshot_gmu(adreno_dev, snapshot);

	sptprac_on = gpudev->sptprac_is_on(adreno_dev);

	/* Return if the GX is off */
+7 −0
Original line number Diff line number Diff line
@@ -174,10 +174,15 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev)
	struct adreno_perfcounters *counters = ADRENO_PERFCOUNTERS(adreno_dev);
	struct adreno_perfcount_group *group;
	unsigned int counter, groupid;
	int ret;

	if (counters == NULL)
		return;

	ret = adreno_perfcntr_active_oob_get(adreno_dev);
	if (ret)
		return;

	for (groupid = 0; groupid < counters->group_count; groupid++) {
		group = &(counters->groups[groupid]);

@@ -197,6 +202,8 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev)
								counter);
		}
	}

	adreno_perfcntr_active_oob_put(adreno_dev);
}

static int adreno_perfcounter_enable(struct adreno_device *adreno_dev,
Loading