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

Commit e7b06b43 authored by Kyle Piefer's avatar Kyle Piefer
Browse files

msm: kgsl: Clear pending GMU IRQs before enabling



The mask register for GMU IRQs defaults to all bits on.
This could lead to pending invalid interrupts that would come
through when the interrupts are enabled on the host side.
Factor out the IRQ enabling and disabling code to make
it cleaner and clear pending IRQs before enabling them.

Additionally, add the HFI_IRQ_CM3_FAULT_MASK interrupt
mask and factor out the IRQ handlers and probe.

CRs-Fixed: 2017390
Change-Id: Iab7a3a8b76d493c016977fda03c7cd9f54166086
Signed-off-by: default avatarKyle Piefer <kpiefer@codeaurora.org>
parent dc0706cf
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -718,9 +718,9 @@
#define A6XX_GMU_GENERAL_7			0x1F9CC

#define A6XX_GMU_AO_INTERRUPT_EN		0x23B03
#define A6XX_GMU_HOST_INTERRUPT_CLR		0x23B04
#define A6XX_GMU_HOST_INTERRUPT_STATUS		0x23B05
#define A6XX_GMU_HOST_INTERRUPT_MASK		0x23B06
#define A6XX_GMU_AO_HOST_INTERRUPT_CLR		0x23B04
#define A6XX_GMU_AO_HOST_INTERRUPT_STATUS	0x23B05
#define A6XX_GMU_AO_HOST_INTERRUPT_MASK		0x23B06
#define A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS	0x23B0C
#define A6XX_GMU_AHB_FENCE_STATUS		0x23B13
#define A6XX_GMU_RBBM_INT_UNMASKED_STATUS	0x23B15
+4 −3
Original line number Diff line number Diff line
@@ -618,9 +618,9 @@ enum adreno_regs {
	ADRENO_REG_VBIF_XIN_HALT_CTRL1,
	ADRENO_REG_VBIF_VERSION,
	ADRENO_REG_GMU_AO_INTERRUPT_EN,
	ADRENO_REG_GMU_HOST_INTERRUPT_CLR,
	ADRENO_REG_GMU_HOST_INTERRUPT_STATUS,
	ADRENO_REG_GMU_HOST_INTERRUPT_MASK,
	ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
	ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
	ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
	ADRENO_REG_GMU_PWR_COL_KEEPALIVE,
	ADRENO_REG_GMU_AHB_FENCE_STATUS,
	ADRENO_REG_GMU_RPMH_POWER_STATE,
@@ -629,6 +629,7 @@ enum adreno_regs {
	ADRENO_REG_GMU_HFI_SFR_ADDR,
	ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
	ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
	ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
	ADRENO_REG_GMU_HOST2GMU_INTR_SET,
	ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
	ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
+10 −9
Original line number Diff line number Diff line
@@ -717,9 +717,8 @@ static int a6xx_gmu_hfi_start(struct kgsl_device *device)
{
	struct gmu_device *gmu = &device->gmu;

	kgsl_gmu_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK,
			(HFI_IRQ_MASK & (~HFI_IRQ_MSGQ_MASK)));

	kgsl_gmu_regrmw(device, A6XX_GMU_GMU2HOST_INTR_MASK,
			HFI_IRQ_MSGQ_MASK, 0);
	kgsl_gmu_regwrite(device, A6XX_GMU_HFI_CTRL_INIT, 1);

	if (timed_poll_check(device,
@@ -2049,12 +2048,12 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
				A6XX_GMU_ALWAYS_ON_COUNTER_H),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_INTERRUPT_EN,
				A6XX_GMU_AO_INTERRUPT_EN),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST_INTERRUPT_CLR,
				A6XX_GMU_HOST_INTERRUPT_CLR),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST_INTERRUPT_STATUS,
				A6XX_GMU_HOST_INTERRUPT_STATUS),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST_INTERRUPT_MASK,
				A6XX_GMU_HOST_INTERRUPT_MASK),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
				A6XX_GMU_AO_HOST_INTERRUPT_CLR),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
				A6XX_GMU_AO_HOST_INTERRUPT_STATUS),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
				A6XX_GMU_AO_HOST_INTERRUPT_MASK),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_PWR_COL_KEEPALIVE,
				A6XX_GMU_GMU_PWR_COL_KEEPALIVE),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_AHB_FENCE_STATUS,
@@ -2071,6 +2070,8 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
				A6XX_GMU_GMU2HOST_INTR_CLR),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
				A6XX_GMU_GMU2HOST_INTR_INFO),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
				A6XX_GMU_GMU2HOST_INTR_MASK),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_SET,
				A6XX_GMU_HOST2GMU_INTR_SET),
	ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
+126 −72
Original line number Diff line number Diff line
@@ -748,44 +748,49 @@ static irqreturn_t gmu_irq_handler(int irq, void *data)
{
	struct gmu_device *gmu = data;
	struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu);
	struct kgsl_hfi *hfi = &gmu->hfi;
	unsigned int status = 0;

	if (irq == gmu->gmu_interrupt_num) {
	adreno_read_gmureg(ADRENO_DEVICE(device),
				ADRENO_REG_GMU_HOST_INTERRUPT_STATUS,
				&status);
			ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS, &status);
	adreno_write_gmureg(ADRENO_DEVICE(device),
			ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR, status);

		/* Ignore GMU_INT_RSCC_COMP interrupts */
	/* Ignore GMU_INT_RSCC_COMP and GMU_INT_DBD WAKEUP interrupts */
	if (status & GMU_INT_WDOG_BITE)
		dev_err_ratelimited(&gmu->pdev->dev,
					"GMU watchdog expired interrupt\n");
		if (status & GMU_INT_DBD_WAKEUP)
			dev_err_ratelimited(&gmu->pdev->dev,
					"GMU doorbell interrupt received\n");
				"GMU watchdog expired interrupt received\n");
	if (status & GMU_INT_HOST_AHB_BUS_ERR)
		dev_err_ratelimited(&gmu->pdev->dev,
				"AHB bus error interrupt received\n");
	if (status & ~GMU_AO_INT_MASK)
		dev_err_ratelimited(&gmu->pdev->dev,
				"Unhandled GMU interrupts 0x%lx\n",
				status & ~GMU_AO_INT_MASK);

	return IRQ_HANDLED;
}

static irqreturn_t hfi_irq_handler(int irq, void *data)
{
	struct kgsl_hfi *hfi = data;
	struct gmu_device *gmu = container_of(hfi, struct gmu_device, hfi);
	struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu);
	unsigned int status = 0;

		adreno_write_gmureg(ADRENO_DEVICE(device),
				ADRENO_REG_GMU_HOST_INTERRUPT_CLR,
				status);
	} else {
	adreno_read_gmureg(ADRENO_DEVICE(device),
				ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
				&status);
			ADRENO_REG_GMU_GMU2HOST_INTR_INFO, &status);
	adreno_write_gmureg(ADRENO_DEVICE(device),
				ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
				status);
			ADRENO_REG_GMU_GMU2HOST_INTR_CLR, status);

		if (status & HFI_IRQ_MASK) {
	if (status & HFI_IRQ_MSGQ_MASK)
		tasklet_hi_schedule(&hfi->tasklet);
		} else
	if (status & HFI_IRQ_CM3_FAULT_MASK)
		dev_err_ratelimited(&gmu->pdev->dev,
					"Unhandled GMU interrupts %x\n",
					status);
	}
				"GMU CM3 fault interrupt received\n");
	if (status & ~HFI_IRQ_MASK)
		dev_err_ratelimited(&gmu->pdev->dev,
				"Unhandled HFI interrupts 0x%lx\n",
				status & ~HFI_IRQ_MASK);

	return IRQ_HANDLED;
}
@@ -978,6 +983,82 @@ static int gmu_regulators_probe(struct gmu_device *gmu,
	return 0;
}

static int gmu_irq_probe(struct gmu_device *gmu)
{
	int ret;
	struct kgsl_hfi *hfi = &gmu->hfi;

	hfi->hfi_interrupt_num = platform_get_irq_byname(gmu->pdev,
			"kgsl_hfi_irq");
	ret = devm_request_irq(&gmu->pdev->dev,
			hfi->hfi_interrupt_num,
			hfi_irq_handler, IRQF_TRIGGER_HIGH,
			"HFI", hfi);
	if (ret) {
		dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n",
				hfi->hfi_interrupt_num, ret);
		return ret;
	}

	gmu->gmu_interrupt_num = platform_get_irq_byname(gmu->pdev,
			"kgsl_gmu_irq");
	ret = devm_request_irq(&gmu->pdev->dev,
			gmu->gmu_interrupt_num,
			gmu_irq_handler, IRQF_TRIGGER_HIGH,
			"GMU", gmu);
	if (ret)
		dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n",
				gmu->gmu_interrupt_num, ret);

	return ret;
}

static void gmu_irq_enable(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct gmu_device *gmu = &device->gmu;
	struct kgsl_hfi *hfi = &gmu->hfi;

	/* Clear any pending IRQs before unmasking on GMU */
	adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
			0xFFFFFFFF);
	adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
			0xFFFFFFFF);

	/* Unmask needed IRQs on GMU */
	adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
			(unsigned int) ~HFI_IRQ_MASK);
	adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
			(unsigned int) ~GMU_AO_INT_MASK);

	/* Enable all IRQs on host */
	enable_irq(hfi->hfi_interrupt_num);
	enable_irq(gmu->gmu_interrupt_num);
}

static void gmu_irq_disable(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct gmu_device *gmu = &device->gmu;
	struct kgsl_hfi *hfi = &gmu->hfi;

	/* Disable all IRQs on host */
	disable_irq(gmu->gmu_interrupt_num);
	disable_irq(hfi->hfi_interrupt_num);

	/* Mask all IRQs on GMU */
	adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
			0xFFFFFFFF);
	adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
			0xFFFFFFFF);

	/* Clear any pending IRQs before disabling */
	adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
			0xFFFFFFFF);
	adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
			0xFFFFFFFF);
}

/* Do not access any GMU registers in GMU probe function */
int gmu_probe(struct kgsl_device *device)
{
@@ -1024,32 +1105,13 @@ int gmu_probe(struct kgsl_device *device)

	gmu->gmu2gpu_offset = (gmu->reg_phys - device->reg_phys) >> 2;

	/* Initialize HFI GMU interrupts */
	hfi->hfi_interrupt_num = platform_get_irq_byname(gmu->pdev,
						"kgsl_hfi_irq");
	ret = devm_request_irq(&gmu->pdev->dev,
				  hfi->hfi_interrupt_num,
				  gmu_irq_handler, IRQF_TRIGGER_HIGH,
				  "GMU", gmu);
	if (ret) {
		dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n",
			      hfi->hfi_interrupt_num, ret);
		goto error;
	}

	gmu->gmu_interrupt_num = platform_get_irq_byname(gmu->pdev,
						"kgsl_gmu_irq");
	ret = devm_request_irq(&gmu->pdev->dev,
				  gmu->gmu_interrupt_num,
				  gmu_irq_handler, IRQF_TRIGGER_HIGH,
				  "GMU", gmu);
	if (ret) {
		dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n",
			      gmu->gmu_interrupt_num, ret);
	/* Initialize HFI and GMU interrupts */
	ret = gmu_irq_probe(gmu);
	if (ret)
		goto error;
	}

	/* Don't enable GMU interrupts until GMU started */
	/* We cannot use gmu_irq_disable because it writes registers */
	disable_irq(gmu->gmu_interrupt_num);
	disable_irq(hfi->hfi_interrupt_num);

@@ -1200,7 +1262,6 @@ int gmu_start(struct kgsl_device *device)
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct gmu_device *gmu = &device->gmu;
	struct kgsl_hfi *hfi = &gmu->hfi;
	int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq;

	if (!kgsl_gmu_isenabled(device))
@@ -1235,8 +1296,7 @@ int gmu_start(struct kgsl_device *device)
		if (ret)
			goto error_bus;

		enable_irq(hfi->hfi_interrupt_num);
		enable_irq(gmu->gmu_interrupt_num);
		gmu_irq_enable(device);

		ret = hfi_start(gmu, GMU_COLD_BOOT);
		if (ret)
@@ -1254,8 +1314,7 @@ int gmu_start(struct kgsl_device *device)
		if (ret)
			goto error_clks;

		enable_irq(hfi->hfi_interrupt_num);
		enable_irq(gmu->gmu_interrupt_num);
		gmu_irq_enable(device);

		ret = hfi_start(gmu, GMU_WARM_BOOT);
		if (ret)
@@ -1293,8 +1352,7 @@ int gmu_start(struct kgsl_device *device)

error_gpu:
	hfi_stop(gmu);
	disable_irq(gmu->gmu_interrupt_num);
	disable_irq(hfi->hfi_interrupt_num);
	gmu_irq_disable(device);
	if (device->state == KGSL_STATE_INIT ||
			device->state == KGSL_STATE_SUSPEND) {
		if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
@@ -1316,7 +1374,6 @@ int gmu_start(struct kgsl_device *device)
void gmu_stop(struct kgsl_device *device)
{
	struct gmu_device *gmu = &device->gmu;
	struct kgsl_hfi *hfi = &gmu->hfi;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);

@@ -1334,9 +1391,7 @@ void gmu_stop(struct kgsl_device *device)
	/* Pending message in all queues are abandoned */
	hfi_stop(gmu);
	clear_bit(GMU_HFI_ON, &gmu->flags);

	disable_irq(gmu->gmu_interrupt_num);
	disable_irq(hfi->hfi_interrupt_num);
	gmu_irq_disable(device);

	gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
	gmu_disable_clks(gmu);
@@ -1359,16 +1414,15 @@ void gmu_remove(struct kgsl_device *device)
	tasklet_kill(&hfi->tasklet);

	gmu_stop(device);
	gmu_irq_disable(device);

	if (gmu->gmu_interrupt_num) {
		disable_irq(gmu->gmu_interrupt_num);
		devm_free_irq(&gmu->pdev->dev,
				gmu->gmu_interrupt_num, gmu);
		gmu->gmu_interrupt_num = 0;
	}

	if (hfi->hfi_interrupt_num) {
		disable_irq(hfi->hfi_interrupt_num);
		devm_free_irq(&gmu->pdev->dev,
				hfi->hfi_interrupt_num, gmu);
		hfi->hfi_interrupt_num = 0;
+0 −1
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@
#define GMU_INT_HOST_AHB_BUS_ERR	BIT(5)
#define GMU_AO_INT_MASK		\
		(GMU_INT_WDOG_BITE |	\
		GMU_INT_DBD_WAKEUP |	\
		GMU_INT_HOST_AHB_BUS_ERR)

#define MAX_GMUFW_SIZE	0x2000	/* in dwords */
Loading