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:
Anthony Liguori 2012-08-15 14:59:21 -05:00
commit 0d16fdd732
34 changed files with 717 additions and 209 deletions

View File

@ -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. */

View File

@ -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"

View File

@ -48,6 +48,7 @@
#include "blockdev.h"
#include "exec-memory.h"
#include "sysbus.h" /* SysBusDevice */
#include "vga-pci.h"
//#define DEBUG_BOARD_INIT

View File

@ -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;

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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
View 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
View 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(&params);
}
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
View 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(&params);
}
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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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__) */

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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);

View File

@ -39,6 +39,7 @@
#include "elf.h"
#include "blockdev.h"
#include "exec-memory.h"
#include "vga-pci.h"
//#define DEBUG_IRQ
//#define DEBUG_EBUS

View File

@ -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
View 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

View File

@ -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,

View File

@ -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);

View File

@ -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

Binary file not shown.

@ -1 +1 @@
Subproject commit d153364253548d6cd91403711f84996e6a7dab31
Subproject commit f21f7a3f46b557eb5923f899ce8b4401b3cc6d91

View File

@ -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)) {

View File

@ -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:

View File

@ -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"