Hi Cédric > Subject: RE: [SPAM] [PATCH v2 03/14] hw/pci-host/aspeed: Add AST2600 PCIe > config space and host bridge > > Hi Cédric > > > Subject: Re: [SPAM] [PATCH v2 03/14] hw/pci-host/aspeed: Add AST2600 > > PCIe config space and host bridge > > > > On 9/11/25 09:24, Jamin Lin wrote: > > > Introduce PCIe config and host bridge model for the AST2600 platform. > > > > > > This patch adds support for the H2X (AHB to PCIe Bus Bridge) > > > controller with a 0x100 byte register space. The register layout is > > > shared between two root complexes: 0x00–0x7f is common, 0x80–0xbf > > > for RC_L, and 0xc0–0xff for RC_H. Only RC_H is modeled in this > > implementation. > > > > > > The RC_H bus uses bus numbers in the 0x80–0xff range instead of the > > > standard root bus 0x00. To allow the PCI subsystem to discover > > > devices, the host bridge logic remaps the root bus number back to > > > 0x00 whenever the configured bus number matches the "bus-nr" property. > > > > > > New MMIO callbacks are added for the H2X config space: > > > - aspeed_pcie_cfg_read() and aspeed_pcie_cfg_write() handle register > > > accesses. > > > - aspeed_pcie_cfg_readwrite() provides configuration read/write support. > > > - aspeed_pcie_cfg_translate_write() handles PCIe byte-enable semantics > for > > > write operations. > > > > > > The reset handler initializes the H2X register block with default > > > values as defined in the AST2600 datasheet. > > > > > > Additional changes: > > > - Implement ASPEED PCIe root complex (TYPE_ASPEED_PCIE_RC). > > > - Wire up interrupt propagation via aspeed_pcie_rc_set_irq(). > > > - Add tracepoints for config read/write and INTx handling. > > > > > > Signed-off-by: Jamin Lin <jamin_...@aspeedtech.com> > > > --- > > > include/hw/pci-host/aspeed_pcie.h | 58 ++++ > > > hw/pci-host/aspeed_pcie.c | 422 > > ++++++++++++++++++++++++++++++ > > > hw/pci-host/trace-events | 4 + > > > 3 files changed, 484 insertions(+) > > > > > > diff --git a/include/hw/pci-host/aspeed_pcie.h > > > b/include/hw/pci-host/aspeed_pcie.h > > > index faf87073ab..e2c5dc6f62 100644 > > > --- a/include/hw/pci-host/aspeed_pcie.h > > > +++ b/include/hw/pci-host/aspeed_pcie.h > > > @@ -24,6 +24,64 @@ > > > #include "hw/pci/pcie_host.h" > > > #include "qom/object.h" > > > > > > +typedef struct AspeedPCIECfgTxDesc { > > > + uint32_t desc0; > > > + uint32_t desc1; > > > + uint32_t desc2; > > > + uint32_t desc3; > > > + uint32_t wdata; > > > + uint32_t rdata_reg; > > > +} AspeedPCIECfgTxDesc; > > > + > > > +typedef struct AspeedPCIERcRegs { > > > + uint32_t int_en_reg; > > > + uint32_t int_sts_reg; > > > +} AspeedPCIERcRegs; > > > + > > > +typedef struct AspeedPCIERegMap { > > > + AspeedPCIERcRegs rc; > > > +} AspeedPCIERegMap; > > > + > > > +#define TYPE_ASPEED_PCIE_RC "aspeed.pcie-rc" > > > +OBJECT_DECLARE_SIMPLE_TYPE(AspeedPCIERcState, ASPEED_PCIE_RC); > > > + > > > +struct AspeedPCIERcState { > > > + PCIExpressHost parent_obj; > > > + > > > + MemoryRegion mmio_window; > > > + MemoryRegion io_window; > > > + MemoryRegion mmio; > > > + MemoryRegion io; > > > + > > > + uint32_t bus_nr; > > > + char name[16]; > > > + qemu_irq irq; > > > +}; > > > + > > > +/* Bridge between AHB bus and PCIe RC. */ #define > > > +TYPE_ASPEED_PCIE_CFG "aspeed.pcie-cfg" > > > +OBJECT_DECLARE_TYPE(AspeedPCIECfgState, AspeedPCIECfgClass, > > > +ASPEED_PCIE_CFG); > > > + > > > +struct AspeedPCIECfgState { > > > + SysBusDevice parent_obj; > > > + > > > + MemoryRegion mmio; > > > + uint32_t *regs; > > > + uint32_t id; > > > + > > > + AspeedPCIERcState rc; > > > +}; > > > + > > > +struct AspeedPCIECfgClass { > > > + SysBusDeviceClass parent_class; > > > + > > > + const AspeedPCIERegMap *reg_map; > > > + const MemoryRegionOps *reg_ops; > > > + > > > + uint64_t rc_bus_nr; > > > + uint64_t nr_regs; > > > +}; > > > + > > > #define TYPE_ASPEED_PCIE_PHY "aspeed.pcie-phy" > > > OBJECT_DECLARE_TYPE(AspeedPCIEPhyState, AspeedPCIEPhyClass, > > > ASPEED_PCIE_PHY); > > > > > > diff --git a/hw/pci-host/aspeed_pcie.c b/hw/pci-host/aspeed_pcie.c > > > index 5584449b17..9fb7c1ef67 100644 > > > --- a/hw/pci-host/aspeed_pcie.c > > > +++ b/hw/pci-host/aspeed_pcie.c > > > @@ -27,6 +27,426 @@ > > > #include "hw/pci/msi.h" > > > #include "trace.h" > > > > > > +/* > > > + * PCIe Root Complex (RC) > > > + */ > > > + > > > +static void aspeed_pcie_rc_set_irq(void *opaque, int irq, int > > > +level) { > > > + AspeedPCIERcState *rc = (AspeedPCIERcState *) opaque; > > > + AspeedPCIECfgState *cfg = > > > + container_of(rc, AspeedPCIECfgState, rc); > > > + AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_GET_CLASS(cfg); > > > + const AspeedPCIERcRegs *rc_regs; > > > > I suggest you cache &apc->reg_map->rc under AspeedPCIECfgState as an > > attribute (at realize time). This will ease reading the code and > > improve performance. > > > Thanks for your review and suggestion. > Will do. > > > > + bool intx; > > > + > > > + assert(irq < PCI_NUM_PINS); > > > + > > > + rc_regs = &apc->reg_map->rc; > > > + > > > + if (level) { > > > + cfg->regs[rc_regs->int_sts_reg] |= BIT(irq); > > > + } else { > > > + cfg->regs[rc_regs->int_sts_reg] &= ~BIT(irq); > > > + } > > > + > > > + intx = !!(cfg->regs[rc_regs->int_sts_reg] & > > cfg->regs[rc_regs->int_en_reg]); > > > + trace_aspeed_pcie_rc_intx_set_irq(cfg->id, irq, intx); > > > + qemu_set_irq(rc->irq, intx); > > > +} > > > + > > > +static int aspeed_pcie_rc_map_irq(PCIDevice *pci_dev, int irq_num) { > > > + return irq_num % PCI_NUM_PINS; > > > +} > > > + > > > +static void aspeed_pcie_rc_realize(DeviceState *dev, Error **errp) { > > > + PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); > > > + AspeedPCIERcState *rc = ASPEED_PCIE_RC(dev); > > > + AspeedPCIECfgState *cfg = > > > + container_of(rc, AspeedPCIECfgState, rc); > > > + PCIHostState *pci = PCI_HOST_BRIDGE(dev); > > > + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > > > + g_autofree char *name; > > > + > > > + /* PCI configuration space */ > > > + pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX); > > > + sysbus_init_mmio(sbd, &pex->mmio); > > > + > > > + /* MMIO and IO region */ > > > + memory_region_init(&rc->mmio, OBJECT(rc), "mmio", > UINT64_MAX); > > > + memory_region_init(&rc->io, OBJECT(rc), "io", 0x10000); > > > + > > > + name = g_strdup_printf("pcie.%d.mmio_window", cfg->id); > > > + memory_region_init_io(&rc->mmio_window, OBJECT(rc), > > &unassigned_io_ops, > > > + OBJECT(rc), name, UINT64_MAX); > > > + name = g_strdup_printf("pcie.%d.ioport_window", cfg->id); > > > + memory_region_init_io(&rc->io_window, OBJECT(rc), > > &unassigned_io_ops, > > > + OBJECT(rc), name, 0x10000); > > > + > > > + memory_region_add_subregion(&rc->mmio_window, 0, > &rc->mmio); > > > + memory_region_add_subregion(&rc->io_window, 0, &rc->io); > > > + sysbus_init_mmio(sbd, &rc->mmio_window); > > > + sysbus_init_mmio(sbd, &rc->io_window); > > > + > > > + sysbus_init_irq(sbd, &rc->irq); > > > + name = g_strdup_printf("pcie.rc%d", cfg->id); > > > + pci->bus = pci_register_root_bus(dev, name, aspeed_pcie_rc_set_irq, > > > + aspeed_pcie_rc_map_irq, > rc, > > &rc->mmio, > > > + &rc->io, 0, 4, > > TYPE_PCIE_BUS); > > > + pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; } > > > + > > > +static const char *aspeed_pcie_rc_root_bus_path(PCIHostState > > *host_bridge, > > > + PCIBus > *rootbus) > > { > > > + AspeedPCIERcState *rc = ASPEED_PCIE_RC(host_bridge); > > > + AspeedPCIECfgState *cfg = > > > + container_of(rc, AspeedPCIECfgState, rc); > > > + > > > + snprintf(rc->name, sizeof(rc->name), "%04x:%02x", cfg->id, > > > + rc->bus_nr); > > > + > > > + return rc->name; > > > +} > > > + > > > +static const Property aspeed_pcie_rc_props[] = { > > > + DEFINE_PROP_UINT32("bus-nr", AspeedPCIERcState, bus_nr, 0), }; > > > + > > > +static void aspeed_pcie_rc_class_init(ObjectClass *klass, const > > > +void > > > +*data) { > > > + PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); > > > + DeviceClass *dc = DEVICE_CLASS(klass); > > > + > > > + dc->desc = "ASPEED PCIe RC"; > > > + dc->realize = aspeed_pcie_rc_realize; > > > + dc->fw_name = "pci"; > > > + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); > > > + > > > + hc->root_bus_path = aspeed_pcie_rc_root_bus_path; > > > + device_class_set_props(dc, aspeed_pcie_rc_props); > > > + > > > + msi_nonbroken = true; > > > +} > > > + > > > +static const TypeInfo aspeed_pcie_rc_info = { > > > + .name = TYPE_ASPEED_PCIE_RC, > > > + .parent = TYPE_PCIE_HOST_BRIDGE, > > > + .instance_size = sizeof(AspeedPCIERcState), > > > + .class_init = aspeed_pcie_rc_class_init, }; > > > + > > > +/* > > > + * PCIe Config > > > + * > > > + * AHB to PCIe Bus Bridge (H2X) > > > + * > > > + * On the AST2600: > > > + * NOTE: rc_l is not supported by this model. > > > + * - Registers 0x00 - 0x7F are shared by both PCIe0 (rc_l) and PCIe1 > > > (rc_h). > > > + * - Registers 0x80 - 0xBF are specific to PCIe0. > > > + * - Registers 0xC0 - 0xFF are specific to PCIe1. > > > + */ > > > + > > > +/* AST2600 */ > > > +REG32(H2X_CTRL, 0x00) > > > + FIELD(H2X_CTRL, CLEAR_RX, 4, 1) > > > +REG32(H2X_TX_CLEAR, 0x08) > > > + FIELD(H2X_TX_CLEAR, IDLE, 0, 1) > > > +REG32(H2X_RDATA, 0x0C) > > > +REG32(H2X_TX_DESC0, 0x10) > > > +REG32(H2X_TX_DESC1, 0x14) > > > +REG32(H2X_TX_DESC2, 0x18) > > > +REG32(H2X_TX_DESC3, 0x1C) > > > +REG32(H2X_TX_DATA, 0x20) > > > +REG32(H2X_TX_STS, 0x24) > > > + FIELD(H2X_TX_STS, IDLE, 31, 1) > > > + FIELD(H2X_TX_STS, RC_L_TX_COMP, 24, 1) > > > + FIELD(H2X_TX_STS, RC_H_TX_COMP, 25, 1) > > > + FIELD(H2X_TX_STS, TRIG, 0, 1) > > > +REG32(H2X_RC_H_CTRL, 0xC0) > > > +REG32(H2X_RC_H_INT_EN, 0xC4) > > > +REG32(H2X_RC_H_INT_STS, 0xC8) > > > + SHARED_FIELD(H2X_RC_INT_INTDONE, 4, 1) > > > + SHARED_FIELD(H2X_RC_INT_INTX, 0, 4) > > > +REG32(H2X_RC_H_RDATA, 0xCC) > > > + > > > +#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ > > > +#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ > > > +#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */ > > > +#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */ > > > + > > > +#define PCIE_CFG_FMTTYPE_MASK(x) (((x) >> 24) & 0xff) #define > > > +PCIE_CFG_BYTE_EN(x) ((x) & 0xf) > > > + > > > +static const AspeedPCIERegMap aspeed_regmap = { > > > + .rc = { > > > + .int_en_reg = R_H2X_RC_H_INT_EN, > > > + .int_sts_reg = R_H2X_RC_H_INT_STS, > > > + }, > > > +}; > > > + > > > +static uint64_t aspeed_pcie_cfg_read(void *opaque, hwaddr addr, > > > + unsigned int size) { > > > + AspeedPCIECfgState *s = ASPEED_PCIE_CFG(opaque); > > > + uint32_t reg = addr >> 2; > > > + uint32_t value = 0; > > > + > > > + value = s->regs[reg]; > > > + > > > + trace_aspeed_pcie_cfg_read(s->id, addr, value); > > > + > > > + return value; > > > +} > > > + > > > +static void aspeed_pcie_cfg_translate_write(uint8_t byte_en, > > > +uint32_t > > *addr, > > > + uint64_t *val, int > > *len) > > > +{ > > > + uint64_t packed_val = 0; > > > + int first_bit = -1; > > > + int index = 0; > > > + int i; > > > + > > > + *len = ctpop8(byte_en); > > > + > > > + if (*len == 0 || *len > 4) { > > > + goto err; > > > + } > > > + > > > + /* Special case: full 4-byte write must be 4-byte aligned */ > > > + if (byte_en == 0x0f) { > > > + if (*addr % 4 != 0) { > > > > This is an aligment issue to be reported as such and not with "invalid > > byte enable" > > > > I think you should remove the "goto err" and generate a > > LOG_GUEST_ERROR instead. > > > Will fix it. > > > + goto err; > > > + } > > > + *val = *val & 0xffffffff; > > > + return; > > > + } > > > + > > > + for (i = 0; i < 4; i++) { > > > + if (byte_en & (1 << i)) { > > > + if (first_bit < 0) { > > > + first_bit = i; > > > + } > > > + packed_val |= ((*val >> (i * 8)) & 0xff) << (index * 8); > > > + index++;> + } > > > + } > > > + > > > + *addr += first_bit; > > > + *val = packed_val; > > > + > > > + return; > > > + > > > +err: > > > + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid byte enable: > > 0x%x\n", > > > + __func__, byte_en); } > > > + > > > +static void aspeed_pcie_cfg_readwrite(AspeedPCIECfgState *s, > > > + const > AspeedPCIECfgTxDesc > > > +*desc) { > > > + AspeedPCIERcState *rc = &s->rc; > > > + PCIHostState *pci; > > > + uint32_t cfg_addr; > > > + PCIDevice *pdev; > > > + uint32_t offset; > > > + uint8_t byte_en; > > > + bool is_write; > > > + uint8_t devfn; > > > + uint64_t val; > > > + uint8_t bus; > > > + int len; > > > + > > > + val = ~0; > > > + is_write = !!(desc->desc0 & BIT(30)); > > > + cfg_addr = desc->desc2; > > > > > > hmm, what about endianess ? > >
We keep .endianness = DEVICE_LITTLE_ENDIAN on the MMIO region, so the guest wire-LE bytes are already converted at the MMIO boundary. Inside the device (s->regs[], FIFOs, and desc.*) we consistently use CPU-endian integers and apply bitfield operations on those. I tried adding explicit le32_to_cpu()/cpu_to_le32() on s->regs[] to “convert” them again to CPU-endian, but that caused a "double swap" on big-endian hosts (e.g. MIPS64). The result was broken config TLP decoding and incorrect byte-enable packing. I experimented with the patch below—does this look incorrect given the MMIO endianness model? case R_H2X_TX_STS: if (data & R_H2X_TX_STS_TRIG_MASK) { - desc.desc0 = s->regs[R_H2X_TX_DESC0]; - desc.desc1 = s->regs[R_H2X_TX_DESC1]; - desc.desc2 = s->regs[R_H2X_TX_DESC2]; - desc.desc3 = s->regs[R_H2X_TX_DESC3]; - desc.wdata = s->regs[R_H2X_TX_DATA]; + desc.desc0 = le32_to_cpu(s->regs[R_H2X_TX_DESC0]); + desc.desc1 = le32_to_cpu(s->regs[R_H2X_TX_DESC1]); + desc.desc2 = le32_to_cpu(s->regs[R_H2X_TX_DESC2]); + desc.desc3 = le32_to_cpu(s->regs[R_H2X_TX_DESC3]); + desc.wdata = le32_to_cpu(s->regs[R_H2X_TX_DATA]); desc.rdata_reg = R_H2X_RC_H_RDATA; aspeed_pcie_cfg_readwrite(s, &desc); ... On MIPS64 (BE) this change made the device non-functional, which aligns with the double-swap hypothesis. My understanding is we should not add these conversions and instead keep s->regs[]/desc.* strictly CPU-endian, relying on the MMIO layer for wire-LE ↔ CPU conversions. I tested the v2 patch series and it passes on a big-endian host machine (qemumips64) Does anything above look incorrect to you? Thanks-Jamin > I am only considering little endianness the same as target side. > Will fix them in v3. > Jamin > > > + bus = (cfg_addr >> 24) & 0xff; > > > + devfn = (cfg_addr >> 16) & 0xff; > > > + offset = cfg_addr & 0xffc; > > > + > > > + pci = PCI_HOST_BRIDGE(rc); > > > + > > > + /* > > > + * On the AST2600, the RC_H bus number ranges from 0x80 to > > > + 0xFF, > > and its > > > + * root port uses bus number 0x80 instead of the standard 0x00. > > > + To > > locate > > > + * the device at root port 0, remap bus number 0x80 to 0x00 so > > > + that > > the > > > + * PCI subsystem can correctly discover the devices. > > > + */ > > > + if (bus == rc->bus_nr) { > > > + bus = 0; > > > + } > > > + > > > + pdev = pci_find_device(pci->bus, bus, devfn); > > > + if (!pdev) { > > > + s->regs[desc->rdata_reg] = ~0; > > > + goto out; > > > + } > > > + > > > + switch (PCIE_CFG_FMTTYPE_MASK(desc->desc0)) { > > > + case TLP_FMTTYPE_CFGWR0: > > > + case TLP_FMTTYPE_CFGWR1: > > > + byte_en = PCIE_CFG_BYTE_EN(desc->desc1); > > > + val = desc->wdata; > > > > what about endianess ? > > > > > + aspeed_pcie_cfg_translate_write(byte_en, &offset, &val, &len); > > > + pci_host_config_write_common(pdev, offset, > > pci_config_size(pdev), > > > + val, len); > > > + break; > > > + case TLP_FMTTYPE_CFGRD0: > > > + case TLP_FMTTYPE_CFGRD1: > > > + val = pci_host_config_read_common(pdev, offset, > > > + pci_config_size(pdev), > > 4); > > > + s->regs[desc->rdata_reg] = val; > > > + break; > > > + default: > > > + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid CFG type. > > DESC0=0x%x\n", > > > + __func__, desc->desc0); > > > + } > > > + > > > +out: > > > + trace_aspeed_pcie_cfg_rw(s->id, is_write ? "write" : "read", > > > +bus, > > devfn, > > > + cfg_addr, val); } > > > + > > > +static void aspeed_pcie_cfg_write(void *opaque, hwaddr addr, > > > +uint64_t > > data, > > > + unsigned int size) { > > > + AspeedPCIECfgState *s = ASPEED_PCIE_CFG(opaque); > > > + AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_GET_CLASS(s); > > > + AspeedPCIECfgTxDesc desc; > > > + uint32_t reg = addr >> 2; > > > + uint32_t rc_reg; > > > + > > > + trace_aspeed_pcie_cfg_write(s->id, addr, data); > > > + > > > + switch (reg) { > > > + case R_H2X_CTRL: > > > + if (data & R_H2X_CTRL_CLEAR_RX_MASK) { > > > + s->regs[R_H2X_RDATA] = ~0; > > > + } > > > + break; > > > + case R_H2X_TX_CLEAR: > > > + if (data & R_H2X_TX_CLEAR_IDLE_MASK) { > > > + s->regs[R_H2X_TX_STS] &= ~R_H2X_TX_STS_IDLE_MASK; > > > + } > > > + break; > > > + case R_H2X_TX_STS: > > > + if (data & R_H2X_TX_STS_TRIG_MASK) { > > > + desc.desc0 = s->regs[R_H2X_TX_DESC0]; > > > + desc.desc1 = s->regs[R_H2X_TX_DESC1]; > > > + desc.desc2 = s->regs[R_H2X_TX_DESC2]; > > > + desc.desc3 = s->regs[R_H2X_TX_DESC3]; > > > + desc.wdata = s->regs[R_H2X_TX_DATA]; > > > + desc.rdata_reg = R_H2X_RC_H_RDATA; > > > > endianess. > > > > > > Thanks, > > > > C. > > > > > > > > > + aspeed_pcie_cfg_readwrite(s, &desc); > > > + rc_reg = apc->reg_map->rc.int_sts_reg; > > > + s->regs[rc_reg] |= H2X_RC_INT_INTDONE_MASK; > > > + s->regs[R_H2X_TX_STS] |= > > > + BIT(R_H2X_TX_STS_RC_H_TX_COMP_SHIFT); > > > + s->regs[R_H2X_TX_STS] |= R_H2X_TX_STS_IDLE_MASK; > > > + } > > > + break; > > > + /* preserve INTx status */ > > > + case R_H2X_RC_H_INT_STS: > > > + if (data & H2X_RC_INT_INTDONE_MASK) { > > > + s->regs[R_H2X_TX_STS] &= > > ~R_H2X_TX_STS_RC_H_TX_COMP_MASK; > > > + } > > > + s->regs[reg] &= ~data | H2X_RC_INT_INTX_MASK; > > > + break; > > > + default: > > > + s->regs[reg] = data; > > > + break; > > > + } > > > +} > > > + > > > +static const MemoryRegionOps aspeed_pcie_cfg_ops = { > > > + .read = aspeed_pcie_cfg_read, > > > + .write = aspeed_pcie_cfg_write, > > > + .endianness = DEVICE_LITTLE_ENDIAN, > > > + .valid = { > > > + .min_access_size = 1, > > > + .max_access_size = 4, > > > + }, > > > +}; > > > + > > > +static void aspeed_pcie_cfg_instance_init(Object *obj) { > > > + AspeedPCIECfgState *s = ASPEED_PCIE_CFG(obj); > > > + > > > + object_initialize_child(obj, "rc", &s->rc, > > > + TYPE_ASPEED_PCIE_RC); > > > + > > > + return; > > > +} > > > + > > > +static void aspeed_pcie_cfg_reset(DeviceState *dev) { > > > + AspeedPCIECfgState *s = ASPEED_PCIE_CFG(dev); > > > + AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_GET_CLASS(s); > > > + > > > + memset(s->regs, 0, apc->nr_regs << 2); } > > > + > > > +static void aspeed_pcie_cfg_realize(DeviceState *dev, Error **errp) { > > > + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > > > + AspeedPCIECfgState *s = ASPEED_PCIE_CFG(dev); > > > + AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_GET_CLASS(s); > > > + g_autofree char *name; > > > + > > > + s->regs = g_new(uint32_t, apc->nr_regs); > > > + name = g_strdup_printf(TYPE_ASPEED_PCIE_CFG ".regs.%d", s->id); > > > + memory_region_init_io(&s->mmio, OBJECT(s), apc->reg_ops, s, > name, > > > + apc->nr_regs << 2); > > > + sysbus_init_mmio(sbd, &s->mmio); > > > + > > > + object_property_set_int(OBJECT(&s->rc), "bus-nr", > > > + apc->rc_bus_nr, > > > + &error_abort); > > > + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rc), errp)) { > > > + return; > > > + } > > > +} > > > + > > > +static void aspeed_pcie_cfg_unrealize(DeviceState *dev) { > > > + AspeedPCIECfgState *s = ASPEED_PCIE_CFG(dev); > > > + > > > + g_free(s->regs); > > > + s->regs = NULL; > > > +} > > > + > > > +static const Property aspeed_pcie_cfg_props[] = { > > > + DEFINE_PROP_UINT32("id", AspeedPCIECfgState, id, 0), }; > > > + > > > +static void aspeed_pcie_cfg_class_init(ObjectClass *klass, const > > > +void > > > +*data) { > > > + DeviceClass *dc = DEVICE_CLASS(klass); > > > + AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_CLASS(klass); > > > + > > > + dc->desc = "ASPEED PCIe Config"; > > > + dc->realize = aspeed_pcie_cfg_realize; > > > + dc->unrealize = aspeed_pcie_cfg_unrealize; > > > + device_class_set_legacy_reset(dc, aspeed_pcie_cfg_reset); > > > + device_class_set_props(dc, aspeed_pcie_cfg_props); > > > + > > > + apc->reg_ops = &aspeed_pcie_cfg_ops; > > > + apc->reg_map = &aspeed_regmap; > > > + apc->nr_regs = 0x100 >> 2; > > > + apc->rc_bus_nr = 0x80; > > > +} > > > + > > > +static const TypeInfo aspeed_pcie_cfg_info = { > > > + .name = TYPE_ASPEED_PCIE_CFG, > > > + .parent = TYPE_SYS_BUS_DEVICE, > > > + .instance_init = aspeed_pcie_cfg_instance_init, > > > + .instance_size = sizeof(AspeedPCIECfgState), > > > + .class_init = aspeed_pcie_cfg_class_init, > > > + .class_size = sizeof(AspeedPCIECfgClass), }; > > > + > > > /* > > > * PCIe PHY > > > * > > > @@ -152,6 +572,8 @@ static const TypeInfo aspeed_pcie_phy_info = { > > > > > > static void aspeed_pcie_register_types(void) > > > { > > > + type_register_static(&aspeed_pcie_rc_info); > > > + type_register_static(&aspeed_pcie_cfg_info); > > > type_register_static(&aspeed_pcie_phy_info); > > > } > > > > > > diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events > > > index > > > 3438516756..2584ea56e2 100644 > > > --- a/hw/pci-host/trace-events > > > +++ b/hw/pci-host/trace-events > > > @@ -1,6 +1,10 @@ > > > # See docs/devel/tracing.rst for syntax documentation. > > > > > > # aspeed_pcie.c > > > +aspeed_pcie_rc_intx_set_irq(uint32_t id, int num, int level) "%d: > > > +num %d > > set IRQ leve %d" > > > +aspeed_pcie_cfg_read(uint32_t id, uint64_t addr, uint32_t value) "%d: > > > +addr 0x%" PRIx64 " value 0x%" PRIx32 aspeed_pcie_cfg_write(uint32_t > > > +id, uint64_t addr, uint32_t value) "%d: addr 0x%" PRIx64 " value 0x%" > > > +PRIx32 aspeed_pcie_cfg_rw(uint32_t id, const char *dir, uint8_t > > > +bus, uint8_t devfn, uint64_t addr, uint64_t data) "%d: %s bus:0x%x > > > +devfn:0x%x addr 0x%" PRIx64 " data 0x%" PRIx64 > > > aspeed_pcie_phy_read(uint32_t id, uint64_t addr, uint32_t value) "%d: > > addr 0x%" PRIx64 " value 0x%" PRIx32 > > > aspeed_pcie_phy_write(uint32_t id, uint64_t addr, uint32_t value) > > > "%d: addr 0x%" PRIx64 " value 0x%" PRIx32 > > >