msm: rpm: panic() on an rpm error interrupt

If the RPM triggers the LOW interrupt it means the RPM has error
fataled. Handle this case so we don't sit spinning on the RPM to
respond until our watchdog times out. We also check this while
polling the ack interrupt in msm_rpm_busy_wait_for_request_completion().

This should allow us to have a nice panic output in the logs
whenever the RPM has crashed and is no longer responsive.

Change-Id: Ia40b95eaffe5bbaa10b62f85ae849eb36b1384e6
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/rpm.c b/arch/arm/mach-msm/rpm.c
index 05b2953..2eac3c1 100644
--- a/arch/arm/mach-msm/rpm.c
+++ b/arch/arm/mach-msm/rpm.c
@@ -239,6 +239,19 @@
 	return 2;
 }
 
+static void msm_rpm_err_fatal(void)
+{
+	/* Tell RPM that we're handling the interrupt */
+	__raw_writel(0x1, msm_rpm_data.ipc_rpm_reg);
+	panic("RPM error fataled");
+}
+
+static irqreturn_t msm_rpm_err_interrupt(int irq, void *dev_id)
+{
+	msm_rpm_err_fatal();
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t msm_rpm_ack_interrupt(int irq, void *dev_id)
 {
 	unsigned long flags;
@@ -267,6 +280,9 @@
 				msm_rpm_request) {
 			if (allow_async_completion)
 				spin_unlock(&msm_rpm_irq_lock);
+			if (gic_is_spi_pending(msm_rpm_data.irq_err))
+				msm_rpm_err_fatal();
+			gic_clear_spi_pending(msm_rpm_data.irq_err);
 			udelay(1);
 			if (allow_async_completion)
 				spin_lock(&msm_rpm_irq_lock);
@@ -355,7 +371,7 @@
 	uint32_t ctx_mask = msm_rpm_get_ctx_mask(ctx);
 	uint32_t ctx_mask_ack = 0;
 	uint32_t sel_masks_ack[SEL_MASK_SIZE];
-	struct irq_chip *irq_chip = NULL;
+	struct irq_chip *irq_chip, *err_chip;
 	int i;
 
 	msm_rpm_request_poll_mode.req = req;
@@ -371,6 +387,13 @@
 		return -ENOSPC;
 	}
 	irq_chip->irq_mask(irq_get_irq_data(irq));
+	err_chip = irq_get_chip(msm_rpm_data.irq_err);
+	if (!err_chip) {
+		irq_chip->irq_unmask(irq_get_irq_data(irq));
+		spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+		return -ENOSPC;
+	}
+	err_chip->irq_mask(irq_get_irq_data(msm_rpm_data.irq_err));
 
 	if (msm_rpm_request) {
 		msm_rpm_busy_wait_for_request_completion(true);
@@ -398,6 +421,7 @@
 	msm_rpm_busy_wait_for_request_completion(false);
 	BUG_ON(msm_rpm_request);
 
+	err_chip->irq_unmask(irq_get_irq_data(msm_rpm_data.irq_err));
 	irq_chip->irq_unmask(irq_get_irq_data(irq));
 	spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
 
@@ -983,6 +1007,14 @@
 		return rc;
 	}
 
+	rc = request_irq(data->irq_err, msm_rpm_err_interrupt,
+			IRQF_TRIGGER_RISING, "rpm_err", NULL);
+	if (rc) {
+		pr_err("%s: failed to request error interrupt: %d\n",
+			__func__, rc);
+		return rc;
+	}
+
 	msm_rpm_populate_map(data);
 
 	return platform_driver_register(&msm_rpm_platform_driver);