Message ID | 1636594528-8175-16-git-send-email-yangxiaojuan@loongson.cn (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add Loongarch softmmu support. | expand |
On 11/11/2021 01:35, Xiaojuan Yang wrote: Hi Xiaojuan, > This is a model of the PCIe Host Bridge found on a Loongson-5000 > processor. It includes a interrupt controller, some interface for > pci and nonpci devices we only emulate part devices for tcg mode. > It support for MSI and MSIX interrupt sources. > > For more detailed info about ls7a1000 you can see the doc at > https://github.com/loongson/LoongArch-Documentation/releases/latest/ > download/Loongson-7A1000-usermanual-2.00-EN.pdf > > Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn> > Signed-off-by: Song Gao <gaosong@loongson.cn> > --- > hw/pci-host/Kconfig | 4 + > hw/pci-host/ls7a.c | 187 +++++++++++++++++++++++++++++++++++++ > hw/pci-host/meson.build | 1 + > include/hw/pci-host/ls7a.h | 47 ++++++++++ > 4 files changed, 239 insertions(+) > create mode 100644 hw/pci-host/ls7a.c > create mode 100644 include/hw/pci-host/ls7a.h > > diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig > index 2b5f7d58cc..b02a9d1454 100644 > --- a/hw/pci-host/Kconfig > +++ b/hw/pci-host/Kconfig > @@ -77,3 +77,7 @@ config MV64361 > bool > select PCI > select I8259 > + > +config PCI_EXPRESS_7A > + bool > + select PCI_EXPRESS > diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c > new file mode 100644 > index 0000000000..90b9fe4830 > --- /dev/null > +++ b/hw/pci-host/ls7a.c > @@ -0,0 +1,187 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * QEMU Loongson 7A1000 North Bridge Emulation > + * > + * Copyright (C) 2021 Loongson Technology Corporation Limited > + */ > + > +#include "qemu/osdep.h" > + > +#include "hw/pci/pci.h" > +#include "hw/pci/pcie_host.h" > +#include "qapi/error.h" > +#include "hw/irq.h" > +#include "hw/pci/pci_bridge.h" > +#include "hw/pci/pci_bus.h" > +#include "sysemu/reset.h" > +#include "hw/pci-host/ls7a.h" > +#include "migration/vmstate.h" > + > +static const VMStateDescription vmstate_ls7a_pcie = { > + .name = "LS7A_PCIE", > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_PCI_DEVICE(dev, LS7APCIState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void pci_ls7a_config_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned size) > +{ > + pci_data_write(opaque, addr, val, size); > +} > + > +static uint64_t pci_ls7a_config_read(void *opaque, > + hwaddr addr, unsigned size) > +{ > + uint64_t val; > + > + val = pci_data_read(opaque, addr, size); > + > + return val; > +} > + > +static const MemoryRegionOps pci_ls7a_config_ops = { > + .read = pci_ls7a_config_read, > + .write = pci_ls7a_config_write, > + .valid = { > + .min_access_size = 1, > + .max_access_size = 4, > + }, > + .impl = { > + .min_access_size = 1, > + .max_access_size = 4, > + }, > + .endianness = DEVICE_NATIVE_ENDIAN, DEVICE_NATIVE_ENDIAN normally isn't the right thing to use: should this be DEVICE_LITTLE_ENDIAN or DEVICE_BIG_ENDIAN? > +}; > + > +static void ls7a_pciehost_realize(DeviceState *dev, Error **errp) > +{ > + LS7APCIEHost *pciehost = LS7A_PCIE_HOST_BRIDGE(dev); > + PCIExpressHost *e = PCIE_HOST_BRIDGE(dev); > + PCIHostState *phb = PCI_HOST_BRIDGE(e); > + > + phb->bus = pci_register_root_bus(dev, "pcie.0", NULL, > + NULL, pciehost, > + get_system_memory(), get_system_io(), > + PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS); > + > + memory_region_init_io(&pciehost->pci_conf, OBJECT(dev), > + &pci_ls7a_config_ops, phb->bus, > + "ls7a_pci_conf", HT1LO_PCICFG_SIZE); > + memory_region_add_subregion(get_system_memory(), HT1LO_PCICFG_BASE, > + &pciehost->pci_conf); > + > + /* Add ls7a pci-io */ > + memory_region_init_alias(&pciehost->pci_io, OBJECT(dev), "ls7a-pci-io", > + get_system_io(), 0, LS7A_PCI_IO_SIZE); > + memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE, > + &pciehost->pci_io); > + > + pcie_host_mmcfg_update(e, true, LS_PCIECFG_BASE, LS_PCIECFG_SIZE); > +} > + > +PCIBus *ls7a_init(MachineState *machine, qemu_irq *pic) > +{ > + DeviceState *dev; > + PCIHostState *phb; > + LS7APCIState *pbs; > + LS7APCIEHost *pciehost; > + PCIDevice *pci_dev; > + PCIExpressHost *e; > + > + dev = qdev_new(TYPE_LS7A_PCIE_HOST_BRIDGE); > + e = PCIE_HOST_BRIDGE(dev); > + phb = PCI_HOST_BRIDGE(e); > + pciehost = LS7A_PCIE_HOST_BRIDGE(dev); > + pciehost->pic = pic; pciehost->pic should be configured as a qdev gpio in the LS7A_PCIE_HOST_BRIDGE device .instance_init function using qdev_init_gpio_out() which is then wired up using qdev_connect_gpio_out(). > + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); > + > + pci_dev = pci_new(PCI_DEVFN(0, 0), TYPE_LS7A_PCIE); > + pbs = LS7A_PCIE(pci_dev); > + pbs->pciehost = pciehost; Here pbs->pciehost should be defined as a qdev link property for the LS7A_PCIE device (search for DEFINE_PROP_LINK for an example of this) > + pbs->pciehost->pci_dev = pbs; ... which means that this can be set in the ls7a_realize() function for the LS7A_PCIE device that should be added. > + pci_realize_and_unref(pci_dev, phb->bus, &error_fatal); > + > + return phb->bus; > +} Global init functions such as ls7a_init() above shouldn't be used anymore since they tend to use board-specific logic and prevent future work towards allowing machine configuration from a separate configuration file (hence the reason for removing the use of pointers above). > +static void ls7a_reset(DeviceState *qdev) > +{ > + uint64_t wmask; > + wmask = ~(-1); Can you combine these onto a single line? And doesn't this fail on 32-bit hosts without being ~(-1ULL)? > + PCIDevice *dev = PCI_DEVICE(qdev); > + > + pci_set_word(dev->config + PCI_STATUS, 0x0010); > + pci_set_word(dev->wmask + PCI_STATUS, wmask & 0xffff); > + pci_set_word(dev->cmask + PCI_STATUS, 0xffff); > + pci_set_byte(dev->config + PCI_HEADER_TYPE, 0x1); > + pci_set_byte(dev->wmask + PCI_HEADER_TYPE, wmask & 0xff); > + pci_set_byte(dev->cmask + PCI_HEADER_TYPE, 0xff); > + pci_set_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID, 0x0014); > + pci_set_word(dev->wmask + PCI_SUBSYSTEM_VENDOR_ID, wmask & 0xffff); > + pci_set_word(dev->cmask + PCI_SUBSYSTEM_VENDOR_ID, 0xffff); > + pci_set_word(dev->config + PCI_SUBSYSTEM_ID, 0x7a00); > + pci_set_word(dev->wmask + PCI_SUBSYSTEM_ID, wmask & 0xffff); > + pci_set_word(dev->cmask + PCI_SUBSYSTEM_ID, 0xffff); > + pci_set_byte(dev->config + PCI_CAPABILITY_LIST, 0x40); > + pci_set_byte(dev->wmask + PCI_CAPABILITY_LIST, wmask & 0xff); > + pci_set_byte(dev->cmask + PCI_CAPABILITY_LIST, 0xff); > +} > + > +static void ls7a_pcie_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); > + > + k->vendor_id = 0x0014; > + k->device_id = 0x7a00; > + k->revision = 0x00; > + k->class_id = PCI_CLASS_BRIDGE_HOST; > + dc->reset = ls7a_reset; > + dc->desc = "LS7A1000 PCIE Host bridge"; > + dc->vmsd = &vmstate_ls7a_pcie; > + /* > + * PCI-facing part of the host bridge, not usable without the > + * host-facing part, which can't be device_add'ed, yet. > + */ > + dc->user_creatable = false; > +} > + > +static const TypeInfo ls7a_pcie_device_info = { > + .name = TYPE_LS7A_PCIE, > + .parent = TYPE_PCI_DEVICE, > + .instance_size = sizeof(LS7APCIState), > + .class_init = ls7a_pcie_class_init, > + .interfaces = (InterfaceInfo[]) { > + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, > + { }, > + }, > +}; > + > +static void ls7a_pciehost_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + dc->realize = ls7a_pciehost_realize; > + dc->fw_name = "pci"; > + dc->user_creatable = false; > +} > + > +static const TypeInfo ls7a_pciehost_info = { > + .name = TYPE_LS7A_PCIE_HOST_BRIDGE, > + .parent = TYPE_PCIE_HOST_BRIDGE, > + .instance_size = sizeof(LS7APCIEHost), > + .class_init = ls7a_pciehost_class_init, > +}; > + > +static void ls7a_register_types(void) > +{ > + type_register_static(&ls7a_pciehost_info); > + type_register_static(&ls7a_pcie_device_info); > +} > + > +type_init(ls7a_register_types) > diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build > index 4c4f39c15c..c4955455fd 100644 > --- a/hw/pci-host/meson.build > +++ b/hw/pci-host/meson.build > @@ -11,6 +11,7 @@ pci_ss.add(when: 'CONFIG_PCI_SABRE', if_true: files('sabre.c')) > pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c')) > pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c')) > pci_ss.add(when: 'CONFIG_SH_PCI', if_true: files('sh_pci.c')) > +pci_ss.add(when: 'CONFIG_PCI_EXPRESS_7A', if_true: files('ls7a.c')) > > # PPC devices > pci_ss.add(when: 'CONFIG_RAVEN_PCI', if_true: files('raven.c')) > diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h > new file mode 100644 > index 0000000000..6b5ba3b442 > --- /dev/null > +++ b/include/hw/pci-host/ls7a.h > @@ -0,0 +1,47 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * QEMU LoongArch CPU > + * > + * Copyright (c) 2021 Loongson Technology Corporation Limited > + */ > + > +#ifndef HW_LS7A_H > +#define HW_LS7A_H > + > +#include "hw/pci/pci.h" > +#include "hw/pci/pcie_host.h" > +#include "hw/pci-host/pam.h" > +#include "qemu/units.h" > +#include "qemu/range.h" > +#include "qom/object.h" > + > +#define HT1LO_PCICFG_BASE 0x1a000000 > +#define HT1LO_PCICFG_SIZE 0x02000000 > + > +#define LS_PCIECFG_BASE 0x20000000 > +#define LS_PCIECFG_SIZE 0x08000000 > + > +#define LS7A_PCI_IO_BASE 0x18000000UL > +#define LS7A_PCI_IO_SIZE 0x00010000 > +typedef struct LS7APCIState LS7APCIState; > +typedef struct LS7APCIEHost { > + PCIExpressHost parent_obj; > + LS7APCIState *pci_dev; > + qemu_irq *pic; > + MemoryRegion pci_conf; > + MemoryRegion pci_io; > +} LS7APCIEHost; > + > +struct LS7APCIState { > + PCIDevice dev; > + LS7APCIEHost *pciehost; > +}; > + > +#define TYPE_LS7A_PCIE_HOST_BRIDGE "ls7a1000-pciehost" > +OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIEHost, LS7A_PCIE_HOST_BRIDGE) > + > +#define TYPE_LS7A_PCIE "ls7a1000_pcie" > +OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIState, LS7A_PCIE) > + > +PCIBus *ls7a_init(MachineState *machine, qemu_irq *irq); > +#endif /* HW_LS7A_H */ ATB, Mark.
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 2b5f7d58cc..b02a9d1454 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -77,3 +77,7 @@ config MV64361 bool select PCI select I8259 + +config PCI_EXPRESS_7A + bool + select PCI_EXPRESS diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c new file mode 100644 index 0000000000..90b9fe4830 --- /dev/null +++ b/hw/pci-host/ls7a.c @@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU Loongson 7A1000 North Bridge Emulation + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" + +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "qapi/error.h" +#include "hw/irq.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" +#include "sysemu/reset.h" +#include "hw/pci-host/ls7a.h" +#include "migration/vmstate.h" + +static const VMStateDescription vmstate_ls7a_pcie = { + .name = "LS7A_PCIE", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, LS7APCIState), + VMSTATE_END_OF_LIST() + } +}; + +static void pci_ls7a_config_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + pci_data_write(opaque, addr, val, size); +} + +static uint64_t pci_ls7a_config_read(void *opaque, + hwaddr addr, unsigned size) +{ + uint64_t val; + + val = pci_data_read(opaque, addr, size); + + return val; +} + +static const MemoryRegionOps pci_ls7a_config_ops = { + .read = pci_ls7a_config_read, + .write = pci_ls7a_config_write, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ls7a_pciehost_realize(DeviceState *dev, Error **errp) +{ + LS7APCIEHost *pciehost = LS7A_PCIE_HOST_BRIDGE(dev); + PCIExpressHost *e = PCIE_HOST_BRIDGE(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(e); + + phb->bus = pci_register_root_bus(dev, "pcie.0", NULL, + NULL, pciehost, + get_system_memory(), get_system_io(), + PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS); + + memory_region_init_io(&pciehost->pci_conf, OBJECT(dev), + &pci_ls7a_config_ops, phb->bus, + "ls7a_pci_conf", HT1LO_PCICFG_SIZE); + memory_region_add_subregion(get_system_memory(), HT1LO_PCICFG_BASE, + &pciehost->pci_conf); + + /* Add ls7a pci-io */ + memory_region_init_alias(&pciehost->pci_io, OBJECT(dev), "ls7a-pci-io", + get_system_io(), 0, LS7A_PCI_IO_SIZE); + memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE, + &pciehost->pci_io); + + pcie_host_mmcfg_update(e, true, LS_PCIECFG_BASE, LS_PCIECFG_SIZE); +} + +PCIBus *ls7a_init(MachineState *machine, qemu_irq *pic) +{ + DeviceState *dev; + PCIHostState *phb; + LS7APCIState *pbs; + LS7APCIEHost *pciehost; + PCIDevice *pci_dev; + PCIExpressHost *e; + + dev = qdev_new(TYPE_LS7A_PCIE_HOST_BRIDGE); + e = PCIE_HOST_BRIDGE(dev); + phb = PCI_HOST_BRIDGE(e); + pciehost = LS7A_PCIE_HOST_BRIDGE(dev); + pciehost->pic = pic; + + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + pci_dev = pci_new(PCI_DEVFN(0, 0), TYPE_LS7A_PCIE); + pbs = LS7A_PCIE(pci_dev); + pbs->pciehost = pciehost; + pbs->pciehost->pci_dev = pbs; + + pci_realize_and_unref(pci_dev, phb->bus, &error_fatal); + + return phb->bus; +} + +static void ls7a_reset(DeviceState *qdev) +{ + uint64_t wmask; + wmask = ~(-1); + PCIDevice *dev = PCI_DEVICE(qdev); + + pci_set_word(dev->config + PCI_STATUS, 0x0010); + pci_set_word(dev->wmask + PCI_STATUS, wmask & 0xffff); + pci_set_word(dev->cmask + PCI_STATUS, 0xffff); + pci_set_byte(dev->config + PCI_HEADER_TYPE, 0x1); + pci_set_byte(dev->wmask + PCI_HEADER_TYPE, wmask & 0xff); + pci_set_byte(dev->cmask + PCI_HEADER_TYPE, 0xff); + pci_set_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID, 0x0014); + pci_set_word(dev->wmask + PCI_SUBSYSTEM_VENDOR_ID, wmask & 0xffff); + pci_set_word(dev->cmask + PCI_SUBSYSTEM_VENDOR_ID, 0xffff); + pci_set_word(dev->config + PCI_SUBSYSTEM_ID, 0x7a00); + pci_set_word(dev->wmask + PCI_SUBSYSTEM_ID, wmask & 0xffff); + pci_set_word(dev->cmask + PCI_SUBSYSTEM_ID, 0xffff); + pci_set_byte(dev->config + PCI_CAPABILITY_LIST, 0x40); + pci_set_byte(dev->wmask + PCI_CAPABILITY_LIST, wmask & 0xff); + pci_set_byte(dev->cmask + PCI_CAPABILITY_LIST, 0xff); +} + +static void ls7a_pcie_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->vendor_id = 0x0014; + k->device_id = 0x7a00; + k->revision = 0x00; + k->class_id = PCI_CLASS_BRIDGE_HOST; + dc->reset = ls7a_reset; + dc->desc = "LS7A1000 PCIE Host bridge"; + dc->vmsd = &vmstate_ls7a_pcie; + /* + * PCI-facing part of the host bridge, not usable without the + * host-facing part, which can't be device_add'ed, yet. + */ + dc->user_creatable = false; +} + +static const TypeInfo ls7a_pcie_device_info = { + .name = TYPE_LS7A_PCIE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(LS7APCIState), + .class_init = ls7a_pcie_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + +static void ls7a_pciehost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = ls7a_pciehost_realize; + dc->fw_name = "pci"; + dc->user_creatable = false; +} + +static const TypeInfo ls7a_pciehost_info = { + .name = TYPE_LS7A_PCIE_HOST_BRIDGE, + .parent = TYPE_PCIE_HOST_BRIDGE, + .instance_size = sizeof(LS7APCIEHost), + .class_init = ls7a_pciehost_class_init, +}; + +static void ls7a_register_types(void) +{ + type_register_static(&ls7a_pciehost_info); + type_register_static(&ls7a_pcie_device_info); +} + +type_init(ls7a_register_types) diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index 4c4f39c15c..c4955455fd 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -11,6 +11,7 @@ pci_ss.add(when: 'CONFIG_PCI_SABRE', if_true: files('sabre.c')) pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c')) pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c')) pci_ss.add(when: 'CONFIG_SH_PCI', if_true: files('sh_pci.c')) +pci_ss.add(when: 'CONFIG_PCI_EXPRESS_7A', if_true: files('ls7a.c')) # PPC devices pci_ss.add(when: 'CONFIG_RAVEN_PCI', if_true: files('raven.c')) diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h new file mode 100644 index 0000000000..6b5ba3b442 --- /dev/null +++ b/include/hw/pci-host/ls7a.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LS7A_H +#define HW_LS7A_H + +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/pci-host/pam.h" +#include "qemu/units.h" +#include "qemu/range.h" +#include "qom/object.h" + +#define HT1LO_PCICFG_BASE 0x1a000000 +#define HT1LO_PCICFG_SIZE 0x02000000 + +#define LS_PCIECFG_BASE 0x20000000 +#define LS_PCIECFG_SIZE 0x08000000 + +#define LS7A_PCI_IO_BASE 0x18000000UL +#define LS7A_PCI_IO_SIZE 0x00010000 +typedef struct LS7APCIState LS7APCIState; +typedef struct LS7APCIEHost { + PCIExpressHost parent_obj; + LS7APCIState *pci_dev; + qemu_irq *pic; + MemoryRegion pci_conf; + MemoryRegion pci_io; +} LS7APCIEHost; + +struct LS7APCIState { + PCIDevice dev; + LS7APCIEHost *pciehost; +}; + +#define TYPE_LS7A_PCIE_HOST_BRIDGE "ls7a1000-pciehost" +OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIEHost, LS7A_PCIE_HOST_BRIDGE) + +#define TYPE_LS7A_PCIE "ls7a1000_pcie" +OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIState, LS7A_PCIE) + +PCIBus *ls7a_init(MachineState *machine, qemu_irq *irq); +#endif /* HW_LS7A_H */