diff mbox series

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

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

Commit Message

Alistair Francis Oct. 30, 2018, 10:17 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                     | 111 ++++++++++++++++++++++++++++
 include/hw/riscv/virt.h             |   8 +-
 4 files changed, 127 insertions(+), 4 deletions(-)

Comments

Bin Meng Nov. 5, 2018, 1:23 p.m. UTC | #1
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
Alistair Francis Nov. 5, 2018, 7:47 p.m. UTC | #2
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
Bin Meng Nov. 6, 2018, 6:45 a.m. UTC | #3
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
Alistair Francis Nov. 7, 2018, 9:46 p.m. UTC | #4
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 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 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 {