On Mon May 13, 2024 at 9:49 PM AEST, Cédric Le Goater wrote: > Hello, > > On 5/10/24 16:30, Nicholas Piggin wrote: > > The POWER8 LPC ISA device irqs all get combined and reported to the line > > connected the PSI LPCHC irq. POWER9 changed this so only internal LPC > > host controller irqs use that line, and the device irqs get routed to > > 4 new lines connected to PSI SERIRQ0-3. > > > > POWER9 also introduced a new feature that automatically clears the irq > > status in the LPC host controller when EOI'ed, so software does not have > > to. > > > > The powernv OPAL (skiboot) firmware managed to work because the LPCHC > > irq handler scanned all LPC irqs and handled those including clearing > > status even on POWER9 systems. So LPC irqs worked despite OPAL thinking > > it was running in POWER9 mode. After this change, UART interrupts show > > up on serirq1 which is where OPAL routes them to: > > > > cat /proc/interrupts > > ... > > 20: 0 XIVE-IRQ 1048563 Level opal-psi#0:lpchc > > ... > > 25: 34 XIVE-IRQ 1048568 Level opal-psi#0:lpc_serirq_mux1 > > > > Whereas they previously turn up on lpchc. > > > > Signed-off-by: Nicholas Piggin <npig...@gmail.com> > > --- > > include/hw/ppc/pnv_lpc.h | 12 ++++- > > hw/ppc/pnv.c | 38 +++++++++++++-- > > hw/ppc/pnv_lpc.c | 100 +++++++++++++++++++++++++++++++++++---- > > 3 files changed, 136 insertions(+), 14 deletions(-) > > > > diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h > > index 5d22c45570..57e324b4dc 100644 > > --- a/include/hw/ppc/pnv_lpc.h > > +++ b/include/hw/ppc/pnv_lpc.h > > @@ -84,8 +84,18 @@ struct PnvLpcController { > > /* XSCOM registers */ > > MemoryRegion xscom_regs; > > > > + /* > > + * In P8, ISA irqs are combined with internal sources to drive the > > + * LPCHC interrupt output. P9 ISA irqs raise one of 4 lines that > > + * drive PSI SERIRQ irqs, routing according to OPB routing registers. > > + */ > > + bool psi_serirq; > > + > > /* PSI to generate interrupts */ > > - qemu_irq psi_irq; > > + qemu_irq psi_irq_lpchc; > > + > > + /* P9 introduced a serirq mode */ > > + qemu_irq psi_irq_serirq[4]; > > }; > > > > struct PnvLpcClass { > > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c > > index 6e3a5ccdec..3b1c05a1d8 100644 > > --- a/hw/ppc/pnv.c > > +++ b/hw/ppc/pnv.c > > @@ -744,18 +744,48 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip > > *chip, Error **errp) > > static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp) > > { > > Pnv9Chip *chip9 = PNV9_CHIP(chip); > > - qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPCHC); > > > > - qdev_connect_gpio_out(DEVICE(&chip9->lpc), 0, irq); > > The pnv_chip_power8*_isa_create() routines also need an update.
Good catch, thank you. > > + qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "LPCHC", 0, > > + qdev_get_gpio_in(DEVICE(&chip9->psi), > > + PSIHB9_IRQ_LPCHC)); > > + > > + qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 0, > > + qdev_get_gpio_in(DEVICE(&chip9->psi), > > + PSIHB9_IRQ_LPC_SIRQ0)); > > + qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 1, > > + qdev_get_gpio_in(DEVICE(&chip9->psi), > > + PSIHB9_IRQ_LPC_SIRQ1)); > > + qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 2, > > + qdev_get_gpio_in(DEVICE(&chip9->psi), > > + PSIHB9_IRQ_LPC_SIRQ2)); > > + qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 3, > > + qdev_get_gpio_in(DEVICE(&chip9->psi), > > + PSIHB9_IRQ_LPC_SIRQ3)); > > + > > return pnv_lpc_isa_create(&chip9->lpc, false, errp); > > } > > > > static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp) > > { > > Pnv10Chip *chip10 = PNV10_CHIP(chip); > > - qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip10->psi), > > PSIHB9_IRQ_LPCHC); > > > > - qdev_connect_gpio_out(DEVICE(&chip10->lpc), 0, irq); > > + qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "LPCHC", 0, > > + qdev_get_gpio_in(DEVICE(&chip10->psi), > > + PSIHB9_IRQ_LPCHC)); > > + > > + qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 0, > > + qdev_get_gpio_in(DEVICE(&chip10->psi), > > + PSIHB9_IRQ_LPC_SIRQ0)); > > + qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 1, > > + qdev_get_gpio_in(DEVICE(&chip10->psi), > > + PSIHB9_IRQ_LPC_SIRQ1)); > > + qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 2, > > + qdev_get_gpio_in(DEVICE(&chip10->psi), > > + PSIHB9_IRQ_LPC_SIRQ2)); > > + qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 3, > > + qdev_get_gpio_in(DEVICE(&chip10->psi), > > + PSIHB9_IRQ_LPC_SIRQ3)); > > + > > return pnv_lpc_isa_create(&chip10->lpc, false, errp); > > } > > > > diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c > > index d692858bee..e28eae672f 100644 > > --- a/hw/ppc/pnv_lpc.c > > +++ b/hw/ppc/pnv_lpc.c > > @@ -64,6 +64,7 @@ enum { > > #define LPC_HC_IRQSER_START_4CLK 0x00000000 > > #define LPC_HC_IRQSER_START_6CLK 0x01000000 > > #define LPC_HC_IRQSER_START_8CLK 0x02000000 > > +#define LPC_HC_IRQSER_AUTO_CLEAR 0x00800000 > > #define LPC_HC_IRQMASK 0x34 /* same bit defs as > > LPC_HC_IRQSTAT */ > > #define LPC_HC_IRQSTAT 0x38 > > #define LPC_HC_IRQ_SERIRQ0 0x80000000 /* all bits down to > > ... */ > > @@ -420,6 +421,34 @@ static const MemoryRegionOps pnv_lpc_mmio_ops = { > > .endianness = DEVICE_BIG_ENDIAN, > > }; > > > > +/* POWER9 serirq routing, see below */ > > +static int irq_to_serirq_route[ISA_NUM_IRQS]; > > This static is not friendly for multichip machines. Could we avoid it and > move the IRQ routes under PnvLpcController ? Ah yes I don't know what I was thinking. It's trivial to move under the controller. I will post a v2 in a bit. Thanks, Nick