aboutsummaryrefslogtreecommitdiff
path: root/hw/occ.c
diff options
context:
space:
mode:
authorShilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>2017-04-07 14:22:37 +0530
committerMichael Neuling <mikey@neuling.org>2017-04-12 16:49:36 +1000
commit044fe827e02734451a1299166d1d020a7d57ff63 (patch)
tree37923bb4af1848d88525bd66cf6beeaf05a04d57 /hw/occ.c
parent2fec26b312960aeee589d628b60cdd42ce83cca5 (diff)
downloadskiboot-044fe827e02734451a1299166d1d020a7d57ff63.zip
skiboot-044fe827e02734451a1299166d1d020a7d57ff63.tar.gz
skiboot-044fe827e02734451a1299166d1d020a7d57ff63.tar.bz2
occ/irq: Fix SCOM address and irq reasons for P9 OCC
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> Signed-off-by: Michael Neuling <mikey@neuling.org>
Diffstat (limited to 'hw/occ.c')
-rw-r--r--hw/occ.c85
1 files changed, 72 insertions, 13 deletions
diff --git a/hw/occ.c b/hw/occ.c
index ee76be6..2720b7b 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -940,24 +940,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
@@ -973,17 +986,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 ? */
@@ -992,7 +1017,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)
@@ -1004,9 +1029,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)