Re: [PATCH 19/26] hw/misc: pfsoc: Honor PolarFire service notification requests
Chao Liu <[email protected]> Mon, 27 Jul 2026 13:32:05 +0800
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
On Thu, Jul 23, 2026 at 11:18:46PM +0800, Bin Meng wrote: > Polling firmware requests system services without requesting an > interrupt. The old model ignored this distinction: > > 1. HSS requests the serial number with REQUEST set and NOTIFY clear. > 2. QEMU synchronously fills the mailbox and clears REQUEST. > 3. QEMU incorrectly asserts PLIC source 96. > 4. HSS polls REQUEST and neither waits for nor handles the interrupt. > 5. PLIC source 96 remains pending. > 6. Linux registers the MPFS mailbox driver. > 7. The stale interrupt immediately enters mpfs_mbox_inbox_isr(). > 8. Linux has not submitted a request or installed its response pointer. > 9. The ISR dereferences that null pointer and faults near address 0x10. > > Honor SERVICES_CR.NOTIFY, let IOSCB own the pending interrupt state, > and route the SYSREG acknowledgement through an IOSCB clear input. > > Signed-off-by: Bin Meng <[email protected]> Reviewed-by: Chao Liu <[email protected]> Thanks, Chao > --- > > include/hw/misc/mchp_pfsoc_ioscb.h | 2 ++ > hw/misc/mchp_pfsoc_ioscb.c | 39 +++++++++++++++++++++++++++--- > hw/misc/mchp_pfsoc_sysreg.c | 9 ++++++- > hw/riscv/microchip_pfsoc.c | 6 ++--- > 4 files changed, 49 insertions(+), 7 deletions(-) > > diff --git a/include/hw/misc/mchp_pfsoc_ioscb.h b/include/hw/misc/mchp_pfsoc_ioscb.h > index fd31427304..e39d995b64 100644 > --- a/include/hw/misc/mchp_pfsoc_ioscb.h > +++ b/include/hw/misc/mchp_pfsoc_ioscb.h > @@ -26,6 +26,7 @@ > #include "hw/core/sysbus.h" > > #define MCHP_PFSOC_IOSCB_MAILBOX_SIZE 0x1000 > +#define MCHP_PFSOC_IOSCB_IRQ_CLEAR "irq-clear" > > typedef struct MchpPfSoCIoscbState { > SysBusDevice parent; > @@ -53,6 +54,7 @@ typedef struct MchpPfSoCIoscbState { > uint32_t services_sr; > uint8_t mailbox_data[MCHP_PFSOC_IOSCB_MAILBOX_SIZE]; > char *serial_number; > + bool irq_pending; > qemu_irq irq; > } MchpPfSoCIoscbState; > > diff --git a/hw/misc/mchp_pfsoc_ioscb.c b/hw/misc/mchp_pfsoc_ioscb.c > index 7c82b55986..ccc2201b7a 100644 > --- a/hw/misc/mchp_pfsoc_ioscb.c > +++ b/hw/misc/mchp_pfsoc_ioscb.c > @@ -192,12 +192,13 @@ static const MemoryRegionOps mchp_pfsoc_io_calib_ddr_ops = { > > #define SERVICES_CR 0x50 > #define SERVICES_CR_REQUEST BIT(0) > +#define SERVICES_CR_NOTIFY BIT(3) > #define SERVICES_CR_COMMAND_SHIFT 16 > #define SERVICES_CR_COMMAND_WIDTH 8 > #define SERVICES_CR_COMMAND_MASK \ > MAKE_64BIT_MASK(SERVICES_CR_COMMAND_SHIFT, SERVICES_CR_COMMAND_WIDTH) > #define SERVICES_CR_MASK \ > - (SERVICES_CR_REQUEST | SERVICES_CR_COMMAND_MASK) > + (SERVICES_CR_REQUEST | SERVICES_CR_NOTIFY | SERVICES_CR_COMMAND_MASK) > #define SERVICES_SR 0x54 > #define SERVICES_SR_STATUS_SHIFT 16 > #define SERVICES_COMMAND_SERIAL_NUMBER 0 > @@ -205,6 +206,21 @@ static const MemoryRegionOps mchp_pfsoc_io_calib_ddr_ops = { > #define SERVICES_STATUS_FAILED 1 > #define SERVICES_MAILBOX_RESPONSE_OFFSET 0 > > +static void mchp_pfsoc_ioscb_update_irq(MchpPfSoCIoscbState *s) > +{ > + qemu_set_irq(s->irq, s->irq_pending); > +} > + > +static void mchp_pfsoc_ioscb_clear_irq(void *opaque, int n, int level) > +{ > + MchpPfSoCIoscbState *s = opaque; > + > + if (level) { > + s->irq_pending = false; > + mchp_pfsoc_ioscb_update_irq(s); > + } > +} > + > static void services_cr_write(MchpPfSoCIoscbState *s, uint32_t value) > { > uint32_t command; > @@ -236,7 +252,15 @@ static void services_cr_write(MchpPfSoCIoscbState *s, uint32_t value) > } > > s->services_sr = status << SERVICES_SR_STATUS_SHIFT; > - qemu_irq_raise(s->irq); > + /* > + * HSS and U-Boot submit polling requests with REQUEST set and NOTIFY > + * clear, then poll REQUEST/BUSY for completion. Linux sets both bits > + * and expects completion through PLIC source 96. > + */ > + if (value & SERVICES_CR_NOTIFY) { > + s->irq_pending = true; > + mchp_pfsoc_ioscb_update_irq(s); > + } > } > > static uint64_t mchp_pfsoc_ctrl_read(void *opaque, hwaddr offset, > @@ -325,7 +349,8 @@ static void mchp_pfsoc_ioscb_reset(DeviceState *dev) > s->services_cr = 0; > s->services_sr = 0; > memset(s->mailbox_data, 0, sizeof(s->mailbox_data)); > - qemu_irq_lower(s->irq); > + s->irq_pending = false; > + mchp_pfsoc_ioscb_update_irq(s); > } > > static const Property mchp_pfsoc_ioscb_properties[] = { > @@ -333,6 +358,13 @@ static const Property mchp_pfsoc_ioscb_properties[] = { > MchpPfSoCIoscbState, serial_number), > }; > > +static void mchp_pfsoc_ioscb_init(Object *obj) > +{ > + /* Accept service interrupt acknowledgements from SYSREG MESSAGE_INT */ > + qdev_init_gpio_in_named(DEVICE(obj), mchp_pfsoc_ioscb_clear_irq, > + MCHP_PFSOC_IOSCB_IRQ_CLEAR, 1); > +} > + > static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp) > { > MchpPfSoCIoscbState *s = MCHP_PFSOC_IOSCB(dev); > @@ -456,6 +488,7 @@ static const TypeInfo mchp_pfsoc_ioscb_info = { > .name = TYPE_MCHP_PFSOC_IOSCB, > .parent = TYPE_SYS_BUS_DEVICE, > .instance_size = sizeof(MchpPfSoCIoscbState), > + .instance_init = mchp_pfsoc_ioscb_init, > .class_init = mchp_pfsoc_ioscb_class_init, > }; > > diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c > index 1d9154280a..899b485da6 100644 > --- a/hw/misc/mchp_pfsoc_sysreg.c > +++ b/hw/misc/mchp_pfsoc_sysreg.c > @@ -77,7 +77,14 @@ static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr offset, > } > break; > case MESSAGE_INT: > - qemu_irq_lower(s->irq); > + /* > + * A MESSAGE_INT write is an acknowledgement event, not a level that > + * remains asserted. Model it as an active-high pulse. The rising edge > + * invokes IOSCB's irq-clear input with level 1, which clears > + * irq_pending and lowers PLIC source 96. The falling edge invokes the > + * input with level 0 and is ignored. > + */ > + qemu_irq_pulse(s->irq); > break; > default: > qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " > diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c > index 63658fbeb0..f348de6fd4 100644 > --- a/hw/riscv/microchip_pfsoc.c > +++ b/hw/riscv/microchip_pfsoc.c > @@ -333,9 +333,6 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) > sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp); > sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysreg), 0, > memmap[MICROCHIP_PFSOC_SYSREG].base); > - sysbus_connect_irq(SYS_BUS_DEVICE(&s->sysreg), 0, > - qdev_get_gpio_in(DEVICE(s->plic), > - MICROCHIP_PFSOC_MAILBOX_IRQ)); > > /* AXISW */ > create_unimplemented_device("microchip.pfsoc.axisw", > @@ -489,6 +486,9 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) > sysbus_connect_irq(SYS_BUS_DEVICE(&s->ioscb), 0, > qdev_get_gpio_in(DEVICE(s->plic), > MICROCHIP_PFSOC_MAILBOX_IRQ)); > + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sysreg), 0, > + qdev_get_gpio_in_named(DEVICE(&s->ioscb), > + MCHP_PFSOC_IOSCB_IRQ_CLEAR, 0)); > > /* FPGA Fabric */ > create_unimplemented_device("microchip.pfsoc.fabricfic3", > -- > 2.34.1 >