diff options
-rw-r--r-- | hw/lpc.c | 25 | ||||
-rw-r--r-- | hw/psi.c | 41 | ||||
-rw-r--r-- | hw/xive.c | 12 | ||||
-rw-r--r-- | include/lpc.h | 3 | ||||
-rw-r--r-- | include/xive.h | 4 |
5 files changed, 79 insertions, 6 deletions
@@ -944,14 +944,35 @@ void lpc_serirq(uint32_t chip_id, uint32_t index) chip_id, irqs, rmask); irqs &= rmask; - /* Handle SerIRQ interrupts */ + /* + * Handle SerIRQ interrupts. Don't clear the latch, + * it will be done in our special EOI callback if + * necessary on DD1 + */ if (irqs) - lpc_dispatch_ser_irqs(lpc, irqs, true); + lpc_dispatch_ser_irqs(lpc, irqs, false); bail: unlock(&lpc->lock); } +void lpc_p9_sirq_eoi(uint32_t chip_id, uint32_t index) +{ + struct proc_chip *chip = get_chip(chip_id); + struct lpcm *lpc; + uint32_t rmask; + + /* No initialized LPC controller on that chip */ + if (!chip || !chip->lpc) + return; + lpc = chip->lpc; + + lock(&lpc->lock); + rmask = lpc->sirq_rmasks[index]; + opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQSTAT, rmask, 4); + unlock(&lpc->lock); +} + void lpc_all_interrupts(uint32_t chip_id) { struct proc_chip *chip = get_chip(chip_id); @@ -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) @@ -2371,7 +2371,7 @@ static int64_t xive_source_set_xive(struct irq_source *is, uint32_t isn, return OPAL_SUCCESS; } -static void xive_source_eoi(struct irq_source *is, uint32_t isn) +void __xive_source_eoi(struct irq_source *is, uint32_t isn) { struct xive_src *s = container_of(is, struct xive_src, is); uint32_t idx = isn - s->esb_base; @@ -2431,6 +2431,16 @@ static void xive_source_eoi(struct irq_source *is, uint32_t isn) } } +static void xive_source_eoi(struct irq_source *is, uint32_t isn) +{ + struct xive_src *s = container_of(is, struct xive_src, is); + + if (s->orig_ops && s->orig_ops->eoi) + s->orig_ops->eoi(is, isn); + + __xive_source_eoi(is, isn); +} + static void xive_source_interrupt(struct irq_source *is, uint32_t isn) { struct xive_src *s = container_of(is, struct xive_src, is); diff --git a/include/lpc.h b/include/lpc.h index 59f0779..3e92d53 100644 --- a/include/lpc.h +++ b/include/lpc.h @@ -98,6 +98,9 @@ extern void lpc_register_client(uint32_t chip_id, const struct lpc_client *clt); /* Manual control of routing on P9 for use by platforms if necessary */ extern void lpc_route_serirq(uint32_t chip_id, uint32_t sirq, uint32_t psi_idx); +/* Clear SerIRQ latch on P9 DD1 */ +extern void lpc_p9_sirq_eoi(uint32_t chip_id, uint32_t index); + /* Default bus accessors */ extern int64_t lpc_write(enum OpalLPCAddressType addr_type, uint32_t addr, uint32_t data, uint32_t sz); diff --git a/include/xive.h b/include/xive.h index e9a01c3..58c4da9 100644 --- a/include/xive.h +++ b/include/xive.h @@ -460,4 +460,8 @@ void xive_cpu_callin(struct cpu_thread *cpu); */ void *xive_get_trigger_port(uint32_t girq); +/* To be used by special EOI override in PSI */ +struct irq_source; +void __xive_source_eoi(struct irq_source *is, uint32_t isn); + #endif /* __XIVE_H__ */ |