From 28290f37e20cda27574f15be9e9499493e3d0fe8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Jul 2013 12:56:24 +0200 Subject: [PATCH 01/18] PPC: E500: Generate device tree on reset Today we generate the device tree once on machine initialization and then store the finalized blob in memory to reload it on reset. This is bad for 2 reasons. First we potentially waste a bunch of RAM for no good reason, as we have all information required to regenerate the device tree available anyways. The second reason is even more important. On machine init when we generate the device tree for the first time, we don't have all of the devices fully initialized yet. But the device tree needs to potentially walk devices to put information about them into the device tree. Move the generation into a reset function. That way we just generate it new every time we reset, solving both of the above issues. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 52 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 9 deletions(-) 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"); From 7770b6f78a2d655e03852a5de238f5926c92be6a Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 13 Aug 2013 14:10:04 +1000 Subject: [PATCH 02/18] pseries: Fix stalls on hypervisor virtual console A number of users are reporting stalls when using the pseries hypervisor virtual console. A simple test case is to paste 15 or 17 characters at a time into the console. Pasting 15 characters at a time works fine but pasting 17 characters hangs for a random amount of time. Other activity (network, qemu monitor etc) unblocks it. If qemu-char tries to send more than 16 characters at once, vty_can_receive returns false. At this point we have to wait for the guest to consume that output. Everything is good so far. The problem occurs when the the guest does consume the output. We need to signal back to the qemu-char layer that we are ready for more input. Without this we block until something else kicks us (eg network activity). Signed-off-by: Anton Blanchard Signed-off-by: Alexander Graf --- hw/char/spapr_vty.c | 2 ++ 1 file changed, 2 insertions(+) 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; } From 1e0c7e554e449abb7bf759339ca2cf8cda232532 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 7 Aug 2013 10:47:01 +1000 Subject: [PATCH 03/18] target-ppc: USE LPCR_ILE to control exception endian on POWER7 On POWER7, LPCR_ILE is used to control what endian guests take their exceptions in so use it instead of MSR_ILE. Signed-off-by: Anton Blanchard Reviewed-by: Anthony Liguori Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 2 ++ target-ppc/excp_helper.c | 10 ++++++++++ 2 files changed, 12 insertions(+) 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]; From bb429d224733c263456c105eab93cd2b5e55add2 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 7 Aug 2013 10:47:00 +1000 Subject: [PATCH 04/18] target-ppc: POWER7 supports the MSR_LE bit Add MSR_LE to the msr_mask for POWER7. Signed-off-by: Anton Blanchard Reviewed-by: Anthony Liguori Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From 95f5b6e3af28a24f97b25649e12f586e19e8a4a1 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 7 Aug 2013 10:47:03 +1000 Subject: [PATCH 05/18] disas/ppc.c: Fix little endian disassembly Use info->endian to select the endian of the instruction to be disassembled. Signed-off-by: Anton Blanchard Reviewed-by: Anthony Liguori Signed-off-by: Alexander Graf --- disas/ppc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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. */ From daf285b6063f20c328f03d6185bbfe9b81ce5fe2 Mon Sep 17 00:00:00 2001 From: Efimov Vasily Date: Wed, 14 Aug 2013 17:26:08 +0400 Subject: [PATCH 06/18] ppc: virtex_ml507: QEMU_OPTION_dtb support for this machine. QEMU has 'dtb' option for specifing the device tree file for the kernel. The patch adds support for this option to the 'virtex_ml507' machine implementation. Signed-off-by: Efimov Vasily Signed-off-by: Alexander Graf --- hw/ppc/virtex_ml507.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) 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) { - return 0; + 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) { + 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"); From bf2ed917d77489189e7bcfea629ca030c8e2639d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 5 Aug 2013 15:27:21 +0200 Subject: [PATCH 07/18] ppc405_boards: Disable debug output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also move one stray debug output into an #ifdef. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppc/ppc405_boards.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index f74e5e52c2..807ada0249 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -42,7 +42,7 @@ #define USE_FLASH_BIOS -#define DEBUG_BOARD_INIT +//#define DEBUG_BOARD_INIT /*****************************************************************************/ /* PPC405EP reference board (IBM) */ @@ -353,9 +353,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 = { From 0d84382ed96cb2cfc3bc5be34d3a045eeb69c9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 5 Aug 2013 15:27:22 +0200 Subject: [PATCH 08/18] ppc405_uc: Disable debug output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppc/ppc405_uc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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, From ad9990acc5ac29ce505fbb2b955928ce335eddfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 5 Aug 2013 15:27:23 +0200 Subject: [PATCH 09/18] ppc405_boards: Don't enforce presence of firmware for qtest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopt error_report() while at it. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppc/ppc405_boards.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index 807ada0249..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" @@ -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 @@ -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); From 779f659021d1754117bce1aab9370dc22f37ae07 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 15 Aug 2013 13:32:38 +0200 Subject: [PATCH 10/18] target-ppc: fix bit extraction for FPBF and FPL Bit extraction for the FP BF and L field of the MTFSFI and MTFSF instructions is wrong and doesn't match the reference manual (which explain the bit number in big endian format). It has been broken in commit 7d08d85645def18eac2a9d672c1868a35e0bcf79. This patch fixes this, which in turn fixes the problem reported by Khem Raj about the floor() function of libm. Reported-by: Khem Raj Signed-off-by: Aurelien Jarno CC: qemu-stable@nongnu.org (1.6) Signed-off-by: Alexander Graf --- target-ppc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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); From 5dac82ce0d8716b54f73f96bf50811644a76e5c2 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 21 Aug 2013 16:02:15 +1000 Subject: [PATCH 11/18] spapr-pci: fix config space access to support bridges spapr-pci config space accessors use find_dev() to find a PCI device. However find_dev() only searched on a primary bus and did not do recursive search through secondary buses so config space access was not possible for devices other that on a primary bus. This fixed find_dev() by using the PCI API pci_find_device() function. This effectively enabled pci bridges on spapr. Signed-off-by: Alexey Kardashevskiy Acked-by: Michael S. Tsirkin Signed-off-by: Alexander Graf --- hw/ppc/spapr_pci.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 1ca35a0a72..65be265b74 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) From a3cedb541ca3ecc82040f597a4054419fdb22fa5 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 20 Aug 2013 16:19:24 +0530 Subject: [PATCH 12/18] target-ppc: Use #define instead of opencoding SLB valid bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use SLB_ESID_V instead of (1 << 27) in the code Reviewed-by: Andreas Färber Signed-off-by: Aneesh Kumar K.V Signed-off-by: Alexander Graf --- target-ppc/mmu_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From f1c2dc7c866a939c39c14729290a21309a1c8a38 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 12 Jul 2013 17:38:24 +1000 Subject: [PATCH 13/18] spapr-pci: rework MSI/MSIX On the sPAPR platform a guest allocates MSI/MSIX vectors via RTAS hypercalls which return global IRQ numbers to a guest so it only operates with those and never touches MSIMessage. Therefore MSIMessage handling is completely hidden in QEMU. Previously every sPAPR PCI host bridge implemented its own MSI window to catch msi_notify()/msix_notify() calls from QEMU devices (virtio-pci or vfio) and route them to the guest via qemu_pulse_irq(). MSIMessage used to be encoded as: .addr - address within the PHB MSI window; .data - the device index on PHB plus vector number. The MSI MR write function translated this MSIMessage to a global IRQ number and called qemu_pulse_irq(). However the total number of IRQs is not really big (at the moment it is 1024 IRQs starting from 4096) and even 16bit data field of MSIMessage seems to be enough to store an IRQ number there. This simplifies MSI handling in sPAPR PHB. Specifically, this does: 1. remove a MSI window from a PHB; 2. add a single memory region for all MSIs to sPAPREnvironment and spapr_pci_msi_init() to initialize it; 3. encode MSIMessage as: * .addr - a fixed address of SPAPR_PCI_MSI_WINDOW==0x40000000000ULL; * .data as an IRQ number. 4. change IRQ allocator to align first IRQ number in a block for MSI. MSI uses lower bits to specify the vector number so the first IRQ has to be aligned. MSIX does not need any special allocator though. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Anthony Liguori Acked-by: Michael S. Tsirkin Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 29 +++++++++++++++--- hw/ppc/spapr_pci.c | 61 ++++++++++++++++--------------------- include/hw/pci-host/spapr.h | 8 +++-- include/hw/ppc/spapr.h | 4 ++- 4 files changed, 60 insertions(+), 42 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 4b566aa410..1ce9b0b040 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 @@ -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_pci.c b/hw/ppc/spapr_pci.c index 65be265b74..9b6ee32acf 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -250,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); @@ -262,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); } @@ -343,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 */ @@ -355,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); @@ -442,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); @@ -459,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 */ @@ -484,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; @@ -498,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) { @@ -521,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; @@ -565,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 @@ -651,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(), }; @@ -693,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/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..41b046666f 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; @@ -303,7 +305,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) { From 33a0e5d8c555091eef6944595d8787cb9274e451 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 19 Aug 2013 15:55:21 +1000 Subject: [PATCH 14/18] xics: move registration of global state to realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Registration of global state belongs into realize so move it there. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/intc/xics.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) 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 = { From 42561bf2e464a2d682707af1640fc2db1e937c42 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 19 Aug 2013 21:04:20 +1000 Subject: [PATCH 15/18] pseries: Add H_SET_MODE hcall to change guest exception endianness H_SET_MODE is used for controlling various partition settings. One of these settings is the endianness a guest takes its exceptions in. Signed-off-by: Anton Blanchard [agraf: fix whitespace] Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 2 +- hw/ppc/spapr_hcall.c | 50 ++++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 17 +++++++++++++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1ce9b0b040..04f0ee3da1 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -282,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)}; 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/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 41b046666f..e37b41983c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -111,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 @@ -145,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 @@ -269,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. From 7bb438b6a102766ac58e1a2981f8749e4515aa01 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 29 Aug 2013 02:00:16 +0200 Subject: [PATCH 16/18] PPC: KVM: Compile fix for qemu_notify_event The function qemu_notify_event is defined by a header that we don't include in the PPC KVM code. Include it to get the code building again. target-ppc/kvm_ppc.c: In function 'kvmppc_timer_hack': target-ppc/kvm_ppc.c:26:5: error: implicit declaration of function 'qemu_notify_event' [-Werror=implicit-function-declaration] target-ppc/kvm_ppc.c:26:5: error: nested extern declaration of 'qemu_notify_event' [-Werror=nested-externs] Signed-off-by: Alexander Graf --- target-ppc/kvm_ppc.c | 1 + 1 file changed, 1 insertion(+) 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" From 59760f2dba6b5729bbbef113c0dc142bf9ec94d3 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 30 Aug 2013 16:11:56 +1000 Subject: [PATCH 17/18] spapr: add "stop-self" RTAS call required to support hot CPU unplug PAPR+ requires two RTAS calls to be supported by the hypervisor in order to allow hotplugging VCPUs from the guest. The "start-cpu" RTAS call was already there but "stop-self" was not. This adds the "stop-self" RTAS call. Signed-off-by: Alexey Kardashevskiy Signed-off-by: Alexander Graf --- hw/ppc/spapr_rtas.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) 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) From 7e472264e9e2727bc7d08fe6f012db76e1c1a193 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 29 Aug 2013 18:05:00 +1000 Subject: [PATCH 18/18] PPC: spapr: iommu: rework traces This converts old style fprintf to traces. Signed-off-by: Alexey Kardashevskiy [agraf: change patch subject] Signed-off-by: Alexander Graf --- hw/ppc/spapr_iommu.c | 71 +++++++++++++++----------------------------- trace-events | 5 ++++ 2 files changed, 29 insertions(+), 47 deletions(-) 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 -/* #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, - }; + 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); - /* 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 }; - } - - 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/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