From 7f11573b9fe6c03a9ad4cd1bbaa761e564d44fce Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 7 Jan 2013 20:13:52 +0100 Subject: openpic: move gcr write into a function The GCR register contains too much functionality to be covered inside of the register switch statement. Move it out into a separate function. Signed-off-by: Alexander Graf --- hw/openpic.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index f6cc07bd6e..085c9549d1 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -644,6 +644,27 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) opp->src[n_IRQ].ivpr); } +static void openpic_gcr_write(OpenPICState *opp, uint64_t val) +{ + if (val & GCR_RESET) { + openpic_reset(&opp->busdev.qdev); + } else if (opp->mpic_mode_mask) { + CPUArchState *env; + int mpic_proxy = 0; + + opp->gcr &= ~opp->mpic_mode_mask; + opp->gcr |= val & opp->mpic_mode_mask; + + /* Set external proxy mode */ + if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { + mpic_proxy = 1; + } + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = mpic_proxy; + } + } +} + static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { @@ -672,23 +693,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0x1000: /* FRR */ break; case 0x1020: /* GCR */ - if (val & GCR_RESET) { - openpic_reset(&opp->busdev.qdev); - } else if (opp->mpic_mode_mask) { - CPUArchState *env; - int mpic_proxy = 0; - - opp->gcr &= ~opp->mpic_mode_mask; - opp->gcr |= val & opp->mpic_mode_mask; - - /* Set external proxy mode */ - if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { - mpic_proxy = 1; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->mpic_proxy = mpic_proxy; - } - } + openpic_gcr_write(opp, val); break; case 0x1080: /* VIR */ break; -- cgit v1.2.3 From 1ac3d71302d9d49427dd068af7eccdd4de128522 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 7 Jan 2013 20:15:28 +0100 Subject: openpic: unify gcr mode mask updates The mode mask already masks out bits we don't care about, so the actual handling code can stay intact regardless. Signed-off-by: Alexander Graf --- hw/openpic.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 085c9549d1..c986b5ddcb 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -646,22 +646,23 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) static void openpic_gcr_write(OpenPICState *opp, uint64_t val) { + CPUArchState *env; + int mpic_proxy = 0; + if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); - } else if (opp->mpic_mode_mask) { - CPUArchState *env; - int mpic_proxy = 0; + return; + } - opp->gcr &= ~opp->mpic_mode_mask; - opp->gcr |= val & opp->mpic_mode_mask; + opp->gcr &= ~opp->mpic_mode_mask; + opp->gcr |= val & opp->mpic_mode_mask; - /* Set external proxy mode */ - if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { - mpic_proxy = 1; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->mpic_proxy = mpic_proxy; - } + /* Set external proxy mode */ + if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { + mpic_proxy = 1; + } + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = mpic_proxy; } } -- cgit v1.2.3 From 86e56a885aa5051c87906dfcd060c59f0af22309 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 7 Jan 2013 20:17:24 +0100 Subject: openpic: set mixed mode as supported The Raven MPIC implementation supports the "Mixed" mode to work with an i8259. While we don't implement mixed mode, we should mark it as a supported mode in the mode bitmap. Signed-off-by: Alexander Graf --- hw/openpic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/openpic.c b/hw/openpic.c index c986b5ddcb..bcafe0a12c 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -1470,6 +1470,7 @@ static int openpic_init(SysBusDevice *dev) opp->irq_ipi0 = RAVEN_IPI_IRQ; opp->irq_tim0 = RAVEN_TMR_IRQ; opp->brr1 = -1; + opp->mpic_mode_mask = GCR_MODE_MIXED; list = list_le; /* Don't map MSI region */ list[2].map = false; -- cgit v1.2.3 From 528e536ea2fd3bfe8412e39a5623e80b254f3ae0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 14 Jan 2013 20:24:16 +0100 Subject: PPC: E500: Calculate loading blob offsets properly We have 3 blobs we need to load when booting the system: - kernel - initrd - dtb We place them in physical memory in that order. At least we should. This patch fixes the location calculation up to take any module into account, fixing the dtb offset along the way. Reported-by: Stuart Yoder Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 7b3e2e6723..e5564ce03f 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -463,7 +463,8 @@ void ppce500_init(PPCE500Params *params) target_long kernel_size=0; target_ulong dt_base = 0; target_ulong initrd_base = 0; - target_long initrd_size=0; + target_long initrd_size = 0; + target_ulong cur_base = 0; int i = 0, j, k; unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; qemu_irq **irqs, *mpic; @@ -626,12 +627,13 @@ void ppce500_init(PPCE500Params *params) params->kernel_filename); exit(1); } + + cur_base = loadaddr + kernel_size; } /* Load initrd. */ if (params->initrd_filename) { - initrd_base = (loadaddr + kernel_size + INITRD_LOAD_PAD) & - ~INITRD_PAD_MASK; + initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; initrd_size = load_image_targphys(params->initrd_filename, initrd_base, ram_size - initrd_base); @@ -640,6 +642,8 @@ void ppce500_init(PPCE500Params *params) params->initrd_filename); exit(1); } + + cur_base = initrd_base + initrd_size; } /* If we're loading a kernel directly, we must load the device tree too. */ @@ -647,7 +651,7 @@ void ppce500_init(PPCE500Params *params) struct boot_info *boot_info; int dt_size; - dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; + dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK; dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base, initrd_size); if (dt_size < 0) { -- cgit v1.2.3 From 746a870b3c44a6c5734691fec013c78520d55f15 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 16 Jan 2013 01:43:43 +0100 Subject: PPC: Provide zero SVR for -cpu e500mc and e5500 Even though our -cpu types for e500mc and e5500 are no real CPUs that actually have version registers, a guest might still want to access said version register and that has to succeed for a guest to be happy. So let's expose a zero SVR value on E500_SVR SPR reads. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3f199c4bb9..2d78529273 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8633,9 +8633,9 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2), /* PowerPC e500v2 v3.0 core */ POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2), - POWERPC_DEF("e500mc", CPU_POWERPC_e500mc, e500mc), + POWERPC_DEF_SVR("e500mc", CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc), #ifdef TARGET_PPC64 - POWERPC_DEF("e5500", CPU_POWERPC_e5500, e5500), + POWERPC_DEF_SVR("e5500", CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500), #endif /* PowerPC e500 microcontrollers */ /* MPC8533 */ -- cgit v1.2.3 From b8dec1443ef6c52e72594c5a861a5d2fd7f05d80 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 Jan 2013 11:19:28 +0100 Subject: PPC: e500: Change in-memory order of load blobs Today, we load into memory in that order. However, Linux has a bug where it can only handle the dtb if it's within the first 64MB of where starts. So instead, let's change the order to making Linux happy. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index e5564ce03f..c36821a99f 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -41,6 +41,7 @@ #define UIMAGE_LOAD_BASE 0 #define DTC_LOAD_PAD 0x1800000 #define DTC_PAD_MASK 0xFFFFF +#define DTB_MAX_SIZE (8 * 1024 * 1024) #define INITRD_LOAD_PAD 0x2000000 #define INITRD_PAD_MASK 0xFFFFFF @@ -629,6 +630,10 @@ void ppce500_init(PPCE500Params *params) } cur_base = loadaddr + kernel_size; + + /* Reserve space for dtb */ + dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK; + cur_base += DTB_MAX_SIZE; } /* Load initrd. */ @@ -651,13 +656,13 @@ void ppce500_init(PPCE500Params *params) struct boot_info *boot_info; int dt_size; - dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK; dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base, initrd_size); if (dt_size < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); } + assert(dt_size < DTB_MAX_SIZE); boot_info = env->load_info; boot_info->entry = entry; -- cgit v1.2.3 From d3dccee187ffeacec1a38ed288c112ffa0e3b513 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Jan 2013 00:06:26 +0100 Subject: Update Linux kernel headers Based on kvm.git a843fac (next) plus dfdebc24 (master). Signed-off-by: Alexander Graf --- linux-headers/asm-powerpc/kvm.h | 6 +++++- linux-headers/linux/kvm.h | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 2fba8a66fb..16064d00ad 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -114,7 +114,10 @@ struct kvm_regs { /* Embedded Floating Point (SPE) -- IVOR32-34 if KVM_SREGS_E_IVOR */ #define KVM_SREGS_E_SPE (1 << 9) -/* External Proxy (EXP) -- EPR */ +/* + * DEPRECATED! USE ONE_REG FOR THIS ONE! + * External Proxy (EXP) -- EPR + */ #define KVM_SREGS_EXP (1 << 10) /* External PID (E.PD) -- EPSC/EPLC */ @@ -412,5 +415,6 @@ struct kvm_get_htab_header { #define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84) #define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85) +#define KVM_REG_PPC_EPR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x86) #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index bfdbf4d1ad..5af935761c 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -168,6 +168,8 @@ struct kvm_pit_config { #define KVM_EXIT_PAPR_HCALL 19 #define KVM_EXIT_S390_UCONTROL 20 #define KVM_EXIT_WATCHDOG 21 +#define KVM_EXIT_S390_TSCH 22 +#define KVM_EXIT_EPR 23 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -285,6 +287,19 @@ struct kvm_run { __u64 ret; __u64 args[9]; } papr_hcall; + /* KVM_EXIT_S390_TSCH */ + struct { + __u16 subchannel_id; + __u16 subchannel_nr; + __u32 io_int_parm; + __u32 io_int_word; + __u32 ipb; + __u8 dequeued; + } s390_tsch; + /* KVM_EXIT_EPR */ + struct { + __u32 epr; + } epr; /* Fix the size of the union. */ char padding[256]; }; @@ -397,10 +412,20 @@ struct kvm_s390_psw { #define KVM_S390_PROGRAM_INT 0xfffe0001u #define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u #define KVM_S390_RESTART 0xfffe0003u +#define KVM_S390_MCHK 0xfffe1000u #define KVM_S390_INT_VIRTIO 0xffff2603u #define KVM_S390_INT_SERVICE 0xffff2401u #define KVM_S390_INT_EMERGENCY 0xffff1201u #define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u +/* Anything below 0xfffe0000u is taken by INT_IO */ +#define KVM_S390_INT_IO(ai,cssid,ssid,schid) \ + (((schid)) | \ + ((ssid) << 16) | \ + ((cssid) << 18) | \ + ((ai) << 26)) +#define KVM_S390_INT_IO_MIN 0x00000000u +#define KVM_S390_INT_IO_MAX 0xfffdffffu + struct kvm_s390_interrupt { __u32 type; @@ -635,6 +660,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_IRQFD_RESAMPLE 82 #define KVM_CAP_PPC_BOOKE_WATCHDOG 83 #define KVM_CAP_PPC_HTAB_FD 84 +#define KVM_CAP_S390_CSS_SUPPORT 85 +#define KVM_CAP_PPC_EPR 86 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.2.3 From e49798b1bd7657722080126bfd5e787efdb3bc23 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 Jan 2013 11:32:21 +0100 Subject: openpic: export e500 epr enable into a ppc.c function Enabling and disabling the EPR capability (mpic_proxy) is a system wide operation. As such, it belongs into the ppc.c file, since that's where PPC specific machine wide logic happens. Signed-off-by: Alexander Graf --- hw/openpic.c | 11 +++++------ hw/ppc.c | 11 +++++++++++ hw/ppc.h | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index bcafe0a12c..cc8ec35b5d 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -40,6 +40,7 @@ #include "sysbus.h" #include "pci/msi.h" #include "qemu/bitops.h" +#include "ppc.h" //#define DEBUG_OPENPIC @@ -646,8 +647,7 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) static void openpic_gcr_write(OpenPICState *opp, uint64_t val) { - CPUArchState *env; - int mpic_proxy = 0; + bool mpic_proxy = false; if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); @@ -659,11 +659,10 @@ static void openpic_gcr_write(OpenPICState *opp, uint64_t val) /* Set external proxy mode */ if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { - mpic_proxy = 1; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->mpic_proxy = mpic_proxy; + mpic_proxy = true; } + + ppce500_set_mpic_proxy(mpic_proxy); } static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, diff --git a/hw/ppc.c b/hw/ppc.c index e473f9e962..1fce604c73 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -428,6 +428,17 @@ void ppce500_irq_init(CPUPPCState *env) env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, cpu, PPCE500_INPUT_NB); } + +/* Enable or Disable the E500 EPR capability */ +void ppce500_set_mpic_proxy(bool enabled) +{ + CPUPPCState *env; + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = enabled; + } +} + /*****************************************************************************/ /* PowerPC time base and decrementer emulation */ diff --git a/hw/ppc.h b/hw/ppc.h index e73ae83b52..ee0cd16ee5 100644 --- a/hw/ppc.h +++ b/hw/ppc.h @@ -73,6 +73,8 @@ void ppc6xx_irq_init (CPUPPCState *env); void ppc970_irq_init (CPUPPCState *env); void ppcPOWER7_irq_init (CPUPPCState *env); +void ppce500_set_mpic_proxy(bool enabled); + /* PPC machines for OpenBIOS */ enum { ARCH_PREP = 0, -- cgit v1.2.3 From 5b95b8b9c1b0cd30a31dbeffdaec35134248b6e9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 Jan 2013 11:54:38 +0100 Subject: PPC: KVM: Add support for EPR with KVM This patch links KVM EPR support to the existing TCG support we have now. Signed-off-by: Alexander Graf --- hw/ppc.c | 6 ++++++ target-ppc/kvm.c | 21 +++++++++++++++++++++ target-ppc/kvm_ppc.h | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/hw/ppc.c b/hw/ppc.c index 1fce604c73..c52e22f708 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -435,7 +435,13 @@ void ppce500_set_mpic_proxy(bool enabled) CPUPPCState *env; for (env = first_cpu; env != NULL; env = env->next_cpu) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs = CPU(cpu); + env->mpic_proxy = enabled; + if (kvm_enabled()) { + kvmppc_set_mpic_proxy(POWERPC_CPU(cs), enabled); + } } } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 19e9f25b19..2f4f06818a 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -846,6 +846,11 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ret = 0; break; #endif + case KVM_EXIT_EPR: + dprintf("handle epr\n"); + run->epr.epr = ldl_phys(env->mpic_iack); + ret = 0; + break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1; @@ -1057,6 +1062,22 @@ void kvmppc_set_papr(PowerPCCPU *cpu) } } +void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) +{ + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); + struct kvm_enable_cap cap = {}; + int ret; + + cap.cap = KVM_CAP_PPC_EPR; + cap.args[0] = mpic_proxy; + ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap); + + if (ret && mpic_proxy) { + cpu_abort(env, "This KVM version does not support EPR\n"); + } +} + int kvmppc_smt_threads(void) { return cap_ppc_smt ? cap_ppc_smt : 1; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 3db21fc889..c30b006674 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -25,6 +25,7 @@ int kvmppc_get_hasidle(CPUPPCState *env); int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); void kvmppc_set_papr(PowerPCCPU *cpu); +void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); int kvmppc_smt_threads(void); #ifndef CONFIG_USER_ONLY off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); @@ -81,6 +82,10 @@ static inline void kvmppc_set_papr(PowerPCCPU *cpu) { } +static inline void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) +{ +} + static inline int kvmppc_smt_threads(void) { return 1; -- cgit v1.2.3