summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-08-09 16:38:07 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-08-11 19:54:22 +1000
commitc28ea2f0b7d6ab1d1ada871690169b21a11aad10 (patch)
tree05b63e7a8dc6f056d226fe966c497393a56e1a2a
parent5ed551115a3ad1925c900b2e0dd7977ad1987f85 (diff)
downloadblackbird-skiboot-c28ea2f0b7d6ab1d1ada871690169b21a11aad10.tar.gz
blackbird-skiboot-c28ea2f0b7d6ab1d1ada871690169b21a11aad10.zip
psi: Add P9 support
This reworks interrupt handling a bit and adds support for XIVE based interrupts and the new sources available on POWER9. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--doc/device-tree/examples/power9-phb4.dts5
-rw-r--r--hw/psi.c425
-rw-r--r--include/interrupts.h2
-rw-r--r--include/psi.h39
-rw-r--r--platforms/rhesus/rhesus.c4
5 files changed, 324 insertions, 151 deletions
diff --git a/doc/device-tree/examples/power9-phb4.dts b/doc/device-tree/examples/power9-phb4.dts
index f25114ff..36de6e2e 100644
--- a/doc/device-tree/examples/power9-phb4.dts
+++ b/doc/device-tree/examples/power9-phb4.dts
@@ -152,6 +152,11 @@
reg = <0x5013000 0x300>;
compatible = "ibm,power9-xive-x";
};
+
+ psihb@5012900 {
+ reg = <0x5012900 0x100>;
+ compatible = "ibm,power9-psihb-x", "ibm,psihb-x";
+ };
};
lpcm-opb@6030000000000 {
diff --git a/hw/psi.c b/hw/psi.c
index a8950505..08dc5897 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -32,6 +32,7 @@
#include <timebase.h>
#include <platform.h>
#include <errorlog.h>
+#include <xive.h>
static LIST_HEAD(psis);
static u64 psi_link_timer;
@@ -39,7 +40,6 @@ static u64 psi_link_timeout;
static bool psi_link_poll_active;
static bool psi_ext_irq_policy = EXTERNAL_IRQ_POLICY_LINUX;
-static void psi_register_interrupts(struct psi *psi);
static void psi_activate_phb(struct psi *psi);
static struct lock psi_lock = LOCK_UNLOCKED;
@@ -272,63 +272,16 @@ static void handle_psi_interrupt(struct psi *psi, u64 val)
printf("PSI: FSP error detected\n");
}
-/* TODO: Determine which of these needs to be handled by powernv */
-static void handle_extra_interrupt(struct psi *psi)
-{
- u64 val;
-
- val = in_be64(psi->regs + PSIHB_IRQ_STATUS);
-
- /*
- * Decode interrupt type, call appropriate handlers
- * when available.
- */
- if (val & PSIHB_IRQ_STAT_OCC)
- occ_interrupt(psi->chip_id);
- if (val & PSIHB_IRQ_STAT_FSI)
- printf("PSI: FSI irq received\n");
- if (val & PSIHB_IRQ_STAT_LPC) {
- lpc_interrupt(psi->chip_id);
-
- /*
- * i2c interrupts are ORed with the LPC ones on
- * Murano DD2.1 and Venice DD2.0
- */
- p8_i2c_interrupt(psi->chip_id);
- }
- if (val & PSIHB_IRQ_STAT_LOCAL_ERR)
- prd_psi_interrupt(psi->chip_id);
- if (val & PSIHB_IRQ_STAT_HOST_ERR) {
- if (platform.external_irq)
- platform.external_irq(psi->chip_id);
- } else {
- u64 xivr;
-
- /*
- * The way our FPGA "pulses" the external interrupt
- * on BMC machines means we might not see it in the
- * status register anymore, so look at the latch in
- * the XIVR
- */
- xivr = in_be64(psi->regs + PSIHB_XIVR_HOST_ERR);
- if (xivr & PPC_BIT(39) && platform.external_irq)
- platform.external_irq(psi->chip_id);
- }
-
- /*
- * TODO: Per Vicente Chung, CRESPs don't generate interrupts,
- * and are just informational. Need to define the policy
- * to handle them.
- */
-}
-
static void psi_spurious_fsp_irq(struct psi *psi)
{
u64 reg, bit;
prerror("PSI: Spurious interrupt, attempting clear\n");
- if (proc_gen == proc_gen_p8) {
+ if (proc_gen == proc_gen_p9) {
+ reg = PSIHB_XSCOM_P9_HBCSR_CLR;
+ bit = PSIHB_XSCOM_P9_HBSCR_FSP_IRQ;
+ } else if (proc_gen == proc_gen_p8) {
reg = PSIHB_XSCOM_P8_HBCSR_CLR;
bit = PSIHB_XSCOM_P8_HBSCR_FSP_IRQ;
} else {
@@ -343,7 +296,7 @@ bool psi_poll_fsp_interrupt(struct psi *psi)
return !!(in_be64(psi->regs + PSIHB_CR) & PSIHB_CR_FSP_IRQ);
}
-static void psi_interrupt(struct irq_source *is, uint32_t isn __unused)
+static void psihb_interrupt(struct irq_source *is, uint32_t isn __unused)
{
struct psi *psi = is->data;
u64 val;
@@ -385,10 +338,6 @@ static void psi_interrupt(struct irq_source *is, uint32_t isn __unused)
fsp_interrupt();
}
- /* P8 additional interrupt? */
- if (proc_gen == proc_gen_p8)
- handle_extra_interrupt(psi);
-
/* Poll the console buffers on any interrupt since we don't
* get send notifications
*/
@@ -438,6 +387,44 @@ static uint64_t psi_p7_irq_attributes(struct irq_source *is __unused,
return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_FREQUENT;
}
+
+/* Called on a fast reset, make sure we aren't stuck with
+ * an accepted and never EOId PSI interrupt
+ */
+void psi_irq_reset(void)
+{
+ struct psi *psi;
+ uint64_t xivr;
+
+ printf("PSI: Hot reset!\n");
+
+ assert(proc_gen == proc_gen_p7);
+
+ list_for_each(&psis, psi, list) {
+ /* Mask the interrupt & clean the XIVR */
+ xivr = 0x000000ff00000000UL;
+ xivr |= P7_IRQ_BUID(psi->interrupt) << 16;
+ out_be64(psi->regs + PSIHB_XIVR, xivr);
+
+#if 0 /* Seems to checkstop ... */
+ /*
+ * Maybe not anymore; we were just blindly sending
+ * this on all iopaths, not just the active one;
+ * We don't even know if those psis are even correct.
+ */
+ /* Send a dummy EOI to make sure the ICP is clear */
+ icp_send_eoi(psi->interrupt);
+#endif
+ }
+}
+
+static const struct irq_source_ops psi_p7_irq_ops = {
+ .get_xive = psi_p7_get_xive,
+ .set_xive = psi_p7_set_xive,
+ .interrupt = psihb_interrupt,
+ .attributes = psi_p7_irq_attributes,
+};
+
static int64_t psi_p8_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t priority)
{
@@ -460,7 +447,7 @@ static int64_t psi_p8_set_xive(struct irq_source *is, uint32_t isn,
case P8_IRQ_PSI_LOCAL_ERR:
xivr_p = PSIHB_XIVR_LOCAL_ERR;
break;
- case P8_IRQ_PSI_HOST_ERR:
+ case P8_IRQ_PSI_EXTERNAL:
xivr_p = PSIHB_XIVR_HOST_ERR;
break;
default:
@@ -499,7 +486,7 @@ static int64_t psi_p8_get_xive(struct irq_source *is, uint32_t isn __unused,
case P8_IRQ_PSI_LOCAL_ERR:
xivr_p = PSIHB_XIVR_LOCAL_ERR;
break;
- case P8_IRQ_PSI_HOST_ERR:
+ case P8_IRQ_PSI_EXTERNAL:
xivr_p = PSIHB_XIVR_HOST_ERR;
break;
default:
@@ -515,65 +502,126 @@ static int64_t psi_p8_get_xive(struct irq_source *is, uint32_t isn __unused,
return OPAL_SUCCESS;
}
+static void psihb_p8_interrupt(struct irq_source *is, uint32_t isn)
+{
+ struct psi *psi = is->data;
+ uint32_t idx = isn - psi->interrupt;
+
+ switch (idx) {
+ case P8_IRQ_PSI_FSP:
+ psihb_interrupt(is, isn);
+ break;
+ case P8_IRQ_PSI_OCC:
+ occ_interrupt(psi->chip_id);
+ break;
+ case P8_IRQ_PSI_FSI:
+ printf("PSI: FSI irq received\n");
+ break;
+ case P8_IRQ_PSI_LPC:
+ lpc_interrupt(psi->chip_id);
+
+ /*
+ * i2c interrupts are ORed with the LPC ones on
+ * Murano DD2.1 and Venice DD2.0
+ */
+ p8_i2c_interrupt(psi->chip_id);
+ break;
+ case P8_IRQ_PSI_LOCAL_ERR:
+ prd_psi_interrupt(psi->chip_id);
+ break;
+ case P8_IRQ_PSI_EXTERNAL:
+ if (platform.external_irq)
+ platform.external_irq(psi->chip_id);
+ break;
+ }
+
+ /*
+ * TODO: Per Vicente Chung, CRESPs don't generate interrupts,
+ * and are just informational. Need to define the policy
+ * to handle them.
+ */
+}
+
static uint64_t psi_p8_irq_attributes(struct irq_source *is, uint32_t isn)
{
struct psi *psi = is->data;
uint32_t idx = isn - psi->interrupt;
uint64_t attr;
- if (idx == P8_IRQ_PSI_HOST_ERR &&
+ if (idx == P8_IRQ_PSI_EXTERNAL &&
psi_ext_irq_policy == EXTERNAL_IRQ_POLICY_LINUX)
return IRQ_ATTR_TARGET_LINUX;
attr = IRQ_ATTR_TARGET_OPAL;
- if (idx == P8_IRQ_PSI_HOST_ERR || idx == P8_IRQ_PSI_LPC ||
+ if (idx == P8_IRQ_PSI_EXTERNAL || idx == P8_IRQ_PSI_LPC ||
idx == P8_IRQ_PSI_FSP)
attr |= IRQ_ATTR_TARGET_FREQUENT;
return attr;
}
-/* Called on a fast reset, make sure we aren't stuck with
- * an accepted and never EOId PSI interrupt
- */
-void psi_irq_reset(void)
-{
- struct psi *psi;
- uint64_t xivr;
-
- printf("PSI: Hot reset!\n");
-
- assert(proc_gen == proc_gen_p7);
+static const struct irq_source_ops psi_p8_irq_ops = {
+ .get_xive = psi_p8_get_xive,
+ .set_xive = psi_p8_set_xive,
+ .interrupt = psihb_p8_interrupt,
+ .attributes = psi_p8_irq_attributes,
+};
- list_for_each(&psis, psi, list) {
- /* Mask the interrupt & clean the XIVR */
- xivr = 0x000000ff00000000UL;
- xivr |= P7_IRQ_BUID(psi->interrupt) << 16;
- out_be64(psi->regs + PSIHB_XIVR, xivr);
+static void psihb_p9_interrupt(struct irq_source *is, uint32_t isn)
+{
+ struct psi *psi = is->data;
+ uint32_t idx = isn - psi->interrupt;
-#if 0 /* Seems to checkstop ... */
- /*
- * Maybe not anymore; we were just blindly sending
- * this on all iopaths, not just the active one;
- * We don't even know if those psis are even correct.
- */
- /* Send a dummy EOI to make sure the ICP is clear */
- icp_send_eoi(psi->interrupt);
-#endif
+ switch (idx) {
+ case P9_PSI_IRQ_PSI:
+ psihb_interrupt(is, isn);
+ break;
+ case P9_PSI_IRQ_OCC:
+ occ_interrupt(psi->chip_id);
+ break;
+ case P9_PSI_IRQ_FSI:
+ printf("PSI: FSI irq received\n");
+ break;
+ case P9_PSI_IRQ_LPCHC:
+ lpc_interrupt(psi->chip_id);
+ break;
+ case P9_PSI_IRQ_LOCAL_ERR:
+ prd_psi_interrupt(psi->chip_id);
+ break;
+ case P9_PSI_IRQ_GLOBAL_ERR:
+ printf("PSI: Global error irq received\n");
+ break;
+ case P9_PSI_IRQ_EXTERNAL:
+ if (platform.external_irq)
+ platform.external_irq(psi->chip_id);
+ break;
+ case P9_PSI_IRQ_LPC_SIRQ0:
+ case P9_PSI_IRQ_LPC_SIRQ1:
+ case P9_PSI_IRQ_LPC_SIRQ2:
+ case P9_PSI_IRQ_LPC_SIRQ3:
+ /* XXX TODO */
+ break;
+ case P9_PSI_IRQ_SBE_I2C:
+ p8_i2c_interrupt(psi->chip_id);
+ break;
+ case P9_PSI_IRQ_DIO:
+ printf("PSI: DIO irq received\n");
+ break;
+ case P9_PSI_IRQ_PSU:
+ printf("PSI: PSU irq received\n");
+ break;
}
}
-static const struct irq_source_ops psi_p7_irq_ops = {
- .get_xive = psi_p7_get_xive,
- .set_xive = psi_p7_set_xive,
- .attributes = psi_p7_irq_attributes,
- .interrupt = psi_interrupt,
-};
+static uint64_t psi_p9_irq_attributes(struct irq_source *is __unused,
+ uint32_t isn __unused)
+{
+ /* XXX For now, all go to OPAL, this will change */
+ return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_FREQUENT;
+}
-static const struct irq_source_ops psi_p8_irq_ops = {
- .get_xive = psi_p8_get_xive,
- .set_xive = psi_p8_set_xive,
- .attributes = psi_p8_irq_attributes,
- .interrupt = psi_interrupt,
+static const struct irq_source_ops psi_p9_irq_ops = {
+ .interrupt = psihb_p9_interrupt,
+ .attributes = psi_p9_irq_attributes,
};
static void psi_tce_enable(struct psi *psi, bool enable)
@@ -586,6 +634,7 @@ static void psi_tce_enable(struct psi *psi, bool enable)
addr = psi->regs + PSIHB_CR;
break;
case proc_gen_p8:
+ case proc_gen_p9:
addr = psi->regs + PSIHB_PHBSCR;
break;
default:
@@ -622,6 +671,7 @@ void psi_init_for_fsp(struct psi *psi)
PSIHB_TAR_16K_ENTRIES);
break;
case proc_gen_p8:
+ case proc_gen_p9:
out_be64(psi->regs + PSIHB_TAR, PSI_TCE_TABLE_BASE |
PSIHB_TAR_256K_ENTRIES);
break;
@@ -663,58 +713,103 @@ void psi_set_external_irq_policy(bool policy)
psi_ext_irq_policy = policy;
}
-/*
- * Register interrupt sources for all working links, not just the active ones.
- * This is a one time activity.
- */
-static void psi_register_interrupts(struct psi *psi)
+static void psi_init_p7_interrupt(struct psi *psi)
+{
+ /* On P7, we get a single interrupt */
+ out_be64(psi->regs + PSIHB_XIVR,
+ P7_IRQ_BUID(psi->interrupt) << 16 |
+ 0xffull << 32);
+
+ /* Configure it in the GX controller as well */
+ gx_configure_psi_buid(psi->chip_id, P7_IRQ_BUID(psi->interrupt));
+
+ /* Register the IRQ source */
+ register_irq_source(&psi_p7_irq_ops, psi, psi->interrupt, 1);
+}
+
+static void psi_init_p8_interrupts(struct psi *psi)
+{
+ /* On P8 we get a block of 8, set up the base/mask
+ * and mask all the sources for now
+ */
+ out_be64(psi->regs + PSIHB_IRSN,
+ SETFIELD(PSIHB_IRSN_COMP, 0ul, psi->interrupt) |
+ SETFIELD(PSIHB_IRSN_MASK, 0ul, 0x7fff8ul) |
+ PSIHB_IRSN_DOWNSTREAM_EN |
+ PSIHB_IRSN_UPSTREAM_EN);
+ out_be64(psi->regs + PSIHB_XIVR_FSP,
+ (0xffull << 32) | (P8_IRQ_PSI_FSP << 29));
+ out_be64(psi->regs + PSIHB_XIVR_OCC,
+ (0xffull << 32) | (P8_IRQ_PSI_OCC << 29));
+ out_be64(psi->regs + PSIHB_XIVR_FSI,
+ (0xffull << 32) | (P8_IRQ_PSI_FSI << 29));
+ out_be64(psi->regs + PSIHB_XIVR_LPC,
+ (0xffull << 32) | (P8_IRQ_PSI_LPC << 29));
+ out_be64(psi->regs + PSIHB_XIVR_LOCAL_ERR,
+ (0xffull << 32) | (P8_IRQ_PSI_LOCAL_ERR << 29));
+ out_be64(psi->regs + PSIHB_XIVR_HOST_ERR,
+ (0xffull << 32) | (P8_IRQ_PSI_EXTERNAL << 29));
+
+ /*
+ * Register the IRQ sources FSP, OCC, FSI, LPC
+ * and Local Error. Host Error is actually the
+ * external interrupt and the policy for that comes
+ * from the platform
+ */
+ register_irq_source(&psi_p8_irq_ops, psi,
+ psi->interrupt, P8_IRQ_PSI_IRQ_COUNT);
+}
+
+static void psi_init_p9_interrupts(struct psi *psi)
+{
+ u64 val;
+
+ /* Reset irq handling and switch to ESB mode */
+ out_be64(psi->regs + PSIHB_INTERRUPT_CONTROL, PSIHB_IRQ_RESET);
+ out_be64(psi->regs + PSIHB_INTERRUPT_CONTROL, 0);
+
+#define PSIHB_ESB_MMIO_DEFAULT 0x0060302031c0000ull
+
+ /* Configure the CI BAR if necessary */
+ val = in_be64(psi->regs + PSIHB_ESB_CI_BASE);
+ if (!(val & PSIHB_ESB_CI_VALID)) {
+ out_be64(psi->regs + PSIHB_ESB_CI_BASE,
+ PSIHB_ESB_MMIO_DEFAULT | PSIHB_ESB_CI_VALID);
+ printf("PSI[0x%03x]: ESB MMIO invalid, reconfiguring...\n",
+ psi->chip_id);
+ }
+ val = in_be64(psi->regs + PSIHB_ESB_CI_BASE);
+ psi->esb_mmio = (void *)(val & ~PSIHB_ESB_CI_VALID);
+ printf("PSI[0x%03x]: ESB MMIO at @%p\n", psi->chip_id, psi->esb_mmio);
+
+ /* Grab and configure the notification port */
+ val = xive_get_notify_port(psi->chip_id, XIVE_HW_SRC_PSI);
+ val |= PSIHB_ESB_NOTIF_VALID;
+ out_be64(psi->regs + PSIHB_ESB_NOTIF_ADDR, val);
+
+ /* Setup interrupt offset */
+ val = xive_get_notify_base(psi->interrupt);
+ val <<= 32;
+ out_be64(psi->regs + PSIHB_IVT_OFFSET, val);
+
+ /* Register sources */
+ xive_register_source(psi->interrupt, P9_PSI_NUM_IRQS,
+ 12, psi->esb_mmio, XIVE_SRC_LSI,
+ psi, &psi_p9_irq_ops);
+}
+
+static void psi_init_interrupts(struct psi *psi)
{
/* Configure the interrupt BUID and mask it */
switch (proc_gen) {
case proc_gen_p7:
- /* On P7, we get a single interrupt */
- out_be64(psi->regs + PSIHB_XIVR,
- P7_IRQ_BUID(psi->interrupt) << 16 |
- 0xffull << 32);
-
- /* Configure it in the GX controller as well */
- gx_configure_psi_buid(psi->chip_id,
- P7_IRQ_BUID(psi->interrupt));
-
- /* Register the IRQ source */
- register_irq_source(&psi_p7_irq_ops,
- psi, psi->interrupt, 1);
+ psi_init_p7_interrupt(psi);
break;
case proc_gen_p8:
- /* On P8 we get a block of 8, set up the base/mask
- * and mask all the sources for now
- */
- out_be64(psi->regs + PSIHB_IRSN,
- SETFIELD(PSIHB_IRSN_COMP, 0ul, psi->interrupt) |
- SETFIELD(PSIHB_IRSN_MASK, 0ul, 0x7fff8ul) |
- PSIHB_IRSN_DOWNSTREAM_EN |
- PSIHB_IRSN_UPSTREAM_EN);
- out_be64(psi->regs + PSIHB_XIVR_FSP,
- (0xffull << 32) | (P8_IRQ_PSI_FSP << 29));
- out_be64(psi->regs + PSIHB_XIVR_OCC,
- (0xffull << 32) | (P8_IRQ_PSI_OCC << 29));
- out_be64(psi->regs + PSIHB_XIVR_FSI,
- (0xffull << 32) | (P8_IRQ_PSI_FSI << 29));
- out_be64(psi->regs + PSIHB_XIVR_LPC,
- (0xffull << 32) | (P8_IRQ_PSI_LPC << 29));
- out_be64(psi->regs + PSIHB_XIVR_LOCAL_ERR,
- (0xffull << 32) | (P8_IRQ_PSI_LOCAL_ERR << 29));
- out_be64(psi->regs + PSIHB_XIVR_HOST_ERR,
- (0xffull << 32) | (P8_IRQ_PSI_HOST_ERR << 29));
-
- /*
- * Register the IRQ sources FSP, OCC, FSI, LPC
- * and Local Error. Host Error is actually the
- * external interrupt and the policy for that comes
- * from the platform
- */
- register_irq_source(&psi_p8_irq_ops, psi,
- psi->interrupt, P8_IRQ_PSI_IRQ_COUNT);
+ psi_init_p8_interrupts(psi);
+ break;
+ case proc_gen_p9:
+ psi_init_p9_interrupts(psi);
break;
default:
/* Unknown: just no interrupts */
@@ -782,6 +877,10 @@ static void psi_create_mm_dtnode(struct psi *psi)
dt_add_property_strings(np, "compatible", "ibm,psi",
"ibm,power8-psi");
break;
+ case proc_gen_p9:
+ dt_add_property_strings(np, "compatible", "ibm,psi",
+ "ibm,power9-psi");
+ break;
default:
dt_add_property_strings(np, "compatible", "ibm,psi");
}
@@ -825,6 +924,8 @@ static struct psi *psi_probe_p7(struct proc_chip *chip, u64 base)
} else
printf("PSI[0x%03x]: Working link not found\n", chip->id);
+ psi->interrupt = get_psi_interrupt(psi->chip_id);
+
return psi;
}
@@ -848,6 +949,36 @@ static struct psi *psi_probe_p8(struct proc_chip *chip, u64 base)
} else
printf("PSI[0x%03x]: Working chip not found\n", chip->id);
+ psi->interrupt = get_psi_interrupt(psi->chip_id);
+
+ return psi;
+}
+
+static struct psi *psi_probe_p9(struct proc_chip *chip, u64 base)
+{
+ struct psi *psi = NULL;
+ uint64_t rc, val;
+
+ rc = xscom_read(chip->id, base + PSIHB_XSCOM_P9_BASE, &val);
+ if (rc) {
+ prerror("PSI[0x%03x]: Error %llx reading PSIHB BAR\n",
+ chip->id, rc);
+ return NULL;
+ }
+ if (!val & PSIHB_XSCOM_P9_HBBAR_EN) {
+ prerror("PSI[0x%03x]: PSIHB BAR Disabled,fixing up (%016llx)\n",
+ chip->id, val);
+#define PSIHB_PSI_MMIO_DEFAULT 0x006030203000000ull
+ val = PSIHB_PSI_MMIO_DEFAULT | PSIHB_XSCOM_P9_HBBAR_EN;
+ xscom_write(chip->id, base + PSIHB_XSCOM_P9_BASE, val);
+ }
+ psi = alloc_psi(base);
+ if (!psi)
+ return NULL;
+ psi->working = true;
+ psi->regs = (void *)(val & ~PSIHB_XSCOM_P9_HBBAR_EN);
+
+ psi->interrupt = xive_alloc_hw_irqs(psi->chip_id, P9_PSI_NUM_IRQS, 16);
return psi;
}
@@ -869,6 +1000,8 @@ static bool psi_init_psihb(struct dt_node *psihb)
psi = psi_probe_p7(chip, base);
else if (dt_node_is_compatible(psihb, "ibm,power8-psihb-x"))
psi = psi_probe_p8(chip, base);
+ else if (dt_node_is_compatible(psihb, "ibm,power9-psihb-x"))
+ psi = psi_probe_p9(chip, base);
else {
prerror("PSI: Unknown processor type\n");
return false;
@@ -886,13 +1019,11 @@ static bool psi_init_psihb(struct dt_node *psihb)
}
psi->chip_id = chip->id;
- psi->interrupt = get_psi_interrupt(chip->id);
-
chip->psi = psi;
- psi_create_mm_dtnode(psi);
- psi_register_interrupts(psi);
psi_activate_phb(psi);
+ psi_init_interrupts(psi);
+ psi_create_mm_dtnode(psi);
printf("PSI[0x%03x]: Found PSI bridge [working=%d, active=%d]\n",
psi->chip_id, psi->working, psi->active);
diff --git a/include/interrupts.h b/include/interrupts.h
index 23d785c2..2f8c275d 100644
--- a/include/interrupts.h
+++ b/include/interrupts.h
@@ -213,7 +213,7 @@ uint32_t p8_irq_to_phb(uint32_t irq);
#define P8_IRQ_PSI_FSI 2
#define P8_IRQ_PSI_LPC 3
#define P8_IRQ_PSI_LOCAL_ERR 4
-#define P8_IRQ_PSI_HOST_ERR 5
+#define P8_IRQ_PSI_EXTERNAL 5 /* Used for UART */
#define P8_IRQ_PSI_IRQ_COUNT 6
/* TBD: NX, AS, ...
diff --git a/include/psi.h b/include/psi.h
index cb8d7eae..68e076c3 100644
--- a/include/psi.h
+++ b/include/psi.h
@@ -106,9 +106,20 @@
#define PSIHB_IRQ_STAT_LOCAL_ERR PPC_BIT(30)
#define PSIHB_IRQ_STAT_HOST_ERR PPC_BIT(31)
-/* Secure version of CR for P8 (TCE enable bit) */
+/* Secure version of CR for P8 and P9 (TCE enable bit) */
#define PSIHB_PHBSCR 0x90
+/* P9 registers */
+
+#define PSIHB_INTERRUPT_CONTROL 0x58
+#define PSIHB_IRQ_METHOD PPC_BIT(0)
+#define PSIHB_IRQ_RESET PPC_BIT(1)
+#define PSIHB_ESB_CI_BASE 0x60
+#define PSIHB_ESB_CI_VALID 1
+#define PSIHB_ESB_NOTIF_ADDR 0x68
+#define PSIHB_ESB_NOTIF_VALID 1
+#define PSIHB_IVT_OFFSET 0x70
+#define PSIHB_IVT_OFF_SHIFT 32
/*
* PSI Host Bridge Registers (XSCOM)
*/
@@ -126,6 +137,31 @@
#define PSIHB_XSCOM_P8_HBCSR_CLR 0x13
#define PSIHB_XSCOM_P8_HBSCR_FSP_IRQ PPC_BIT(17)
+#define PSIHB_XSCOM_P9_BASE 0xa
+#define PSIHB_XSCOM_P9_HBBAR_EN PPC_BIT(63)
+#define PSIHB_XSCOM_P9_HBCSR 0xe
+#define PSIHB_XSCOM_P9_HBCSR_SET 0x12
+#define PSIHB_XSCOM_P9_HBCSR_CLR 0x13
+#define PSIHB_XSCOM_P9_HBSCR_FSP_IRQ PPC_BIT(17)
+
+/* P9 PSI Interrupts */
+#define P9_PSI_IRQ_PSI 0
+#define P9_PSI_IRQ_OCC 1
+#define P9_PSI_IRQ_FSI 2
+#define P9_PSI_IRQ_LPCHC 3
+#define P9_PSI_IRQ_LOCAL_ERR 4
+#define P9_PSI_IRQ_GLOBAL_ERR 5
+#define P9_PSI_IRQ_EXTERNAL 6
+#define P9_PSI_IRQ_LPC_SIRQ0 7
+#define P9_PSI_IRQ_LPC_SIRQ1 8
+#define P9_PSI_IRQ_LPC_SIRQ2 9
+#define P9_PSI_IRQ_LPC_SIRQ3 10
+#define P9_PSI_IRQ_SBE_I2C 11
+#define P9_PSI_IRQ_DIO 12
+#define P9_PSI_IRQ_PSU 13
+#define P9_PSI_NUM_IRQS 16
+
+
/*
* Layout of the PSI DMA address space
@@ -205,6 +241,7 @@ struct psi {
struct list_node list;
uint64_t xscom_base;
void *regs;
+ void *esb_mmio;
unsigned int chip_id;
unsigned int interrupt;
bool working;
diff --git a/platforms/rhesus/rhesus.c b/platforms/rhesus/rhesus.c
index a3af777b..8faf2955 100644
--- a/platforms/rhesus/rhesus.c
+++ b/platforms/rhesus/rhesus.c
@@ -198,8 +198,8 @@ static void rhesus_dt_fixup_uart(struct dt_node *lpc, bool has_irq)
*/
if (has_irq) {
uint32_t chip_id = dt_get_chip_id(lpc);
- uint32_t irq = get_psi_interrupt(chip_id) + P8_IRQ_PSI_HOST_ERR;
- dt_add_property_cells(uart, "interrupts", irq);
+ uint32_t irq = get_psi_interrupt(chip_id) + P8_IRQ_PSI_EXTERNAL;
+ dt_add_property_cells(uart, "interrupts", irq, 1);
dt_add_property_cells(uart, "interrupt-parent",
get_ics_phandle());
}
OpenPOWER on IntegriCloud