diff mbox series

[RFC,v3,22/27] hw/loongarch: Add some devices support for 3A5000.

Message ID 1638619645-11283-23-git-send-email-yangxiaojuan@loongson.cn (mailing list archive)
State New, archived
Headers show
Series Add LoongArch softmmu support. | expand

Commit Message

Xiaojuan Yang Dec. 4, 2021, 12:07 p.m. UTC
1.Add uart,virtio-net,vga and usb for 3A5000.
2.Add irq set and map for the pci host. Non pci device
use irq 0-16, pci device use 16-64.
3.Add some unimplented device to emulate guest unused
memory space.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/loongarch/Kconfig            |  8 +++++
 hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
 hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
 include/hw/intc/loongarch_ipi.h |  2 ++
 include/hw/pci-host/ls7a.h      |  4 +++
 softmmu/qdev-monitor.c          |  3 +-
 6 files changed, 117 insertions(+), 5 deletions(-)

Comments

Philippe Mathieu-Daudé Dec. 4, 2021, 5:54 p.m. UTC | #1
On 12/4/21 13:07, Xiaojuan Yang wrote:
> 1.Add uart,virtio-net,vga and usb for 3A5000.
> 2.Add irq set and map for the pci host. Non pci device
> use irq 0-16, pci device use 16-64.
> 3.Add some unimplented device to emulate guest unused
> memory space.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>  hw/loongarch/Kconfig            |  8 +++++
>  hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>  hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>  include/hw/intc/loongarch_ipi.h |  2 ++
>  include/hw/pci-host/ls7a.h      |  4 +++
>  softmmu/qdev-monitor.c          |  3 +-
>  6 files changed, 117 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 468e3acc74..9ea3b92708 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -1,5 +1,13 @@
>  config LOONGSON3_LS7A
>      bool
> +    imply VGA_PCI
> +    imply VIRTIO_VGA
> +    imply PARALLEL

Is there really a parallel port? If so, maybe you forgot to
instantiate it.
Xiaojuan Yang Dec. 6, 2021, 6:55 a.m. UTC | #2
Hi,

On 12/05/2021 01:54 AM, Philippe Mathieu-Daudé wrote:
> On 12/4/21 13:07, Xiaojuan Yang wrote:
>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>> 2.Add irq set and map for the pci host. Non pci device
>> use irq 0-16, pci device use 16-64.
>> 3.Add some unimplented device to emulate guest unused
>> memory space.
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>  hw/loongarch/Kconfig            |  8 +++++
>>  hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>  hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>  include/hw/intc/loongarch_ipi.h |  2 ++
>>  include/hw/pci-host/ls7a.h      |  4 +++
>>  softmmu/qdev-monitor.c          |  3 +-
>>  6 files changed, 117 insertions(+), 5 deletions(-)
>>
>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>> index 468e3acc74..9ea3b92708 100644
>> --- a/hw/loongarch/Kconfig
>> +++ b/hw/loongarch/Kconfig
>> @@ -1,5 +1,13 @@
>>  config LOONGSON3_LS7A
>>      bool
>> +    imply VGA_PCI
>> +    imply VIRTIO_VGA
>> +    imply PARALLEL
> 
> Is there really a parallel port? If so, maybe you forgot to
> instantiate it.
> 
There is no parallel port, I will fix it, thanks.
Mark Cave-Ayland Dec. 18, 2021, 10:02 a.m. UTC | #3
On 04/12/2021 12:07, Xiaojuan Yang wrote:

> 1.Add uart,virtio-net,vga and usb for 3A5000.
> 2.Add irq set and map for the pci host. Non pci device
> use irq 0-16, pci device use 16-64.
> 3.Add some unimplented device to emulate guest unused
> memory space.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/loongarch/Kconfig            |  8 +++++
>   hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>   hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>   include/hw/intc/loongarch_ipi.h |  2 ++
>   include/hw/pci-host/ls7a.h      |  4 +++
>   softmmu/qdev-monitor.c          |  3 +-
>   6 files changed, 117 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 468e3acc74..9ea3b92708 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -1,5 +1,13 @@
>   config LOONGSON3_LS7A
>       bool
> +    imply VGA_PCI
> +    imply VIRTIO_VGA
> +    imply PARALLEL
> +    imply PCI_DEVICES
> +    select ISA_BUS
> +    select SERIAL
> +    select SERIAL_ISA
> +    select VIRTIO_PCI
>       select PCI_EXPRESS_7A
>       select LOONGARCH_IPI
>       select LOONGARCH_PCH_PIC
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> index c42f830208..e4a02e7c18 100644
> --- a/hw/loongarch/loongson3.c
> +++ b/hw/loongarch/loongson3.c
> @@ -10,8 +10,11 @@
>   #include "qemu/datadir.h"
>   #include "qapi/error.h"
>   #include "hw/boards.h"
> +#include "hw/char/serial.h"
>   #include "sysemu/sysemu.h"
>   #include "sysemu/qtest.h"
> +#include "hw/irq.h"
> +#include "net/net.h"
>   #include "sysemu/runstate.h"
>   #include "sysemu/reset.h"
>   #include "hw/loongarch/loongarch.h"
> @@ -20,6 +23,7 @@
>   #include "hw/intc/loongarch_pch_pic.h"
>   #include "hw/intc/loongarch_pch_msi.h"
>   #include "hw/pci-host/ls7a.h"
> +#include "hw/misc/unimp.h"
>   
>   
>   static void loongarch_cpu_reset(void *opaque)
> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>       memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>   }
>   
> -static void loongson3_irq_init(MachineState *machine)
> +static PCIBus *loongson3_irq_init(MachineState *machine)
>   {
>       LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>       SysBusDevice *d;
> +    PCIBus *pci_bus;
>       int cpu, pin, i;
>       unsigned long ipi_addr;
>   
> @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>       sysbus_realize_and_unref(d, &error_fatal);
>       sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>   
> +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
> +
>       /* Connect 64 pch_pic irqs to extioi */
>       for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>           sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>           sysbus_connect_irq(d, i,
>                              qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>       }
> +
> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
> +    d = SYS_BUS_DEVICE(pciehost);
> +    sysbus_realize_and_unref(d, &error_fatal);
> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
> +
> +    /* Connect 48 pci irq to pch_pic */
> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
> +        qdev_connect_gpio_out(pciehost, i,
> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
> +    }
> +
> +    return pci_bus;
> +}
> +
> +/* Network support */
> +static void network_init(PCIBus *pci_bus)
> +{
> +    int i;
> +
> +    for (i = 0; i < nb_nics; i++) {
> +        NICInfo *nd = &nd_table[i];
> +
> +        if (!nd->model) {
> +            nd->model = g_strdup("virtio");
> +        }
> +
> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
> +    }
>   }
>   
>   static void loongson3_init(MachineState *machine)
> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>       MemoryRegion *address_space_mem = get_system_memory();
>       LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>       int i;
> +    PCIBus *pci_bus = NULL;
>   
>       if (!cpu_model) {
>           cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>       memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>       offset += highram_size;
>   
> +    /*
> +     * There are some invalid guest memory access.
> +     * Create some unimplemented devices to emulate this.
> +     */
> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
> +
>       /* Initialize the IO interrupt subsystem */
> -    loongson3_irq_init(machine);
> +    pci_bus = loongson3_irq_init(machine);
> +
> +    /* Network card */
> +    network_init(pci_bus);
> +
> +    /* VGA setup. Don't bother loading the bios. */
> +    pci_vga_init(pci_bus);
> +
> +    pci_create_simple(pci_bus, -1, "pci-ohci");

By passing in -1 then you're allowing the PCI code to choose a suitable 
device/function which feels odd for an in-built device. Is this not fixed in real 
hardware?

Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines 
that don't have these devices in-built.

>       LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>       LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
> index a783fb2eda..06cd641573 100644
> --- a/hw/pci-host/ls7a.c
> +++ b/hw/pci-host/ls7a.c
> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>       }
>   };
>   
> +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
> +{
> +    PCIINTxRoute route;
> +
> +    route.irq = pin;
> +    route.mode = PCI_INTX_ENABLED;
> +    return route;
> +}
> +
> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
> +{
> +    PCIBus *bus;
> +    int offset, irq;
> +
> +    bus = pci_get_bus(d);
> +    if (bus->parent_dev) {
> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
> +        return irq;
> +    }

Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, 
for example pci_change_irq_level()?

> +    /* pci device start from irq 80 */
> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
> +
> +    return irq;
> +}
> +
> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
> +{
> +    LS7APCIEHost *pciehost = opaque;
> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
> +
> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
> +}
> +
>   static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>                                     uint64_t val, unsigned size)
>   {
> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>       LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>       PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>   
> -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
> +                                     pci_ls7a_map_irq, s,
>                                        get_system_memory(), get_system_io(),
>                                        PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>   
> +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
> +
>       memory_region_init_io(&s->pci_conf, OBJECT(dev),
>                             &pci_ls7a_config_ops, pci->bus,
>                             "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>       object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>       qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>       qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
> +
> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>   }
>   
>   static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
> index d2397e53e7..1113c3b1a8 100644
> --- a/include/hw/intc/loongarch_ipi.h
> +++ b/include/hw/intc/loongarch_ipi.h
> @@ -8,6 +8,8 @@
>   #ifndef HW_LOONGARCH_IPI_H
>   #define HW_LOONGARCH_IPI_H
>   
> +#include "hw/sysbus.h"
> +
>   /* Mainy used by iocsr read and write */
>   #define SMP_IPI_MAILBOX      0x1000ULL
>   #define CORE_STATUS_OFF       0x0
> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
> index ac938d6d5f..3b9ad1e175 100644
> --- a/include/hw/pci-host/ls7a.h
> +++ b/include/hw/pci-host/ls7a.h
> @@ -37,6 +37,9 @@
>   #define LS7A_DEVICE_IRQS        16
>   #define LS7A_PCI_IRQS           48
>   
> +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
> +#define LS7A_UART_BASE          0x1fe001e0
> +
>   struct LS7APCIState {
>       /*< private >*/
>       PCIDevice parent_obj;
> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>   
>       LS7APCIState pci_dev;
>   
> +    qemu_irq irqs[LS7A_PCI_IRQS];
>       MemoryRegion pci_conf;
>       MemoryRegion pci_io;
>   } LS7APCIEHost;
> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
> index 01f3834db5..49491d74a1 100644
> --- a/softmmu/qdev-monitor.c
> +++ b/softmmu/qdev-monitor.c
> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>                                 QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>                                 QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>                                 QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
> +                              QEMU_ARCH_LOONGARCH)

This part looks like it belongs to another patch?

>   #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>   #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)


ATB,

Mark.
Xiaojuan Yang Dec. 22, 2021, 8:26 a.m. UTC | #4
Hi, Mark

On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
> On 04/12/2021 12:07, Xiaojuan Yang wrote:
> 
>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>> 2.Add irq set and map for the pci host. Non pci device
>> use irq 0-16, pci device use 16-64.
>> 3.Add some unimplented device to emulate guest unused
>> memory space.
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>   hw/loongarch/Kconfig            |  8 +++++
>>   hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>   hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>   include/hw/intc/loongarch_ipi.h |  2 ++
>>   include/hw/pci-host/ls7a.h      |  4 +++
>>   softmmu/qdev-monitor.c          |  3 +-
>>   6 files changed, 117 insertions(+), 5 deletions(-)
>>
>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>> index 468e3acc74..9ea3b92708 100644
>> --- a/hw/loongarch/Kconfig
>> +++ b/hw/loongarch/Kconfig
>> @@ -1,5 +1,13 @@
>>   config LOONGSON3_LS7A
>>       bool
>> +    imply VGA_PCI
>> +    imply VIRTIO_VGA
>> +    imply PARALLEL
>> +    imply PCI_DEVICES
>> +    select ISA_BUS
>> +    select SERIAL
>> +    select SERIAL_ISA
>> +    select VIRTIO_PCI
>>       select PCI_EXPRESS_7A
>>       select LOONGARCH_IPI
>>       select LOONGARCH_PCH_PIC
>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>> index c42f830208..e4a02e7c18 100644
>> --- a/hw/loongarch/loongson3.c
>> +++ b/hw/loongarch/loongson3.c
>> @@ -10,8 +10,11 @@
>>   #include "qemu/datadir.h"
>>   #include "qapi/error.h"
>>   #include "hw/boards.h"
>> +#include "hw/char/serial.h"
>>   #include "sysemu/sysemu.h"
>>   #include "sysemu/qtest.h"
>> +#include "hw/irq.h"
>> +#include "net/net.h"
>>   #include "sysemu/runstate.h"
>>   #include "sysemu/reset.h"
>>   #include "hw/loongarch/loongarch.h"
>> @@ -20,6 +23,7 @@
>>   #include "hw/intc/loongarch_pch_pic.h"
>>   #include "hw/intc/loongarch_pch_msi.h"
>>   #include "hw/pci-host/ls7a.h"
>> +#include "hw/misc/unimp.h"
>>       static void loongarch_cpu_reset(void *opaque)
>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>       memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>   }
>>   -static void loongson3_irq_init(MachineState *machine)
>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>   {
>>       LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>       SysBusDevice *d;
>> +    PCIBus *pci_bus;
>>       int cpu, pin, i;
>>       unsigned long ipi_addr;
>>   @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>       sysbus_realize_and_unref(d, &error_fatal);
>>       sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>   +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>> +
>>       /* Connect 64 pch_pic irqs to extioi */
>>       for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>           sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>           sysbus_connect_irq(d, i,
>>                              qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>       }
>> +
>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>> +    d = SYS_BUS_DEVICE(pciehost);
>> +    sysbus_realize_and_unref(d, &error_fatal);
>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>> +
>> +    /* Connect 48 pci irq to pch_pic */
>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>> +        qdev_connect_gpio_out(pciehost, i,
>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>> +    }
>> +
>> +    return pci_bus;
>> +}
>> +
>> +/* Network support */
>> +static void network_init(PCIBus *pci_bus)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < nb_nics; i++) {
>> +        NICInfo *nd = &nd_table[i];
>> +
>> +        if (!nd->model) {
>> +            nd->model = g_strdup("virtio");
>> +        }
>> +
>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>> +    }
>>   }
>>     static void loongson3_init(MachineState *machine)
>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>       MemoryRegion *address_space_mem = get_system_memory();
>>       LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>       int i;
>> +    PCIBus *pci_bus = NULL;
>>         if (!cpu_model) {
>>           cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>       memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>       offset += highram_size;
>>   +    /*
>> +     * There are some invalid guest memory access.
>> +     * Create some unimplemented devices to emulate this.
>> +     */
>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>> +
>>       /* Initialize the IO interrupt subsystem */
>> -    loongson3_irq_init(machine);
>> +    pci_bus = loongson3_irq_init(machine);
>> +
>> +    /* Network card */
>> +    network_init(pci_bus);
>> +
>> +    /* VGA setup. Don't bother loading the bios. */
>> +    pci_vga_init(pci_bus);
>> +
>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
> 
> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
> 
> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.

The machine has these devices but we don't want to emulate all the devices, only emulated part devices. 
I don't know if it is ok to do like this.

> 
>>       LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>       LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>> index a783fb2eda..06cd641573 100644
>> --- a/hw/pci-host/ls7a.c
>> +++ b/hw/pci-host/ls7a.c
>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>       }
>>   };
>>   +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>> +{
>> +    PCIINTxRoute route;
>> +
>> +    route.irq = pin;
>> +    route.mode = PCI_INTX_ENABLED;
>> +    return route;
>> +}
>> +
>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>> +{
>> +    PCIBus *bus;
>> +    int offset, irq;
>> +
>> +    bus = pci_get_bus(d);
>> +    if (bus->parent_dev) {
>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>> +        return irq;
>> +    }
> 
> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?

We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.

> 
>> +    /* pci device start from irq 80 */
>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>> +
>> +    return irq;
>> +}
>> +
>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>> +{
>> +    LS7APCIEHost *pciehost = opaque;
>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>> +
>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>> +}
>> +
>>   static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>                                     uint64_t val, unsigned size)
>>   {
>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>       LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>       PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>   -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>> +                                     pci_ls7a_map_irq, s,
>>                                        get_system_memory(), get_system_io(),
>>                                        PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>   +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>> +
>>       memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>                             &pci_ls7a_config_ops, pci->bus,
>>                             "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>       object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>       qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>       qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>> +
>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>   }
>>     static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>> index d2397e53e7..1113c3b1a8 100644
>> --- a/include/hw/intc/loongarch_ipi.h
>> +++ b/include/hw/intc/loongarch_ipi.h
>> @@ -8,6 +8,8 @@
>>   #ifndef HW_LOONGARCH_IPI_H
>>   #define HW_LOONGARCH_IPI_H
>>   +#include "hw/sysbus.h"
>> +
>>   /* Mainy used by iocsr read and write */
>>   #define SMP_IPI_MAILBOX      0x1000ULL
>>   #define CORE_STATUS_OFF       0x0
>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>> index ac938d6d5f..3b9ad1e175 100644
>> --- a/include/hw/pci-host/ls7a.h
>> +++ b/include/hw/pci-host/ls7a.h
>> @@ -37,6 +37,9 @@
>>   #define LS7A_DEVICE_IRQS        16
>>   #define LS7A_PCI_IRQS           48
>>   +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>> +#define LS7A_UART_BASE          0x1fe001e0
>> +
>>   struct LS7APCIState {
>>       /*< private >*/
>>       PCIDevice parent_obj;
>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>         LS7APCIState pci_dev;
>>   +    qemu_irq irqs[LS7A_PCI_IRQS];
>>       MemoryRegion pci_conf;
>>       MemoryRegion pci_io;
>>   } LS7APCIEHost;
>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>> index 01f3834db5..49491d74a1 100644
>> --- a/softmmu/qdev-monitor.c
>> +++ b/softmmu/qdev-monitor.c
>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>                                 QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>                                 QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>                                 QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>> +                              QEMU_ARCH_LOONGARCH)
> 
> This part looks like it belongs to another patch?

OK, I will put this part to a separate patch.

Thanks,
Xiaojuan

> 
>>   #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>   #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
> 
> 
> ATB,
> 
> Mark.
Mark Cave-Ayland Dec. 23, 2021, 10:52 a.m. UTC | #5
On 22/12/2021 08:26, yangxiaojuan wrote:

> Hi, Mark
> 
> On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>
>>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>>> 2.Add irq set and map for the pci host. Non pci device
>>> use irq 0-16, pci device use 16-64.
>>> 3.Add some unimplented device to emulate guest unused
>>> memory space.
>>>
>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>> ---
>>>    hw/loongarch/Kconfig            |  8 +++++
>>>    hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>>    hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>>    include/hw/intc/loongarch_ipi.h |  2 ++
>>>    include/hw/pci-host/ls7a.h      |  4 +++
>>>    softmmu/qdev-monitor.c          |  3 +-
>>>    6 files changed, 117 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>> index 468e3acc74..9ea3b92708 100644
>>> --- a/hw/loongarch/Kconfig
>>> +++ b/hw/loongarch/Kconfig
>>> @@ -1,5 +1,13 @@
>>>    config LOONGSON3_LS7A
>>>        bool
>>> +    imply VGA_PCI
>>> +    imply VIRTIO_VGA
>>> +    imply PARALLEL
>>> +    imply PCI_DEVICES
>>> +    select ISA_BUS
>>> +    select SERIAL
>>> +    select SERIAL_ISA
>>> +    select VIRTIO_PCI
>>>        select PCI_EXPRESS_7A
>>>        select LOONGARCH_IPI
>>>        select LOONGARCH_PCH_PIC
>>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>>> index c42f830208..e4a02e7c18 100644
>>> --- a/hw/loongarch/loongson3.c
>>> +++ b/hw/loongarch/loongson3.c
>>> @@ -10,8 +10,11 @@
>>>    #include "qemu/datadir.h"
>>>    #include "qapi/error.h"
>>>    #include "hw/boards.h"
>>> +#include "hw/char/serial.h"
>>>    #include "sysemu/sysemu.h"
>>>    #include "sysemu/qtest.h"
>>> +#include "hw/irq.h"
>>> +#include "net/net.h"
>>>    #include "sysemu/runstate.h"
>>>    #include "sysemu/reset.h"
>>>    #include "hw/loongarch/loongarch.h"
>>> @@ -20,6 +23,7 @@
>>>    #include "hw/intc/loongarch_pch_pic.h"
>>>    #include "hw/intc/loongarch_pch_msi.h"
>>>    #include "hw/pci-host/ls7a.h"
>>> +#include "hw/misc/unimp.h"
>>>        static void loongarch_cpu_reset(void *opaque)
>>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>>        memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>>    }
>>>    -static void loongson3_irq_init(MachineState *machine)
>>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>>    {
>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>>        SysBusDevice *d;
>>> +    PCIBus *pci_bus;
>>>        int cpu, pin, i;
>>>        unsigned long ipi_addr;
>>>    @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>>        sysbus_realize_and_unref(d, &error_fatal);
>>>        sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>>    +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>>> +
>>>        /* Connect 64 pch_pic irqs to extioi */
>>>        for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>            sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>>            sysbus_connect_irq(d, i,
>>>                               qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>>        }
>>> +
>>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>>> +    d = SYS_BUS_DEVICE(pciehost);
>>> +    sysbus_realize_and_unref(d, &error_fatal);
>>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>>> +
>>> +    /* Connect 48 pci irq to pch_pic */
>>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>>> +        qdev_connect_gpio_out(pciehost, i,
>>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>>> +    }
>>> +
>>> +    return pci_bus;
>>> +}
>>> +
>>> +/* Network support */
>>> +static void network_init(PCIBus *pci_bus)
>>> +{
>>> +    int i;
>>> +
>>> +    for (i = 0; i < nb_nics; i++) {
>>> +        NICInfo *nd = &nd_table[i];
>>> +
>>> +        if (!nd->model) {
>>> +            nd->model = g_strdup("virtio");
>>> +        }
>>> +
>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>> +    }
>>>    }
>>>      static void loongson3_init(MachineState *machine)
>>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>>        MemoryRegion *address_space_mem = get_system_memory();
>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>        int i;
>>> +    PCIBus *pci_bus = NULL;
>>>          if (!cpu_model) {
>>>            cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>>        memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>>        offset += highram_size;
>>>    +    /*
>>> +     * There are some invalid guest memory access.
>>> +     * Create some unimplemented devices to emulate this.
>>> +     */
>>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>>> +
>>>        /* Initialize the IO interrupt subsystem */
>>> -    loongson3_irq_init(machine);
>>> +    pci_bus = loongson3_irq_init(machine);
>>> +
>>> +    /* Network card */
>>> +    network_init(pci_bus);
>>> +
>>> +    /* VGA setup. Don't bother loading the bios. */
>>> +    pci_vga_init(pci_bus);
>>> +
>>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
>>
>> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
>>
>> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.
> 
> The machine has these devices but we don't want to emulate all the devices, only emulated part devices.
> I don't know if it is ok to do like this.

I'm not sure I understand what you mean by part devices here - could you give an example?

>>>        LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>>        LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>>> index a783fb2eda..06cd641573 100644
>>> --- a/hw/pci-host/ls7a.c
>>> +++ b/hw/pci-host/ls7a.c
>>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>>        }
>>>    };
>>>    +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>>> +{
>>> +    PCIINTxRoute route;
>>> +
>>> +    route.irq = pin;
>>> +    route.mode = PCI_INTX_ENABLED;
>>> +    return route;
>>> +}
>>> +
>>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>>> +{
>>> +    PCIBus *bus;
>>> +    int offset, irq;
>>> +
>>> +    bus = pci_get_bus(d);
>>> +    if (bus->parent_dev) {
>>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>>> +        return irq;
>>> +    }
>>
>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
> 
> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.

I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected 
via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at 
pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to 
map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), 
which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?

>>> +    /* pci device start from irq 80 */
>>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>>> +
>>> +    return irq;
>>> +}
>>> +
>>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>>> +{
>>> +    LS7APCIEHost *pciehost = opaque;
>>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>> +
>>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>>> +}
>>> +
>>>    static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>>                                      uint64_t val, unsigned size)
>>>    {
>>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>>        LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>>        PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>>    -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>>> +                                     pci_ls7a_map_irq, s,
>>>                                         get_system_memory(), get_system_io(),
>>>                                         PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>>    +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>>> +
>>>        memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>>                              &pci_ls7a_config_ops, pci->bus,
>>>                              "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>>        object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>>        qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>>        qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>>> +
>>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>>    }
>>>      static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>>> index d2397e53e7..1113c3b1a8 100644
>>> --- a/include/hw/intc/loongarch_ipi.h
>>> +++ b/include/hw/intc/loongarch_ipi.h
>>> @@ -8,6 +8,8 @@
>>>    #ifndef HW_LOONGARCH_IPI_H
>>>    #define HW_LOONGARCH_IPI_H
>>>    +#include "hw/sysbus.h"
>>> +
>>>    /* Mainy used by iocsr read and write */
>>>    #define SMP_IPI_MAILBOX      0x1000ULL
>>>    #define CORE_STATUS_OFF       0x0
>>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>>> index ac938d6d5f..3b9ad1e175 100644
>>> --- a/include/hw/pci-host/ls7a.h
>>> +++ b/include/hw/pci-host/ls7a.h
>>> @@ -37,6 +37,9 @@
>>>    #define LS7A_DEVICE_IRQS        16
>>>    #define LS7A_PCI_IRQS           48
>>>    +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>>> +#define LS7A_UART_BASE          0x1fe001e0
>>> +
>>>    struct LS7APCIState {
>>>        /*< private >*/
>>>        PCIDevice parent_obj;
>>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>>          LS7APCIState pci_dev;
>>>    +    qemu_irq irqs[LS7A_PCI_IRQS];
>>>        MemoryRegion pci_conf;
>>>        MemoryRegion pci_io;
>>>    } LS7APCIEHost;
>>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>>> index 01f3834db5..49491d74a1 100644
>>> --- a/softmmu/qdev-monitor.c
>>> +++ b/softmmu/qdev-monitor.c
>>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>>                                  QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>>                                  QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>>                                  QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>>> +                              QEMU_ARCH_LOONGARCH)
>>
>> This part looks like it belongs to another patch?
> 
> OK, I will put this part to a separate patch.
> 
> Thanks,
> Xiaojuan
> 
>>
>>>    #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>>    #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)

ATB,

Mark.
Xiaojuan Yang Jan. 10, 2022, 2:26 a.m. UTC | #6
Hi, Mark

On 12/23/2021 06:52 PM, Mark Cave-Ayland wrote:
> On 22/12/2021 08:26, yangxiaojuan wrote:
> 
>> Hi, Mark
>>
>> On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
>>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>>
>>>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>>>> 2.Add irq set and map for the pci host. Non pci device
>>>> use irq 0-16, pci device use 16-64.
>>>> 3.Add some unimplented device to emulate guest unused
>>>> memory space.
>>>>
>>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>> ---
>>>>    hw/loongarch/Kconfig            |  8 +++++
>>>>    hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>>>    hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>>>    include/hw/intc/loongarch_ipi.h |  2 ++
>>>>    include/hw/pci-host/ls7a.h      |  4 +++
>>>>    softmmu/qdev-monitor.c          |  3 +-
>>>>    6 files changed, 117 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>>> index 468e3acc74..9ea3b92708 100644
>>>> --- a/hw/loongarch/Kconfig
>>>> +++ b/hw/loongarch/Kconfig
>>>> @@ -1,5 +1,13 @@
>>>>    config LOONGSON3_LS7A
>>>>        bool
>>>> +    imply VGA_PCI
>>>> +    imply VIRTIO_VGA
>>>> +    imply PARALLEL
>>>> +    imply PCI_DEVICES
>>>> +    select ISA_BUS
>>>> +    select SERIAL
>>>> +    select SERIAL_ISA
>>>> +    select VIRTIO_PCI
>>>>        select PCI_EXPRESS_7A
>>>>        select LOONGARCH_IPI
>>>>        select LOONGARCH_PCH_PIC
>>>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>>>> index c42f830208..e4a02e7c18 100644
>>>> --- a/hw/loongarch/loongson3.c
>>>> +++ b/hw/loongarch/loongson3.c
>>>> @@ -10,8 +10,11 @@
>>>>    #include "qemu/datadir.h"
>>>>    #include "qapi/error.h"
>>>>    #include "hw/boards.h"
>>>> +#include "hw/char/serial.h"
>>>>    #include "sysemu/sysemu.h"
>>>>    #include "sysemu/qtest.h"
>>>> +#include "hw/irq.h"
>>>> +#include "net/net.h"
>>>>    #include "sysemu/runstate.h"
>>>>    #include "sysemu/reset.h"
>>>>    #include "hw/loongarch/loongarch.h"
>>>> @@ -20,6 +23,7 @@
>>>>    #include "hw/intc/loongarch_pch_pic.h"
>>>>    #include "hw/intc/loongarch_pch_msi.h"
>>>>    #include "hw/pci-host/ls7a.h"
>>>> +#include "hw/misc/unimp.h"
>>>>        static void loongarch_cpu_reset(void *opaque)
>>>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>>>        memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>>>    }
>>>>    -static void loongson3_irq_init(MachineState *machine)
>>>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>>>    {
>>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>>>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>>>        SysBusDevice *d;
>>>> +    PCIBus *pci_bus;
>>>>        int cpu, pin, i;
>>>>        unsigned long ipi_addr;
>>>>    @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>>>        sysbus_realize_and_unref(d, &error_fatal);
>>>>        sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>>>    +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>>>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>>>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>>>> +
>>>>        /* Connect 64 pch_pic irqs to extioi */
>>>>        for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>>            sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>>>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>>>            sysbus_connect_irq(d, i,
>>>>                               qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>>>        }
>>>> +
>>>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>>>> +    d = SYS_BUS_DEVICE(pciehost);
>>>> +    sysbus_realize_and_unref(d, &error_fatal);
>>>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>>>> +
>>>> +    /* Connect 48 pci irq to pch_pic */
>>>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>>>> +        qdev_connect_gpio_out(pciehost, i,
>>>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>>>> +    }
>>>> +
>>>> +    return pci_bus;
>>>> +}
>>>> +
>>>> +/* Network support */
>>>> +static void network_init(PCIBus *pci_bus)
>>>> +{
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < nb_nics; i++) {
>>>> +        NICInfo *nd = &nd_table[i];
>>>> +
>>>> +        if (!nd->model) {
>>>> +            nd->model = g_strdup("virtio");
>>>> +        }
>>>> +
>>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>>> +    }
>>>>    }
>>>>      static void loongson3_init(MachineState *machine)
>>>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>>>        MemoryRegion *address_space_mem = get_system_memory();
>>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>>        int i;
>>>> +    PCIBus *pci_bus = NULL;
>>>>          if (!cpu_model) {
>>>>            cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>>>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>>>        memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>>>        offset += highram_size;
>>>>    +    /*
>>>> +     * There are some invalid guest memory access.
>>>> +     * Create some unimplemented devices to emulate this.
>>>> +     */
>>>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>>>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>>>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>>>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>>>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>>>> +
>>>>        /* Initialize the IO interrupt subsystem */
>>>> -    loongson3_irq_init(machine);
>>>> +    pci_bus = loongson3_irq_init(machine);
>>>> +
>>>> +    /* Network card */
>>>> +    network_init(pci_bus);
>>>> +
>>>> +    /* VGA setup. Don't bother loading the bios. */
>>>> +    pci_vga_init(pci_bus);
>>>> +
>>>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
>>>
>>> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
>>>
>>> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.
>>
>> The machine has these devices but we don't want to emulate all the devices, only emulated part devices.
>> I don't know if it is ok to do like this.
> 
> I'm not sure I understand what you mean by part devices here - could you give an example?


For example the ls7a1000 support multiple devices, such as sata, gmac, uart, rtc and so on. But we just realize the rtc.

> 
>>>>        LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>>>        LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>>>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>>>> index a783fb2eda..06cd641573 100644
>>>> --- a/hw/pci-host/ls7a.c
>>>> +++ b/hw/pci-host/ls7a.c
>>>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>>>        }
>>>>    };
>>>>    +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>>>> +{
>>>> +    PCIINTxRoute route;
>>>> +
>>>> +    route.irq = pin;
>>>> +    route.mode = PCI_INTX_ENABLED;
>>>> +    return route;
>>>> +}
>>>> +
>>>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>>>> +{
>>>> +    PCIBus *bus;
>>>> +    int offset, irq;
>>>> +
>>>> +    bus = pci_get_bus(d);
>>>> +    if (bus->parent_dev) {
>>>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>>>> +        return irq;
>>>> +    }
>>>
>>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
>>
>> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
>> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.
> 
> I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?
> 

For this part, I'm a bit confused. I think some pcie devices can directly connect to the host bridges while the pci devices will connected via a pcie-to-pci bridge. So the map irq is like this. 
I will learn more about PCIe to verify whether this idea is correct. Thank you!
 
>>>> +    /* pci device start from irq 80 */
>>>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>>>> +
>>>> +    return irq;
>>>> +}
>>>> +
>>>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>>>> +{
>>>> +    LS7APCIEHost *pciehost = opaque;
>>>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>> +
>>>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>>>> +}
>>>> +
>>>>    static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>>>                                      uint64_t val, unsigned size)
>>>>    {
>>>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>>>        LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>>>        PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>>>    -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>>>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>>>> +                                     pci_ls7a_map_irq, s,
>>>>                                         get_system_memory(), get_system_io(),
>>>>                                         PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>>>    +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>>>> +
>>>>        memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>>>                              &pci_ls7a_config_ops, pci->bus,
>>>>                              "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>>>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>>>        object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>>>        qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>>>        qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>>>> +
>>>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>>>    }
>>>>      static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>>>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>>>> index d2397e53e7..1113c3b1a8 100644
>>>> --- a/include/hw/intc/loongarch_ipi.h
>>>> +++ b/include/hw/intc/loongarch_ipi.h
>>>> @@ -8,6 +8,8 @@
>>>>    #ifndef HW_LOONGARCH_IPI_H
>>>>    #define HW_LOONGARCH_IPI_H
>>>>    +#include "hw/sysbus.h"
>>>> +
>>>>    /* Mainy used by iocsr read and write */
>>>>    #define SMP_IPI_MAILBOX      0x1000ULL
>>>>    #define CORE_STATUS_OFF       0x0
>>>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>>>> index ac938d6d5f..3b9ad1e175 100644
>>>> --- a/include/hw/pci-host/ls7a.h
>>>> +++ b/include/hw/pci-host/ls7a.h
>>>> @@ -37,6 +37,9 @@
>>>>    #define LS7A_DEVICE_IRQS        16
>>>>    #define LS7A_PCI_IRQS           48
>>>>    +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>>>> +#define LS7A_UART_BASE          0x1fe001e0
>>>> +
>>>>    struct LS7APCIState {
>>>>        /*< private >*/
>>>>        PCIDevice parent_obj;
>>>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>>>          LS7APCIState pci_dev;
>>>>    +    qemu_irq irqs[LS7A_PCI_IRQS];
>>>>        MemoryRegion pci_conf;
>>>>        MemoryRegion pci_io;
>>>>    } LS7APCIEHost;
>>>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>>>> index 01f3834db5..49491d74a1 100644
>>>> --- a/softmmu/qdev-monitor.c
>>>> +++ b/softmmu/qdev-monitor.c
>>>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>>>                                  QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>>>                                  QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>>>                                  QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>>>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>>>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>>>> +                              QEMU_ARCH_LOONGARCH)
>>>
>>> This part looks like it belongs to another patch?
>>
>> OK, I will put this part to a separate patch.
>>
>> Thanks,
>> Xiaojuan
>>
>>>
>>>>    #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>>>    #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
> 
> ATB,
> 
> Mark.
bibo mao Jan. 12, 2022, 9:37 a.m. UTC | #7
On 12/23/2021 06:52 PM, Mark Cave-Ayland wrote:
> On 22/12/2021 08:26, yangxiaojuan wrote:
> 
>> Hi, Mark
>>
>> On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
>>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>>
>>>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>>>> 2.Add irq set and map for the pci host. Non pci device
>>>> use irq 0-16, pci device use 16-64.
>>>> 3.Add some unimplented device to emulate guest unused
>>>> memory space.
>>>>
>>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>> ---
>>>>    hw/loongarch/Kconfig            |  8 +++++
>>>>    hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>>>    hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>>>    include/hw/intc/loongarch_ipi.h |  2 ++
>>>>    include/hw/pci-host/ls7a.h      |  4 +++
>>>>    softmmu/qdev-monitor.c          |  3 +-
>>>>    6 files changed, 117 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>>> index 468e3acc74..9ea3b92708 100644
>>>> --- a/hw/loongarch/Kconfig
>>>> +++ b/hw/loongarch/Kconfig
>>>> @@ -1,5 +1,13 @@
>>>>    config LOONGSON3_LS7A
>>>>        bool
>>>> +    imply VGA_PCI
>>>> +    imply VIRTIO_VGA
>>>> +    imply PARALLEL
>>>> +    imply PCI_DEVICES
>>>> +    select ISA_BUS
>>>> +    select SERIAL
>>>> +    select SERIAL_ISA
>>>> +    select VIRTIO_PCI
>>>>        select PCI_EXPRESS_7A
>>>>        select LOONGARCH_IPI
>>>>        select LOONGARCH_PCH_PIC
>>>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>>>> index c42f830208..e4a02e7c18 100644
>>>> --- a/hw/loongarch/loongson3.c
>>>> +++ b/hw/loongarch/loongson3.c
>>>> @@ -10,8 +10,11 @@
>>>>    #include "qemu/datadir.h"
>>>>    #include "qapi/error.h"
>>>>    #include "hw/boards.h"
>>>> +#include "hw/char/serial.h"
>>>>    #include "sysemu/sysemu.h"
>>>>    #include "sysemu/qtest.h"
>>>> +#include "hw/irq.h"
>>>> +#include "net/net.h"
>>>>    #include "sysemu/runstate.h"
>>>>    #include "sysemu/reset.h"
>>>>    #include "hw/loongarch/loongarch.h"
>>>> @@ -20,6 +23,7 @@
>>>>    #include "hw/intc/loongarch_pch_pic.h"
>>>>    #include "hw/intc/loongarch_pch_msi.h"
>>>>    #include "hw/pci-host/ls7a.h"
>>>> +#include "hw/misc/unimp.h"
>>>>        static void loongarch_cpu_reset(void *opaque)
>>>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>>>        memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>>>    }
>>>>    -static void loongson3_irq_init(MachineState *machine)
>>>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>>>    {
>>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>>>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>>>        SysBusDevice *d;
>>>> +    PCIBus *pci_bus;
>>>>        int cpu, pin, i;
>>>>        unsigned long ipi_addr;
>>>>    @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>>>        sysbus_realize_and_unref(d, &error_fatal);
>>>>        sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>>>    +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>>>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>>>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>>>> +
>>>>        /* Connect 64 pch_pic irqs to extioi */
>>>>        for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>>            sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>>>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>>>            sysbus_connect_irq(d, i,
>>>>                               qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>>>        }
>>>> +
>>>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>>>> +    d = SYS_BUS_DEVICE(pciehost);
>>>> +    sysbus_realize_and_unref(d, &error_fatal);
>>>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>>>> +
>>>> +    /* Connect 48 pci irq to pch_pic */
>>>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>>>> +        qdev_connect_gpio_out(pciehost, i,
>>>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>>>> +    }
>>>> +
>>>> +    return pci_bus;
>>>> +}
>>>> +
>>>> +/* Network support */
>>>> +static void network_init(PCIBus *pci_bus)
>>>> +{
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < nb_nics; i++) {
>>>> +        NICInfo *nd = &nd_table[i];
>>>> +
>>>> +        if (!nd->model) {
>>>> +            nd->model = g_strdup("virtio");
>>>> +        }
>>>> +
>>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>>> +    }
>>>>    }
>>>>      static void loongson3_init(MachineState *machine)
>>>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>>>        MemoryRegion *address_space_mem = get_system_memory();
>>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>>        int i;
>>>> +    PCIBus *pci_bus = NULL;
>>>>          if (!cpu_model) {
>>>>            cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>>>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>>>        memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>>>        offset += highram_size;
>>>>    +    /*
>>>> +     * There are some invalid guest memory access.
>>>> +     * Create some unimplemented devices to emulate this.
>>>> +     */
>>>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>>>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>>>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>>>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>>>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>>>> +
>>>>        /* Initialize the IO interrupt subsystem */
>>>> -    loongson3_irq_init(machine);
>>>> +    pci_bus = loongson3_irq_init(machine);
>>>> +
>>>> +    /* Network card */
>>>> +    network_init(pci_bus);
>>>> +
>>>> +    /* VGA setup. Don't bother loading the bios. */
>>>> +    pci_vga_init(pci_bus);
>>>> +
>>>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
>>>
>>> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
>>>
>>> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.
>>
>> The machine has these devices but we don't want to emulate all the devices, only emulated part devices.
>> I don't know if it is ok to do like this.
> 
> I'm not sure I understand what you mean by part devices here - could you give an example?
> 
>>>>        LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>>>        LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>>>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>>>> index a783fb2eda..06cd641573 100644
>>>> --- a/hw/pci-host/ls7a.c
>>>> +++ b/hw/pci-host/ls7a.c
>>>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>>>        }
>>>>    };
>>>>    +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>>>> +{
>>>> +    PCIINTxRoute route;
>>>> +
>>>> +    route.irq = pin;
>>>> +    route.mode = PCI_INTX_ENABLED;
>>>> +    return route;
>>>> +}
>>>> +
>>>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>>>> +{
>>>> +    PCIBus *bus;
>>>> +    int offset, irq;
>>>> +
>>>> +    bus = pci_get_bus(d);
>>>> +    if (bus->parent_dev) {
>>>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>>>> +        return irq;
>>>> +    }
>>>
>>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
>>
>> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
>> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.
> 
> I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?

Oh, we will remove these lines. Our original thoughts is that irq-lines of
root bridge is connected with irq controller, so root bridge can have more than
4 irq-lines, non root-bridge has 4 irq-lines at most.

From the code it is only treated as pcie root bridge, and its parent_dev is NULL
always. and we can simply add these sentences such as:
    /* pci device start from irq 80 */
    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;

    return irq;

regards
bibo, mao

> 
>>>> +    /* pci device start from irq 80 */
>>>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>>>> +
>>>> +    return irq;
>>>> +}
>>>> +
>>>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>>>> +{
>>>> +    LS7APCIEHost *pciehost = opaque;
>>>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>> +
>>>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>>>> +}
>>>> +
>>>>    static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>>>                                      uint64_t val, unsigned size)
>>>>    {
>>>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>>>        LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>>>        PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>>>    -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>>>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>>>> +                                     pci_ls7a_map_irq, s,
>>>>                                         get_system_memory(), get_system_io(),
>>>>                                         PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>>>    +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>>>> +
>>>>        memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>>>                              &pci_ls7a_config_ops, pci->bus,
>>>>                              "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>>>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>>>        object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>>>        qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>>>        qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>>>> +
>>>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>>>    }
>>>>      static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>>>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>>>> index d2397e53e7..1113c3b1a8 100644
>>>> --- a/include/hw/intc/loongarch_ipi.h
>>>> +++ b/include/hw/intc/loongarch_ipi.h
>>>> @@ -8,6 +8,8 @@
>>>>    #ifndef HW_LOONGARCH_IPI_H
>>>>    #define HW_LOONGARCH_IPI_H
>>>>    +#include "hw/sysbus.h"
>>>> +
>>>>    /* Mainy used by iocsr read and write */
>>>>    #define SMP_IPI_MAILBOX      0x1000ULL
>>>>    #define CORE_STATUS_OFF       0x0
>>>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>>>> index ac938d6d5f..3b9ad1e175 100644
>>>> --- a/include/hw/pci-host/ls7a.h
>>>> +++ b/include/hw/pci-host/ls7a.h
>>>> @@ -37,6 +37,9 @@
>>>>    #define LS7A_DEVICE_IRQS        16
>>>>    #define LS7A_PCI_IRQS           48
>>>>    +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>>>> +#define LS7A_UART_BASE          0x1fe001e0
>>>> +
>>>>    struct LS7APCIState {
>>>>        /*< private >*/
>>>>        PCIDevice parent_obj;
>>>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>>>          LS7APCIState pci_dev;
>>>>    +    qemu_irq irqs[LS7A_PCI_IRQS];
>>>>        MemoryRegion pci_conf;
>>>>        MemoryRegion pci_io;
>>>>    } LS7APCIEHost;
>>>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>>>> index 01f3834db5..49491d74a1 100644
>>>> --- a/softmmu/qdev-monitor.c
>>>> +++ b/softmmu/qdev-monitor.c
>>>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>>>                                  QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>>>                                  QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>>>                                  QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>>>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>>>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>>>> +                              QEMU_ARCH_LOONGARCH)
>>>
>>> This part looks like it belongs to another patch?
>>
>> OK, I will put this part to a separate patch.
>>
>> Thanks,
>> Xiaojuan
>>
>>>
>>>>    #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>>>    #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
> 
> ATB,
> 
> Mark.
Mark Cave-Ayland Jan. 15, 2022, 2:03 p.m. UTC | #8
On 10/01/2022 02:26, yangxiaojuan wrote:

> Hi, Mark
> 
> On 12/23/2021 06:52 PM, Mark Cave-Ayland wrote:
>> On 22/12/2021 08:26, yangxiaojuan wrote:
>>
>>> Hi, Mark
>>>
>>> On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
>>>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>>>
>>>>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>>>>> 2.Add irq set and map for the pci host. Non pci device
>>>>> use irq 0-16, pci device use 16-64.
>>>>> 3.Add some unimplented device to emulate guest unused
>>>>> memory space.
>>>>>
>>>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>>> ---
>>>>>     hw/loongarch/Kconfig            |  8 +++++
>>>>>     hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>>>>     hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>>>>     include/hw/intc/loongarch_ipi.h |  2 ++
>>>>>     include/hw/pci-host/ls7a.h      |  4 +++
>>>>>     softmmu/qdev-monitor.c          |  3 +-
>>>>>     6 files changed, 117 insertions(+), 5 deletions(-)
>>>>>
>>>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>>>> index 468e3acc74..9ea3b92708 100644
>>>>> --- a/hw/loongarch/Kconfig
>>>>> +++ b/hw/loongarch/Kconfig
>>>>> @@ -1,5 +1,13 @@
>>>>>     config LOONGSON3_LS7A
>>>>>         bool
>>>>> +    imply VGA_PCI
>>>>> +    imply VIRTIO_VGA
>>>>> +    imply PARALLEL
>>>>> +    imply PCI_DEVICES
>>>>> +    select ISA_BUS
>>>>> +    select SERIAL
>>>>> +    select SERIAL_ISA
>>>>> +    select VIRTIO_PCI
>>>>>         select PCI_EXPRESS_7A
>>>>>         select LOONGARCH_IPI
>>>>>         select LOONGARCH_PCH_PIC
>>>>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>>>>> index c42f830208..e4a02e7c18 100644
>>>>> --- a/hw/loongarch/loongson3.c
>>>>> +++ b/hw/loongarch/loongson3.c
>>>>> @@ -10,8 +10,11 @@
>>>>>     #include "qemu/datadir.h"
>>>>>     #include "qapi/error.h"
>>>>>     #include "hw/boards.h"
>>>>> +#include "hw/char/serial.h"
>>>>>     #include "sysemu/sysemu.h"
>>>>>     #include "sysemu/qtest.h"
>>>>> +#include "hw/irq.h"
>>>>> +#include "net/net.h"
>>>>>     #include "sysemu/runstate.h"
>>>>>     #include "sysemu/reset.h"
>>>>>     #include "hw/loongarch/loongarch.h"
>>>>> @@ -20,6 +23,7 @@
>>>>>     #include "hw/intc/loongarch_pch_pic.h"
>>>>>     #include "hw/intc/loongarch_pch_msi.h"
>>>>>     #include "hw/pci-host/ls7a.h"
>>>>> +#include "hw/misc/unimp.h"
>>>>>         static void loongarch_cpu_reset(void *opaque)
>>>>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>>>>         memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>>>>     }
>>>>>     -static void loongson3_irq_init(MachineState *machine)
>>>>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>>>>     {
>>>>>         LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>>>>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>>>>         SysBusDevice *d;
>>>>> +    PCIBus *pci_bus;
>>>>>         int cpu, pin, i;
>>>>>         unsigned long ipi_addr;
>>>>>     @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>>>>         sysbus_realize_and_unref(d, &error_fatal);
>>>>>         sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>>>>     +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>>>>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>>>>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>>>>> +
>>>>>         /* Connect 64 pch_pic irqs to extioi */
>>>>>         for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>>>             sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>>>>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>>>>             sysbus_connect_irq(d, i,
>>>>>                                qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>>>>         }
>>>>> +
>>>>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>>>>> +    d = SYS_BUS_DEVICE(pciehost);
>>>>> +    sysbus_realize_and_unref(d, &error_fatal);
>>>>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>>>>> +
>>>>> +    /* Connect 48 pci irq to pch_pic */
>>>>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>>>>> +        qdev_connect_gpio_out(pciehost, i,
>>>>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>>>>> +    }
>>>>> +
>>>>> +    return pci_bus;
>>>>> +}
>>>>> +
>>>>> +/* Network support */
>>>>> +static void network_init(PCIBus *pci_bus)
>>>>> +{
>>>>> +    int i;
>>>>> +
>>>>> +    for (i = 0; i < nb_nics; i++) {
>>>>> +        NICInfo *nd = &nd_table[i];
>>>>> +
>>>>> +        if (!nd->model) {
>>>>> +            nd->model = g_strdup("virtio");
>>>>> +        }
>>>>> +
>>>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>>>> +    }
>>>>>     }
>>>>>       static void loongson3_init(MachineState *machine)
>>>>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>>>>         MemoryRegion *address_space_mem = get_system_memory();
>>>>>         LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>>>         int i;
>>>>> +    PCIBus *pci_bus = NULL;
>>>>>           if (!cpu_model) {
>>>>>             cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>>>>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>>>>         memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>>>>         offset += highram_size;
>>>>>     +    /*
>>>>> +     * There are some invalid guest memory access.
>>>>> +     * Create some unimplemented devices to emulate this.
>>>>> +     */
>>>>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>>>>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>>>>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>>>>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>>>>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>>>>> +
>>>>>         /* Initialize the IO interrupt subsystem */
>>>>> -    loongson3_irq_init(machine);
>>>>> +    pci_bus = loongson3_irq_init(machine);
>>>>> +
>>>>> +    /* Network card */
>>>>> +    network_init(pci_bus);
>>>>> +
>>>>> +    /* VGA setup. Don't bother loading the bios. */
>>>>> +    pci_vga_init(pci_bus);
>>>>> +
>>>>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
>>>>
>>>> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
>>>>
>>>> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.
>>>
>>> The machine has these devices but we don't want to emulate all the devices, only emulated part devices.
>>> I don't know if it is ok to do like this.
>>
>> I'm not sure I understand what you mean by part devices here - could you give an example?
> 
> 
> For example the ls7a1000 support multiple devices, such as sata, gmac, uart, rtc and so on. But we just realize the rtc.

 From what I understand from the patchset you are creating a special "virt" board so 
of course it is up to you which devices you wish to support as long as they are 
documented somewhere.

>>
>>>>>         LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>>>>         LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>>>>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>>>>> index a783fb2eda..06cd641573 100644
>>>>> --- a/hw/pci-host/ls7a.c
>>>>> +++ b/hw/pci-host/ls7a.c
>>>>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>>>>         }
>>>>>     };
>>>>>     +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>>>>> +{
>>>>> +    PCIINTxRoute route;
>>>>> +
>>>>> +    route.irq = pin;
>>>>> +    route.mode = PCI_INTX_ENABLED;
>>>>> +    return route;
>>>>> +}
>>>>> +
>>>>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>>>>> +{
>>>>> +    PCIBus *bus;
>>>>> +    int offset, irq;
>>>>> +
>>>>> +    bus = pci_get_bus(d);
>>>>> +    if (bus->parent_dev) {
>>>>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>>>>> +        return irq;
>>>>> +    }
>>>>
>>>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
>>>
>>> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
>>> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.
>>
>> I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?
>>
> 
> For this part, I'm a bit confused. I think some pcie devices can directly connect to the host bridges while the pci devices will connected via a pcie-to-pci bridge. So the map irq is like this.
> I will learn more about PCIe to verify whether this idea is correct. Thank you!
>   
>>>>> +    /* pci device start from irq 80 */
>>>>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>>>>> +
>>>>> +    return irq;
>>>>> +}
>>>>> +
>>>>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>>>>> +{
>>>>> +    LS7APCIEHost *pciehost = opaque;
>>>>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>>> +
>>>>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>>>>> +}
>>>>> +
>>>>>     static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>>>>                                       uint64_t val, unsigned size)
>>>>>     {
>>>>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>>>>         LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>>>>         PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>>>>     -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>>>>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>>>>> +                                     pci_ls7a_map_irq, s,
>>>>>                                          get_system_memory(), get_system_io(),
>>>>>                                          PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>>>>     +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>>>>> +
>>>>>         memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>>>>                               &pci_ls7a_config_ops, pci->bus,
>>>>>                               "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>>>>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>>>>         object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>>>>         qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>>>>         qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>>>>> +
>>>>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>>>>     }
>>>>>       static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>>>>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>>>>> index d2397e53e7..1113c3b1a8 100644
>>>>> --- a/include/hw/intc/loongarch_ipi.h
>>>>> +++ b/include/hw/intc/loongarch_ipi.h
>>>>> @@ -8,6 +8,8 @@
>>>>>     #ifndef HW_LOONGARCH_IPI_H
>>>>>     #define HW_LOONGARCH_IPI_H
>>>>>     +#include "hw/sysbus.h"
>>>>> +
>>>>>     /* Mainy used by iocsr read and write */
>>>>>     #define SMP_IPI_MAILBOX      0x1000ULL
>>>>>     #define CORE_STATUS_OFF       0x0
>>>>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>>>>> index ac938d6d5f..3b9ad1e175 100644
>>>>> --- a/include/hw/pci-host/ls7a.h
>>>>> +++ b/include/hw/pci-host/ls7a.h
>>>>> @@ -37,6 +37,9 @@
>>>>>     #define LS7A_DEVICE_IRQS        16
>>>>>     #define LS7A_PCI_IRQS           48
>>>>>     +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>>>>> +#define LS7A_UART_BASE          0x1fe001e0
>>>>> +
>>>>>     struct LS7APCIState {
>>>>>         /*< private >*/
>>>>>         PCIDevice parent_obj;
>>>>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>>>>           LS7APCIState pci_dev;
>>>>>     +    qemu_irq irqs[LS7A_PCI_IRQS];
>>>>>         MemoryRegion pci_conf;
>>>>>         MemoryRegion pci_io;
>>>>>     } LS7APCIEHost;
>>>>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>>>>> index 01f3834db5..49491d74a1 100644
>>>>> --- a/softmmu/qdev-monitor.c
>>>>> +++ b/softmmu/qdev-monitor.c
>>>>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>>>>                                   QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>>>>                                   QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>>>>                                   QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>>>>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>>>>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>>>>> +                              QEMU_ARCH_LOONGARCH)
>>>>
>>>> This part looks like it belongs to another patch?
>>>
>>> OK, I will put this part to a separate patch.
>>>
>>> Thanks,
>>> Xiaojuan
>>>
>>>>
>>>>>     #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>>>>     #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
>>
>> ATB,
>>
>> Mark.


ATB,

Mark.
Mark Cave-Ayland Jan. 15, 2022, 2:05 p.m. UTC | #9
On 12/01/2022 09:37, maobibo wrote:

>>>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
>>>
>>> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
>>> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.
>>
>> I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?
> 
> Oh, we will remove these lines. Our original thoughts is that irq-lines of
> root bridge is connected with irq controller, so root bridge can have more than
> 4 irq-lines, non root-bridge has 4 irq-lines at most.
> 
>>From the code it is only treated as pcie root bridge, and its parent_dev is NULL
> always. and we can simply add these sentences such as:
>      /* pci device start from irq 80 */
>      offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>      irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
> 
>      return irq;

Right, that makes more sense to me. Generally root bridges are different enough from 
downstream bridges to be modelled as a separate device (often with a slightly 
different product id), so if you can remove the parent_dev check and use the above 
that works for me.


ATB,

Mark.
diff mbox series

Patch

diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 468e3acc74..9ea3b92708 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -1,5 +1,13 @@ 
 config LOONGSON3_LS7A
     bool
+    imply VGA_PCI
+    imply VIRTIO_VGA
+    imply PARALLEL
+    imply PCI_DEVICES
+    select ISA_BUS
+    select SERIAL
+    select SERIAL_ISA
+    select VIRTIO_PCI
     select PCI_EXPRESS_7A
     select LOONGARCH_IPI
     select LOONGARCH_PCH_PIC
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index c42f830208..e4a02e7c18 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -10,8 +10,11 @@ 
 #include "qemu/datadir.h"
 #include "qapi/error.h"
 #include "hw/boards.h"
+#include "hw/char/serial.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/qtest.h"
+#include "hw/irq.h"
+#include "net/net.h"
 #include "sysemu/runstate.h"
 #include "sysemu/reset.h"
 #include "hw/loongarch/loongarch.h"
@@ -20,6 +23,7 @@ 
 #include "hw/intc/loongarch_pch_pic.h"
 #include "hw/intc/loongarch_pch_msi.h"
 #include "hw/pci-host/ls7a.h"
+#include "hw/misc/unimp.h"
 
 
 static void loongarch_cpu_reset(void *opaque)
@@ -91,11 +95,12 @@  static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
     memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
 }
 
-static void loongson3_irq_init(MachineState *machine)
+static PCIBus *loongson3_irq_init(MachineState *machine)
 {
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
-    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
+    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
     SysBusDevice *d;
+    PCIBus *pci_bus;
     int cpu, pin, i;
     unsigned long ipi_addr;
 
@@ -135,6 +140,10 @@  static void loongson3_irq_init(MachineState *machine)
     sysbus_realize_and_unref(d, &error_fatal);
     sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
 
+    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
+                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
+                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+
     /* Connect 64 pch_pic irqs to extioi */
     for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
         sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
@@ -149,6 +158,35 @@  static void loongson3_irq_init(MachineState *machine)
         sysbus_connect_irq(d, i,
                            qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
     }
+
+    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
+    d = SYS_BUS_DEVICE(pciehost);
+    sysbus_realize_and_unref(d, &error_fatal);
+    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
+
+    /* Connect 48 pci irq to pch_pic */
+    for (i = 0; i < LS7A_PCI_IRQS; i++) {
+        qdev_connect_gpio_out(pciehost, i,
+                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
+    }
+
+    return pci_bus;
+}
+
+/* Network support */
+static void network_init(PCIBus *pci_bus)
+{
+    int i;
+
+    for (i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!nd->model) {
+            nd->model = g_strdup("virtio");
+        }
+
+        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
+    }
 }
 
 static void loongson3_init(MachineState *machine)
@@ -161,6 +199,7 @@  static void loongson3_init(MachineState *machine)
     MemoryRegion *address_space_mem = get_system_memory();
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
     int i;
+    PCIBus *pci_bus = NULL;
 
     if (!cpu_model) {
         cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
@@ -207,8 +246,26 @@  static void loongson3_init(MachineState *machine)
     memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
     offset += highram_size;
 
+    /*
+     * There are some invalid guest memory access.
+     * Create some unimplemented devices to emulate this.
+     */
+    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
+    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
+    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
+    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
+    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
+
     /* Initialize the IO interrupt subsystem */
-    loongson3_irq_init(machine);
+    pci_bus = loongson3_irq_init(machine);
+
+    /* Network card */
+    network_init(pci_bus);
+
+    /* VGA setup. Don't bother loading the bios. */
+    pci_vga_init(pci_bus);
+
+    pci_create_simple(pci_bus, -1, "pci-ohci");
 
     LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
     LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
index a783fb2eda..06cd641573 100644
--- a/hw/pci-host/ls7a.c
+++ b/hw/pci-host/ls7a.c
@@ -28,6 +28,41 @@  static const VMStateDescription vmstate_ls7a_pcie = {
     }
 };
 
+static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
+{
+    PCIINTxRoute route;
+
+    route.irq = pin;
+    route.mode = PCI_INTX_ENABLED;
+    return route;
+}
+
+static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
+{
+    PCIBus *bus;
+    int offset, irq;
+
+    bus = pci_get_bus(d);
+    if (bus->parent_dev) {
+        irq = pci_swizzle_map_irq_fn(d, irq_num);
+        return irq;
+    }
+
+    /* pci device start from irq 80 */
+    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
+    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
+
+    return irq;
+}
+
+static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
+{
+    LS7APCIEHost *pciehost = opaque;
+    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
+
+    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
+}
+
 static void pci_ls7a_config_write(void *opaque, hwaddr addr,
                                   uint64_t val, unsigned size)
 {
@@ -64,10 +99,13 @@  static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
     LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
     PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
 
-    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
+    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
+                                     pci_ls7a_map_irq, s,
                                      get_system_memory(), get_system_io(),
                                      PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
 
+    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
+
     memory_region_init_io(&s->pci_conf, OBJECT(dev),
                           &pci_ls7a_config_ops, pci->bus,
                           "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
@@ -137,6 +175,8 @@  static void ls7a_pciehost_initfn(Object *obj)
     object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
     qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
     qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
+
+    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
 }
 
 static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
index d2397e53e7..1113c3b1a8 100644
--- a/include/hw/intc/loongarch_ipi.h
+++ b/include/hw/intc/loongarch_ipi.h
@@ -8,6 +8,8 @@ 
 #ifndef HW_LOONGARCH_IPI_H
 #define HW_LOONGARCH_IPI_H
 
+#include "hw/sysbus.h"
+
 /* Mainy used by iocsr read and write */
 #define SMP_IPI_MAILBOX      0x1000ULL
 #define CORE_STATUS_OFF       0x0
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index ac938d6d5f..3b9ad1e175 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -37,6 +37,9 @@ 
 #define LS7A_DEVICE_IRQS        16
 #define LS7A_PCI_IRQS           48
 
+#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
+#define LS7A_UART_BASE          0x1fe001e0
+
 struct LS7APCIState {
     /*< private >*/
     PCIDevice parent_obj;
@@ -51,6 +54,7 @@  typedef struct LS7APCIEHost {
 
     LS7APCIState pci_dev;
 
+    qemu_irq irqs[LS7A_PCI_IRQS];
     MemoryRegion pci_conf;
     MemoryRegion pci_io;
 } LS7APCIEHost;
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index 01f3834db5..49491d74a1 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -60,7 +60,8 @@  typedef struct QDevAlias
                               QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
                               QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
                               QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
-                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
+                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
+                              QEMU_ARCH_LOONGARCH)
 #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
 #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)