Merge remote-tracking branch 'agraf/ppc-for-upstream' into staging
* agraf/ppc-for-upstream: (24 commits) openpic: Added BRR1 register pseries: Update SLOF firmware image pseries dma: DMA window params added to PHB and DT population changed pseries: Add PCI MSI/MSI-X support pseries: Add trace event for PCI irqs pseries: Export find_phb() utility function for PCI code pseries: added allocator for a block of IRQs pseries: Separate PCI RTAS setup from common from emulation specific PCI setup pseries: Rework irq assignment to avoid carrying qemu_irqs around pseries: Remove extraneous prints pseries: Update SLOF PPC: spapr: Remove global variable PPC: spapr: Rework VGA select logic xbzrle: fix compilation on ppc32 spapr: Add support for -vga option Add one new file vga-pci.h and cleanup on all platforms Revert "PPC: e500: Use new MPIC dt format" ppc: Fix bug in handling of PAPR hypercall exits PPC: e500: add generic e500 platform PPC: e500: split mpc8544ds machine from generic e500 code ...
This commit is contained in:
commit
0d16fdd732
@ -11,6 +11,7 @@
|
||||
#include "qemu-log.h"
|
||||
#include "sysemu.h"
|
||||
#include "vmware_vga.h"
|
||||
#include "vga-pci.h"
|
||||
|
||||
|
||||
/* PCI IO reads/writes, to byte-word addressable memory. */
|
||||
|
@ -27,8 +27,8 @@
|
||||
* available at http://home.worldonline.dk/~finth/
|
||||
*/
|
||||
#include "hw.h"
|
||||
#include "pc.h"
|
||||
#include "pci.h"
|
||||
#include "vga-pci.h"
|
||||
#include "console.h"
|
||||
#include "vga_int.h"
|
||||
#include "loader.h"
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "blockdev.h"
|
||||
#include "exec-memory.h"
|
||||
#include "sysbus.h" /* SysBusDevice */
|
||||
#include "vga-pci.h"
|
||||
|
||||
//#define DEBUG_BOARD_INIT
|
||||
|
||||
|
17
hw/openpic.c
17
hw/openpic.c
@ -130,6 +130,17 @@ enum {
|
||||
#define MPIC_CPU_REG_START 0x20000
|
||||
#define MPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
|
||||
|
||||
/*
|
||||
* Block Revision Register1 (BRR1): QEMU does not fully emulate
|
||||
* any version on MPIC. So to start with, set the IP version to 0.
|
||||
*
|
||||
* NOTE: This is Freescale MPIC specific register. Keep it here till
|
||||
* this code is refactored for different variants of OPENPIC and MPIC.
|
||||
*/
|
||||
#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
|
||||
#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
|
||||
#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
|
||||
|
||||
enum mpic_ide_bits {
|
||||
IDR_EP = 31,
|
||||
IDR_CI0 = 30,
|
||||
@ -595,6 +606,8 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
|
||||
if (addr & 0xF)
|
||||
return;
|
||||
switch (addr) {
|
||||
case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
|
||||
break;
|
||||
case 0x40:
|
||||
case 0x50:
|
||||
case 0x60:
|
||||
@ -671,6 +684,7 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
|
||||
case 0x1090: /* PINT */
|
||||
retval = 0x00000000;
|
||||
break;
|
||||
case 0x00: /* Block Revision Register1 (BRR1) */
|
||||
case 0x40:
|
||||
case 0x50:
|
||||
case 0x60:
|
||||
@ -893,6 +907,9 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
|
||||
dst = &opp->dst[idx];
|
||||
addr &= 0xFF0;
|
||||
switch (addr) {
|
||||
case 0x00: /* Block Revision Register1 (BRR1) */
|
||||
retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
|
||||
break;
|
||||
case 0x80: /* PCTP */
|
||||
retval = dst->pctp;
|
||||
break;
|
||||
|
1
hw/pc.c
1
hw/pc.c
@ -51,6 +51,7 @@
|
||||
#include "exec-memory.h"
|
||||
#include "arch_init.h"
|
||||
#include "bitmap.h"
|
||||
#include "vga-pci.h"
|
||||
|
||||
/* output Bochs bios info messages */
|
||||
//#define DEBUG_BIOS
|
||||
|
4
hw/pc.h
4
hw/pc.h
@ -189,14 +189,10 @@ static inline DeviceState *isa_vga_init(ISABus *bus)
|
||||
return &dev->qdev;
|
||||
}
|
||||
|
||||
DeviceState *pci_vga_init(PCIBus *bus);
|
||||
int isa_vga_mm_init(target_phys_addr_t vram_base,
|
||||
target_phys_addr_t ctrl_base, int it_shift,
|
||||
MemoryRegion *address_space);
|
||||
|
||||
/* cirrus_vga.c */
|
||||
DeviceState *pci_cirrus_vga_init(PCIBus *bus);
|
||||
|
||||
/* ne2000.c */
|
||||
static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
|
||||
{
|
||||
|
@ -15,7 +15,7 @@ obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o
|
||||
obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
|
||||
obj-y += ppc440_bamboo.o
|
||||
# PowerPC E500 boards
|
||||
obj-$(CONFIG_FDT) += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
|
||||
obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o
|
||||
# PowerPC 440 Xilinx ML507 reference board.
|
||||
obj-y += virtex_ml507.o
|
||||
# PowerPC OpenPIC
|
||||
@ -26,3 +26,5 @@ obj-$(CONFIG_FDT) += ../device_tree.o
|
||||
obj-y += xilinx_ethlite.o
|
||||
|
||||
obj-y := $(addprefix ../,$(obj-y))
|
||||
|
||||
obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* QEMU PowerPC MPC8544DS board emulation
|
||||
* QEMU PowerPC e500-based platforms
|
||||
*
|
||||
* Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
@ -16,20 +16,21 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "qemu-common.h"
|
||||
#include "e500.h"
|
||||
#include "net.h"
|
||||
#include "hw.h"
|
||||
#include "pc.h"
|
||||
#include "pci.h"
|
||||
#include "boards.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pc.h"
|
||||
#include "hw/pci.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu.h"
|
||||
#include "kvm.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "device_tree.h"
|
||||
#include "openpic.h"
|
||||
#include "ppc.h"
|
||||
#include "loader.h"
|
||||
#include "hw/openpic.h"
|
||||
#include "hw/ppc.h"
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
#include "sysbus.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec-memory.h"
|
||||
#include "host-utils.h"
|
||||
|
||||
@ -42,6 +43,7 @@
|
||||
|
||||
#define RAM_SIZES_ALIGN (64UL << 20)
|
||||
|
||||
/* TODO: parameterize */
|
||||
#define MPC8544_CCSRBAR_BASE 0xE0000000ULL
|
||||
#define MPC8544_CCSRBAR_SIZE 0x00100000ULL
|
||||
#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000ULL)
|
||||
@ -66,18 +68,18 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
|
||||
int i;
|
||||
const uint32_t tmp[] = {
|
||||
/* IDSEL 0x11 J17 Slot 1 */
|
||||
0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0,
|
||||
0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0,
|
||||
0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0,
|
||||
0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
|
||||
0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
|
||||
0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
|
||||
0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
|
||||
0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
|
||||
|
||||
/* IDSEL 0x12 J16 Slot 2 */
|
||||
0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0,
|
||||
0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0,
|
||||
0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0,
|
||||
0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
|
||||
0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
|
||||
0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
|
||||
0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
|
||||
0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
|
||||
};
|
||||
for (i = 0; i < ARRAY_SIZE(tmp); i++) {
|
||||
for (i = 0; i < (7 * 8); i++) {
|
||||
pci_map[i] = cpu_to_be32(tmp[i]);
|
||||
}
|
||||
}
|
||||
@ -95,7 +97,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
|
||||
qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
|
||||
qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
|
||||
qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
|
||||
qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2, 0, 0);
|
||||
qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
|
||||
qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
|
||||
qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
|
||||
|
||||
@ -104,31 +106,28 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
|
||||
}
|
||||
}
|
||||
|
||||
static int mpc8544_load_device_tree(CPUPPCState *env,
|
||||
static int ppce500_load_device_tree(CPUPPCState *env,
|
||||
PPCE500Params *params,
|
||||
target_phys_addr_t addr,
|
||||
target_phys_addr_t ramsize,
|
||||
target_phys_addr_t initrd_base,
|
||||
target_phys_addr_t initrd_size,
|
||||
const char *kernel_cmdline)
|
||||
target_phys_addr_t initrd_size)
|
||||
{
|
||||
int ret = -1;
|
||||
uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
|
||||
uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
|
||||
int fdt_size;
|
||||
void *fdt;
|
||||
uint8_t hypercall[16];
|
||||
uint32_t clock_freq = 400000000;
|
||||
uint32_t tb_freq = 400000000;
|
||||
int i;
|
||||
const char *compatible = "MPC8544DS\0MPC85xxDS";
|
||||
int compatible_len = sizeof("MPC8544DS\0MPC85xxDS");
|
||||
const char *toplevel_compat = NULL; /* user override */
|
||||
char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
|
||||
char model[] = "MPC8544DS";
|
||||
char soc[128];
|
||||
char mpic[128];
|
||||
uint32_t mpic_ph;
|
||||
char gutil[128];
|
||||
char pci[128];
|
||||
uint32_t pci_map[9 * 8];
|
||||
uint32_t pci_map[7 * 8];
|
||||
uint32_t pci_ranges[14] =
|
||||
{
|
||||
0x2000000, 0x0, 0xc0000000,
|
||||
@ -145,14 +144,9 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
|
||||
|
||||
machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
|
||||
if (machine_opts) {
|
||||
const char *tmp;
|
||||
dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
|
||||
dtb_file = qemu_opt_get(machine_opts, "dtb");
|
||||
tmp = qemu_opt_get(machine_opts, "dt_compatible");
|
||||
if (tmp) {
|
||||
compatible = tmp;
|
||||
compatible_len = strlen(compatible) + 1;
|
||||
}
|
||||
toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
|
||||
}
|
||||
|
||||
if (dtb_file) {
|
||||
@ -175,8 +169,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
|
||||
}
|
||||
|
||||
/* Manipulate device tree in memory. */
|
||||
qemu_devtree_setprop_string(fdt, "/", "model", model);
|
||||
qemu_devtree_setprop(fdt, "/", "compatible", compatible, compatible_len);
|
||||
qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
|
||||
qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
|
||||
|
||||
@ -201,7 +193,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
|
||||
}
|
||||
|
||||
ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
|
||||
kernel_cmdline);
|
||||
params->kernel_cmdline);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "couldn't set /chosen/bootargs\n");
|
||||
|
||||
@ -282,18 +274,15 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
|
||||
MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
|
||||
qemu_devtree_add_subnode(fdt, mpic);
|
||||
qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
|
||||
qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
|
||||
qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
|
||||
qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
|
||||
MPC8544_CCSRBAR_BASE, 0x40000);
|
||||
qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
|
||||
qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4);
|
||||
qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
|
||||
mpic_ph = qemu_devtree_alloc_phandle(fdt);
|
||||
qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
|
||||
qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
|
||||
qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
|
||||
qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0);
|
||||
qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0);
|
||||
qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255);
|
||||
|
||||
/*
|
||||
* We have to generate ser1 first, because Linux takes the first
|
||||
@ -323,7 +312,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
|
||||
pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
|
||||
qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
|
||||
qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
|
||||
qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
|
||||
qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
|
||||
qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
|
||||
for (i = 0; i < 14; i++) {
|
||||
pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
|
||||
@ -337,6 +326,13 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
|
||||
qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
|
||||
qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
|
||||
|
||||
params->fixup_devtree(params, fdt);
|
||||
|
||||
if (toplevel_compat) {
|
||||
qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
|
||||
strlen(toplevel_compat) + 1);
|
||||
}
|
||||
|
||||
done:
|
||||
if (dumpdtb) {
|
||||
/* Dump the dtb to a file and quit */
|
||||
@ -388,7 +384,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env)
|
||||
env->tlb_dirty = true;
|
||||
}
|
||||
|
||||
static void mpc8544ds_cpu_reset_sec(void *opaque)
|
||||
static void ppce500_cpu_reset_sec(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
@ -401,7 +397,7 @@ static void mpc8544ds_cpu_reset_sec(void *opaque)
|
||||
env->exception_index = EXCP_HLT;
|
||||
}
|
||||
|
||||
static void mpc8544ds_cpu_reset(void *opaque)
|
||||
static void ppce500_cpu_reset(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
@ -417,12 +413,7 @@ static void mpc8544ds_cpu_reset(void *opaque)
|
||||
mmubooke_create_initial_mapping(env);
|
||||
}
|
||||
|
||||
static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
const char *cpu_model)
|
||||
void ppce500_init(PPCE500Params *params)
|
||||
{
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
@ -443,8 +434,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
CPUPPCState *firstenv = NULL;
|
||||
|
||||
/* Setup CPUs */
|
||||
if (cpu_model == NULL) {
|
||||
cpu_model = "e500v2_v30";
|
||||
if (params->cpu_model == NULL) {
|
||||
params->cpu_model = "e500v2_v30";
|
||||
}
|
||||
|
||||
irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
|
||||
@ -453,7 +444,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
PowerPCCPU *cpu;
|
||||
qemu_irq *input;
|
||||
|
||||
cpu = cpu_ppc_init(cpu_model);
|
||||
cpu = cpu_ppc_init(params->cpu_model);
|
||||
if (cpu == NULL) {
|
||||
fprintf(stderr, "Unable to initialize CPU!\n");
|
||||
exit(1);
|
||||
@ -478,11 +469,11 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
/* Primary CPU */
|
||||
struct boot_info *boot_info;
|
||||
boot_info = g_malloc0(sizeof(struct boot_info));
|
||||
qemu_register_reset(mpc8544ds_cpu_reset, cpu);
|
||||
qemu_register_reset(ppce500_cpu_reset, cpu);
|
||||
env->load_info = boot_info;
|
||||
} else {
|
||||
/* Secondary CPUs */
|
||||
qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu);
|
||||
qemu_register_reset(ppce500_cpu_reset_sec, cpu);
|
||||
}
|
||||
}
|
||||
|
||||
@ -542,43 +533,45 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
|
||||
|
||||
/* Load kernel. */
|
||||
if (kernel_filename) {
|
||||
kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
|
||||
if (params->kernel_filename) {
|
||||
kernel_size = load_uimage(params->kernel_filename, &entry,
|
||||
&loadaddr, NULL);
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
|
||||
&elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
|
||||
kernel_size = load_elf(params->kernel_filename, NULL, NULL,
|
||||
&elf_entry, &elf_lowaddr, NULL, 1,
|
||||
ELF_MACHINE, 0);
|
||||
entry = elf_entry;
|
||||
loadaddr = elf_lowaddr;
|
||||
}
|
||||
/* XXX try again as binary */
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
params->kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load initrd. */
|
||||
if (initrd_filename) {
|
||||
if (params->initrd_filename) {
|
||||
initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
|
||||
initrd_size = load_image_targphys(initrd_filename, initrd_base,
|
||||
initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
|
||||
ram_size - initrd_base);
|
||||
|
||||
if (initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
initrd_filename);
|
||||
params->initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're loading a kernel directly, we must load the device tree too. */
|
||||
if (kernel_filename) {
|
||||
if (params->kernel_filename) {
|
||||
struct boot_info *boot_info;
|
||||
int dt_size;
|
||||
|
||||
dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
|
||||
dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
|
||||
initrd_size, kernel_cmdline);
|
||||
dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
|
||||
initrd_size);
|
||||
if (dt_size < 0) {
|
||||
fprintf(stderr, "couldn't load device tree\n");
|
||||
exit(1);
|
||||
@ -594,17 +587,3 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
kvmppc_init();
|
||||
}
|
||||
}
|
||||
|
||||
static QEMUMachine mpc8544ds_machine = {
|
||||
.name = "mpc8544ds",
|
||||
.desc = "mpc8544ds",
|
||||
.init = mpc8544ds_init,
|
||||
.max_cpus = 15,
|
||||
};
|
||||
|
||||
static void mpc8544ds_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&mpc8544ds_machine);
|
||||
}
|
||||
|
||||
machine_init(mpc8544ds_machine_init);
|
21
hw/ppc/e500.h
Normal file
21
hw/ppc/e500.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef PPCE500_H
|
||||
#define PPCE500_H
|
||||
|
||||
typedef struct PPCE500Params {
|
||||
/* Standard QEMU machine init params */
|
||||
ram_addr_t ram_size;
|
||||
const char *boot_device;
|
||||
const char *kernel_filename;
|
||||
const char *kernel_cmdline;
|
||||
const char *initrd_filename;
|
||||
const char *cpu_model;
|
||||
|
||||
/* e500-specific params */
|
||||
|
||||
/* required -- must at least add toplevel board compatible */
|
||||
void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
|
||||
} PPCE500Params;
|
||||
|
||||
void ppce500_init(PPCE500Params *params);
|
||||
|
||||
#endif
|
60
hw/ppc/e500plat.c
Normal file
60
hw/ppc/e500plat.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Generic device-tree-driven paravirt PPC e500 platform
|
||||
*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "qemu-common.h"
|
||||
#include "e500.h"
|
||||
#include "../boards.h"
|
||||
#include "device_tree.h"
|
||||
|
||||
static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
|
||||
{
|
||||
const char model[] = "QEMU ppce500";
|
||||
const char compatible[] = "fsl,qemu-e500";
|
||||
|
||||
qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
|
||||
qemu_devtree_setprop(fdt, "/", "compatible", compatible,
|
||||
sizeof(compatible));
|
||||
}
|
||||
|
||||
static void e500plat_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
const char *cpu_model)
|
||||
{
|
||||
PPCE500Params params = {
|
||||
.ram_size = ram_size,
|
||||
.boot_device = boot_device,
|
||||
.kernel_filename = kernel_filename,
|
||||
.kernel_cmdline = kernel_cmdline,
|
||||
.initrd_filename = initrd_filename,
|
||||
.cpu_model = cpu_model,
|
||||
.fixup_devtree = e500plat_fixup_devtree,
|
||||
};
|
||||
|
||||
ppce500_init(¶ms);
|
||||
}
|
||||
|
||||
static QEMUMachine e500plat_machine = {
|
||||
.name = "ppce500",
|
||||
.desc = "generic paravirt e500 platform",
|
||||
.init = e500plat_init,
|
||||
.max_cpus = 15,
|
||||
};
|
||||
|
||||
static void e500plat_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&e500plat_machine);
|
||||
}
|
||||
|
||||
machine_init(e500plat_machine_init);
|
61
hw/ppc/mpc8544ds.c
Normal file
61
hw/ppc/mpc8544ds.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Support for the PPC e500-based mpc8544ds board
|
||||
*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "qemu-common.h"
|
||||
#include "e500.h"
|
||||
#include "../boards.h"
|
||||
#include "device_tree.h"
|
||||
|
||||
static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
|
||||
{
|
||||
const char model[] = "MPC8544DS";
|
||||
const char compatible[] = "MPC8544DS\0MPC85xxDS";
|
||||
|
||||
qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
|
||||
qemu_devtree_setprop(fdt, "/", "compatible", compatible,
|
||||
sizeof(compatible));
|
||||
}
|
||||
|
||||
static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
const char *cpu_model)
|
||||
{
|
||||
PPCE500Params params = {
|
||||
.ram_size = ram_size,
|
||||
.boot_device = boot_device,
|
||||
.kernel_filename = kernel_filename,
|
||||
.kernel_cmdline = kernel_cmdline,
|
||||
.initrd_filename = initrd_filename,
|
||||
.cpu_model = cpu_model,
|
||||
.fixup_devtree = mpc8544ds_fixup_devtree,
|
||||
};
|
||||
|
||||
ppce500_init(¶ms);
|
||||
}
|
||||
|
||||
|
||||
static QEMUMachine ppce500_machine = {
|
||||
.name = "mpc8544ds",
|
||||
.desc = "mpc8544ds",
|
||||
.init = mpc8544ds_init,
|
||||
.max_cpus = 15,
|
||||
};
|
||||
|
||||
static void ppce500_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&ppce500_machine);
|
||||
}
|
||||
|
||||
machine_init(ppce500_machine_init);
|
@ -52,7 +52,6 @@
|
||||
#include "adb.h"
|
||||
#include "mac_dbdma.h"
|
||||
#include "nvram.h"
|
||||
#include "pc.h"
|
||||
#include "pci.h"
|
||||
#include "net.h"
|
||||
#include "sysemu.h"
|
||||
@ -68,6 +67,7 @@
|
||||
#include "hw/usb.h"
|
||||
#include "blockdev.h"
|
||||
#include "exec-memory.h"
|
||||
#include "vga-pci.h"
|
||||
|
||||
#define MAX_IDE_BUS 2
|
||||
#define CFG_ADDR 0xf0000510
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "adb.h"
|
||||
#include "mac_dbdma.h"
|
||||
#include "nvram.h"
|
||||
#include "pc.h"
|
||||
#include "sysemu.h"
|
||||
#include "net.h"
|
||||
#include "isa.h"
|
||||
@ -44,6 +43,7 @@
|
||||
#include "kvm_ppc.h"
|
||||
#include "blockdev.h"
|
||||
#include "exec-memory.h"
|
||||
#include "vga-pci.h"
|
||||
|
||||
#define MAX_IDE_BUS 2
|
||||
#define CFG_ADDR 0xf0000510
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "blockdev.h"
|
||||
#include "arch_init.h"
|
||||
#include "exec-memory.h"
|
||||
#include "vga-pci.h"
|
||||
|
||||
//#define HARD_DEBUG_PPC_IO
|
||||
//#define DEBUG_PPC_IO
|
||||
|
101
hw/spapr.c
101
hw/spapr.c
@ -41,10 +41,12 @@
|
||||
#include "hw/spapr_vio.h"
|
||||
#include "hw/spapr_pci.h"
|
||||
#include "hw/xics.h"
|
||||
#include "hw/msi.h"
|
||||
|
||||
#include "kvm.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "pci.h"
|
||||
#include "vga-pci.h"
|
||||
|
||||
#include "exec-memory.h"
|
||||
|
||||
@ -78,16 +80,15 @@
|
||||
#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000)
|
||||
#define SPAPR_PCI_MEM_WIN_SIZE 0x20000000
|
||||
#define SPAPR_PCI_IO_WIN_ADDR (0x10000000000ULL + 0x80000000)
|
||||
#define SPAPR_PCI_MSI_WIN_ADDR (0x10000000000ULL + 0x90000000)
|
||||
|
||||
#define PHANDLE_XICP 0x00001111
|
||||
|
||||
sPAPREnvironment *spapr;
|
||||
|
||||
qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
|
||||
enum xics_irq_type type)
|
||||
int spapr_allocate_irq(int hint, enum xics_irq_type type)
|
||||
{
|
||||
uint32_t irq;
|
||||
qemu_irq qirq;
|
||||
int irq;
|
||||
|
||||
if (hint) {
|
||||
irq = hint;
|
||||
@ -96,16 +97,40 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
|
||||
irq = spapr->next_irq++;
|
||||
}
|
||||
|
||||
qirq = xics_assign_irq(spapr->icp, irq, type);
|
||||
if (!qirq) {
|
||||
return NULL;
|
||||
/* Configure irq type */
|
||||
if (!xics_get_qirq(spapr->icp, irq)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (irq_num) {
|
||||
*irq_num = irq;
|
||||
xics_set_irq_type(spapr->icp, irq, type);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/* Allocate block of consequtive IRQs, returns a number of the first */
|
||||
int spapr_allocate_irq_block(int num, enum xics_irq_type type)
|
||||
{
|
||||
int first = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
int irq;
|
||||
|
||||
irq = spapr_allocate_irq(0, type);
|
||||
if (!irq) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == i) {
|
||||
first = irq;
|
||||
}
|
||||
|
||||
/* If the above doesn't create a consecutive block then that's
|
||||
* an internal bug */
|
||||
assert(irq == (first + i));
|
||||
}
|
||||
|
||||
return qirq;
|
||||
return first;
|
||||
}
|
||||
|
||||
static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr)
|
||||
@ -257,6 +282,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||
_FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
|
||||
}
|
||||
_FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
|
||||
_FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
|
||||
_FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
|
||||
_FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
|
||||
|
||||
_FDT((fdt_end_node(fdt)));
|
||||
|
||||
@ -481,7 +509,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
||||
}
|
||||
|
||||
QLIST_FOREACH(phb, &spapr->phbs, list) {
|
||||
ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt);
|
||||
ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
@ -503,7 +531,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
||||
}
|
||||
}
|
||||
|
||||
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
||||
if (!spapr->has_graphics) {
|
||||
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
||||
}
|
||||
|
||||
_FDT((fdt_pack(fdt)));
|
||||
|
||||
@ -532,8 +562,6 @@ static void spapr_reset(void *opaque)
|
||||
{
|
||||
sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
|
||||
|
||||
fprintf(stderr, "sPAPR reset\n");
|
||||
|
||||
/* flush out the hash table */
|
||||
memset(spapr->htab, 0, spapr->htab_size);
|
||||
|
||||
@ -556,6 +584,23 @@ static void spapr_cpu_reset(void *opaque)
|
||||
cpu_reset(CPU(cpu));
|
||||
}
|
||||
|
||||
/* Returns whether we want to use VGA or not */
|
||||
static int spapr_vga_init(PCIBus *pci_bus)
|
||||
{
|
||||
switch (vga_interface_type) {
|
||||
case VGA_STD:
|
||||
pci_vga_init(pci_bus);
|
||||
return 1;
|
||||
case VGA_NONE:
|
||||
return 0;
|
||||
default:
|
||||
fprintf(stderr, "This vga model is not supported,"
|
||||
"currently it only supports -vga std\n");
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* pSeries LPAR / sPAPR hardware init */
|
||||
static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
@ -576,6 +621,8 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
long pteg_shift = 17;
|
||||
char *filename;
|
||||
|
||||
msi_supported = true;
|
||||
|
||||
spapr = g_malloc0(sizeof(*spapr));
|
||||
QLIST_INIT(&spapr->phbs);
|
||||
|
||||
@ -687,10 +734,13 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
}
|
||||
|
||||
/* Set up PCI */
|
||||
spapr_pci_rtas_init();
|
||||
|
||||
spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID,
|
||||
SPAPR_PCI_MEM_WIN_ADDR,
|
||||
SPAPR_PCI_MEM_WIN_SIZE,
|
||||
SPAPR_PCI_IO_WIN_ADDR);
|
||||
SPAPR_PCI_IO_WIN_ADDR,
|
||||
SPAPR_PCI_MSI_WIN_ADDR);
|
||||
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
NICInfo *nd = &nd_table[i];
|
||||
@ -710,20 +760,17 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
spapr_vscsi_create(spapr->vio_bus);
|
||||
}
|
||||
|
||||
/* Graphics */
|
||||
if (spapr_vga_init(QLIST_FIRST(&spapr->phbs)->host_state.bus)) {
|
||||
spapr->has_graphics = true;
|
||||
}
|
||||
|
||||
if (rma_size < (MIN_RMA_SLOF << 20)) {
|
||||
fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
|
||||
"%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "sPAPR memory map:\n");
|
||||
fprintf(stderr, "RTAS : 0x%08lx..%08lx\n",
|
||||
(unsigned long)spapr->rtas_addr,
|
||||
(unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1));
|
||||
fprintf(stderr, "FDT : 0x%08lx..%08lx\n",
|
||||
(unsigned long)spapr->fdt_addr,
|
||||
(unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1));
|
||||
|
||||
if (kernel_filename) {
|
||||
uint64_t lowaddr = 0;
|
||||
|
||||
@ -739,8 +786,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Kernel : 0x%08x..%08lx\n",
|
||||
KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1);
|
||||
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
@ -755,8 +800,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Ramdisk : 0x%08lx..%08lx\n",
|
||||
(long)initrd_base, (long)(initrd_base + initrd_size - 1));
|
||||
} else {
|
||||
initrd_base = 0;
|
||||
initrd_size = 0;
|
||||
@ -770,10 +813,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
exit(1);
|
||||
}
|
||||
g_free(filename);
|
||||
fprintf(stderr, "Firmware load : 0x%08x..%08lx\n",
|
||||
0, fw_size);
|
||||
fprintf(stderr, "Firmware runtime : 0x%08lx..%08lx\n",
|
||||
load_limit, (unsigned long)spapr->fdt_addr);
|
||||
|
||||
spapr->entry_point = 0x100;
|
||||
|
||||
|
17
hw/spapr.h
17
hw/spapr.h
@ -23,6 +23,7 @@ typedef struct sPAPREnvironment {
|
||||
int next_irq;
|
||||
int rtc_offset;
|
||||
char *cpu_model;
|
||||
bool has_graphics;
|
||||
} sPAPREnvironment;
|
||||
|
||||
#define H_SUCCESS 0
|
||||
@ -288,17 +289,17 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
|
||||
target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
|
||||
target_ulong *args);
|
||||
|
||||
qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
|
||||
enum xics_irq_type type);
|
||||
int spapr_allocate_irq(int hint, enum xics_irq_type type);
|
||||
int spapr_allocate_irq_block(int num, enum xics_irq_type type);
|
||||
|
||||
static inline qemu_irq spapr_allocate_msi(uint32_t hint, uint32_t *irq_num)
|
||||
static inline int spapr_allocate_msi(int hint)
|
||||
{
|
||||
return spapr_allocate_irq(hint, irq_num, XICS_MSI);
|
||||
return spapr_allocate_irq(hint, XICS_MSI);
|
||||
}
|
||||
|
||||
static inline qemu_irq spapr_allocate_lsi(uint32_t hint, uint32_t *irq_num)
|
||||
static inline int spapr_allocate_lsi(int hint)
|
||||
{
|
||||
return spapr_allocate_irq(hint, irq_num, XICS_LSI);
|
||||
return spapr_allocate_irq(hint, XICS_LSI);
|
||||
}
|
||||
|
||||
static inline uint32_t rtas_ld(target_ulong phys, int n)
|
||||
@ -336,6 +337,8 @@ void spapr_iommu_init(void);
|
||||
DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size);
|
||||
void spapr_tce_free(DMAContext *dma);
|
||||
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
||||
DMAContext *dma);
|
||||
uint32_t liobn, uint64_t window, uint32_t size);
|
||||
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
|
||||
DMAContext *dma);
|
||||
|
||||
#endif /* !defined (__HW_SPAPR_H__) */
|
||||
|
@ -216,31 +216,47 @@ void spapr_iommu_init(void)
|
||||
}
|
||||
|
||||
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
||||
DMAContext *dma)
|
||||
uint32_t liobn, uint64_t window, uint32_t size)
|
||||
{
|
||||
if (dma) {
|
||||
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
|
||||
uint32_t dma_prop[] = {cpu_to_be32(tcet->liobn),
|
||||
0, 0,
|
||||
0, cpu_to_be32(tcet->window_size)};
|
||||
int ret;
|
||||
uint32_t dma_prop[5];
|
||||
int ret;
|
||||
|
||||
ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
dma_prop[0] = cpu_to_be32(liobn);
|
||||
dma_prop[1] = cpu_to_be32(window >> 32);
|
||||
dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF);
|
||||
dma_prop[3] = 0; /* window size is 32 bits */
|
||||
dma_prop[4] = cpu_to_be32(size);
|
||||
|
||||
ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fdt_setprop(fdt, node_off, propname, dma_prop,
|
||||
sizeof(dma_prop));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
|
||||
DMAContext *iommu)
|
||||
{
|
||||
if (!iommu) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iommu->translate == spapr_tce_translate) {
|
||||
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, iommu);
|
||||
return spapr_dma_dt(fdt, node_off, propname,
|
||||
tcet->liobn, 0, tcet->window_size);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
|
||||
}
|
||||
|
||||
if (sdev->signal_state & 1) {
|
||||
qemu_irq_pulse(sdev->qirq);
|
||||
qemu_irq_pulse(spapr_vio_qirq(sdev));
|
||||
}
|
||||
|
||||
return size;
|
||||
|
326
hw/spapr_pci.c
326
hw/spapr_pci.c
@ -24,32 +24,57 @@
|
||||
*/
|
||||
#include "hw.h"
|
||||
#include "pci.h"
|
||||
#include "msi.h"
|
||||
#include "msix.h"
|
||||
#include "pci_host.h"
|
||||
#include "hw/spapr.h"
|
||||
#include "hw/spapr_pci.h"
|
||||
#include "exec-memory.h"
|
||||
#include <libfdt.h>
|
||||
#include "trace.h"
|
||||
|
||||
#include "hw/pci_internals.h"
|
||||
|
||||
static PCIDevice *find_dev(sPAPREnvironment *spapr,
|
||||
uint64_t buid, uint32_t config_addr)
|
||||
/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
|
||||
#define RTAS_QUERY_FN 0
|
||||
#define RTAS_CHANGE_FN 1
|
||||
#define RTAS_RESET_FN 2
|
||||
#define RTAS_CHANGE_MSI_FN 3
|
||||
#define RTAS_CHANGE_MSIX_FN 4
|
||||
|
||||
/* Interrupt types to return on RTAS_CHANGE_* */
|
||||
#define RTAS_TYPE_MSI 1
|
||||
#define RTAS_TYPE_MSIX 2
|
||||
|
||||
static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
|
||||
{
|
||||
int devfn = (config_addr >> 8) & 0xFF;
|
||||
sPAPRPHBState *phb;
|
||||
|
||||
QLIST_FOREACH(phb, &spapr->phbs, list) {
|
||||
BusChild *kid;
|
||||
|
||||
if (phb->buid != buid) {
|
||||
continue;
|
||||
}
|
||||
return phb;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) {
|
||||
PCIDevice *dev = (PCIDevice *)kid->child;
|
||||
if (dev->devfn == devfn) {
|
||||
return dev;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
|
||||
uint32_t config_addr)
|
||||
{
|
||||
sPAPRPHBState *phb = find_phb(spapr, buid);
|
||||
BusChild *kid;
|
||||
int devfn = (config_addr >> 8) & 0xFF;
|
||||
|
||||
if (!phb) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) {
|
||||
PCIDevice *dev = (PCIDevice *)kid->child;
|
||||
if (dev->devfn == devfn) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,6 +224,191 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
|
||||
finish_write_pci_config(spapr, 0, addr, size, val, rets);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an entry with config_addr or returns the empty one if not found AND
|
||||
* alloc_new is set.
|
||||
* At the moment the msi_table entries are never released so there is
|
||||
* no point to look till the end of the list if we need to find the free entry.
|
||||
*/
|
||||
static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
|
||||
bool alloc_new)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SPAPR_MSIX_MAX_DEVS; ++i) {
|
||||
if (!phb->msi_table[i].nvec) {
|
||||
break;
|
||||
}
|
||||
if (phb->msi_table[i].config_addr == config_addr) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if ((i < SPAPR_MSIX_MAX_DEVS) && alloc_new) {
|
||||
trace_spapr_pci_msi("Allocating new MSI config", i, config_addr);
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set MSI/MSIX message data.
|
||||
* This is required for msi_notify()/msix_notify() which
|
||||
* will write at the addresses via spapr_msi_write().
|
||||
*/
|
||||
static void spapr_msi_setmsg(PCIDevice *pdev, target_phys_addr_t addr,
|
||||
bool msix, unsigned req_num)
|
||||
{
|
||||
unsigned i;
|
||||
MSIMessage msg = { .address = addr, .data = 0 };
|
||||
|
||||
if (!msix) {
|
||||
msi_set_message(pdev, msg);
|
||||
trace_spapr_pci_msi_setup(pdev->name, 0, msg.address);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < req_num; ++i) {
|
||||
msg.address = addr | (i << 2);
|
||||
msix_set_message(pdev, i, msg);
|
||||
trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtas_ibm_change_msi(sPAPREnvironment *spapr,
|
||||
uint32_t token, uint32_t nargs,
|
||||
target_ulong args, uint32_t nret,
|
||||
target_ulong rets)
|
||||
{
|
||||
uint32_t config_addr = rtas_ld(args, 0);
|
||||
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||
unsigned int func = rtas_ld(args, 3);
|
||||
unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
|
||||
unsigned int seq_num = rtas_ld(args, 5);
|
||||
unsigned int ret_intr_type;
|
||||
int ndev, irq;
|
||||
sPAPRPHBState *phb = NULL;
|
||||
PCIDevice *pdev = NULL;
|
||||
|
||||
switch (func) {
|
||||
case RTAS_CHANGE_MSI_FN:
|
||||
case RTAS_CHANGE_FN:
|
||||
ret_intr_type = RTAS_TYPE_MSI;
|
||||
break;
|
||||
case RTAS_CHANGE_MSIX_FN:
|
||||
ret_intr_type = RTAS_TYPE_MSIX;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func);
|
||||
rtas_st(rets, 0, -3); /* Parameter error */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fins sPAPRPHBState */
|
||||
phb = find_phb(spapr, buid);
|
||||
if (phb) {
|
||||
pdev = find_dev(spapr, buid, config_addr);
|
||||
}
|
||||
if (!phb || !pdev) {
|
||||
rtas_st(rets, 0, -3); /* Parameter error */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Releasing MSIs */
|
||||
if (!req_num) {
|
||||
ndev = spapr_msicfg_find(phb, config_addr, false);
|
||||
if (ndev < 0) {
|
||||
trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
|
||||
rtas_st(rets, 0, -1); /* Hardware error */
|
||||
return;
|
||||
}
|
||||
trace_spapr_pci_msi("Released MSIs", ndev, config_addr);
|
||||
rtas_st(rets, 0, 0);
|
||||
rtas_st(rets, 1, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enabling MSI */
|
||||
|
||||
/* Find a device number in the map to add or reuse the existing one */
|
||||
ndev = spapr_msicfg_find(phb, config_addr, true);
|
||||
if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
|
||||
fprintf(stderr, "No free entry for a new MSI device\n");
|
||||
rtas_st(rets, 0, -1); /* Hardware error */
|
||||
return;
|
||||
}
|
||||
trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
|
||||
|
||||
/* Check if there is an old config and MSI number has not changed */
|
||||
if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
|
||||
/* Unexpected behaviour */
|
||||
fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev);
|
||||
rtas_st(rets, 0, -1); /* Hardware error */
|
||||
return;
|
||||
}
|
||||
|
||||
/* There is no cached config, allocate MSIs */
|
||||
if (!phb->msi_table[ndev].nvec) {
|
||||
irq = spapr_allocate_irq_block(req_num, XICS_MSI);
|
||||
if (irq < 0) {
|
||||
fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
|
||||
rtas_st(rets, 0, -1); /* Hardware error */
|
||||
return;
|
||||
}
|
||||
phb->msi_table[ndev].irq = irq;
|
||||
phb->msi_table[ndev].nvec = req_num;
|
||||
phb->msi_table[ndev].config_addr = config_addr;
|
||||
}
|
||||
|
||||
/* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
|
||||
spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
|
||||
ret_intr_type == RTAS_TYPE_MSIX, req_num);
|
||||
|
||||
rtas_st(rets, 0, 0);
|
||||
rtas_st(rets, 1, req_num);
|
||||
rtas_st(rets, 2, ++seq_num);
|
||||
rtas_st(rets, 3, ret_intr_type);
|
||||
|
||||
trace_spapr_pci_rtas_ibm_change_msi(func, req_num);
|
||||
}
|
||||
|
||||
static void rtas_ibm_query_interrupt_source_number(sPAPREnvironment *spapr,
|
||||
uint32_t token,
|
||||
uint32_t nargs,
|
||||
target_ulong args,
|
||||
uint32_t nret,
|
||||
target_ulong rets)
|
||||
{
|
||||
uint32_t config_addr = rtas_ld(args, 0);
|
||||
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||
unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
|
||||
int ndev;
|
||||
sPAPRPHBState *phb = NULL;
|
||||
|
||||
/* Fins sPAPRPHBState */
|
||||
phb = find_phb(spapr, buid);
|
||||
if (!phb) {
|
||||
rtas_st(rets, 0, -3); /* Parameter error */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find device descriptor and start IRQ */
|
||||
ndev = spapr_msicfg_find(phb, config_addr, false);
|
||||
if (ndev < 0) {
|
||||
trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
|
||||
rtas_st(rets, 0, -1); /* Hardware error */
|
||||
return;
|
||||
}
|
||||
|
||||
intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num;
|
||||
trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
|
||||
intr_src_num);
|
||||
|
||||
rtas_st(rets, 0, 0);
|
||||
rtas_st(rets, 1, intr_src_num);
|
||||
rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
|
||||
}
|
||||
|
||||
static int pci_spapr_swizzle(int slot, int pin)
|
||||
{
|
||||
return (slot + pin) % PCI_NUM_PINS;
|
||||
@ -223,7 +433,8 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
|
||||
*/
|
||||
sPAPRPHBState *phb = opaque;
|
||||
|
||||
qemu_set_irq(phb->lsi_table[irq_num].qirq, level);
|
||||
trace_spapr_pci_lsi_set(phb->busname, irq_num, phb->lsi_table[irq_num].irq);
|
||||
qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
|
||||
}
|
||||
|
||||
static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
|
||||
@ -263,6 +474,33 @@ static const MemoryRegionOps spapr_io_ops = {
|
||||
.write = spapr_io_write
|
||||
};
|
||||
|
||||
/*
|
||||
* MSI/MSIX memory region implementation.
|
||||
* The handler handles both MSI and MSIX.
|
||||
* For MSI-X, the vector number is encoded as a part of the address,
|
||||
* data is set to 0.
|
||||
* For MSI, the vector number is encoded in least bits in data.
|
||||
*/
|
||||
static void spapr_msi_write(void *opaque, target_phys_addr_t addr,
|
||||
uint64_t data, unsigned size)
|
||||
{
|
||||
sPAPRPHBState *phb = opaque;
|
||||
int ndev = addr >> 16;
|
||||
int vec = ((addr & 0xFFFF) >> 2) | data;
|
||||
uint32_t irq = phb->msi_table[ndev].irq + vec;
|
||||
|
||||
trace_spapr_pci_msi_write(addr, data, irq);
|
||||
|
||||
qemu_irq_pulse(xics_get_qirq(spapr->icp, irq));
|
||||
}
|
||||
|
||||
static const MemoryRegionOps spapr_msi_ops = {
|
||||
/* There is no .read as the read result is undefined by PCI spec */
|
||||
.read = NULL,
|
||||
.write = spapr_msi_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN
|
||||
};
|
||||
|
||||
/*
|
||||
* PHB PCI device
|
||||
*/
|
||||
@ -276,11 +514,10 @@ static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
|
||||
|
||||
static int spapr_phb_init(SysBusDevice *s)
|
||||
{
|
||||
sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
|
||||
sPAPRPHBState *phb = DO_UPCAST(sPAPRPHBState, host_state.busdev, s);
|
||||
char *namebuf;
|
||||
int i;
|
||||
PCIBus *bus;
|
||||
uint32_t liobn;
|
||||
|
||||
phb->dtbusname = g_strdup_printf("pci@%" PRIx64, phb->buid);
|
||||
namebuf = alloca(strlen(phb->dtbusname) + 32);
|
||||
@ -314,31 +551,42 @@ static int spapr_phb_init(SysBusDevice *s)
|
||||
memory_region_add_subregion(get_system_memory(), phb->io_win_addr,
|
||||
&phb->iowindow);
|
||||
|
||||
bus = pci_register_bus(&phb->busdev.qdev,
|
||||
/* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
|
||||
* we need to allocate some memory to catch those writes coming
|
||||
* from msi_notify()/msix_notify() */
|
||||
if (msi_supported) {
|
||||
sprintf(namebuf, "%s.msi", phb->dtbusname);
|
||||
memory_region_init_io(&phb->msiwindow, &spapr_msi_ops, phb,
|
||||
namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
|
||||
memory_region_add_subregion(get_system_memory(), phb->msi_win_addr,
|
||||
&phb->msiwindow);
|
||||
}
|
||||
|
||||
bus = pci_register_bus(&phb->host_state.busdev.qdev,
|
||||
phb->busname ? phb->busname : phb->dtbusname,
|
||||
pci_spapr_set_irq, pci_spapr_map_irq, phb,
|
||||
&phb->memspace, &phb->iospace,
|
||||
PCI_DEVFN(0, 0), PCI_NUM_PINS);
|
||||
phb->host_state.bus = bus;
|
||||
|
||||
liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16);
|
||||
phb->dma = spapr_tce_new_dma_context(liobn, 0x40000000);
|
||||
phb->dma_liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16);
|
||||
phb->dma_window_start = 0;
|
||||
phb->dma_window_size = 0x40000000;
|
||||
phb->dma = spapr_tce_new_dma_context(phb->dma_liobn, phb->dma_window_size);
|
||||
pci_setup_iommu(bus, spapr_pci_dma_context_fn, phb);
|
||||
|
||||
QLIST_INSERT_HEAD(&spapr->phbs, phb, list);
|
||||
|
||||
/* Initialize the LSI table */
|
||||
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||
qemu_irq qirq;
|
||||
uint32_t num;
|
||||
uint32_t irq;
|
||||
|
||||
qirq = spapr_allocate_lsi(0, &num);
|
||||
if (!qirq) {
|
||||
irq = spapr_allocate_lsi(0);
|
||||
if (!irq) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
phb->lsi_table[i].dt_irq = num;
|
||||
phb->lsi_table[i].qirq = qirq;
|
||||
phb->lsi_table[i].irq = irq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -351,6 +599,7 @@ static Property spapr_phb_properties[] = {
|
||||
DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000),
|
||||
DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0),
|
||||
DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000),
|
||||
DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -361,11 +610,6 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
sdc->init = spapr_phb_init;
|
||||
dc->props = spapr_phb_properties;
|
||||
|
||||
spapr_rtas_register("read-pci-config", rtas_read_pci_config);
|
||||
spapr_rtas_register("write-pci-config", rtas_write_pci_config);
|
||||
spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
|
||||
spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
|
||||
}
|
||||
|
||||
static TypeInfo spapr_phb_info = {
|
||||
@ -378,7 +622,7 @@ static TypeInfo spapr_phb_info = {
|
||||
void spapr_create_phb(sPAPREnvironment *spapr,
|
||||
const char *busname, uint64_t buid,
|
||||
uint64_t mem_win_addr, uint64_t mem_win_size,
|
||||
uint64_t io_win_addr)
|
||||
uint64_t io_win_addr, uint64_t msi_win_addr)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
@ -391,6 +635,7 @@ void spapr_create_phb(sPAPREnvironment *spapr,
|
||||
qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr);
|
||||
qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size);
|
||||
qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr);
|
||||
qdev_prop_set_uint64(dev, "msi_win_addr", msi_win_addr);
|
||||
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
@ -406,9 +651,9 @@ void spapr_create_phb(sPAPREnvironment *spapr,
|
||||
#define b_fff(x) b_x((x), 8, 3) /* function number */
|
||||
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
|
||||
|
||||
int spapr_populate_pci_devices(sPAPRPHBState *phb,
|
||||
uint32_t xics_phandle,
|
||||
void *fdt)
|
||||
int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
||||
uint32_t xics_phandle,
|
||||
void *fdt)
|
||||
{
|
||||
int bus_off, i, j;
|
||||
char nodename[256];
|
||||
@ -477,7 +722,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
|
||||
irqmap[2] = 0;
|
||||
irqmap[3] = cpu_to_be32(j+1);
|
||||
irqmap[4] = cpu_to_be32(xics_phandle);
|
||||
irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].dt_irq);
|
||||
irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq);
|
||||
irqmap[6] = cpu_to_be32(0x8);
|
||||
}
|
||||
}
|
||||
@ -485,11 +730,26 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
|
||||
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
|
||||
sizeof(interrupt_map)));
|
||||
|
||||
spapr_dma_dt(fdt, bus_off, "ibm,dma-window", phb->dma);
|
||||
spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
|
||||
phb->dma_liobn, phb->dma_window_start,
|
||||
phb->dma_window_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spapr_pci_rtas_init(void)
|
||||
{
|
||||
spapr_rtas_register("read-pci-config", rtas_read_pci_config);
|
||||
spapr_rtas_register("write-pci-config", rtas_write_pci_config);
|
||||
spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
|
||||
spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
|
||||
if (msi_supported) {
|
||||
spapr_rtas_register("ibm,query-interrupt-source-number",
|
||||
rtas_ibm_query_interrupt_source_number);
|
||||
spapr_rtas_register("ibm,change-msi", rtas_ibm_change_msi);
|
||||
}
|
||||
}
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&spapr_phb_info);
|
||||
|
@ -27,8 +27,9 @@
|
||||
#include "hw/pci_host.h"
|
||||
#include "hw/xics.h"
|
||||
|
||||
#define SPAPR_MSIX_MAX_DEVS 32
|
||||
|
||||
typedef struct sPAPRPHBState {
|
||||
SysBusDevice busdev;
|
||||
PCIHostState host_state;
|
||||
|
||||
uint64_t buid;
|
||||
@ -37,27 +38,44 @@ typedef struct sPAPRPHBState {
|
||||
|
||||
MemoryRegion memspace, iospace;
|
||||
target_phys_addr_t mem_win_addr, mem_win_size, io_win_addr, io_win_size;
|
||||
MemoryRegion memwindow, iowindow;
|
||||
target_phys_addr_t msi_win_addr;
|
||||
MemoryRegion memwindow, iowindow, msiwindow;
|
||||
|
||||
uint32_t dma_liobn;
|
||||
uint64_t dma_window_start;
|
||||
uint64_t dma_window_size;
|
||||
DMAContext *dma;
|
||||
|
||||
struct {
|
||||
uint32_t dt_irq;
|
||||
qemu_irq qirq;
|
||||
uint32_t irq;
|
||||
} lsi_table[PCI_NUM_PINS];
|
||||
|
||||
struct {
|
||||
uint32_t config_addr;
|
||||
uint32_t irq;
|
||||
int nvec;
|
||||
} msi_table[SPAPR_MSIX_MAX_DEVS];
|
||||
|
||||
QLIST_ENTRY(sPAPRPHBState) list;
|
||||
} sPAPRPHBState;
|
||||
|
||||
static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
|
||||
{
|
||||
return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
|
||||
}
|
||||
|
||||
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
|
||||
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
|
||||
|
||||
void spapr_create_phb(sPAPREnvironment *spapr,
|
||||
const char *busname, uint64_t buid,
|
||||
uint64_t mem_win_addr, uint64_t mem_win_size,
|
||||
uint64_t io_win_addr);
|
||||
uint64_t io_win_addr, uint64_t msi_win_addr);
|
||||
|
||||
int spapr_populate_pci_devices(sPAPRPHBState *phb,
|
||||
uint32_t xics_phandle,
|
||||
void *fdt);
|
||||
int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
||||
uint32_t xics_phandle,
|
||||
void *fdt);
|
||||
|
||||
void spapr_pci_rtas_init(void);
|
||||
|
||||
#endif /* __HW_SPAPR_PCI_H__ */
|
||||
|
@ -49,7 +49,7 @@
|
||||
#endif
|
||||
|
||||
static Property spapr_vio_props[] = {
|
||||
DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
|
||||
DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -132,8 +132,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->qirq) {
|
||||
uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
|
||||
if (dev->irq) {
|
||||
uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
|
||||
|
||||
ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
|
||||
sizeof(ints_prop));
|
||||
@ -142,7 +142,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
|
||||
}
|
||||
}
|
||||
|
||||
ret = spapr_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
|
||||
ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -306,7 +306,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
|
||||
dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
|
||||
|
||||
if (dev->signal_state & 1) {
|
||||
qemu_irq_pulse(dev->qirq);
|
||||
qemu_irq_pulse(spapr_vio_qirq(dev));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -459,8 +459,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
|
||||
dev->qdev.id = id;
|
||||
}
|
||||
|
||||
dev->qirq = spapr_allocate_msi(dev->vio_irq_num, &dev->vio_irq_num);
|
||||
if (!dev->qirq) {
|
||||
dev->irq = spapr_allocate_msi(dev->irq);
|
||||
if (!dev->irq) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -61,8 +61,7 @@ struct VIOsPAPRDevice {
|
||||
DeviceState qdev;
|
||||
uint32_t reg;
|
||||
uint32_t flags;
|
||||
qemu_irq qirq;
|
||||
uint32_t vio_irq_num;
|
||||
uint32_t irq;
|
||||
target_ulong signal_state;
|
||||
VIOsPAPR_CRQ crq;
|
||||
DMAContext *dma;
|
||||
@ -85,6 +84,11 @@ extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
|
||||
|
||||
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
|
||||
|
||||
static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev)
|
||||
{
|
||||
return xics_get_qirq(spapr->icp, dev->irq);
|
||||
}
|
||||
|
||||
static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
|
||||
uint32_t size, DMADirection dir)
|
||||
{
|
||||
|
@ -26,7 +26,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
|
||||
|
||||
if ((dev->in == dev->out) && size) {
|
||||
/* toggle line to simulate edge interrupt */
|
||||
qemu_irq_pulse(dev->sdev.qirq);
|
||||
qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
|
||||
}
|
||||
for (i = 0; i < size; i++) {
|
||||
assert((dev->in - dev->out) < VTERM_BUFSIZE);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "elf.h"
|
||||
#include "blockdev.h"
|
||||
#include "exec-memory.h"
|
||||
#include "vga-pci.h"
|
||||
|
||||
//#define DEBUG_IRQ
|
||||
//#define DEBUG_EBUS
|
||||
|
@ -23,8 +23,8 @@
|
||||
*/
|
||||
#include "hw.h"
|
||||
#include "console.h"
|
||||
#include "pc.h"
|
||||
#include "pci.h"
|
||||
#include "vga-pci.h"
|
||||
#include "vga_int.h"
|
||||
#include "pixel_ops.h"
|
||||
#include "qemu-timer.h"
|
||||
|
12
hw/vga-pci.h
Normal file
12
hw/vga-pci.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef VGA_PCI_H
|
||||
#define VGA_PCI_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
|
||||
/* vga-pci.c */
|
||||
DeviceState *pci_vga_init(PCIBus *bus);
|
||||
|
||||
/* cirrus_vga.c */
|
||||
DeviceState *pci_cirrus_vga_init(PCIBus *bus);
|
||||
|
||||
#endif
|
12
hw/xics.c
12
hw/xics.c
@ -315,18 +315,24 @@ static void ics_eoi(struct ics_state *ics, int nr)
|
||||
* Exported functions
|
||||
*/
|
||||
|
||||
qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
|
||||
enum xics_irq_type type)
|
||||
qemu_irq xics_get_qirq(struct icp_state *icp, int irq)
|
||||
{
|
||||
if ((irq < icp->ics->offset)
|
||||
|| (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return icp->ics->qirqs[irq - icp->ics->offset];
|
||||
}
|
||||
|
||||
void xics_set_irq_type(struct icp_state *icp, int irq,
|
||||
enum xics_irq_type type)
|
||||
{
|
||||
assert((irq >= icp->ics->offset)
|
||||
&& (irq < (icp->ics->offset + icp->ics->nr_irqs)));
|
||||
assert((type == XICS_MSI) || (type == XICS_LSI));
|
||||
|
||||
icp->ics->irqs[irq - icp->ics->offset].type = type;
|
||||
return icp->ics->qirqs[irq - icp->ics->offset];
|
||||
}
|
||||
|
||||
static target_ulong h_cppr(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
|
@ -36,8 +36,9 @@ enum xics_irq_type {
|
||||
XICS_LSI, /* Level-signalled interrupt */
|
||||
};
|
||||
|
||||
qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
|
||||
enum xics_irq_type type);
|
||||
qemu_irq xics_get_qirq(struct icp_state *icp, int irq);
|
||||
void xics_set_irq_type(struct icp_state *icp, int irq,
|
||||
enum xics_irq_type type);
|
||||
|
||||
struct icp_state *xics_system_init(int nr_irqs);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
||||
implementation for certain IBM POWER hardware. The sources are at
|
||||
https://github.com/dgibson/SLOF, and the image currently in qemu is
|
||||
built from git tag qemu-slof-20120217.
|
||||
built from git tag qemu-slof-20120731.
|
||||
|
||||
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
|
||||
legacy x86 software to communicate with an attached serial console as
|
||||
|
BIN
pc-bios/slof.bin
BIN
pc-bios/slof.bin
Binary file not shown.
@ -1 +1 @@
|
||||
Subproject commit d153364253548d6cd91403711f84996e6a7dab31
|
||||
Subproject commit f21f7a3f46b557eb5923f899ce8b4401b3cc6d91
|
2
savevm.c
2
savevm.c
@ -2473,7 +2473,7 @@ int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
|
||||
/* word at a time for speed, use of 32-bit long okay */
|
||||
if (!res) {
|
||||
/* truncation to 32-bit long okay */
|
||||
long mask = 0x0101010101010101ULL;
|
||||
long mask = (long)0x0101010101010101ULL;
|
||||
while (i < slen) {
|
||||
xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i);
|
||||
if ((xor - mask) & ~xor & (mask << 7)) {
|
||||
|
@ -766,7 +766,7 @@ int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run)
|
||||
dprintf("handle PAPR hypercall\n");
|
||||
run->papr_hcall.ret = spapr_hypercall(env, run->papr_hcall.nr,
|
||||
run->papr_hcall.args);
|
||||
ret = 1;
|
||||
ret = 0;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -970,3 +970,11 @@ qxl_render_blit_guest_primary_initialized(void) ""
|
||||
qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]"
|
||||
qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d"
|
||||
qxl_render_update_area_done(void *cookie) "%p"
|
||||
|
||||
# hw/spapr_pci.c
|
||||
spapr_pci_msi(const char *msg, uint32_t n, uint32_t ca) "%s (device#%d, cfg=%x)"
|
||||
spapr_pci_msi_setup(const char *name, unsigned vector, uint64_t addr) "dev\"%s\" vector %u, addr=%"PRIx64
|
||||
spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %u"
|
||||
spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u"
|
||||
spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
|
||||
spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
|
||||
|
Loading…
Reference in New Issue
Block a user