diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-06-22 15:14:08 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-06-22 15:14:08 +0100 |
commit | c52e53f429aa562539f5da2e7c21c66c6f9a8a16 (patch) | |
tree | 796b50aff53f4895e1d83708756a97ff37e76e97 /target | |
parent | 45eb6fb6cea28cdc937764aac6585751047bb294 (diff) | |
parent | e5ca28ecab5c69b7578e22391a66c97c3979ffd8 (diff) |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.0-20180622' into staging
ppc patch queue 2018-06-22
Another assorted patch of patches for ppc and spapr.
* Rework of guest pagesize handling for ppc, which avoids guest
visibly different behaviour between accelerators
* A number of Pnv cleanups, working towards more complete POWER9
support
* Migration of VPA data, a significant bugfix
# gpg: Signature made Fri 22 Jun 2018 05:23:16 BST
# gpg: using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-3.0-20180622: (23 commits)
spapr: Don't rewrite mmu capabilities in KVM mode
spapr: Limit available pagesizes to provide a consistent guest environment
target/ppc: Add ppc_hash64_filter_pagesizes()
spapr: Use maximum page size capability to simplify memory backend checking
spapr: Maximum (HPT) pagesize property
pseries: Update SLOF firmware image to qemu-slof-20180621
target/ppc: Add missing opcode for icbt on PPC440
ppc4xx_i2c: Implement directcntl register
ppc4xx_i2c: Remove unimplemented sdata and intr registers
sm501: Fix hardware cursor color conversion
fpu_helper.c: fix helper_fpscr_clrbit() function
spapr: remove unused spapr_irq routines
spapr: split the IRQ allocation sequence
target/ppc: Add kvmppc_hpt_needs_host_contiguous_pages() helper
spapr: Add cpu_apply hook to capabilities
spapr: Compute effective capability values earlier
target/ppc: Allow cpu compatiblity checks based on type, not instance
ppc/pnv: consolidate the creation of the ISA bus device tree
ppc/pnv: introduce Pnv8Chip and Pnv9Chip models
spapr_cpu_core: migrate VPA related state
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/ppc/compat.c | 27 | ||||
-rw-r--r-- | target/ppc/cpu.h | 4 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 28 | ||||
-rw-r--r-- | target/ppc/kvm.c | 146 | ||||
-rw-r--r-- | target/ppc/kvm_ppc.h | 11 | ||||
-rw-r--r-- | target/ppc/mmu-hash64.c | 59 | ||||
-rw-r--r-- | target/ppc/mmu-hash64.h | 3 | ||||
-rw-r--r-- | target/ppc/translate.c | 2 |
8 files changed, 196 insertions, 84 deletions
diff --git a/target/ppc/compat.c b/target/ppc/compat.c index 807c906f68..7de4bf3122 100644 --- a/target/ppc/compat.c +++ b/target/ppc/compat.c @@ -105,17 +105,13 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr) return NULL; } -bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, - uint32_t min_compat_pvr, uint32_t max_compat_pvr) +static bool pcc_compat(PowerPCCPUClass *pcc, uint32_t compat_pvr, + uint32_t min_compat_pvr, uint32_t max_compat_pvr) { - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); const CompatInfo *compat = compat_by_pvr(compat_pvr); const CompatInfo *min = compat_by_pvr(min_compat_pvr); const CompatInfo *max = compat_by_pvr(max_compat_pvr); -#if !defined(CONFIG_USER_ONLY) - g_assert(cpu->vhyp); -#endif g_assert(!min_compat_pvr || min); g_assert(!max_compat_pvr || max); @@ -134,6 +130,25 @@ bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, return true; } +bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, + uint32_t min_compat_pvr, uint32_t max_compat_pvr) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + +#if !defined(CONFIG_USER_ONLY) + g_assert(cpu->vhyp); +#endif + + return pcc_compat(pcc, compat_pvr, min_compat_pvr, max_compat_pvr); +} + +bool ppc_type_check_compat(const char *cputype, uint32_t compat_pvr, + uint32_t min_compat_pvr, uint32_t max_compat_pvr) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(object_class_by_name(cputype)); + return pcc_compat(pcc, compat_pvr, min_compat_pvr, max_compat_pvr); +} + void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp) { const CompatInfo *compat = compat_by_pvr(compat_pvr); diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 874da6efbc..c7f3fb6b73 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1369,7 +1369,11 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch) #if defined(TARGET_PPC64) bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, uint32_t min_compat_pvr, uint32_t max_compat_pvr); +bool ppc_type_check_compat(const char *cputype, uint32_t compat_pvr, + uint32_t min_compat_pvr, uint32_t max_compat_pvr); + void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp); + #if !defined(CONFIG_USER_ONLY) void ppc_set_compat_all(uint32_t compat_pvr, Error **errp); #endif diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index d31a933cbb..7714bfe0f9 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -325,6 +325,34 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) case FPSCR_RN: fpscr_set_rounding_mode(env); break; + case FPSCR_VXSNAN: + case FPSCR_VXISI: + case FPSCR_VXIDI: + case FPSCR_VXZDZ: + case FPSCR_VXIMZ: + case FPSCR_VXVC: + case FPSCR_VXSOFT: + case FPSCR_VXSQRT: + case FPSCR_VXCVI: + if (!fpscr_ix) { + /* Set VX bit to zero */ + env->fpscr &= ~(1 << FPSCR_VX); + } + break; + case FPSCR_OX: + case FPSCR_UX: + case FPSCR_ZX: + case FPSCR_XX: + case FPSCR_VE: + case FPSCR_OE: + case FPSCR_UE: + case FPSCR_ZE: + case FPSCR_XE: + if (!fpscr_eex) { + /* Set the FEX bit */ + env->fpscr &= ~(1 << FPSCR_FEX); + } + break; default: break; } diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 5c0e313ca6..4df4ff6cbf 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -406,107 +406,106 @@ target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu, } } -static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift) +bool kvmppc_hpt_needs_host_contiguous_pages(void) { - if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) { - return true; + PowerPCCPU *cpu = POWERPC_CPU(first_cpu); + static struct kvm_ppc_smmu_info smmu_info; + + if (!kvm_enabled()) { + return false; } - return (1ul << shift) <= rampgsize; + kvm_get_smmu_info(cpu, &smmu_info); + return !!(smmu_info.flags & KVM_PPC_PAGE_SIZES_REAL); } -static long max_cpu_page_size; - -static void kvm_fixup_page_sizes(PowerPCCPU *cpu) +void kvm_check_mmu(PowerPCCPU *cpu, Error **errp) { - static struct kvm_ppc_smmu_info smmu_info; - static bool has_smmu_info; - CPUPPCState *env = &cpu->env; + struct kvm_ppc_smmu_info smmu_info; int iq, ik, jq, jk; - /* We only handle page sizes for 64-bit server guests for now */ - if (!(env->mmu_model & POWERPC_MMU_64)) { + /* For now, we only have anything to check on hash64 MMUs */ + if (!cpu->hash64_opts || !kvm_enabled()) { return; } - /* Collect MMU info from kernel if not already */ - if (!has_smmu_info) { - kvm_get_smmu_info(cpu, &smmu_info); - has_smmu_info = true; - } + kvm_get_smmu_info(cpu, &smmu_info); - if (!max_cpu_page_size) { - max_cpu_page_size = qemu_getrampagesize(); + if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG) + && !(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) { + error_setg(errp, + "KVM does not support 1TiB segments which guest expects"); + return; } - /* Convert to QEMU form */ - memset(cpu->hash64_opts->sps, 0, sizeof(*cpu->hash64_opts->sps)); - - /* If we have HV KVM, we need to forbid CI large pages if our - * host page size is smaller than 64K. - */ - if (smmu_info.flags & KVM_PPC_PAGE_SIZES_REAL) { - if (getpagesize() >= 0x10000) { - cpu->hash64_opts->flags |= PPC_HASH64_CI_LARGEPAGE; - } else { - cpu->hash64_opts->flags &= ~PPC_HASH64_CI_LARGEPAGE; - } + if (smmu_info.slb_size < cpu->hash64_opts->slb_size) { + error_setg(errp, "KVM only supports %u SLB entries, but guest needs %u", + smmu_info.slb_size, cpu->hash64_opts->slb_size); + return; } /* - * XXX This loop should be an entry wide AND of the capabilities that - * the selected CPU has with the capabilities that KVM supports. + * Verify that every pagesize supported by the cpu model is + * supported by KVM with the same encodings */ - for (ik = iq = 0; ik < KVM_PPC_PAGE_SIZES_MAX_SZ; ik++) { + for (iq = 0; iq < ARRAY_SIZE(cpu->hash64_opts->sps); iq++) { PPCHash64SegmentPageSizes *qsps = &cpu->hash64_opts->sps[iq]; - struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik]; + struct kvm_ppc_one_seg_page_size *ksps; - if (!kvm_valid_page_size(smmu_info.flags, max_cpu_page_size, - ksps->page_shift)) { - continue; - } - qsps->page_shift = ksps->page_shift; - qsps->slb_enc = ksps->slb_enc; - for (jk = jq = 0; jk < KVM_PPC_PAGE_SIZES_MAX_SZ; jk++) { - if (!kvm_valid_page_size(smmu_info.flags, max_cpu_page_size, - ksps->enc[jk].page_shift)) { - continue; - } - qsps->enc[jq].page_shift = ksps->enc[jk].page_shift; - qsps->enc[jq].pte_enc = ksps->enc[jk].pte_enc; - if (++jq >= PPC_PAGE_SIZES_MAX_SZ) { + for (ik = 0; ik < ARRAY_SIZE(smmu_info.sps); ik++) { + if (qsps->page_shift == smmu_info.sps[ik].page_shift) { break; } } - if (++iq >= PPC_PAGE_SIZES_MAX_SZ) { - break; + if (ik >= ARRAY_SIZE(smmu_info.sps)) { + error_setg(errp, "KVM doesn't support for base page shift %u", + qsps->page_shift); + return; } - } - cpu->hash64_opts->slb_size = smmu_info.slb_size; - if (!(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) { - cpu->hash64_opts->flags &= ~PPC_HASH64_1TSEG; - } -} - -bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path) -{ - Object *mem_obj = object_resolve_path(obj_path, NULL); - long pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(mem_obj)); - return pagesize >= max_cpu_page_size; -} + ksps = &smmu_info.sps[ik]; + if (ksps->slb_enc != qsps->slb_enc) { + error_setg(errp, +"KVM uses SLB encoding 0x%x for page shift %u, but guest expects 0x%x", + ksps->slb_enc, ksps->page_shift, qsps->slb_enc); + return; + } -#else /* defined (TARGET_PPC64) */ + for (jq = 0; jq < ARRAY_SIZE(qsps->enc); jq++) { + for (jk = 0; jk < ARRAY_SIZE(ksps->enc); jk++) { + if (qsps->enc[jq].page_shift == ksps->enc[jk].page_shift) { + break; + } + } -static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu) -{ -} + if (jk >= ARRAY_SIZE(ksps->enc)) { + error_setg(errp, "KVM doesn't support page shift %u/%u", + qsps->enc[jq].page_shift, qsps->page_shift); + return; + } + if (qsps->enc[jq].pte_enc != ksps->enc[jk].pte_enc) { + error_setg(errp, +"KVM uses PTE encoding 0x%x for page shift %u/%u, but guest expects 0x%x", + ksps->enc[jk].pte_enc, qsps->enc[jq].page_shift, + qsps->page_shift, qsps->enc[jq].pte_enc); + return; + } + } + } -bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path) -{ - return true; + if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) { + /* Mostly what guest pagesizes we can use are related to the + * host pages used to map guest RAM, which is handled in the + * platform code. Cache-Inhibited largepages (64k) however are + * used for I/O, so if they're mapped to the host at all it + * will be a normal mapping, not a special hugepage one used + * for RAM. */ + if (getpagesize() < 0x10000) { + error_setg(errp, + "KVM can't supply 64kiB CI pages, which guest expects"); + } + } } - #endif /* !defined (TARGET_PPC64) */ unsigned long kvm_arch_vcpu_id(CPUState *cpu) @@ -552,9 +551,6 @@ int kvm_arch_init_vcpu(CPUState *cs) CPUPPCState *cenv = &cpu->env; int ret; - /* Gather server mmu info from KVM and update the CPU state */ - kvm_fixup_page_sizes(cpu); - /* Synchronize sregs with kvm */ ret = kvm_arch_sync_sregs(cpu); if (ret) { diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index e2840e1d33..657582bb32 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -70,7 +70,8 @@ int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift); int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift); bool kvmppc_pvr_workaround_required(PowerPCCPU *cpu); -bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path); +bool kvmppc_hpt_needs_host_contiguous_pages(void); +void kvm_check_mmu(PowerPCCPU *cpu, Error **errp); #else @@ -222,9 +223,13 @@ static inline uint64_t kvmppc_rma_size(uint64_t current_size, return ram_size; } -static inline bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path) +static inline bool kvmppc_hpt_needs_host_contiguous_pages(void) +{ + return false; +} + +static inline void kvm_check_mmu(PowerPCCPU *cpu, Error **errp) { - return true; } static inline bool kvmppc_has_cap_spapr_vfio(void) diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index aa200cba4c..276d9015e7 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -1166,3 +1166,62 @@ const PPCHash64Options ppc_hash64_opts_POWER7 = { }, } }; + +void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu, + bool (*cb)(void *, uint32_t, uint32_t), + void *opaque) +{ + PPCHash64Options *opts = cpu->hash64_opts; + int i; + int n = 0; + bool ci_largepage = false; + + assert(opts); + + n = 0; + for (i = 0; i < ARRAY_SIZE(opts->sps); i++) { + PPCHash64SegmentPageSizes *sps = &opts->sps[i]; + int j; + int m = 0; + + assert(n <= i); + + if (!sps->page_shift) { + break; + } + + for (j = 0; j < ARRAY_SIZE(sps->enc); j++) { + PPCHash64PageSize *ps = &sps->enc[j]; + + assert(m <= j); + if (!ps->page_shift) { + break; + } + + if (cb(opaque, sps->page_shift, ps->page_shift)) { + if (ps->page_shift >= 16) { + ci_largepage = true; + } + sps->enc[m++] = *ps; + } + } + + /* Clear rest of the row */ + for (j = m; j < ARRAY_SIZE(sps->enc); j++) { + memset(&sps->enc[j], 0, sizeof(sps->enc[j])); + } + + if (m) { + n++; + } + } + + /* Clear the rest of the table */ + for (i = n; i < ARRAY_SIZE(opts->sps); i++) { + memset(&opts->sps[i], 0, sizeof(opts->sps[i])); + } + + if (!ci_largepage) { + opts->flags &= ~PPC_HASH64_CI_LARGEPAGE; + } +} diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index 53dcec5b93..f11efc9cbc 100644 --- a/target/ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h @@ -20,6 +20,9 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu, void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); void ppc_hash64_init(PowerPCCPU *cpu); void ppc_hash64_finalize(PowerPCCPU *cpu); +void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu, + bool (*cb)(void *, uint32_t, uint32_t), + void *opaque); #endif /* diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 5fe1ba6555..3a215a1dc6 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6707,6 +6707,8 @@ GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, GEN_HANDLER(msync_4xx, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE), GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE, PPC2_BOOKE206), +GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, + PPC_440_SPEC), GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC), |