diff mbox

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

Message ID 1491462213-20033-1-git-send-email-shilpa.bhat@linux.vnet.ibm.com
State Superseded
Headers show

Commit Message

Shilpasri G Bhat April 6, 2017, 7:03 a.m. UTC
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@neuling.org>
Signed-off-by: Shilpasri G Bhat <shilpa.bhat@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(-)

Comments

Stewart Smith April 7, 2017, 1:14 a.m. UTC | #1
Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com> writes:
>  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;

Won't this always evaluate to true?

on p9:
not p8 (true) or not p9 (false) or quirk (false) = true
on p8:
not p8 (false) or not p9 (true) or quirk (false) = true

proc_gen < p8 would work.

(in future, when we have a new chip that doesn't have OCC_IRQ working
yet, we could always just add in the quirk)
Vaidyanathan Srinivasan April 7, 2017, 5:59 a.m. UTC | #2
* Stewart Smith <stewart@linux.vnet.ibm.com> [2017-04-07 11:14:16]:

> Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com> writes:
> >  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;
> 
> Won't this always evaluate to true?

Yes :(

Should have been 
        if ((proc_gen != proc_gen_p8 && proc_gen != proc_gen_p9) ||
                chip_quirk(QUIRK_NO_OCC_IRQ))

> on p9:
> not p8 (true) or not p9 (false) or quirk (false) = true
> on p8:
> not p8 (false) or not p9 (true) or quirk (false) = true
> 
> proc_gen < p8 would work.

Yes, but we mostly boot old code in new hardware first, so how about:
        if (proc_gen < proc_gen_p8 || proc_gen > proc_gen_p9 ||
                        chip_quirk(QUIRK_NO_OCC_IRQ))

> (in future, when we have a new chip that doesn't have OCC_IRQ working
> yet, we could always just add in the quirk)

After adding support in future platform we can just bump the proc_gen_p9

--Vaidy
diff mbox

Patch

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);