Message ID | 546aa18b75a04a281e82706ea41ee9a4a9f3e2bc.1540937826.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 |
Hi, On Wed, Oct 31, 2018 at 6:22 AM 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 | 111 ++++++++++++++++++++++++++++ > include/hw/riscv/virt.h | 8 +- > 4 files changed, 127 insertions(+), 4 deletions(-) > > 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 4a137a503c..2fbe58ba4b 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,10 @@ static const struct MemmapEntry { > [VIRT_UART0] = { 0x10000000, 0x100 }, > [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, > [VIRT_DRAM] = { 0x80000000, 0x0 }, > + [VIRT_PCIE_MMIO] = { 0x2000000000, 0x4000000 }, Does this work with RV32? > + [VIRT_PCIE_PIO] = { 0x2010000, 0x40000000 }, > + [VIRT_PCIE_ECAM] = { 0x40000000, 0x20000000 }, > + > }; > > static uint64_t load_kernel(const char *kernel_filename) > @@ -98,6 +104,37 @@ static hwaddr load_initrd(const char *filename, uint64_t mem_size, > return *start + size; > } > > +#define INTERREUPT_MAP_WIDTH 7 > + > +static void create_pcie_irq_map(void *fdt, char *nodename, > + uint32_t plic_phandle) > +{ > + int pin; > + uint32_t full_irq_map[GPEX_NUM_IRQS * INTERREUPT_MAP_WIDTH] = { 0 }; > + uint32_t *irq_map = full_irq_map; > + > + for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { > + int irq_nr = PCIE_IRQ + (pin % PCI_NUM_PINS); > + int i; > + > + uint32_t map[] = { > + 0, 0, 0, > + pin + 1, plic_phandle, 0, irq_nr}; > + > + /* Convert map to big endian */ > + for (i = 0; i < INTERREUPT_MAP_WIDTH; i++) { > + irq_map[i] = cpu_to_be32(map[i]); > + } > + irq_map += INTERREUPT_MAP_WIDTH; > + } > + > + qemu_fdt_setprop(fdt, nodename, "interrupt-map", > + full_irq_map, sizeof(full_irq_map)); > + > + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", > + 0, 0, 0, 0x7); > +} > + > static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > uint64_t mem_size, const char *cmdline) > { > @@ -233,6 +270,31 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > g_free(nodename); > } > > + nodename = g_strdup_printf("/pci@%lx", > + (long) memmap[VIRT_PCIE_MMIO].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_cell(fdt, nodename, "linux,pci-domain", 0); > + qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0, > + memmap[VIRT_PCIE_ECAM].base / > + PCIE_MMCFG_SIZE_MIN - 1); > + qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0); > + qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x20, 0, > + 0, memmap[VIRT_PCIE_ECAM].size); > + qemu_fdt_setprop_cells(fdt, nodename, "ranges", > + memmap[VIRT_PCIE_PIO].base, > + 0, memmap[VIRT_PCIE_PIO].size, > + 0, memmap[VIRT_PCIE_MMIO].base, > + 0, memmap[VIRT_PCIE_MMIO].size); This does not conform with the PCI bus ranges encoding. > + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); > + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", PCIE_IRQ); > + create_pcie_irq_map(fdt, nodename, plic_phandle); > + > nodename = g_strdup_printf("/test@%lx", > (long)memmap[VIRT_TEST].base); > qemu_fdt_add_subnode(fdt, nodename); > @@ -262,6 +324,47 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > return fdt; > } > [snip] Regards, Bin
On Mon, Nov 5, 2018 at 5:24 AM Bin Meng <bmeng.cn@gmail.com> wrote: > > Hi, > > On Wed, Oct 31, 2018 at 6:22 AM 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 | 111 ++++++++++++++++++++++++++++ > > include/hw/riscv/virt.h | 8 +- > > 4 files changed, 127 insertions(+), 4 deletions(-) > > > > 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 4a137a503c..2fbe58ba4b 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,10 @@ static const struct MemmapEntry { > > [VIRT_UART0] = { 0x10000000, 0x100 }, > > [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, > > [VIRT_DRAM] = { 0x80000000, 0x0 }, > > + [VIRT_PCIE_MMIO] = { 0x2000000000, 0x4000000 }, > > Does this work with RV32? That's a good point, probably not. This is based on the HiFive unleashed values to be as similar as possible. > > > + [VIRT_PCIE_PIO] = { 0x2010000, 0x40000000 }, > > + [VIRT_PCIE_ECAM] = { 0x40000000, 0x20000000 }, > > + > > }; > > > > static uint64_t load_kernel(const char *kernel_filename) > > @@ -98,6 +104,37 @@ static hwaddr load_initrd(const char *filename, uint64_t mem_size, > > return *start + size; > > } > > > > +#define INTERREUPT_MAP_WIDTH 7 > > + > > +static void create_pcie_irq_map(void *fdt, char *nodename, > > + uint32_t plic_phandle) > > +{ > > + int pin; > > + uint32_t full_irq_map[GPEX_NUM_IRQS * INTERREUPT_MAP_WIDTH] = { 0 }; > > + uint32_t *irq_map = full_irq_map; > > + > > + for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { > > + int irq_nr = PCIE_IRQ + (pin % PCI_NUM_PINS); > > + int i; > > + > > + uint32_t map[] = { > > + 0, 0, 0, > > + pin + 1, plic_phandle, 0, irq_nr}; > > + > > + /* Convert map to big endian */ > > + for (i = 0; i < INTERREUPT_MAP_WIDTH; i++) { > > + irq_map[i] = cpu_to_be32(map[i]); > > + } > > + irq_map += INTERREUPT_MAP_WIDTH; > > + } > > + > > + qemu_fdt_setprop(fdt, nodename, "interrupt-map", > > + full_irq_map, sizeof(full_irq_map)); > > + > > + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", > > + 0, 0, 0, 0x7); > > +} > > + > > static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > > uint64_t mem_size, const char *cmdline) > > { > > @@ -233,6 +270,31 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > > g_free(nodename); > > } > > > > + nodename = g_strdup_printf("/pci@%lx", > > + (long) memmap[VIRT_PCIE_MMIO].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_cell(fdt, nodename, "linux,pci-domain", 0); > > + qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0, > > + memmap[VIRT_PCIE_ECAM].base / > > + PCIE_MMCFG_SIZE_MIN - 1); > > + qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0); > > + qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x20, 0, > > + 0, memmap[VIRT_PCIE_ECAM].size); > > + qemu_fdt_setprop_cells(fdt, nodename, "ranges", > > + memmap[VIRT_PCIE_PIO].base, > > + 0, memmap[VIRT_PCIE_PIO].size, > > + 0, memmap[VIRT_PCIE_MMIO].base, > > + 0, memmap[VIRT_PCIE_MMIO].size); > > This does not conform with the PCI bus ranges encoding. Do you know what should? I have tried so many different combinations here and nothing seems to work. Alistair > > > + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); > > + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", PCIE_IRQ); > > + create_pcie_irq_map(fdt, nodename, plic_phandle); > > + > > nodename = g_strdup_printf("/test@%lx", > > (long)memmap[VIRT_TEST].base); > > qemu_fdt_add_subnode(fdt, nodename); > > @@ -262,6 +324,47 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > > return fdt; > > } > > > > [snip] > > Regards, > Bin
Hi Alistair, On Tue, Nov 6, 2018 at 3:47 AM Alistair Francis <alistair23@gmail.com> wrote: > > On Mon, Nov 5, 2018 at 5:24 AM Bin Meng <bmeng.cn@gmail.com> wrote: > > > > Hi, > > > > On Wed, Oct 31, 2018 at 6:22 AM 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 | 111 ++++++++++++++++++++++++++++ > > > include/hw/riscv/virt.h | 8 +- > > > 4 files changed, 127 insertions(+), 4 deletions(-) > > > > > > 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 4a137a503c..2fbe58ba4b 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,10 @@ static const struct MemmapEntry { > > > [VIRT_UART0] = { 0x10000000, 0x100 }, > > > [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, > > > [VIRT_DRAM] = { 0x80000000, 0x0 }, > > > + [VIRT_PCIE_MMIO] = { 0x2000000000, 0x4000000 }, > > > > Does this work with RV32? > > That's a good point, probably not. This is based on the HiFive > unleashed values to be as similar as possible. > Please specifying a 32-bit address to make it work for both 32-bit and 64-bit. > > > > > + [VIRT_PCIE_PIO] = { 0x2010000, 0x40000000 }, > > > + [VIRT_PCIE_ECAM] = { 0x40000000, 0x20000000 }, Forgot to mention: the maximum size of ECAM is 0x10000000 by spec. > > > + > > > }; > > > > > > static uint64_t load_kernel(const char *kernel_filename) > > > @@ -98,6 +104,37 @@ static hwaddr load_initrd(const char *filename, uint64_t mem_size, > > > return *start + size; > > > } > > > > > > +#define INTERREUPT_MAP_WIDTH 7 > > > + > > > +static void create_pcie_irq_map(void *fdt, char *nodename, > > > + uint32_t plic_phandle) > > > +{ > > > + int pin; > > > + uint32_t full_irq_map[GPEX_NUM_IRQS * INTERREUPT_MAP_WIDTH] = { 0 }; > > > + uint32_t *irq_map = full_irq_map; > > > + > > > + for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { > > > + int irq_nr = PCIE_IRQ + (pin % PCI_NUM_PINS); > > > + int i; > > > + > > > + uint32_t map[] = { > > > + 0, 0, 0, > > > + pin + 1, plic_phandle, 0, irq_nr}; > > > + > > > + /* Convert map to big endian */ > > > + for (i = 0; i < INTERREUPT_MAP_WIDTH; i++) { > > > + irq_map[i] = cpu_to_be32(map[i]); > > > + } > > > + irq_map += INTERREUPT_MAP_WIDTH; > > > + } > > > + > > > + qemu_fdt_setprop(fdt, nodename, "interrupt-map", > > > + full_irq_map, sizeof(full_irq_map)); > > > + > > > + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", > > > + 0, 0, 0, 0x7); > > > +} > > > + > > > static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > > > uint64_t mem_size, const char *cmdline) > > > { > > > @@ -233,6 +270,31 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > > > g_free(nodename); > > > } > > > > > > + nodename = g_strdup_printf("/pci@%lx", > > > + (long) memmap[VIRT_PCIE_MMIO].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_cell(fdt, nodename, "linux,pci-domain", 0); > > > + qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0, > > > + memmap[VIRT_PCIE_ECAM].base / > > > + PCIE_MMCFG_SIZE_MIN - 1); > > > + qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0); > > > + qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x20, 0, > > > + 0, memmap[VIRT_PCIE_ECAM].size); > > > + qemu_fdt_setprop_cells(fdt, nodename, "ranges", > > > + memmap[VIRT_PCIE_PIO].base, > > > + 0, memmap[VIRT_PCIE_PIO].size, > > > + 0, memmap[VIRT_PCIE_MMIO].base, > > > + 0, memmap[VIRT_PCIE_MMIO].size); > > > > This does not conform with the PCI bus ranges encoding. > > Do you know what should? > > I have tried so many different combinations here and nothing seems to work. > qemu_fdt_setprop_sized_cells(fdt, nodename, "ranges", 1, FDT_PCI_RANGE_IOPORT, 2, 0, 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, 1, FDT_PCI_RANGE_MMIO_64BIT, 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size); Note if we are using 32-bit address for the MMIO, FDT_PCI_RANGE_MMIO_64BIT should be FDT_PCI_RANGE_MMIO. Regards, Bin
On Mon, Nov 5, 2018 at 10:45 PM Bin Meng <bmeng.cn@gmail.com> wrote: > > Hi Alistair, > > On Tue, Nov 6, 2018 at 3:47 AM Alistair Francis <alistair23@gmail.com> wrote: > > > > On Mon, Nov 5, 2018 at 5:24 AM Bin Meng <bmeng.cn@gmail.com> wrote: > > > > > > Hi, > > > > > > On Wed, Oct 31, 2018 at 6:22 AM 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 | 111 ++++++++++++++++++++++++++++ > > > > include/hw/riscv/virt.h | 8 +- > > > > 4 files changed, 127 insertions(+), 4 deletions(-) > > > > > > > > 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 4a137a503c..2fbe58ba4b 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,10 @@ static const struct MemmapEntry { > > > > [VIRT_UART0] = { 0x10000000, 0x100 }, > > > > [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, > > > > [VIRT_DRAM] = { 0x80000000, 0x0 }, > > > > + [VIRT_PCIE_MMIO] = { 0x2000000000, 0x4000000 }, > > > > > > Does this work with RV32? > > > > That's a good point, probably not. This is based on the HiFive > > unleashed values to be as similar as possible. > > > > Please specifying a 32-bit address to make it work for both 32-bit and 64-bit. Fixed. > > > > > > > > + [VIRT_PCIE_PIO] = { 0x2010000, 0x40000000 }, > > > > + [VIRT_PCIE_ECAM] = { 0x40000000, 0x20000000 }, > > Forgot to mention: the maximum size of ECAM is 0x10000000 by spec. Fixed > > > > > + > > > > }; > > > > > > > > static uint64_t load_kernel(const char *kernel_filename) > > > > @@ -98,6 +104,37 @@ static hwaddr load_initrd(const char *filename, uint64_t mem_size, > > > > return *start + size; > > > > } > > > > > > > > +#define INTERREUPT_MAP_WIDTH 7 > > > > + > > > > +static void create_pcie_irq_map(void *fdt, char *nodename, > > > > + uint32_t plic_phandle) > > > > +{ > > > > + int pin; > > > > + uint32_t full_irq_map[GPEX_NUM_IRQS * INTERREUPT_MAP_WIDTH] = { 0 }; > > > > + uint32_t *irq_map = full_irq_map; > > > > + > > > > + for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { > > > > + int irq_nr = PCIE_IRQ + (pin % PCI_NUM_PINS); > > > > + int i; > > > > + > > > > + uint32_t map[] = { > > > > + 0, 0, 0, > > > > + pin + 1, plic_phandle, 0, irq_nr}; > > > > + > > > > + /* Convert map to big endian */ > > > > + for (i = 0; i < INTERREUPT_MAP_WIDTH; i++) { > > > > + irq_map[i] = cpu_to_be32(map[i]); > > > > + } > > > > + irq_map += INTERREUPT_MAP_WIDTH; > > > > + } > > > > + > > > > + qemu_fdt_setprop(fdt, nodename, "interrupt-map", > > > > + full_irq_map, sizeof(full_irq_map)); > > > > + > > > > + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", > > > > + 0, 0, 0, 0x7); > > > > +} > > > > + > > > > static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > > > > uint64_t mem_size, const char *cmdline) > > > > { > > > > @@ -233,6 +270,31 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, > > > > g_free(nodename); > > > > } > > > > > > > > + nodename = g_strdup_printf("/pci@%lx", > > > > + (long) memmap[VIRT_PCIE_MMIO].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_cell(fdt, nodename, "linux,pci-domain", 0); > > > > + qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0, > > > > + memmap[VIRT_PCIE_ECAM].base / > > > > + PCIE_MMCFG_SIZE_MIN - 1); > > > > + qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0); > > > > + qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x20, 0, > > > > + 0, memmap[VIRT_PCIE_ECAM].size); > > > > + qemu_fdt_setprop_cells(fdt, nodename, "ranges", > > > > + memmap[VIRT_PCIE_PIO].base, > > > > + 0, memmap[VIRT_PCIE_PIO].size, > > > > + 0, memmap[VIRT_PCIE_MMIO].base, > > > > + 0, memmap[VIRT_PCIE_MMIO].size); > > > > > > This does not conform with the PCI bus ranges encoding. > > > > Do you know what should? > > > > I have tried so many different combinations here and nothing seems to work. > > > > qemu_fdt_setprop_sized_cells(fdt, nodename, "ranges", > 1, FDT_PCI_RANGE_IOPORT, 2, 0, > 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, > 1, FDT_PCI_RANGE_MMIO_64BIT, > 2, memmap[VIRT_PCIE_MMIO].base, > 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size); I'm sure I tried this (based on the ARM virt implementation) and it didn't work, but it's working now. Thanks for the help! It looks like memory accesses are fully working, interrupts still aren't though. Alistair > > Note if we are using 32-bit address for the MMIO, > FDT_PCI_RANGE_MMIO_64BIT should be FDT_PCI_RANGE_MMIO. > > Regards, > Bin
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 4a137a503c..2fbe58ba4b 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,10 @@ static const struct MemmapEntry { [VIRT_UART0] = { 0x10000000, 0x100 }, [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, [VIRT_DRAM] = { 0x80000000, 0x0 }, + [VIRT_PCIE_MMIO] = { 0x2000000000, 0x4000000 }, + [VIRT_PCIE_PIO] = { 0x2010000, 0x40000000 }, + [VIRT_PCIE_ECAM] = { 0x40000000, 0x20000000 }, + }; static uint64_t load_kernel(const char *kernel_filename) @@ -98,6 +104,37 @@ static hwaddr load_initrd(const char *filename, uint64_t mem_size, return *start + size; } +#define INTERREUPT_MAP_WIDTH 7 + +static void create_pcie_irq_map(void *fdt, char *nodename, + uint32_t plic_phandle) +{ + int pin; + uint32_t full_irq_map[GPEX_NUM_IRQS * INTERREUPT_MAP_WIDTH] = { 0 }; + uint32_t *irq_map = full_irq_map; + + for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { + int irq_nr = PCIE_IRQ + (pin % PCI_NUM_PINS); + int i; + + uint32_t map[] = { + 0, 0, 0, + pin + 1, plic_phandle, 0, irq_nr}; + + /* Convert map to big endian */ + for (i = 0; i < INTERREUPT_MAP_WIDTH; i++) { + irq_map[i] = cpu_to_be32(map[i]); + } + irq_map += INTERREUPT_MAP_WIDTH; + } + + qemu_fdt_setprop(fdt, nodename, "interrupt-map", + full_irq_map, sizeof(full_irq_map)); + + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", + 0, 0, 0, 0x7); +} + static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, uint64_t mem_size, const char *cmdline) { @@ -233,6 +270,31 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, g_free(nodename); } + nodename = g_strdup_printf("/pci@%lx", + (long) memmap[VIRT_PCIE_MMIO].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_cell(fdt, nodename, "linux,pci-domain", 0); + qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0, + memmap[VIRT_PCIE_ECAM].base / + PCIE_MMCFG_SIZE_MIN - 1); + qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0); + qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x20, 0, + 0, memmap[VIRT_PCIE_ECAM].size); + qemu_fdt_setprop_cells(fdt, nodename, "ranges", + memmap[VIRT_PCIE_PIO].base, + 0, memmap[VIRT_PCIE_PIO].size, + 0, memmap[VIRT_PCIE_MMIO].base, + 0, memmap[VIRT_PCIE_MMIO].size); + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", PCIE_IRQ); + create_pcie_irq_map(fdt, nodename, plic_phandle); + nodename = g_strdup_printf("/test@%lx", (long)memmap[VIRT_TEST].base); qemu_fdt_add_subnode(fdt, nodename); @@ -262,6 +324,47 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, return fdt; } + +static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, + hwaddr ecam_base, hwaddr ecam_size, + hwaddr mmio_base, hwaddr mmio_size, + hwaddr pio_base, + DeviceState *plic, bool link_up) +{ + DeviceState *dev; + MemoryRegion *ecam_alias, *ecam_reg; + MemoryRegion *mmio_alias, *mmio_reg; + qemu_irq irq; + int i; + + dev = qdev_create(NULL, TYPE_GPEX_HOST); + + qdev_init_nofail(dev); + + ecam_alias = g_new0(MemoryRegion, 1); + ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam", + ecam_reg, 0, ecam_size); + memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias); + + mmio_alias = g_new0(MemoryRegion, 1); + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", + mmio_reg, mmio_base, mmio_size); + memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); + + for (i = 0; i < GPEX_NUM_IRQS; i++) { + irq = qdev_get_gpio_in(plic, PCIE_IRQ + i); + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); + gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i); + } + + return dev; +} + static void riscv_virt_board_init(MachineState *machine) { const struct MemmapEntry *memmap = virt_memmap; @@ -384,6 +487,14 @@ static void riscv_virt_board_init(MachineState *machine) qdev_get_gpio_in(DEVICE(s->plic), VIRTIO_IRQ + i)); } + gpex_pcie_init(system_memory, + memmap[VIRT_PCIE_MMIO].base, + memmap[VIRT_PCIE_MMIO].size, + memmap[VIRT_PCIE_ECAM].base, + memmap[VIRT_PCIE_ECAM].size, + memmap[VIRT_PCIE_PIO].base, + DEVICE(s->plic), 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..dd4feddb42 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -38,14 +38,18 @@ enum { VIRT_PLIC, VIRT_UART0, VIRT_VIRTIO, - VIRT_DRAM + VIRT_DRAM, + VIRT_PCIE_MMIO, + VIRT_PCIE_PIO, + VIRT_PCIE_ECAM }; enum { UART0_IRQ = 10, VIRTIO_IRQ = 1, /* 1 to 8 */ VIRTIO_COUNT = 8, - VIRTIO_NDEV = 0x35 + PCIE_IRQ = 0x20, /* 32 to 35 */ + VIRTIO_NDEV = 0x36 }; enum {
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 | 111 ++++++++++++++++++++++++++++ include/hw/riscv/virt.h | 8 +- 4 files changed, 127 insertions(+), 4 deletions(-)