diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/lpc.c | 25 | ||||
-rw-r--r-- | hw/psi.c | 41 | ||||
-rw-r--r-- | hw/xive.c | 12 |
3 files changed, 72 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); |