aboutsummaryrefslogtreecommitdiff
path: root/hw/psi.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2017-02-03 20:51:58 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-02-07 14:16:03 +1100
commit7d252cdeb5f5f85d4a386859e0c87613162bcf31 (patch)
treeb0defc9d54750cdc509171eb2b5f3db3bc8bb77d /hw/psi.c
parentdcffe14d4075ac9e8bfce6eb1c53401630a6582f (diff)
downloadskiboot-7d252cdeb5f5f85d4a386859e0c87613162bcf31.zip
skiboot-7d252cdeb5f5f85d4a386859e0c87613162bcf31.tar.gz
skiboot-7d252cdeb5f5f85d4a386859e0c87613162bcf31.tar.bz2
xive/psi/lpc: Handle proper clearing of LPC SerIRQ latch on DD1
On DD1, the LPC SerIRQ are latched to 1 in HW but never back to 0, we need an explicit clear after running the handler. (Not before as they are level interrupts, they will be latched again if they are still pending). For now we do that in lpc_dispatch_ser_irqs() but that only works for interrupts routed to OPAL. In order to support routing LPC interrutps to Linux, we need a custom EOI handler that does the clearing of the latch before we do the EOI in the ESB. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/psi.c')
-rw-r--r--hw/psi.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/hw/psi.c b/hw/psi.c
index 5d97fbb..93b5a75 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -657,6 +657,24 @@ static char *psi_p9_irq_name(struct irq_source *is, uint32_t isn)
return strdup(names[idx]);
}
+static void psi_p9_irq_dd1_eoi(struct irq_source *is, uint32_t isn)
+{
+ struct psi *psi = is->data;
+ unsigned int idx = isn & 0xf;
+
+ if (idx >= P9_PSI_IRQ_LPC_SIRQ0 &&
+ idx <= P9_PSI_IRQ_LPC_SIRQ3)
+ lpc_p9_sirq_eoi(psi->chip_id, idx - P9_PSI_IRQ_LPC_SIRQ0);
+ __xive_source_eoi(is, isn);
+}
+
+static const struct irq_source_ops psi_p9_dd1_irq_ops = {
+ .interrupt = psihb_p9_interrupt,
+ .attributes = psi_p9_irq_attributes,
+ .name = psi_p9_irq_name,
+ .eoi = psi_p9_irq_dd1_eoi,
+};
+
static const struct irq_source_ops psi_p9_irq_ops = {
.interrupt = psihb_p9_interrupt,
.attributes = psi_p9_irq_attributes,
@@ -797,6 +815,8 @@ static void psi_init_p8_interrupts(struct psi *psi)
static void psi_init_p9_interrupts(struct psi *psi)
{
+ struct proc_chip *c;
+ bool is_dd2;
u64 val;
/* Reset irq handling and switch to ESB mode */
@@ -829,9 +849,24 @@ static void psi_init_p9_interrupts(struct psi *psi)
out_be64(psi->regs + PSIHB_IVT_OFFSET, val);
/* Register sources */
- xive_register_hw_source(psi->interrupt, P9_PSI_NUM_IRQS,
- 12, psi->esb_mmio, XIVE_SRC_LSI,
- psi, &psi_p9_irq_ops);
+ c = next_chip(NULL);
+ is_dd2 = (c && c->ec_level >= 0x20);
+
+ if (is_dd2) {
+ prlog(PR_DEBUG,
+ "PSI[0x%03x]: Interrupts sources registered for P9 DD2.x\n",
+ psi->chip_id);
+ xive_register_hw_source(psi->interrupt, P9_PSI_NUM_IRQS,
+ 12, psi->esb_mmio, XIVE_SRC_LSI,
+ psi, &psi_p9_irq_ops);
+ } else {
+ prlog(PR_DEBUG,
+ "PSI[0x%03x]: Interrupts sources registered for P9 DD1.x\n",
+ psi->chip_id);
+ xive_register_hw_source(psi->interrupt, P9_PSI_NUM_IRQS,
+ 12, psi->esb_mmio, XIVE_SRC_LSI,
+ psi, &psi_p9_dd1_irq_ops);
+ }
}
static void psi_init_interrupts(struct psi *psi)