RISC-V Changes for 3.2, Part 1
This pull request contains the first set of RISC-V patches I'd like to target for the 3.2 development cycle. It's really just a collection of bug fixes with one major new feature: PCIe can now be attached to RISC-V guests. This has passed my usual test of booting the latest Linux RC into a Fedora disk image on the virt machine. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEAM520YNJYN/OiG3470yhUCzLq0EFAlwdDlkTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRDvTKFQLMurQWJgEACdUZuZIYGu1b1QjOLmSzPSVa+EvP5V +AAXekfsk3T3dNuVDtQyb2IfcPsI/QZkr6WcO0gWsY4TWPXwm6fMKyvZFBFxq2hM RWYtgeHDSSJ1ZY0AGz8Lz//zC76rJfbQDl5TsPQEX0ARCdV8VI0Uh0paaWDRypHz 5tXruzuHAp0dKk9czyBGC//LrWdNBMGhcti9QxN0ivyvR6FXJndEGvY9UL5WcF8t rPbX+r1n/lezaJTdKAybyy5SaEQoyGChhxyESA9MCj1foE3MKd5oXArOGEmU6dwP PdJznOn1T/4IozAMHYUpzSIlJ5ssoa/KdZbULE4MIWBmfh0+AeVYDnmrGEffdmWw d2MNJrn1yFSEaey+i19DCZIl2+4xbpjzq3GZVDllGGDznXNiG3ORiaiCOATLDubJ WYHxLETln/Ix1fBq3u6QbV7GeJ6EIZ+MobNwJEq1kvmyoU3tqrcFBOYMw7usvTda TcYDVNbhtWtdv0EhwxFpV+8otamcWfoE7OTl5Msy+9ZpV9JWABssvU/aXu68eNi/ nHlCggrXUh4i4c+XoPeyckTj4GQ8QpoSt8PNx8SIbz+ElKC5BoChInXo8o1XKjhA wYLYyL7XH6NjdQAlerIvWIKA6tWKG8SqL8kvr9P05tZLmzc4UoQ1h5QlXf5BiAKO e4qNigdEd+VtYw== =BAOm -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-3.2-part1' into staging RISC-V Changes for 3.2, Part 1 This pull request contains the first set of RISC-V patches I'd like to target for the 3.2 development cycle. It's really just a collection of bug fixes with one major new feature: PCIe can now be attached to RISC-V guests. This has passed my usual test of booting the latest Linux RC into a Fedora disk image on the virt machine. # gpg: Signature made Fri 21 Dec 2018 16:01:29 GMT # gpg: using RSA key EF4CA1502CCBAB41 # gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" # gpg: aka "Palmer Dabbelt <palmer@sifive.com>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41 * remotes/palmer/tags/riscv-for-master-3.2-part1: MAINTAINERS: Mark RISC-V as Supported riscv/cpu: use device_class_set_parent_realize target/riscv/pmp.c: Fix pmp_decode_napot() sifive_uart: Implement interrupt pending register RISC-V: Enable second UART on sifive_e and sifive_u RISC-V: Fix PLIC pending bitfield reads RISC-V: Fix CLINT timecmp low 32-bit writes RISC-V: Add hartid and \n to interrupt logging sifive_u: Set 'clock-frequency' DT property for SiFive UART sifive_u: Add clock DT node for GEM ethernet riscv: Enable VGA and PCIE_VGA hw/riscv/virt: Connect the gpex PCIe hw/riscv/virt: Adjust memory layout spacing hw/riscv/virt: Increase the number of interrupts Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
20d6c7312f
@ -262,7 +262,7 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
|
||||
M: Sagar Karandikar <sagark@eecs.berkeley.edu>
|
||||
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
|
||||
L: qemu-riscv@nongnu.org
|
||||
S: Maintained
|
||||
S: Supported
|
||||
F: target/riscv/
|
||||
F: hw/riscv/
|
||||
F: include/hw/riscv/
|
||||
|
@ -1,7 +1,13 @@
|
||||
# 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_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
|
@ -1,7 +1,13 @@
|
||||
# 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_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
|
@ -146,15 +146,15 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
error_report("clint: invalid timecmp hartid: %zu", hartid);
|
||||
} else if ((addr & 0x7) == 0) {
|
||||
/* timecmp_lo */
|
||||
uint64_t timecmp = env->timecmp;
|
||||
uint64_t timecmp_hi = env->timecmp >> 32;
|
||||
sifive_clint_write_timecmp(RISCV_CPU(cpu),
|
||||
timecmp << 32 | (value & 0xFFFFFFFF));
|
||||
timecmp_hi << 32 | (value & 0xFFFFFFFF));
|
||||
return;
|
||||
} else if ((addr & 0x7) == 4) {
|
||||
/* timecmp_hi */
|
||||
uint64_t timecmp = env->timecmp;
|
||||
uint64_t timecmp_lo = env->timecmp;
|
||||
sifive_clint_write_timecmp(RISCV_CPU(cpu),
|
||||
value << 32 | (timecmp & 0xFFFFFFFF));
|
||||
value << 32 | (timecmp_lo & 0xFFFFFFFF));
|
||||
} else {
|
||||
error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
|
||||
}
|
||||
|
@ -192,9 +192,8 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
|
||||
memmap[SIFIVE_E_QSPI0].base, memmap[SIFIVE_E_QSPI0].size);
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm0",
|
||||
memmap[SIFIVE_E_PWM0].base, memmap[SIFIVE_E_PWM0].size);
|
||||
/* sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base,
|
||||
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic),
|
||||
SIFIVE_E_UART1_IRQ)); */
|
||||
sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base,
|
||||
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART1_IRQ));
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi1",
|
||||
memmap[SIFIVE_E_QSPI1].base, memmap[SIFIVE_E_QSPI1].size);
|
||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm1",
|
||||
|
@ -214,7 +214,7 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size)
|
||||
} else if (addr >= plic->pending_base && /* 1 bit per source */
|
||||
addr < plic->pending_base + (plic->num_sources >> 3))
|
||||
{
|
||||
uint32_t word = (addr - plic->priority_base) >> 2;
|
||||
uint32_t word = (addr - plic->pending_base) >> 2;
|
||||
if (RISCV_DEBUG_PLIC) {
|
||||
qemu_log("plic: read pending: word=%d value=%d\n",
|
||||
word, plic->pending[word]);
|
||||
|
@ -85,7 +85,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
int cpu;
|
||||
uint32_t *cells;
|
||||
char *nodename;
|
||||
uint32_t plic_phandle;
|
||||
char ethclk_names[] = "pclk\0hclk\0tx_clk";
|
||||
uint32_t plic_phandle, ethclk_phandle;
|
||||
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
@ -197,6 +198,17 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
g_free(cells);
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/soc/ethclk");
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SIFIVE_U_GEM_CLOCK_FREQ);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "phandle", 3);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", 3);
|
||||
ethclk_phandle = qemu_fdt_get_phandle(fdt, nodename);
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/soc/ethernet@%lx",
|
||||
(long)memmap[SIFIVE_U_GEM].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
@ -208,6 +220,10 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
qemu_fdt_setprop_string(fdt, nodename, "phy-mode", "gmii");
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
||||
ethclk_phandle, ethclk_phandle, ethclk_phandle);
|
||||
qemu_fdt_setprop(fdt, nodename, "clocks-names", ethclk_names,
|
||||
sizeof(ethclk_names));
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", 1);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0);
|
||||
g_free(nodename);
|
||||
@ -225,6 +241,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||
0x0, memmap[SIFIVE_U_UART0].base,
|
||||
0x0, memmap[SIFIVE_U_UART0].size);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SIFIVE_U_CLOCK_FREQ / 2);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 1);
|
||||
|
||||
@ -350,9 +368,8 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
||||
memmap[SIFIVE_U_PLIC].size);
|
||||
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
|
||||
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
|
||||
/* sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
|
||||
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic),
|
||||
SIFIVE_U_UART1_IRQ)); */
|
||||
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
|
||||
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
|
||||
sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
|
||||
memmap[SIFIVE_U_CLINT].size, smp_cpus,
|
||||
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
||||
|
@ -28,12 +28,26 @@
|
||||
* Not yet implemented:
|
||||
*
|
||||
* Transmit FIFO using "qemu/fifo8.h"
|
||||
* SIFIVE_UART_IE_TXWM interrupts
|
||||
* SIFIVE_UART_IE_RXWM interrupts must honor fifo watermark
|
||||
* Rx FIFO watermark interrupt trigger threshold
|
||||
* Tx FIFO watermark interrupt trigger threshold.
|
||||
*/
|
||||
|
||||
/* Returns the state of the IP (interrupt pending) register */
|
||||
static uint64_t uart_ip(SiFiveUARTState *s)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
|
||||
uint64_t txcnt = SIFIVE_UART_GET_TXCNT(s->txctrl);
|
||||
uint64_t rxcnt = SIFIVE_UART_GET_RXCNT(s->rxctrl);
|
||||
|
||||
if (txcnt != 0) {
|
||||
ret |= SIFIVE_UART_IP_TXWM;
|
||||
}
|
||||
if (s->rx_fifo_len > rxcnt) {
|
||||
ret |= SIFIVE_UART_IP_RXWM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void update_irq(SiFiveUARTState *s)
|
||||
{
|
||||
int cond = 0;
|
||||
@ -69,7 +83,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
case SIFIVE_UART_IE:
|
||||
return s->ie;
|
||||
case SIFIVE_UART_IP:
|
||||
return s->rx_fifo_len ? SIFIVE_UART_IP_RXWM : 0;
|
||||
return uart_ip(s);
|
||||
case SIFIVE_UART_TXCTRL:
|
||||
return s->txctrl;
|
||||
case SIFIVE_UART_RXCTRL:
|
||||
|
147
hw/riscv/virt.c
147
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>
|
||||
@ -47,14 +49,17 @@ static const struct MemmapEntry {
|
||||
hwaddr base;
|
||||
hwaddr size;
|
||||
} virt_memmap[] = {
|
||||
[VIRT_DEBUG] = { 0x0, 0x100 },
|
||||
[VIRT_MROM] = { 0x1000, 0x11000 },
|
||||
[VIRT_TEST] = { 0x100000, 0x1000 },
|
||||
[VIRT_CLINT] = { 0x2000000, 0x10000 },
|
||||
[VIRT_PLIC] = { 0xc000000, 0x4000000 },
|
||||
[VIRT_UART0] = { 0x10000000, 0x100 },
|
||||
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
|
||||
[VIRT_DRAM] = { 0x80000000, 0x0 },
|
||||
[VIRT_DEBUG] = { 0x0, 0x100 },
|
||||
[VIRT_MROM] = { 0x1000, 0x11000 },
|
||||
[VIRT_TEST] = { 0x100000, 0x1000 },
|
||||
[VIRT_CLINT] = { 0x2000000, 0x10000 },
|
||||
[VIRT_PLIC] = { 0xc000000, 0x4000000 },
|
||||
[VIRT_UART0] = { 0x10000000, 0x100 },
|
||||
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
|
||||
[VIRT_DRAM] = { 0x80000000, 0x0 },
|
||||
[VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
|
||||
[VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 },
|
||||
[VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
|
||||
};
|
||||
|
||||
static uint64_t load_kernel(const char *kernel_filename)
|
||||
@ -98,6 +103,51 @@ static hwaddr load_initrd(const char *filename, uint64_t mem_size,
|
||||
return *start + size;
|
||||
}
|
||||
|
||||
static void create_pcie_irq_map(void *fdt, char *nodename,
|
||||
uint32_t plic_phandle)
|
||||
{
|
||||
int pin, dev;
|
||||
uint32_t
|
||||
full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * FDT_INT_MAP_WIDTH] = {};
|
||||
uint32_t *irq_map = full_irq_map;
|
||||
|
||||
/* This code creates a standard swizzle of interrupts such that
|
||||
* each device's first interrupt is based on it's PCI_SLOT number.
|
||||
* (See pci_swizzle_map_irq_fn())
|
||||
*
|
||||
* We only need one entry per interrupt in the table (not one per
|
||||
* possible slot) seeing the interrupt-map-mask will allow the table
|
||||
* to wrap to any number of devices.
|
||||
*/
|
||||
for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
|
||||
int devfn = dev * 0x8;
|
||||
|
||||
for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
|
||||
int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
|
||||
int i = 0;
|
||||
|
||||
irq_map[i] = cpu_to_be32(devfn << 8);
|
||||
|
||||
i += FDT_PCI_ADDR_CELLS;
|
||||
irq_map[i] = cpu_to_be32(pin + 1);
|
||||
|
||||
i += FDT_PCI_INT_CELLS;
|
||||
irq_map[i++] = cpu_to_be32(plic_phandle);
|
||||
|
||||
i += FDT_PLIC_ADDR_CELLS;
|
||||
irq_map[i] = cpu_to_be32(irq_nr);
|
||||
|
||||
irq_map += FDT_INT_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",
|
||||
0x1800, 0, 0, 0x7);
|
||||
}
|
||||
|
||||
static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
uint64_t mem_size, const char *cmdline)
|
||||
{
|
||||
@ -203,7 +253,10 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
|
||||
(long)memmap[VIRT_PLIC].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
|
||||
FDT_PLIC_ADDR_CELLS);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
|
||||
FDT_PLIC_INT_CELLS);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0");
|
||||
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
|
||||
@ -233,6 +286,33 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
nodename = g_strdup_printf("/soc/pci@%lx",
|
||||
(long) memmap[VIRT_PCIE_ECAM].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
|
||||
FDT_PCI_ADDR_CELLS);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells",
|
||||
FDT_PCI_INT_CELLS);
|
||||
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", 0, memmap[VIRT_PCIE_ECAM].base,
|
||||
0, memmap[VIRT_PCIE_ECAM].size);
|
||||
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,
|
||||
2, memmap[VIRT_PCIE_MMIO].base,
|
||||
2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size);
|
||||
create_pcie_irq_map(fdt, nodename, plic_phandle);
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/test@%lx",
|
||||
(long)memmap[VIRT_TEST].base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
@ -263,6 +343,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;
|
||||
@ -385,6 +506,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_ECAM].base,
|
||||
memmap[VIRT_PCIE_ECAM].size,
|
||||
memmap[VIRT_PCIE_MMIO].base,
|
||||
memmap[VIRT_PCIE_MMIO].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);
|
||||
|
@ -63,7 +63,8 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_U_CLOCK_FREQ = 1000000000
|
||||
SIFIVE_U_CLOCK_FREQ = 1000000000,
|
||||
SIFIVE_U_GEM_CLOCK_FREQ = 125000000
|
||||
};
|
||||
|
||||
#define SIFIVE_U_PLIC_HART_CONFIG "MS"
|
||||
|
@ -43,6 +43,9 @@ enum {
|
||||
SIFIVE_UART_IP_RXWM = 2 /* Receive watermark interrupt pending */
|
||||
};
|
||||
|
||||
#define SIFIVE_UART_GET_TXCNT(txctrl) ((txctrl >> 16) & 0x7)
|
||||
#define SIFIVE_UART_GET_RXCNT(rxctrl) ((rxctrl >> 16) & 0x7)
|
||||
|
||||
#define TYPE_SIFIVE_UART "riscv.sifive.uart"
|
||||
|
||||
#define SIFIVE_UART(obj) \
|
||||
|
@ -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 = 10
|
||||
PCIE_IRQ = 0x20, /* 32 to 35 */
|
||||
VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -62,6 +66,13 @@ enum {
|
||||
#define VIRT_PLIC_CONTEXT_BASE 0x200000
|
||||
#define VIRT_PLIC_CONTEXT_STRIDE 0x1000
|
||||
|
||||
#define FDT_PCI_ADDR_CELLS 3
|
||||
#define FDT_PCI_INT_CELLS 1
|
||||
#define FDT_PLIC_ADDR_CELLS 0
|
||||
#define FDT_PLIC_INT_CELLS 1
|
||||
#define FDT_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + 1 + \
|
||||
FDT_PLIC_ADDR_CELLS + FDT_PLIC_INT_CELLS)
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
#define VIRT_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
|
||||
#elif defined(TARGET_RISCV64)
|
||||
|
@ -330,8 +330,8 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
|
||||
CPUClass *cc = CPU_CLASS(c);
|
||||
DeviceClass *dc = DEVICE_CLASS(c);
|
||||
|
||||
mcc->parent_realize = dc->realize;
|
||||
dc->realize = riscv_cpu_realize;
|
||||
device_class_set_parent_realize(dc, riscv_cpu_realize,
|
||||
&mcc->parent_realize);
|
||||
|
||||
mcc->parent_reset = cc->reset;
|
||||
cc->reset = riscv_cpu_reset;
|
||||
|
@ -445,11 +445,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||
if (RISCV_DEBUG_INTERRUPT) {
|
||||
int log_cause = cs->exception_index & RISCV_EXCP_INT_MASK;
|
||||
if (cs->exception_index & RISCV_EXCP_INT_FLAG) {
|
||||
qemu_log_mask(LOG_TRACE, "core 0: trap %s, epc 0x" TARGET_FMT_lx,
|
||||
riscv_intr_names[log_cause], env->pc);
|
||||
qemu_log_mask(LOG_TRACE, "core "
|
||||
TARGET_FMT_ld ": trap %s, epc 0x" TARGET_FMT_lx "\n",
|
||||
env->mhartid, riscv_intr_names[log_cause], env->pc);
|
||||
} else {
|
||||
qemu_log_mask(LOG_TRACE, "core 0: intr %s, epc 0x" TARGET_FMT_lx,
|
||||
riscv_excp_names[log_cause], env->pc);
|
||||
qemu_log_mask(LOG_TRACE, "core "
|
||||
TARGET_FMT_ld ": intr %s, epc 0x" TARGET_FMT_lx "\n",
|
||||
env->mhartid, riscv_excp_names[log_cause], env->pc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,8 +513,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
if (hasbadaddr) {
|
||||
if (RISCV_DEBUG_INTERRUPT) {
|
||||
qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld
|
||||
": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
|
||||
qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x"
|
||||
TARGET_FMT_lx "\n", env->mhartid, env->badaddr);
|
||||
}
|
||||
env->sbadaddr = env->badaddr;
|
||||
} else {
|
||||
@ -536,8 +538,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
if (hasbadaddr) {
|
||||
if (RISCV_DEBUG_INTERRUPT) {
|
||||
qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld
|
||||
": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
|
||||
qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x"
|
||||
TARGET_FMT_lx "\n", env->mhartid, env->badaddr);
|
||||
}
|
||||
env->mbadaddr = env->badaddr;
|
||||
} else {
|
||||
|
@ -138,7 +138,7 @@ static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea)
|
||||
return;
|
||||
} else {
|
||||
target_ulong t1 = ctz64(~a);
|
||||
target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 3;
|
||||
target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 2;
|
||||
target_ulong range = ((target_ulong)1 << (t1 + 3)) - 1;
|
||||
*sa = base;
|
||||
*ea = base + range;
|
||||
|
Loading…
Reference in New Issue
Block a user