[Skiboot] [PATCH V3] occ: irq: Fix SCOM address and irq reasons for OCC_MISC register
Shilpasri G Bhat
shilpa.bhat at linux.vnet.ibm.com
Fri Apr 7 18:52:37 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 V2:
- Fix the proc_gen check to return if (proc_gen < proc_gen_p8).
proc_gen > proc_gen_p9 is not required as we do scom in the switch
case. The new hardware gets gated in the switch case.
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.
hw/occ.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++---------
hw/psi.c | 4 +--
include/skiboot.h | 7 +++--
3 files changed, 79 insertions(+), 17 deletions(-)
diff --git a/hw/occ.c b/hw/occ.c
index 7b502b4..145d669 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -1279,24 +1279,37 @@ 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 || chip_quirk(QUIRK_NO_OCC_IRQ))
return;
/* Find a functional PSI. This ensures an interrupt even if
@@ -1312,17 +1325,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 +1356,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 +1368,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