On Tue, Sep 06, 2022 at 10:05:51PM +0000, Titus Rwantare wrote: > This allows BMC firmware for npcm7xx BMCs to talk to a PECI client > in qemu. > > Signed-off-by: Titus Rwantare <tit...@google.com> > Reviewed-by: Patrick Venture <vent...@google.com>
Looks good to me! Reviewed-by: Peter Delevoryas <pe...@pjd.dev> > --- > MAINTAINERS | 3 +- > hw/arm/Kconfig | 1 + > hw/arm/npcm7xx.c | 9 ++ > hw/peci/meson.build | 1 + > hw/peci/npcm7xx_peci.c | 204 +++++++++++++++++++++++++++++++++ > hw/peci/trace-events | 5 + > include/hw/arm/npcm7xx.h | 2 + > include/hw/peci/npcm7xx_peci.h | 37 ++++++ > 8 files changed, 261 insertions(+), 1 deletion(-) > create mode 100644 hw/peci/npcm7xx_peci.c > create mode 100644 include/hw/peci/npcm7xx_peci.h > > diff --git a/MAINTAINERS b/MAINTAINERS > index 14ab29679d..f87dfe5bfa 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -2959,7 +2959,7 @@ R: Paolo Bonzini <pbonz...@redhat.com> > R: Bandan Das <b...@redhat.com> > R: Stefan Hajnoczi <stefa...@redhat.com> > R: Thomas Huth <th...@redhat.com> > -R: Darren Kenny <darren.ke...@oracle.com> > +R: Darren Kenny <darren.ke...@oracle.com> > R: Qiuhao Li <qiuhao...@outlook.com> > S: Maintained > F: tests/qtest/fuzz/ > @@ -3218,6 +3218,7 @@ S: Maintained > F: hw/peci/peci-core.c > F: hw/peci/peci-client.c > F: include/hw/peci/peci.h > +F: hw/peci/npcm7xx_peci.c > > Firmware schema specifications > M: Philippe Mathieu-Daudé <f4...@amsat.org> > diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig > index 15fa79afd3..cb38c6c88f 100644 > --- a/hw/arm/Kconfig > +++ b/hw/arm/Kconfig > @@ -408,6 +408,7 @@ config NPCM7XX > select SSI > select UNIMP > select PCA954X > + select PECI > > config FSL_IMX25 > bool > diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c > index d85cc02765..d408dd7eb4 100644 > --- a/hw/arm/npcm7xx.c > +++ b/hw/arm/npcm7xx.c > @@ -45,6 +45,7 @@ > #define NPCM7XX_CLK_BA (0xf0801000) > #define NPCM7XX_MC_BA (0xf0824000) > #define NPCM7XX_RNG_BA (0xf000b000) > +#define NPCM7XX_PECI_BA (0xf0100000) > > /* USB Host modules */ > #define NPCM7XX_EHCI_BA (0xf0806000) > @@ -83,6 +84,7 @@ enum NPCM7xxInterrupt { > NPCM7XX_UART1_IRQ, > NPCM7XX_UART2_IRQ, > NPCM7XX_UART3_IRQ, > + NPCM7XX_PECI_IRQ = 6, > NPCM7XX_EMC1RX_IRQ = 15, > NPCM7XX_EMC1TX_IRQ, > NPCM7XX_MMC_IRQ = 26, > @@ -445,6 +447,7 @@ static void npcm7xx_init(Object *obj) > } > > object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI); > + object_initialize_child(obj, "peci", &s->peci, TYPE_NPCM7XX_PECI); > } > > static void npcm7xx_realize(DeviceState *dev, Error **errp) > @@ -715,6 +718,12 @@ static void npcm7xx_realize(DeviceState *dev, Error > **errp) > sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0, > npcm7xx_irq(s, NPCM7XX_MMC_IRQ)); > > + /* PECI */ > + sysbus_realize(SYS_BUS_DEVICE(&s->peci), &error_abort); > + sysbus_mmio_map(SYS_BUS_DEVICE(&s->peci), 0, NPCM7XX_PECI_BA); > + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0, > + npcm7xx_irq(s, NPCM7XX_PECI_IRQ)); > + > create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * > KiB); > create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * > KiB); > create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * > KiB); > diff --git a/hw/peci/meson.build b/hw/peci/meson.build > index 01cfa95abe..ee033eb915 100644 > --- a/hw/peci/meson.build > +++ b/hw/peci/meson.build > @@ -1 +1,2 @@ > softmmu_ss.add(when: 'CONFIG_PECI', if_true: files('peci-core.c', > 'peci-client.c')) > +softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_peci.c')) > diff --git a/hw/peci/npcm7xx_peci.c b/hw/peci/npcm7xx_peci.c > new file mode 100644 > index 0000000000..17a2642898 > --- /dev/null > +++ b/hw/peci/npcm7xx_peci.c > @@ -0,0 +1,204 @@ > +/* > + * Nuvoton NPCM7xx PECI Module > + * > + * Copyright 2021 Google LLC > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + */ > + > +#include "qemu/osdep.h" > +#include "hw/peci/npcm7xx_peci.h" > +#include "qemu/bitops.h" > +#include "qemu/log.h" > +#include "qemu/units.h" > +#include "trace.h" > + > +#define PECI_CTL_STS 0 > +#define PECI_CTL_STS_DONE_EN BIT(6) > +#define PECI_CTL_STS_ABRT_ERR BIT(4) > +#define PECI_CTL_STS_CRC_ERR BIT(3) > +#define PECI_CTL_STS_DONE BIT(1) > +#define PECI_CTL_STS_START_BUSY BIT(0) > +#define PECI_RD_LENGTH 0x4 > +#define PECI_ADDR 0x8 > +#define PECI_CMD 0xC > +#define PECI_CTL2 0x10 > +#define PECI_WR_LENGTH 0x1C > +#define PECI_PDDR 0x2C > +#define PECI_DAT_INOUT(reg) (0x100 + (reg) * 4) > + > +static uint64_t npcm7xx_peci_read(void *opaque, hwaddr offset, unsigned size) > +{ > + NPCM7xxPECIState *ps = NPCM7XX_PECI(opaque); > + uint8_t ret = 0; > + > + if (!ps->bus->num_clients) { > + qemu_log_mask(LOG_GUEST_ERROR, "%s: no peci clients added to > board\n", > + __func__); > + return 0; > + } > + > + qemu_irq_lower(ps->irq); > + > + switch (offset) { > + case PECI_CTL_STS: > + ret = ps->status; > + break; > + > + case PECI_RD_LENGTH: > + ret = ps->pcmd.rd_length; > + break; > + > + case PECI_ADDR: > + ret = ps->pcmd.addr; > + break; > + > + case PECI_CMD: > + ret = ps->pcmd.cmd; > + break; > + > + case PECI_CTL2: > + ret = ps->ctl2; > + break; > + > + case PECI_WR_LENGTH: > + ret = ps->pcmd.wr_length; > + break; > + > + case PECI_PDDR: > + qemu_log_mask(LOG_UNIMP, "%s: PECI PDDR is unimplemented.\n", > __func__); > + ret = ps->pddr; /* undoc register */ > + break; > + > + case PECI_DAT_INOUT(0) ... PECI_DAT_INOUT(63): > + ret = ps->pcmd.tx[(offset - PECI_DAT_INOUT(0)) / 4]; > + break; > + > + default: > + qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register 0x%lx\n", > + __func__, offset); > + ret = 0xff; > + break; > + } > + trace_npcm7xx_peci_read(offset, ret); > + return ret; > +} > + > +static void npcm7xx_peci_write(void *opaque, hwaddr offset, uint64_t input, > + unsigned size) > +{ > + NPCM7xxPECIState *ps = NPCM7XX_PECI(opaque); > + uint8_t data = input & 0xff; > + > + trace_npcm7xx_peci_write(offset, input); > + > + /* ignore writes if the bus has not been populated */ > + if (!ps->bus->num_clients) { > + qemu_log_mask(LOG_GUEST_ERROR, "%s: no peci clients added to > board\n", > + __func__); > + return; > + } > + > + switch (offset) { > + case PECI_CTL_STS: > + ps->status = data; > + /* STS_START busy is set by the bmc when the request is written */ > + if (data & PECI_CTL_STS_START_BUSY) { > + if (!peci_handle_cmd(ps->bus, &(ps->pcmd))) { > + ps->status |= PECI_CTL_STS_ABRT_ERR; > + } > + ps->status |= PECI_CTL_STS_DONE; > + ps->status &= ~PECI_CTL_STS_START_BUSY; > + qemu_irq_raise(ps->irq); > + } > + break; > + > + case PECI_RD_LENGTH: > + ps->pcmd.rd_length = data; > + break; > + > + case PECI_ADDR: > + ps->pcmd.addr = data; > + break; > + > + case PECI_CMD: > + ps->pcmd.cmd = data; > + break; > + > + case PECI_CTL2: > + ps->ctl2 = data; > + break; > + > + case PECI_WR_LENGTH: > + ps->pcmd.wr_length = data; > + break; > + > + case PECI_PDDR: > + ps->pddr = data; > + break; > + > + case PECI_DAT_INOUT(0) ... PECI_DAT_INOUT(63): > + ps->pcmd.rx[(offset - PECI_DAT_INOUT(0)) / 4] = data; > + break; > + > + default: > + qemu_log_mask(LOG_GUEST_ERROR, > + "%s: to unknown register 0x%lx : 0x%lx\n", > + __func__, offset, input); > + return; > + } > + > +} > + > +static void npcm7xx_peci_reset(Object *obj, ResetType type) > +{ > + NPCM7xxPECIState *ps = NPCM7XX_PECI(obj); > + > + ps->status = PECI_CTL_STS_DONE_EN; > +} > + > +static const MemoryRegionOps npcm7xx_peci_ops = { > + .read = npcm7xx_peci_read, > + .write = npcm7xx_peci_write, > + .endianness = DEVICE_NATIVE_ENDIAN, > + .valid = { > + .min_access_size = 1, > + .min_access_size = 1, > + .unaligned = false, > + }, > +}; > + > +static void npcm7xx_peci_realize(DeviceState *dev, Error **errp) > +{ > + NPCM7xxPECIState *ps = NPCM7XX_PECI(dev); > + SysBusDevice *sbd = &ps->parent; > + > + memory_region_init_io(&ps->iomem, OBJECT(ps), &npcm7xx_peci_ops, ps, > + TYPE_NPCM7XX_PECI, 4 * KiB); > + > + sysbus_init_mmio(sbd, &ps->iomem); > + sysbus_init_irq(sbd, &ps->irq); > + > + ps->bus = peci_bus_create(DEVICE(ps)); > +} > + > +static void npcm7xx_peci_class_init(ObjectClass *klass, void *data) > +{ > + ResettableClass *rc = RESETTABLE_CLASS(klass); > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + dc->desc = "NPCM7xx PECI Module"; > + dc->realize = npcm7xx_peci_realize; > + rc->phases.enter = npcm7xx_peci_reset; > +} > + > +static const TypeInfo npcm7xx_peci_types[] = { > + { > + .name = TYPE_NPCM7XX_PECI, > + .parent = TYPE_SYS_BUS_DEVICE, > + .instance_size = sizeof(NPCM7xxPECIState), > + .class_init = npcm7xx_peci_class_init, > + }, > +}; > + > +DEFINE_TYPES(npcm7xx_peci_types) > diff --git a/hw/peci/trace-events b/hw/peci/trace-events > index f90c998dd9..a895b21f7b 100644 > --- a/hw/peci/trace-events > +++ b/hw/peci/trace-events > @@ -3,3 +3,8 @@ > # peci-core.c > peci_handle_cmd(const char* s, uint8_t addr) "%s @ 0x%02" PRIx8 > peci_rd_pkg_cfg(const char* s) "%s" > + > +# npcm7xx_peci.c > +npcm7xx_peci_cmd(uint64_t cmd) "cmd: 0x%04" PRIx64 > +npcm7xx_peci_read(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " > value: 0x%08" PRIx64 > +npcm7xx_peci_write(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " > value: 0x%08" PRIx64 > diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h > index ce593235d9..9e7cf8b774 100644 > --- a/include/hw/arm/npcm7xx.h > +++ b/include/hw/arm/npcm7xx.h > @@ -30,6 +30,7 @@ > #include "hw/misc/npcm7xx_rng.h" > #include "hw/net/npcm7xx_emc.h" > #include "hw/nvram/npcm7xx_otp.h" > +#include "hw/peci/npcm7xx_peci.h" > #include "hw/timer/npcm7xx_timer.h" > #include "hw/ssi/npcm7xx_fiu.h" > #include "hw/usb/hcd-ehci.h" > @@ -105,6 +106,7 @@ typedef struct NPCM7xxState { > NPCM7xxFIUState fiu[2]; > NPCM7xxEMCState emc[2]; > NPCM7xxSDHCIState mmc; > + NPCM7xxPECIState peci; > } NPCM7xxState; > > #define TYPE_NPCM7XX "npcm7xx" > diff --git a/include/hw/peci/npcm7xx_peci.h b/include/hw/peci/npcm7xx_peci.h > new file mode 100644 > index 0000000000..421f445041 > --- /dev/null > +++ b/include/hw/peci/npcm7xx_peci.h > @@ -0,0 +1,37 @@ > +/* > + * Nuvoton NPCM7xx PECI Module > + * > + * Copyright 2021 Google LLC > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + */ > + > +#ifndef NPCM7XX_PECI_H > +#define NPCM7XX_PECI_H > + > +#include "exec/memory.h" > +#include "hw/irq.h" > +#include "hw/peci/peci.h" > +#include "hw/sysbus.h" > + > +typedef struct NPCM7xxPECIState { > + SysBusDevice parent; > + > + MemoryRegion iomem; > + > + PECIBus *bus; > + qemu_irq irq; > + > + PECICmd pcmd; > + > + /* Registers */ > + uint8_t status; > + uint8_t ctl2; > + uint8_t pddr; > +} NPCM7xxPECIState; > + > +#define TYPE_NPCM7XX_PECI "npcm7xx-peci" > +#define NPCM7XX_PECI(obj) \ > + OBJECT_CHECK(NPCM7xxPECIState, (obj), TYPE_NPCM7XX_PECI) > + > +#endif /* NPCM7XX_PECI_H */ > -- > 2.37.2.789.g6183377224-goog >