aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2013-09-03 01:35:25 +0200
committerAurelien Jarno <aurelien@aurel32.net>2013-09-03 01:35:25 +0200
commit32f3bd6d4d6d6f835cbc2b9241fe8c32d2898d73 (patch)
tree5707fa4d0eaba20af83e93be41f1dfe752860800
parent3207bf2549a1a84c577d2f6a481192566a059163 (diff)
parent7e472264e9e2727bc7d08fe6f012db76e1c1a193 (diff)
downloadqemu-arm-32f3bd6d4d6d6f835cbc2b9241fe8c32d2898d73.tar.gz
Merge branch 'ppc-for-upstream' of git://github.com/agraf/qemu
* 'ppc-for-upstream' of git://github.com/agraf/qemu: PPC: spapr: iommu: rework traces spapr: add "stop-self" RTAS call required to support hot CPU unplug PPC: KVM: Compile fix for qemu_notify_event pseries: Add H_SET_MODE hcall to change guest exception endianness xics: move registration of global state to realize() spapr-pci: rework MSI/MSIX target-ppc: Use #define instead of opencoding SLB valid bit spapr-pci: fix config space access to support bridges target-ppc: fix bit extraction for FPBF and FPL ppc405_boards: Don't enforce presence of firmware for qtest ppc405_uc: Disable debug output ppc405_boards: Disable debug output ppc: virtex_ml507: QEMU_OPTION_dtb support for this machine. disas/ppc.c: Fix little endian disassembly target-ppc: POWER7 supports the MSR_LE bit target-ppc: USE LPCR_ILE to control exception endian on POWER7 pseries: Fix stalls on hypervisor virtual console PPC: E500: Generate device tree on reset
-rw-r--r--disas/ppc.c3
-rw-r--r--hw/char/spapr_vty.c2
-rw-r--r--hw/intc/xics.c21
-rw-r--r--hw/ppc/e500.c52
-rw-r--r--hw/ppc/ppc405_boards.c39
-rw-r--r--hw/ppc/ppc405_uc.c16
-rw-r--r--hw/ppc/spapr.c31
-rw-r--r--hw/ppc/spapr_hcall.c50
-rw-r--r--hw/ppc/spapr_iommu.c71
-rw-r--r--hw/ppc/spapr_pci.c73
-rw-r--r--hw/ppc/spapr_rtas.c23
-rw-r--r--hw/ppc/virtex_ml507.c29
-rw-r--r--include/hw/pci-host/spapr.h8
-rw-r--r--include/hw/ppc/spapr.h21
-rw-r--r--target-ppc/cpu.h2
-rw-r--r--target-ppc/excp_helper.c10
-rw-r--r--target-ppc/kvm_ppc.c1
-rw-r--r--target-ppc/mmu_helper.c2
-rw-r--r--target-ppc/translate.c4
-rw-r--r--target-ppc/translate_init.c2
-rw-r--r--trace-events5
21 files changed, 305 insertions, 160 deletions
diff --git a/disas/ppc.c b/disas/ppc.c
index c149506fd8..99c4cbc3ab 100644
--- a/disas/ppc.c
+++ b/disas/ppc.c
@@ -5157,7 +5157,8 @@ int
print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info)
{
int dialect = (char *) info->private_data - (char *) 0;
- return print_insn_powerpc (memaddr, info, 1, dialect);
+ return print_insn_powerpc (memaddr, info, info->endian == BFD_ENDIAN_BIG,
+ dialect);
}
/* Print a big endian PowerPC instruction. */
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index a7997213b6..9c2aef82e6 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -47,6 +47,8 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
}
+ qemu_chr_accept_input(dev->chardev);
+
return n;
}
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 6b3c071588..31868c4d18 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -642,6 +642,17 @@ static void xics_realize(DeviceState *dev, Error **errp)
ICSState *ics = icp->ics;
int i;
+ /* Registration of global state belongs into realize */
+ spapr_rtas_register("ibm,set-xive", rtas_set_xive);
+ spapr_rtas_register("ibm,get-xive", rtas_get_xive);
+ spapr_rtas_register("ibm,int-off", rtas_int_off);
+ spapr_rtas_register("ibm,int-on", rtas_int_on);
+
+ spapr_register_hypercall(H_CPPR, h_cppr);
+ spapr_register_hypercall(H_IPI, h_ipi);
+ spapr_register_hypercall(H_XIRR, h_xirr);
+ spapr_register_hypercall(H_EOI, h_eoi);
+
ics->nr_irqs = icp->nr_irqs;
ics->offset = XICS_IRQ_BASE;
ics->icp = icp;
@@ -678,16 +689,6 @@ static void xics_class_init(ObjectClass *oc, void *data)
dc->realize = xics_realize;
dc->props = xics_properties;
dc->reset = xics_reset;
-
- spapr_rtas_register("ibm,set-xive", rtas_set_xive);
- spapr_rtas_register("ibm,get-xive", rtas_get_xive);
- spapr_rtas_register("ibm,int-off", rtas_int_off);
- spapr_rtas_register("ibm,int-on", rtas_int_on);
-
- spapr_register_hypercall(H_CPPR, h_cppr);
- spapr_register_hypercall(H_IPI, h_ipi);
- spapr_register_hypercall(H_XIRR, h_xirr);
- spapr_register_hypercall(H_EOI, h_eoi);
}
static const TypeInfo xics_info = {
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index e79612b0e9..9059ff9bc7 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -123,13 +123,14 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
}
}
-static int ppce500_load_device_tree(CPUPPCState *env,
- QEMUMachineInitArgs *args,
+static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
PPCE500Params *params,
hwaddr addr,
hwaddr initrd_base,
- hwaddr initrd_size)
+ hwaddr initrd_size,
+ bool dry_run)
{
+ CPUPPCState *env = first_cpu->env_ptr;
int ret = -1;
uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) };
int fdt_size;
@@ -369,12 +370,10 @@ static int ppce500_load_device_tree(CPUPPCState *env,
}
done:
- qemu_devtree_dumpdtb(fdt, fdt_size);
- ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
- if (ret < 0) {
- goto out;
+ if (!dry_run) {
+ qemu_devtree_dumpdtb(fdt, fdt_size);
+ cpu_physical_memory_write(addr, fdt, fdt_size);
}
- g_free(fdt);
ret = fdt_size;
out:
@@ -383,6 +382,41 @@ out:
return ret;
}
+typedef struct DeviceTreeParams {
+ QEMUMachineInitArgs args;
+ PPCE500Params params;
+ hwaddr addr;
+ hwaddr initrd_base;
+ hwaddr initrd_size;
+} DeviceTreeParams;
+
+static void ppce500_reset_device_tree(void *opaque)
+{
+ DeviceTreeParams *p = opaque;
+ ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base,
+ p->initrd_size, false);
+}
+
+static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
+ PPCE500Params *params,
+ hwaddr addr,
+ hwaddr initrd_base,
+ hwaddr initrd_size)
+{
+ DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
+ p->args = *args;
+ p->params = *params;
+ p->addr = addr;
+ p->initrd_base = initrd_base;
+ p->initrd_size = initrd_size;
+
+ qemu_register_reset(ppce500_reset_device_tree, p);
+
+ /* Issue the device tree loader once, so that we get the size of the blob */
+ return ppce500_load_device_tree(args, params, addr, initrd_base,
+ initrd_size, true);
+}
+
/* Create -kernel TLB entries for BookE. */
static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
{
@@ -746,7 +780,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
struct boot_info *boot_info;
int dt_size;
- dt_size = ppce500_load_device_tree(env, args, params, dt_base,
+ dt_size = ppce500_prep_device_tree(args, params, dt_base,
initrd_base, initrd_size);
if (dt_size < 0) {
fprintf(stderr, "couldn't load device tree\n");
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index f74e5e52c2..75b2177c9c 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -27,9 +27,11 @@
#include "hw/timer/m48t59.h"
#include "hw/block/flash.h"
#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
#include "block/block.h"
#include "hw/boards.h"
#include "qemu/log.h"
+#include "qemu/error-report.h"
#include "hw/loader.h"
#include "sysemu/blockdev.h"
#include "exec/address-spaces.h"
@@ -42,7 +44,7 @@
#define USE_FLASH_BIOS
-#define DEBUG_BOARD_INIT
+//#define DEBUG_BOARD_INIT
/*****************************************************************************/
/* PPC405EP reference board (IBM) */
@@ -252,17 +254,20 @@ static void ref405ep_init(QEMUMachineInitArgs *args)
if (filename) {
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
g_free(filename);
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ error_report("Could not load PowerPC BIOS '%s'", bios_name);
+ exit(1);
+ }
+ bios_size = (bios_size + 0xfff) & ~0xfff;
+ memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
+ } else if (!qtest_enabled() || kernel_filename != NULL) {
+ error_report("Could not load PowerPC BIOS '%s'", bios_name);
+ exit(1);
} else {
+ /* Avoid an uninitialized variable warning */
bios_size = -1;
}
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
- bios_name);
- exit(1);
- }
- bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_set_readonly(bios, true);
- memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
}
/* Register FPGA */
#ifdef DEBUG_BOARD_INIT
@@ -353,9 +358,9 @@ static void ref405ep_init(QEMUMachineInitArgs *args)
bdloc = 0;
}
#ifdef DEBUG_BOARD_INIT
+ printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
printf("%s: Done\n", __func__);
#endif
- printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
}
static QEMUMachine ref405ep_machine = {
@@ -569,17 +574,17 @@ static void taihu_405ep_init(QEMUMachineInitArgs *args)
if (filename) {
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
g_free(filename);
- } else {
- bios_size = -1;
- }
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
- bios_name);
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ error_report("Could not load PowerPC BIOS '%s'", bios_name);
+ exit(1);
+ }
+ bios_size = (bios_size + 0xfff) & ~0xfff;
+ memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
+ } else if (!qtest_enabled()) {
+ error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
- bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_set_readonly(bios, true);
- memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
}
/* Register Linux flash */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index 0ef5254cd7..6d6a7f1203 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -30,15 +30,15 @@
#include "qemu/log.h"
#include "exec/address-spaces.h"
-#define DEBUG_OPBA
-#define DEBUG_SDRAM
-#define DEBUG_GPIO
-#define DEBUG_SERIAL
-#define DEBUG_OCM
+//#define DEBUG_OPBA
+//#define DEBUG_SDRAM
+//#define DEBUG_GPIO
+//#define DEBUG_SERIAL
+//#define DEBUG_OCM
//#define DEBUG_I2C
-#define DEBUG_GPT
-#define DEBUG_MAL
-#define DEBUG_CLOCKS
+//#define DEBUG_GPT
+//#define DEBUG_MAL
+//#define DEBUG_CLOCKS
//#define DEBUG_CLOCKS_LL
ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 4b566aa410..04f0ee3da1 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -88,6 +88,9 @@ int spapr_allocate_irq(int hint, bool lsi)
if (hint) {
irq = hint;
+ if (hint >= spapr->next_irq) {
+ spapr->next_irq = hint + 1;
+ }
/* FIXME: we should probably check for collisions somehow */
} else {
irq = spapr->next_irq++;
@@ -103,22 +106,39 @@ int spapr_allocate_irq(int hint, bool lsi)
return irq;
}
-/* Allocate block of consequtive IRQs, returns a number of the first */
-int spapr_allocate_irq_block(int num, bool lsi)
+/*
+ * Allocate block of consequtive IRQs, returns a number of the first.
+ * If msi==true, aligns the first IRQ number to num.
+ */
+int spapr_allocate_irq_block(int num, bool lsi, bool msi)
{
int first = -1;
- int i;
+ int i, hint = 0;
+
+ /*
+ * MSIMesage::data is used for storing VIRQ so
+ * it has to be aligned to num to support multiple
+ * MSI vectors. MSI-X is not affected by this.
+ * The hint is used for the first IRQ, the rest should
+ * be allocated continously.
+ */
+ if (msi) {
+ assert((num == 1) || (num == 2) || (num == 4) ||
+ (num == 8) || (num == 16) || (num == 32));
+ hint = (spapr->next_irq + num - 1) & ~(num - 1);
+ }
for (i = 0; i < num; ++i) {
int irq;
- irq = spapr_allocate_irq(0, lsi);
+ irq = spapr_allocate_irq(hint, lsi);
if (!irq) {
return -1;
}
if (0 == i) {
first = irq;
+ hint = 0;
}
/* If the above doesn't create a consecutive block then that's
@@ -262,7 +282,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
- "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
+ "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk\0hcall-set-mode";
char qemu_hypertas_prop[] = "hcall-memop1";
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
@@ -1214,6 +1234,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
spapr_create_nvram(spapr);
/* Set up PCI */
+ spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW);
spapr_pci_rtas_init();
phb = spapr_create_phb(spapr, 0);
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 67d6cd91d1..89e6a00dd9 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -657,6 +657,54 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return H_SUCCESS;
}
+static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ CPUState *cs;
+ target_ulong mflags = args[0];
+ target_ulong resource = args[1];
+ target_ulong value1 = args[2];
+ target_ulong value2 = args[3];
+ target_ulong ret = H_P2;
+
+ if (resource == H_SET_MODE_ENDIAN) {
+ if (value1) {
+ ret = H_P3;
+ goto out;
+ }
+ if (value2) {
+ ret = H_P4;
+ goto out;
+ }
+
+ switch (mflags) {
+ case H_SET_MODE_ENDIAN_BIG:
+ for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ PowerPCCPU *cp = POWERPC_CPU(cs);
+ CPUPPCState *env = &cp->env;
+ env->spr[SPR_LPCR] &= ~LPCR_ILE;
+ }
+ ret = H_SUCCESS;
+ break;
+
+ case H_SET_MODE_ENDIAN_LITTLE:
+ for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ PowerPCCPU *cp = POWERPC_CPU(cs);
+ CPUPPCState *env = &cp->env;
+ env->spr[SPR_LPCR] |= LPCR_ILE;
+ }
+ ret = H_SUCCESS;
+ break;
+
+ default:
+ ret = H_UNSUPPORTED_FLAG;
+ }
+ }
+
+out:
+ return ret;
+}
+
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
@@ -734,6 +782,8 @@ static void hypercall_register_types(void)
/* qemu/KVM-PPC specific hcalls */
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
+
+ spapr_register_hypercall(H_SET_MODE, h_set_mode);
}
type_init(hypercall_register_types)
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 3d4a1fcfe1..ef45f4f0cc 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -22,13 +22,12 @@
#include "kvm_ppc.h"
#include "sysemu/dma.h"
#include "exec/address-spaces.h"
+#include "trace.h"
#include "hw/ppc/spapr.h"
#include <libfdt.h>
-/* #define DEBUG_TCE */
-
enum sPAPRTCEAccess {
SPAPR_TCE_FAULT = 0,
SPAPR_TCE_RO = 1,
@@ -61,44 +60,28 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
{
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
uint64_t tce;
-
-#ifdef DEBUG_TCE
- fprintf(stderr, "spapr_tce_translate liobn=0x%" PRIx32 " addr=0x"
- DMA_ADDR_FMT "\n", tcet->liobn, addr);
-#endif
+ IOMMUTLBEntry ret = {
+ .target_as = &address_space_memory,
+ .iova = 0,
+ .translated_addr = 0,
+ .addr_mask = ~(hwaddr)0,
+ .perm = IOMMU_NONE,
+ };
if (tcet->bypass) {
- return (IOMMUTLBEntry) {
- .target_as = &address_space_memory,
- .iova = 0,
- .translated_addr = 0,
- .addr_mask = ~(hwaddr)0,
- .perm = IOMMU_RW,
- };
- }
-
- /* Check if we are in bound */
- if (addr >= tcet->window_size) {
-#ifdef DEBUG_TCE
- fprintf(stderr, "spapr_tce_translate out of bounds\n");
-#endif
- return (IOMMUTLBEntry) { .perm = IOMMU_NONE };
+ ret.perm = IOMMU_RW;
+ } else if (addr < tcet->window_size) {
+ /* Check if we are in bound */
+ tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
+ ret.iova = addr & ~SPAPR_TCE_PAGE_MASK;
+ ret.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK;
+ ret.addr_mask = SPAPR_TCE_PAGE_MASK;
+ ret.perm = tce;
}
+ trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
+ ret.addr_mask);
- tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
-
-#ifdef DEBUG_TCE
- fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n",
- (tce & ~SPAPR_TCE_PAGE_MASK), SPAPR_TCE_PAGE_MASK + 1);
-#endif
-
- return (IOMMUTLBEntry) {
- .target_as = &address_space_memory,
- .iova = addr & ~SPAPR_TCE_PAGE_MASK,
- .translated_addr = tce & ~SPAPR_TCE_PAGE_MASK,
- .addr_mask = SPAPR_TCE_PAGE_MASK,
- .perm = tce,
- };
+ return ret;
}
static int spapr_tce_table_pre_load(void *opaque)
@@ -150,10 +133,7 @@ static int spapr_tce_table_realize(DeviceState *dev)
}
tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT;
-#ifdef DEBUG_TCE
- fprintf(stderr, "spapr_iommu: New TCE table @ %p, liobn=0x%x, "
- "table @ %p, fd=%d\n", tcet, liobn, tcet->table, tcet->fd);
-#endif
+ trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd);
memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
"iommu-spapr", UINT64_MAX);
@@ -250,20 +230,17 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong liobn = args[0];
target_ulong ioba = args[1];
target_ulong tce = args[2];
+ target_ulong ret = H_PARAMETER;
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
if (tcet) {
- return put_tce_emu(tcet, ioba, tce);
+ ret = put_tce_emu(tcet, ioba, tce);
}
-#ifdef DEBUG_TCE
- fprintf(stderr, "%s on liobn=" TARGET_FMT_lx /*%s*/
- " ioba 0x" TARGET_FMT_lx " TCE 0x" TARGET_FMT_lx "\n",
- __func__, liobn, /*dev->qdev.id, */ioba, tce);
-#endif
+ trace_spapr_iommu_put(liobn, ioba, tce, ret);
- return H_PARAMETER;
+ return ret;
}
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 1ca35a0a72..9b6ee32acf 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -65,22 +65,14 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
{
sPAPRPHBState *sphb = find_phb(spapr, buid);
PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
- BusState *bus = BUS(phb->bus);
- BusChild *kid;
+ int bus_num = (config_addr >> 16) & 0xFF;
int devfn = (config_addr >> 8) & 0xFF;
if (!phb) {
return NULL;
}
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- PCIDevice *dev = (PCIDevice *)kid->child;
- if (dev->devfn == devfn) {
- return dev;
- }
- }
-
- return NULL;
+ return pci_find_device(phb->bus, bus_num, devfn);
}
static uint32_t rtas_pci_cfgaddr(uint32_t arg)
@@ -258,11 +250,11 @@ static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
* 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, hwaddr addr,
- bool msix, unsigned req_num)
+static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
+ unsigned first_irq, unsigned req_num)
{
unsigned i;
- MSIMessage msg = { .address = addr, .data = 0 };
+ MSIMessage msg = { .address = addr, .data = first_irq };
if (!msix) {
msi_set_message(pdev, msg);
@@ -270,8 +262,7 @@ static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
return;
}
- for (i = 0; i < req_num; ++i) {
- msg.address = addr | (i << 2);
+ for (i = 0; i < req_num; ++i, ++msg.data) {
msix_set_message(pdev, i, msg);
trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
}
@@ -351,7 +342,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* There is no cached config, allocate MSIs */
if (!phb->msi_table[ndev].nvec) {
- irq = spapr_allocate_irq_block(req_num, false);
+ irq = spapr_allocate_irq_block(req_num, false,
+ ret_intr_type == RTAS_TYPE_MSI);
if (irq < 0) {
fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
rtas_st(rets, 0, -1); /* Hardware error */
@@ -363,8 +355,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
/* 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);
+ spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX,
+ phb->msi_table[ndev].irq, req_num);
rtas_st(rets, 0, 0);
rtas_st(rets, 1, req_num);
@@ -450,10 +442,7 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
static void spapr_msi_write(void *opaque, hwaddr 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;
+ uint32_t irq = data;
trace_spapr_pci_msi_write(addr, data, irq);
@@ -467,6 +456,23 @@ static const MemoryRegionOps spapr_msi_ops = {
.endianness = DEVICE_LITTLE_ENDIAN
};
+void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
+{
+ /*
+ * 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().
+ * As MSIMessage:addr is going to be the same and MSIMessage:data
+ * is going to be a VIRQ number, 4 bytes of the MSI MR will only
+ * be used.
+ */
+ spapr->msi_win_addr = addr;
+ memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
+ "msi", getpagesize());
+ memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
+ &spapr->msiwindow);
+}
+
/*
* PHB PCI device
*/
@@ -492,8 +498,7 @@ static int spapr_phb_init(SysBusDevice *s)
if ((sphb->buid != -1) || (sphb->dma_liobn != -1)
|| (sphb->mem_win_addr != -1)
- || (sphb->io_win_addr != -1)
- || (sphb->msi_win_addr != -1)) {
+ || (sphb->io_win_addr != -1)) {
fprintf(stderr, "Either \"index\" or other parameters must"
" be specified for PAPR PHB, not both\n");
return -1;
@@ -506,7 +511,6 @@ static int spapr_phb_init(SysBusDevice *s)
+ sphb->index * SPAPR_PCI_WINDOW_SPACING;
sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF;
sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF;
- sphb->msi_win_addr = windows_base + SPAPR_PCI_MSI_WIN_OFF;
}
if (sphb->buid == -1) {
@@ -529,11 +533,6 @@ static int spapr_phb_init(SysBusDevice *s)
return -1;
}
- if (sphb->msi_win_addr == -1) {
- fprintf(stderr, "MSI window address not specified for PHB\n");
- return -1;
- }
-
if (find_phb(spapr, sphb->buid)) {
fprintf(stderr, "PCI host bridges must have unique BUIDs\n");
return -1;
@@ -573,18 +572,6 @@ static int spapr_phb_init(SysBusDevice *s)
get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE);
memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
&sphb->iowindow);
-
- /* 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", sphb->dtbusname);
- memory_region_init_io(&sphb->msiwindow, OBJECT(sphb), &spapr_msi_ops, sphb,
- namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
- memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr,
- &sphb->msiwindow);
- }
-
/*
* Selecting a busname is more complex than you'd think, due to
* interacting constraints. If the user has specified an id
@@ -659,7 +646,6 @@ static Property spapr_phb_properties[] = {
DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size,
SPAPR_PCI_IO_WIN_SIZE),
- DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, -1),
DEFINE_PROP_END_OF_LIST(),
};
@@ -701,7 +687,6 @@ static const VMStateDescription vmstate_spapr_pci = {
VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState),
VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState),
VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState),
- VMSTATE_UINT64_EQUAL(msi_win_addr, sPAPRPHBState),
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
VMSTATE_STRUCT_ARRAY(msi_table, sPAPRPHBState, SPAPR_MSIX_MAX_DEVS, 0,
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 394ce05ba2..eb542f218a 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -202,6 +202,28 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
rtas_st(rets, 0, -3);
}
+static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+
+ cs->halted = 1;
+ cpu_exit(cs);
+ /*
+ * While stopping a CPU, the guest calls H_CPPR which
+ * effectively disables interrupts on XICS level.
+ * However decrementer interrupts in TCG can still
+ * wake the CPU up so here we disable interrupts in MSR
+ * as well.
+ * As rtas_start_cpu() resets the whole MSR anyway, there is
+ * no need to bother with specific bits, we just clear it.
+ */
+ env->msr = 0;
+}
+
static struct rtas_call {
const char *name;
spapr_rtas_fn fn;
@@ -322,6 +344,7 @@ static void core_rtas_register_types(void)
spapr_rtas_register("query-cpu-stopped-state",
rtas_query_cpu_stopped_state);
spapr_rtas_register("start-cpu", rtas_start_cpu);
+ spapr_rtas_register("stop-self", rtas_stop_self);
}
type_init(core_rtas_register_types)
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 08e77fbef5..e9468b1b25 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -141,22 +141,31 @@ static int xilinx_load_device_tree(hwaddr addr,
{
char *path;
int fdt_size;
- void *fdt;
+ void *fdt = NULL;
int r;
+ const char *dtb_filename;
- /* Try the local "ppc.dtb" override. */
- fdt = load_device_tree("ppc.dtb", &fdt_size);
- if (!fdt) {
- path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
- if (path) {
- fdt = load_device_tree(path, &fdt_size);
- g_free(path);
+ dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
+ if (dtb_filename) {
+ fdt = load_device_tree(dtb_filename, &fdt_size);
+ if (!fdt) {
+ error_report("Error while loading device tree file '%s'",
+ dtb_filename);
}
+ } else {
+ /* Try the local "ppc.dtb" override. */
+ fdt = load_device_tree("ppc.dtb", &fdt_size);
if (!fdt) {
- return 0;
+ path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ if (path) {
+ fdt = load_device_tree(path, &fdt_size);
+ g_free(path);
+ }
}
}
-
+ if (!fdt) {
+ return 0;
+ }
r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
if (r < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index 93f9511325..970b4a9e4a 100644
--- a/include/hw/pci-host/spapr.h
+++ b/include/hw/pci-host/spapr.h
@@ -43,8 +43,7 @@ typedef struct sPAPRPHBState {
MemoryRegion memspace, iospace;
hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
- hwaddr msi_win_addr;
- MemoryRegion memwindow, iowindow, msiwindow;
+ MemoryRegion memwindow, iowindow;
uint32_t dma_liobn;
uint64_t dma_window_start;
@@ -73,7 +72,8 @@ typedef struct sPAPRPHBState {
#define SPAPR_PCI_MMIO_WIN_SIZE 0x20000000
#define SPAPR_PCI_IO_WIN_OFF 0x80000000
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
-#define SPAPR_PCI_MSI_WIN_OFF 0x90000000
+
+#define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
@@ -88,6 +88,8 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
uint32_t xics_phandle,
void *fdt);
+void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr);
+
void spapr_pci_rtas_init(void);
#endif /* __HW_SPAPR_PCI_H__ */
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 9fc197286c..e37b41983c 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -13,6 +13,8 @@ struct sPAPRNVRAM;
typedef struct sPAPREnvironment {
struct VIOsPAPRBus *vio_bus;
QLIST_HEAD(, sPAPRPHBState) phbs;
+ hwaddr msi_win_addr;
+ MemoryRegion msiwindow;
struct sPAPRNVRAM *nvram;
XICSState *icp;
@@ -109,6 +111,15 @@ typedef struct sPAPREnvironment {
#define H_NOT_ENOUGH_RESOURCES -44
#define H_R_STATE -45
#define H_RESCINDEND -46
+#define H_P2 -55
+#define H_P3 -56
+#define H_P4 -57
+#define H_P5 -58
+#define H_P6 -59
+#define H_P7 -60
+#define H_P8 -61
+#define H_P9 -62
+#define H_UNSUPPORTED_FLAG -256
#define H_MULTI_THREADS_ACTIVE -9005
@@ -143,6 +154,11 @@ typedef struct sPAPREnvironment {
#define H_PP1 (1ULL<<(63-62))
#define H_PP2 (1ULL<<(63-63))
+/* H_SET_MODE flags */
+#define H_SET_MODE_ENDIAN 4
+#define H_SET_MODE_ENDIAN_BIG 0
+#define H_SET_MODE_ENDIAN_LITTLE 1
+
/* VASI States */
#define H_VASI_INVALID 0
#define H_VASI_ENABLED 1
@@ -267,7 +283,8 @@ typedef struct sPAPREnvironment {
#define H_GET_EM_PARMS 0x2B8
#define H_SET_MPP 0x2D0
#define H_GET_MPP 0x2D4
-#define MAX_HCALL_OPCODE H_GET_MPP
+#define H_SET_MODE 0x31C
+#define MAX_HCALL_OPCODE H_SET_MODE
/* The hcalls above are standardized in PAPR and implemented by pHyp
* as well.
@@ -303,7 +320,7 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
target_ulong *args);
int spapr_allocate_irq(int hint, bool lsi);
-int spapr_allocate_irq_block(int num, bool lsi);
+int spapr_allocate_irq_block(int num, bool lsi, bool msi);
static inline int spapr_allocate_msi(int hint)
{
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 711db083e0..422a6bbd2e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -453,6 +453,8 @@ struct ppc_slb_t {
#define MSR_RI 1 /* Recoverable interrupt 1 */
#define MSR_LE 0 /* Little-endian mode 1 hflags */
+#define LPCR_ILE (1 << (63-38))
+
#define msr_sf ((env->msr >> MSR_SF) & 1)
#define msr_isf ((env->msr >> MSR_ISF) & 1)
#define msr_shv ((env->msr >> MSR_SHV) & 1)
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index e9fcad8ef6..e957761109 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -611,9 +611,19 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
tlb_flush(env, 1);
}
+#ifdef TARGET_PPC64
+ if (excp_model == POWERPC_EXCP_POWER7) {
+ if (env->spr[SPR_LPCR] & LPCR_ILE) {
+ new_msr |= (target_ulong)1 << MSR_LE;
+ }
+ } else if (msr_ile) {
+ new_msr |= (target_ulong)1 << MSR_LE;
+ }
+#else
if (msr_ile) {
new_msr |= (target_ulong)1 << MSR_LE;
}
+#endif
/* Jump to handler */
vector = env->excp_vectors[excp];
diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
index 9b8365503b..f769acd44c 100644
--- a/target-ppc/kvm_ppc.c
+++ b/target-ppc/kvm_ppc.c
@@ -15,6 +15,7 @@
#include "qemu/timer.h"
#include "kvm_ppc.h"
#include "sysemu/device_tree.h"
+#include "qemu/main-loop.h"
#define PROC_DEVTREE_PATH "/proc/device-tree"
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 5dd4e05f78..9c9132ea81 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -2061,7 +2061,7 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
/* ESID = srnum */
rb |= ((uint32_t)srnum & 0xf) << 28;
/* Set the valid bit */
- rb |= 1 << 27;
+ rb |= SLB_ESID_V;
/* Index = ESID */
rb |= (uint32_t)srnum;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index f07d70d866..41f40486eb 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -428,9 +428,9 @@ EXTRACT_HELPER(CRM, 12, 8);
EXTRACT_HELPER(SR, 16, 4);
/* mtfsf/mtfsfi */
-EXTRACT_HELPER(FPBF, 19, 3);
+EXTRACT_HELPER(FPBF, 23, 3);
EXTRACT_HELPER(FPIMM, 12, 4);
-EXTRACT_HELPER(FPL, 21, 1);
+EXTRACT_HELPER(FPL, 25, 1);
EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 609f797083..d2645bad28 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -7227,7 +7227,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD;
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205;
- pcc->msr_mask = 0x800000000204FF36ULL;
+ pcc->msr_mask = 0x800000000204FF37ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
diff --git a/trace-events b/trace-events
index 3856b5c206..aaad3560f4 100644
--- a/trace-events
+++ b/trace-events
@@ -1133,6 +1133,11 @@ xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_
xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]"
xics_ics_eoi(int nr) "ics_eoi: irq %#x"
+# hw/ppc/spapr_iommu.c
+spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
+spapr_iommu_xlate(uint64_t liobn, uint64_t ioba, uint64_t tce, unsigned perm, unsigned pgsize) "liobn=%"PRIx64" 0x%"PRIx64" -> 0x%"PRIx64" perm=%u mask=%x"
+spapr_iommu_new_table(uint64_t liobn, void *tcet, void *table, int fd) "liobn=%"PRIx64" tcet=%p table=%p fd=%d"
+
# util/hbitmap.c
hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx"
hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64