diff options
author | Aurelien Jarno <aurelien@aurel32.net> | 2013-09-03 01:35:25 +0200 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2013-09-03 01:35:25 +0200 |
commit | 32f3bd6d4d6d6f835cbc2b9241fe8c32d2898d73 (patch) | |
tree | 5707fa4d0eaba20af83e93be41f1dfe752860800 | |
parent | 3207bf2549a1a84c577d2f6a481192566a059163 (diff) | |
parent | 7e472264e9e2727bc7d08fe6f012db76e1c1a193 (diff) |
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.c | 3 | ||||
-rw-r--r-- | hw/char/spapr_vty.c | 2 | ||||
-rw-r--r-- | hw/intc/xics.c | 21 | ||||
-rw-r--r-- | hw/ppc/e500.c | 52 | ||||
-rw-r--r-- | hw/ppc/ppc405_boards.c | 39 | ||||
-rw-r--r-- | hw/ppc/ppc405_uc.c | 16 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 31 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 50 | ||||
-rw-r--r-- | hw/ppc/spapr_iommu.c | 71 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 73 | ||||
-rw-r--r-- | hw/ppc/spapr_rtas.c | 23 | ||||
-rw-r--r-- | hw/ppc/virtex_ml507.c | 29 | ||||
-rw-r--r-- | include/hw/pci-host/spapr.h | 8 | ||||
-rw-r--r-- | include/hw/ppc/spapr.h | 21 | ||||
-rw-r--r-- | target-ppc/cpu.h | 2 | ||||
-rw-r--r-- | target-ppc/excp_helper.c | 10 | ||||
-rw-r--r-- | target-ppc/kvm_ppc.c | 1 | ||||
-rw-r--r-- | target-ppc/mmu_helper.c | 2 | ||||
-rw-r--r-- | target-ppc/translate.c | 4 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 2 | ||||
-rw-r--r-- | trace-events | 5 |
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 |