On Wed, 2021-04-07 at 19:16 +0200, Cédric Le Goater wrote: > When we introduced support for the AST2600 SoC, the XDMA controller > was forgotten. It went unnoticed because it's not used under > emulation. > But the register layout being different, the reset procedure is bogus > and this breaks kexec. > > Add a AspeedXDMAClass to take into account the register differences.
Thanks Cedric! Reviewed-by: Eddie James <eaja...@linux.ibm.com> > > Cc: Eddie James <eaja...@linux.ibm.com> > Signed-off-by: Cédric Le Goater <c...@kaod.org> > --- > include/hw/misc/aspeed_xdma.h | 17 ++++- > hw/arm/aspeed_ast2600.c | 3 +- > hw/arm/aspeed_soc.c | 3 +- > hw/misc/aspeed_xdma.c | 124 +++++++++++++++++++++++++++----- > -- > 4 files changed, 121 insertions(+), 26 deletions(-) > > diff --git a/include/hw/misc/aspeed_xdma.h > b/include/hw/misc/aspeed_xdma.h > index a2dea96984f3..b1478fd1c681 100644 > --- a/include/hw/misc/aspeed_xdma.h > +++ b/include/hw/misc/aspeed_xdma.h > @@ -13,7 +13,10 @@ > #include "qom/object.h" > > #define TYPE_ASPEED_XDMA "aspeed.xdma" > -OBJECT_DECLARE_SIMPLE_TYPE(AspeedXDMAState, ASPEED_XDMA) > +#define TYPE_ASPEED_2400_XDMA TYPE_ASPEED_XDMA "-ast2400" > +#define TYPE_ASPEED_2500_XDMA TYPE_ASPEED_XDMA "-ast2500" > +#define TYPE_ASPEED_2600_XDMA TYPE_ASPEED_XDMA "-ast2600" > +OBJECT_DECLARE_TYPE(AspeedXDMAState, AspeedXDMAClass, ASPEED_XDMA) > > #define ASPEED_XDMA_NUM_REGS (ASPEED_XDMA_REG_SIZE / > sizeof(uint32_t)) > #define ASPEED_XDMA_REG_SIZE 0x7C > @@ -28,4 +31,16 @@ struct AspeedXDMAState { > uint32_t regs[ASPEED_XDMA_NUM_REGS]; > }; > > +struct AspeedXDMAClass { > + SysBusDeviceClass parent_class; > + > + uint8_t cmdq_endp; > + uint8_t cmdq_wrp; > + uint8_t cmdq_rdp; > + uint8_t intr_ctrl; > + uint32_t intr_ctrl_mask; > + uint8_t intr_status; > + uint32_t intr_complete; > +}; > + > #endif /* ASPEED_XDMA_H */ > diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c > index e0fbb020c770..c60824bfeecb 100644 > --- a/hw/arm/aspeed_ast2600.c > +++ b/hw/arm/aspeed_ast2600.c > @@ -187,7 +187,8 @@ static void aspeed_soc_ast2600_init(Object *obj) > object_initialize_child(obj, "mii[*]", &s->mii[i], > TYPE_ASPEED_MII); > } > > - object_initialize_child(obj, "xdma", &s->xdma, > TYPE_ASPEED_XDMA); > + snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", > socname); > + object_initialize_child(obj, "xdma", &s->xdma, typename); > > snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); > object_initialize_child(obj, "gpio", &s->gpio, typename); > diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c > index 8ed29113f79f..4a95d27d9d63 100644 > --- a/hw/arm/aspeed_soc.c > +++ b/hw/arm/aspeed_soc.c > @@ -199,7 +199,8 @@ static void aspeed_soc_init(Object *obj) > TYPE_FTGMAC100); > } > > - object_initialize_child(obj, "xdma", &s->xdma, > TYPE_ASPEED_XDMA); > + snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", > socname); > + object_initialize_child(obj, "xdma", &s->xdma, typename); > > snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); > object_initialize_child(obj, "gpio", &s->gpio, typename); > diff --git a/hw/misc/aspeed_xdma.c b/hw/misc/aspeed_xdma.c > index 533d237e3ce2..1c21577c98c9 100644 > --- a/hw/misc/aspeed_xdma.c > +++ b/hw/misc/aspeed_xdma.c > @@ -30,6 +30,19 @@ > #define XDMA_IRQ_ENG_STAT_US_COMP BIT(4) > #define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5) > #define XDMA_IRQ_ENG_STAT_RESET 0xF8000000 > + > +#define XDMA_AST2600_BMC_CMDQ_ADDR 0x14 > +#define XDMA_AST2600_BMC_CMDQ_ENDP 0x18 > +#define XDMA_AST2600_BMC_CMDQ_WRP 0x1c > +#define XDMA_AST2600_BMC_CMDQ_RDP 0x20 > +#define XDMA_AST2600_IRQ_CTRL 0x38 > +#define XDMA_AST2600_IRQ_CTRL_US_COMP BIT(16) > +#define XDMA_AST2600_IRQ_CTRL_DS_COMP BIT(17) > +#define XDMA_AST2600_IRQ_CTRL_W_MASK 0x017003FF > +#define XDMA_AST2600_IRQ_STATUS 0x3c > +#define XDMA_AST2600_IRQ_STATUS_US_COMP BIT(16) > +#define XDMA_AST2600_IRQ_STATUS_DS_COMP BIT(17) > + > #define XDMA_MEM_SIZE 0x1000 > > #define TO_REG(addr) ((addr) / sizeof(uint32_t)) > @@ -52,56 +65,48 @@ static void aspeed_xdma_write(void *opaque, > hwaddr addr, uint64_t val, > unsigned int idx; > uint32_t val32 = (uint32_t)val; > AspeedXDMAState *xdma = opaque; > + AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma); > > if (addr >= ASPEED_XDMA_REG_SIZE) { > return; > } > > - switch (addr) { > - case XDMA_BMC_CMDQ_ENDP: > + if (addr == axc->cmdq_endp) { > xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK; > - break; > - case XDMA_BMC_CMDQ_WRP: > + } else if (addr == axc->cmdq_wrp) { > idx = TO_REG(addr); > xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK; > - xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx]; > + xdma->regs[TO_REG(axc->cmdq_rdp)] = xdma->regs[idx]; > > trace_aspeed_xdma_write(addr, val); > > if (xdma->bmc_cmdq_readp_set) { > xdma->bmc_cmdq_readp_set = 0; > } else { > - xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |= > - XDMA_IRQ_ENG_STAT_US_COMP | > XDMA_IRQ_ENG_STAT_DS_COMP; > + xdma->regs[TO_REG(axc->intr_status)] |= axc- > >intr_complete; > > - if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] & > - (XDMA_IRQ_ENG_CTRL_US_COMP | > XDMA_IRQ_ENG_CTRL_DS_COMP)) > + if (xdma->regs[TO_REG(axc->intr_ctrl)] & axc- > >intr_complete) { > qemu_irq_raise(xdma->irq); > + } > } > - break; > - case XDMA_BMC_CMDQ_RDP: > + } else if (addr == axc->cmdq_rdp) { > trace_aspeed_xdma_write(addr, val); > > if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) { > xdma->bmc_cmdq_readp_set = 1; > } > - break; > - case XDMA_IRQ_ENG_CTRL: > - xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK; > - break; > - case XDMA_IRQ_ENG_STAT: > + } else if (addr == axc->intr_ctrl) { > + xdma->regs[TO_REG(addr)] = val32 & axc->intr_ctrl_mask; > + } else if (addr == axc->intr_status) { > trace_aspeed_xdma_write(addr, val); > > idx = TO_REG(addr); > - if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | > XDMA_IRQ_ENG_STAT_DS_COMP)) { > - xdma->regs[idx] &= > - ~(XDMA_IRQ_ENG_STAT_US_COMP | > XDMA_IRQ_ENG_STAT_DS_COMP); > + if (val32 & axc->intr_complete) { > + xdma->regs[idx] &= ~axc->intr_complete; > qemu_irq_lower(xdma->irq); > } > - break; > - default: > + } else { > xdma->regs[TO_REG(addr)] = val32; > - break; > } > } > > @@ -127,10 +132,11 @@ static void aspeed_xdma_realize(DeviceState > *dev, Error **errp) > static void aspeed_xdma_reset(DeviceState *dev) > { > AspeedXDMAState *xdma = ASPEED_XDMA(dev); > + AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma); > > xdma->bmc_cmdq_readp_set = 0; > memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE); > - xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET; > + xdma->regs[TO_REG(axc->intr_status)] = XDMA_IRQ_ENG_STAT_RESET; > > qemu_irq_lower(xdma->irq); > } > @@ -144,6 +150,73 @@ static const VMStateDescription > aspeed_xdma_vmstate = { > }, > }; > > +static void aspeed_2600_xdma_class_init(ObjectClass *klass, void > *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); > + > + dc->desc = "ASPEED 2600 XDMA Controller"; > + > + axc->cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP; > + axc->cmdq_wrp = XDMA_AST2600_BMC_CMDQ_WRP; > + axc->cmdq_rdp = XDMA_AST2600_BMC_CMDQ_RDP; > + axc->intr_ctrl = XDMA_AST2600_IRQ_CTRL; > + axc->intr_ctrl_mask = XDMA_AST2600_IRQ_CTRL_W_MASK; > + axc->intr_status = XDMA_AST2600_IRQ_STATUS; > + axc->intr_complete = XDMA_AST2600_IRQ_STATUS_US_COMP | > + XDMA_AST2600_IRQ_STATUS_DS_COMP; > +} > + > +static const TypeInfo aspeed_2600_xdma_info = { > + .name = TYPE_ASPEED_2600_XDMA, > + .parent = TYPE_ASPEED_XDMA, > + .class_init = aspeed_2600_xdma_class_init, > +}; > + > +static void aspeed_2500_xdma_class_init(ObjectClass *klass, void > *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); > + > + dc->desc = "ASPEED 2500 XDMA Controller"; > + > + axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP; > + axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP; > + axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP; > + axc->intr_ctrl = XDMA_IRQ_ENG_CTRL; > + axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK; > + axc->intr_status = XDMA_IRQ_ENG_STAT; > + axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | > XDMA_IRQ_ENG_STAT_DS_COMP; > +}; > + > +static const TypeInfo aspeed_2500_xdma_info = { > + .name = TYPE_ASPEED_2500_XDMA, > + .parent = TYPE_ASPEED_XDMA, > + .class_init = aspeed_2500_xdma_class_init, > +}; > + > +static void aspeed_2400_xdma_class_init(ObjectClass *klass, void > *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); > + > + dc->desc = "ASPEED 2400 XDMA Controller"; > + > + axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP; > + axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP; > + axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP; > + axc->intr_ctrl = XDMA_IRQ_ENG_CTRL; > + axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK; > + axc->intr_status = XDMA_IRQ_ENG_STAT; > + axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | > XDMA_IRQ_ENG_STAT_DS_COMP; > +}; > + > +static const TypeInfo aspeed_2400_xdma_info = { > + .name = TYPE_ASPEED_2400_XDMA, > + .parent = TYPE_ASPEED_XDMA, > + .class_init = aspeed_2400_xdma_class_init, > +}; > + > static void aspeed_xdma_class_init(ObjectClass *classp, void *data) > { > DeviceClass *dc = DEVICE_CLASS(classp); > @@ -158,10 +231,15 @@ static const TypeInfo aspeed_xdma_info = { > .parent = TYPE_SYS_BUS_DEVICE, > .instance_size = sizeof(AspeedXDMAState), > .class_init = aspeed_xdma_class_init, > + .class_size = sizeof(AspeedXDMAClass), > + .abstract = true, > }; > > static void aspeed_xdma_register_type(void) > { > type_register_static(&aspeed_xdma_info); > + type_register_static(&aspeed_2400_xdma_info); > + type_register_static(&aspeed_2500_xdma_info); > + type_register_static(&aspeed_2600_xdma_info); > } > type_init(aspeed_xdma_register_type);