diff mbox series

[v5,2/5] hw/riscv/virt: Connect the gpex PCIe

Message ID 727db304cd3676f89da0f2f9c5ba12e65795683c.1538683492.git.alistair.francis@wdc.com
State New
Headers show
Series Connect a PCIe host and graphics support to RISC-V | expand

Commit Message

Alistair Francis Oct. 4, 2018, 8:06 p.m. UTC
Connect the gpex PCIe device based on the device tree included in the
HiFive Unleashed ROM.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 default-configs/riscv32-softmmu.mak |  6 ++-
 default-configs/riscv64-softmmu.mak |  6 ++-
 hw/riscv/virt.c                     | 58 +++++++++++++++++++++++++++++
 include/hw/riscv/virt.h             |  4 +-
 4 files changed, 71 insertions(+), 3 deletions(-)

Comments

Peter Maydell Oct. 25, 2018, 6:47 p.m. UTC | #1
On 4 October 2018 at 21:06, Alistair Francis <Alistair.Francis@wdc.com> wrote:
> Connect the gpex PCIe device based on the device tree included in the
> HiFive Unleashed ROM.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  default-configs/riscv32-softmmu.mak |  6 ++-
>  default-configs/riscv64-softmmu.mak |  6 ++-
>  hw/riscv/virt.c                     | 58 +++++++++++++++++++++++++++++
>  include/hw/riscv/virt.h             |  4 +-
>  4 files changed, 71 insertions(+), 3 deletions(-)

> +static inline DeviceState *
> +gpex_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr,
> +                 hwaddr cfg_base, uint64_t cfg_size,
> +                 hwaddr mmio_base, uint64_t mmio_size,
> +                 qemu_irq irq, bool link_up)
> +{
> +    DeviceState *dev;
> +    MemoryRegion *cfg, *mmio;
> +
> +    dev = qdev_create(NULL, TYPE_GPEX_HOST);
> +
> +    qdev_init_nofail(dev);
> +
> +    cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> +    memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0);
> +
> +    mmio = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> +    memory_region_add_subregion_overlap(sys_mem, 0, mmio, 0);

You probably also want to map the gpex's mmio region 2,
which is the PCI IO BAR window. Otherwise PCI devices
with IO BARs won't work right.

> +
> +    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);

GPEX has 4 interrupt lines, corresponding to classic PCI
IRQs A, B, C, D. You need to wire them all up, or only the
first PCI device plugged in will have a working interrupt.
You also don't look to have the bit of device-tree generation
that sets up the interrupt-map, which tells the guest about
the mapping from PCI devfns (ie, which slot the card is in) to
IRQ lines.

> +
> +    return dev;
> +}
> +
>  static void riscv_virt_board_init(MachineState *machine)
>  {
>      const struct MemmapEntry *memmap = virt_memmap;
> @@ -382,6 +436,10 @@ static void riscv_virt_board_init(MachineState *machine)
>              qdev_get_gpio_in(DEVICE(s->plic), VIRTIO_IRQ + i));
>      }
>
> +    gpex_pcie_init(system_memory, 0, memmap[VIRT_PCIE].base,
> +                           memmap[VIRT_PCIE].size, 0x40000000, 0x20000000,

You could put the MMIO BAR window base and size in your memmap[] too...

> +                           qdev_get_gpio_in(DEVICE(s->plic), PCIE_IRQ), true);

thanks
-- PMM
Alistair Francis Oct. 30, 2018, 9:39 p.m. UTC | #2
On Thu, Oct 25, 2018 at 11:47 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On 4 October 2018 at 21:06, Alistair Francis <Alistair.Francis@wdc.com> wrote:
> > Connect the gpex PCIe device based on the device tree included in the
> > HiFive Unleashed ROM.
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  default-configs/riscv32-softmmu.mak |  6 ++-
> >  default-configs/riscv64-softmmu.mak |  6 ++-
> >  hw/riscv/virt.c                     | 58 +++++++++++++++++++++++++++++
> >  include/hw/riscv/virt.h             |  4 +-
> >  4 files changed, 71 insertions(+), 3 deletions(-)
>
> > +static inline DeviceState *
> > +gpex_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr,
> > +                 hwaddr cfg_base, uint64_t cfg_size,
> > +                 hwaddr mmio_base, uint64_t mmio_size,
> > +                 qemu_irq irq, bool link_up)
> > +{
> > +    DeviceState *dev;
> > +    MemoryRegion *cfg, *mmio;
> > +
> > +    dev = qdev_create(NULL, TYPE_GPEX_HOST);
> > +
> > +    qdev_init_nofail(dev);
> > +
> > +    cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> > +    memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0);
> > +
> > +    mmio = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> > +    memory_region_add_subregion_overlap(sys_mem, 0, mmio, 0);
>
> You probably also want to map the gpex's mmio region 2,
> which is the PCI IO BAR window. Otherwise PCI devices
> with IO BARs won't work right.

Ah, I missed this one. Fixed in the next version.

>
> > +
> > +    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
>
> GPEX has 4 interrupt lines, corresponding to classic PCI
> IRQs A, B, C, D. You need to wire them all up, or only the
> first PCI device plugged in will have a working interrupt.
> You also don't look to have the bit of device-tree generation
> that sets up the interrupt-map, which tells the guest about
> the mapping from PCI devfns (ie, which slot the card is in) to
> IRQ lines.

Yep, I based this on the Xilinx PCIe as that's what I started with. I
have updated to use an interrupt-map similar to the ARM virt board.
Interrupts look like they are working now.

>
> > +
> > +    return dev;
> > +}
> > +
> >  static void riscv_virt_board_init(MachineState *machine)
> >  {
> >      const struct MemmapEntry *memmap = virt_memmap;
> > @@ -382,6 +436,10 @@ static void riscv_virt_board_init(MachineState *machine)
> >              qdev_get_gpio_in(DEVICE(s->plic), VIRTIO_IRQ + i));
> >      }
> >
> > +    gpex_pcie_init(system_memory, 0, memmap[VIRT_PCIE].base,
> > +                           memmap[VIRT_PCIE].size, 0x40000000, 0x20000000,
>
> You could put the MMIO BAR window base and size in your memmap[] too...

Fixed in v6.

Alistair

>
> > +                           qdev_get_gpio_in(DEVICE(s->plic), PCIE_IRQ), true);
>
> thanks
> -- PMM
diff mbox series

Patch

diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
index 7937c69e22..3e3d195f37 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -1,7 +1,11 @@ 
 # Default configuration for riscv-softmmu
 
+include pci.mak
+
 CONFIG_SERIAL=y
 CONFIG_VIRTIO_MMIO=y
-include virtio.mak
 
 CONFIG_CADENCE=y
+
+CONFIG_PCI_GENERIC=y
+CONFIG_PCI_XILINX=y
diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
index 7937c69e22..3e3d195f37 100644
--- a/default-configs/riscv64-softmmu.mak
+++ b/default-configs/riscv64-softmmu.mak
@@ -1,7 +1,11 @@ 
 # Default configuration for riscv-softmmu
 
+include pci.mak
+
 CONFIG_SERIAL=y
 CONFIG_VIRTIO_MMIO=y
-include virtio.mak
 
 CONFIG_CADENCE=y
+
+CONFIG_PCI_GENERIC=y
+CONFIG_PCI_XILINX=y
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 005169eabc..9bd2c10581 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -39,6 +39,8 @@ 
 #include "sysemu/arch_init.h"
 #include "sysemu/device_tree.h"
 #include "exec/address-spaces.h"
+#include "hw/pci/pci.h"
+#include "hw/pci-host/gpex.h"
 #include "elf.h"
 
 #include <libfdt.h>
@@ -55,6 +57,7 @@  static const struct MemmapEntry {
     [VIRT_UART0] =    { 0x10000000,      0x100 },
     [VIRT_VIRTIO] =   { 0x10001000,     0x1000 },
     [VIRT_DRAM] =     { 0x80000000,        0x0 },
+    [VIRT_PCIE] =     { 0x2000000000, 0x4000000 },
 };
 
 static uint64_t load_kernel(const char *kernel_filename)
@@ -233,6 +236,32 @@  static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
         g_free(nodename);
     }
 
+    nodename = g_strdup_printf("/pci@%lx",
+        (long) memmap[VIRT_PCIE].base);
+    qemu_fdt_add_subnode(fdt, nodename);
+    qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", 0x3);
+    qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells", 0x1);
+    qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0x2);
+    qemu_fdt_setprop_string(fdt, nodename, "compatible",
+                            "pci-host-ecam-generic");
+    qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci");
+    qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x20, 0x0, 0x0,
+                           memmap[VIRT_PCIE].size);
+    qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
+    qemu_fdt_setprop_cells(fdt, nodename, "ranges", 0x2000000, 0x0,
+                           0x40000000, 0x0, 0x40000000, 0x0, 0x20000000);
+    qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
+    qemu_fdt_setprop_cells(fdt, nodename, "interrupts", PCIE_IRQ);
+    g_free(nodename);
+
+    nodename = g_strdup_printf("/pci@%lx/interrupt-controller",
+            (long) memmap[VIRT_PCIE].base);
+    qemu_fdt_add_subnode(fdt, nodename);
+    qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", 0x00);
+    qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells", 0x1);
+    qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
+    g_free(nodename);
+
     nodename = g_strdup_printf("/test@%lx",
         (long)memmap[VIRT_TEST].base);
     qemu_fdt_add_subnode(fdt, nodename);
@@ -260,6 +289,31 @@  static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
     return fdt;
 }
 
+
+static inline DeviceState *
+gpex_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr,
+                 hwaddr cfg_base, uint64_t cfg_size,
+                 hwaddr mmio_base, uint64_t mmio_size,
+                 qemu_irq irq, bool link_up)
+{
+    DeviceState *dev;
+    MemoryRegion *cfg, *mmio;
+
+    dev = qdev_create(NULL, TYPE_GPEX_HOST);
+
+    qdev_init_nofail(dev);
+
+    cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+    memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0);
+
+    mmio = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+    memory_region_add_subregion_overlap(sys_mem, 0, mmio, 0);
+
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    return dev;
+}
+
 static void riscv_virt_board_init(MachineState *machine)
 {
     const struct MemmapEntry *memmap = virt_memmap;
@@ -382,6 +436,10 @@  static void riscv_virt_board_init(MachineState *machine)
             qdev_get_gpio_in(DEVICE(s->plic), VIRTIO_IRQ + i));
     }
 
+    gpex_pcie_init(system_memory, 0, memmap[VIRT_PCIE].base,
+                           memmap[VIRT_PCIE].size, 0x40000000, 0x20000000,
+                           qdev_get_gpio_in(DEVICE(s->plic), PCIE_IRQ), true);
+
     serial_mm_init(system_memory, memmap[VIRT_UART0].base,
         0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193,
         serial_hd(0), DEVICE_LITTLE_ENDIAN);
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 7cb2742070..d0129c2ca5 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -38,13 +38,15 @@  enum {
     VIRT_PLIC,
     VIRT_UART0,
     VIRT_VIRTIO,
-    VIRT_DRAM
+    VIRT_DRAM,
+    VIRT_PCIE
 };
 
 enum {
     UART0_IRQ = 10,
     VIRTIO_IRQ = 1, /* 1 to 8 */
     VIRTIO_COUNT = 8,
+    PCIE_IRQ = 0x20,
     VIRTIO_NDEV = 0x35
 };