Message ID | 727db304cd3676f89da0f2f9c5ba12e65795683c.1538683492.git.alistair.francis@wdc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Connect a PCIe host and graphics support to RISC-V | expand |
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
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 --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 };
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(-)