@@ -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)
@@ -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");
@@ -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);
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(-)