[Skiboot] [PATCH V2] occ: irq: Fix SCOM address and irq reasons for OCC_MISC register

Shilpasri G Bhat shilpa.bhat at linux.vnet.ibm.com
Thu Apr 6 17:03:33 AEST 2017


This patch fixes the SCOM address for OCC_MISC register which is used
for OCC interupts. In P9, OCC sends an interrupt to notify change in
the shared memory like throttle status. This patch handles this
interrupt reason.

Originally-from: Michael Neuling <mikey at neuling.org>
Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
Changes from V1:
- s/_AND/_CLEAR
- Add irq reason bits for i2c ownership change and shared memory
  change
- Handle shared memory change interrupt reason
- Reuse OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY bit in
  occ_send_dummy_interrupt() for P9.
- Is there a way to avoid switch(proc_gen) in occ_send_dummy_interrupt()

 hw/occ.c          | 86 ++++++++++++++++++++++++++++++++++++++++++++++---------
 hw/psi.c          |  4 +--
 include/skiboot.h |  7 +++--
 3 files changed, 80 insertions(+), 17 deletions(-)

diff --git a/hw/occ.c b/hw/occ.c
index 7b502b4..8548513 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -1279,24 +1279,38 @@ static struct fsp_client fsp_occ_client = {
 	.message = fsp_occ_msg,
 };
 
-#define OCB_OCI_OCCMISC		0x6a020
-#define OCB_OCI_OCCMISC_AND	0x6a021
-#define OCB_OCI_OCCMISC_OR	0x6a022
+#define P8_OCB_OCI_OCCMISC		0x6a020
+#define P8_OCB_OCI_OCCMISC_AND		0x6a021
+#define P8_OCB_OCI_OCCMISC_OR		0x6a022
+
+#define P9_OCB_OCI_OCCMISC		0x6c080
+#define P9_OCB_OCI_OCCMISC_CLEAR	0x6c081
+#define P9_OCB_OCI_OCCMISC_OR		0x6c082
+
 #define OCB_OCI_OCIMISC_IRQ		PPC_BIT(0)
 #define OCB_OCI_OCIMISC_IRQ_TMGT	PPC_BIT(1)
 #define OCB_OCI_OCIMISC_IRQ_SLW_TMR	PPC_BIT(14)
 #define OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY	PPC_BIT(15)
-#define OCB_OCI_OCIMISC_MASK		(OCB_OCI_OCIMISC_IRQ_TMGT | \
+
+#define P8_OCB_OCI_OCIMISC_MASK		(OCB_OCI_OCIMISC_IRQ_TMGT | \
 					 OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY | \
 					 OCB_OCI_OCIMISC_IRQ_SLW_TMR)
 
+#define OCB_OCI_OCIMISC_IRQ_I2C		PPC_BIT(2)
+#define OCB_OCI_OCIMISC_IRQ_SHMEM	PPC_BIT(3)
+#define P9_OCB_OCI_OCIMISC_MASK		(OCB_OCI_OCIMISC_IRQ_TMGT | \
+					 OCB_OCI_OCIMISC_IRQ_I2C | \
+					 OCB_OCI_OCIMISC_IRQ_SHMEM | \
+					 OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY)
+
 void occ_send_dummy_interrupt(void)
 {
 	struct psi *psi;
 	struct proc_chip *chip = get_chip(this_cpu()->chip_id);
 
 	/* Emulators and P7 doesn't do this */
-	if (proc_gen != proc_gen_p8 || chip_quirk(QUIRK_NO_OCC_IRQ))
+	if (proc_gen != proc_gen_p8 ||  proc_gen != proc_gen_p9 ||
+	    chip_quirk(QUIRK_NO_OCC_IRQ))
 		return;
 
 	/* Find a functional PSI. This ensures an interrupt even if
@@ -1312,17 +1326,29 @@ void occ_send_dummy_interrupt(void)
 		return;
 	}
 
-	xscom_write(psi->chip_id, OCB_OCI_OCCMISC_OR,
-		    OCB_OCI_OCIMISC_IRQ | OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY);
+	switch (proc_gen) {
+	case proc_gen_p8:
+		xscom_write(psi->chip_id, P8_OCB_OCI_OCCMISC_OR,
+			    OCB_OCI_OCIMISC_IRQ |
+			    OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY);
+		break;
+	case proc_gen_p9:
+		xscom_write(psi->chip_id, P9_OCB_OCI_OCCMISC_OR,
+			    OCB_OCI_OCIMISC_IRQ |
+			    OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY);
+		break;
+	default:
+		break;
+	}
 }
 
-void occ_interrupt(uint32_t chip_id)
+void occ_p8_interrupt(uint32_t chip_id)
 {
 	uint64_t ireg;
 	int64_t rc;
 
 	/* The OCC interrupt is used to mux up to 15 different sources */
-	rc = xscom_read(chip_id, OCB_OCI_OCCMISC, &ireg);
+	rc = xscom_read(chip_id, P8_OCB_OCI_OCCMISC, &ireg);
 	if (rc) {
 		prerror("OCC: Failed to read interrupt status !\n");
 		/* Should we mask it in the XIVR ? */
@@ -1331,7 +1357,7 @@ void occ_interrupt(uint32_t chip_id)
 	prlog(PR_TRACE, "OCC: IRQ received: %04llx\n", ireg >> 48);
 
 	/* Clear the bits */
-	xscom_write(chip_id, OCB_OCI_OCCMISC_AND, ~ireg);
+	xscom_write(chip_id, P8_OCB_OCI_OCCMISC_AND, ~ireg);
 
 	/* Dispatch */
 	if (ireg & OCB_OCI_OCIMISC_IRQ_TMGT)
@@ -1343,9 +1369,43 @@ void occ_interrupt(uint32_t chip_id)
 	 * OCCMISC_AND write. Check if there are any new source bits set,
 	 * and trigger another interrupt if so.
 	 */
-	rc = xscom_read(chip_id, OCB_OCI_OCCMISC, &ireg);
-	if (!rc && (ireg & OCB_OCI_OCIMISC_MASK))
-		xscom_write(chip_id, OCB_OCI_OCCMISC_OR, OCB_OCI_OCIMISC_IRQ);
+	rc = xscom_read(chip_id, P8_OCB_OCI_OCCMISC, &ireg);
+	if (!rc && (ireg & P8_OCB_OCI_OCIMISC_MASK))
+		xscom_write(chip_id, P8_OCB_OCI_OCCMISC_OR,
+			    OCB_OCI_OCIMISC_IRQ);
+}
+
+void occ_p9_interrupt(uint32_t chip_id)
+{
+	u64 ireg;
+	s64 rc;
+
+	/* The OCC interrupt is used to mux up to 15 different sources */
+	rc = xscom_read(chip_id, P9_OCB_OCI_OCCMISC, &ireg);
+	if (rc) {
+		prerror("OCC: Failed to read interrupt status !\n");
+		return;
+	}
+	prlog(PR_TRACE, "OCC: IRQ received: %04llx\n", ireg >> 48);
+
+	/* Clear the bits */
+	xscom_write(chip_id, P9_OCB_OCI_OCCMISC_CLEAR, ireg);
+
+	/* Dispatch */
+	if (ireg & OCB_OCI_OCIMISC_IRQ_TMGT)
+		prd_tmgt_interrupt(chip_id);
+
+	if (ireg & OCB_OCI_OCIMISC_IRQ_SHMEM)
+		occ_throttle_poll(NULL);
+
+	/* We may have masked-out OCB_OCI_OCIMISC_IRQ in the previous
+	 * OCCMISC_AND write. Check if there are any new source bits set,
+	 * and trigger another interrupt if so.
+	 */
+	rc = xscom_read(chip_id, P9_OCB_OCI_OCCMISC, &ireg);
+	if (!rc && (ireg & P9_OCB_OCI_OCIMISC_MASK))
+		xscom_write(chip_id, P9_OCB_OCI_OCCMISC_OR,
+			    OCB_OCI_OCIMISC_IRQ);
 }
 
 void occ_fsp_init(void)
diff --git a/hw/psi.c b/hw/psi.c
index 089f429..cc7db44 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -485,7 +485,7 @@ static void psihb_p8_interrupt(struct irq_source *is, uint32_t isn)
 		psihb_interrupt(is, isn);
 		break;
 	case P8_IRQ_PSI_OCC:
-		occ_interrupt(psi->chip_id);
+		occ_p8_interrupt(psi->chip_id);
 		break;
 	case P8_IRQ_PSI_FSI:
 		printf("PSI: FSI irq received\n");
@@ -572,7 +572,7 @@ static void psihb_p9_interrupt(struct irq_source *is, uint32_t isn)
 		psihb_interrupt(is, isn);
 		break;
 	case P9_PSI_IRQ_OCC:
-		occ_interrupt(psi->chip_id);
+		occ_p9_interrupt(psi->chip_id);
 		break;
 	case P9_PSI_IRQ_FSI:
 		printf("PSI: FSI irq received\n");
diff --git a/include/skiboot.h b/include/skiboot.h
index 8bc767a..2b1f8a5 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -254,10 +254,13 @@ enum {
 extern void uart_set_console_policy(int policy);
 extern bool uart_enabled(void);
 
-/* OCC interrupt */
-extern void occ_interrupt(uint32_t chip_id);
+/* OCC interrupt for P8 */
+extern void occ_p8_interrupt(uint32_t chip_id);
 extern void occ_send_dummy_interrupt(void);
 
+/* OCC interrupt for P9 */
+extern void occ_p9_interrupt(uint32_t chip_id);
+
 /* OCC load support */
 extern void occ_poke_load_queue(void);
 
-- 
1.8.3.1



More information about the Skiboot mailing list