From patchwork Thu Feb 2 05:13:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gibson X-Patchwork-Id: 722820 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3vDVd75fKDz9s7C for ; Thu, 2 Feb 2017 17:36:11 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.b="EPBA7IDI"; dkim-atps=neutral Received: from localhost ([::1]:54671 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cZB05-00032D-BJ for incoming@patchwork.ozlabs.org; Thu, 02 Feb 2017 01:36:09 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52003) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cZ9k1-0007d1-Az for qemu-devel@nongnu.org; Thu, 02 Feb 2017 00:15:34 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cZ9jv-0003zP-1O for qemu-devel@nongnu.org; Thu, 02 Feb 2017 00:15:29 -0500 Received: from ozlabs.org ([103.22.144.67]:36603) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cZ9ju-0003uv-8Y; Thu, 02 Feb 2017 00:15:22 -0500 Received: by ozlabs.org (Postfix, from userid 1007) id 3vDSqT3XSPz9s8W; Thu, 2 Feb 2017 16:14:59 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gibson.dropbear.id.au; s=201602; t=1486012501; bh=8c1XQvFZP8xGCM+kXh2uKy6sDynic6CH9ihysESksas=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EPBA7IDI06V6v3keLy/aPJKJtHAbECrQ2YsLQaBBC4l4IHYurzczoSsZfOvtjlNb2 UtIGj3rgGgZDbbHwjXUKFqng8xPHzSlR9DiydT5RsBL0qEIeE2uI4RHMAokFxtU3cs ZQBV/QbZ1P7U0TU3aJNM+7GDPaiZyaY7dGUdtAAM= From: David Gibson To: peter.maydell@linaro.org Date: Thu, 2 Feb 2017 16:13:59 +1100 Message-Id: <20170202051445.5735-62-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170202051445.5735-1-david@gibson.dropbear.id.au> References: <20170202051445.5735-1-david@gibson.dropbear.id.au> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 103.22.144.67 Subject: [Qemu-devel] [PULL 061/107] pseries: Rewrite CAS PVR compatibility logic X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: lvivier@redhat.com, thuth@redhat.com, qemu-devel@nongnu.org, mdroth@linux.vnet.ibm.com, agraf@suse.de, aik@ozlabs.ru, qemu-ppc@nongnu.org, David Gibson Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" During boot, PAPR guests negotiate CPU model support with the ibm,client-architecture-support mechanism. The logic to implement this in qemu is very convoluted. This cleans it up to be cleaner, using the new ppc_check_compat() call. The new logic for choosing a compatibility mode is: 1. Usually, use the most recent compatibility mode that is a) supported by the guest b) supported by the CPU and c) no later than the maximum allowed (if specified) 2. If no suitable compatibility mode was found, the guest *does* support this CPU explicitly, and no maximum compatibility mode is specified, then use "raw" mode for the current CPU 3. Otherwise, fail the boot. This differs from the results of the old code: the old code preferred using "raw" mode to a compatibility mode, whereas the new code prefers a compatibility mode if available. Using compatibility mode preferentially means that we're more likely to be able to migrate the guest to a similar but not identical host. Signed-off-by: David Gibson --- hw/ppc/spapr_hcall.c | 104 ++++++++++++++++----------------------------------- hw/ppc/trace-events | 2 +- 2 files changed, 34 insertions(+), 72 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 51681f3..f4531c5 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -935,98 +935,60 @@ static void do_set_compat(CPUState *cs, run_on_cpu_data arg) ppc_set_compat(cpu, s->compat_pvr, &s->err); } -#define get_compat_level(cpuver) ( \ - ((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \ - ((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \ - ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \ - ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0) - -static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr, - unsigned max_lvl, unsigned *compat_lvl, - unsigned *compat_pvr) -{ - unsigned lvl = get_compat_level(pvr); - bool is205, is206, is207; - - if (!lvl) { - return; - } - - /* If it is a logical PVR, try to determine the highest level */ - is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) && - (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05)); - is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) && - ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) || - (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS))); - is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) && - (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07)); - - if (is205 || is206 || is207) { - if (!max_lvl) { - /* User did not set the level, choose the highest */ - if (*compat_lvl <= lvl) { - *compat_lvl = lvl; - *compat_pvr = pvr; - } - } else if (max_lvl >= lvl) { - /* User chose the level, don't set higher than this */ - *compat_lvl = lvl; - *compat_pvr = pvr; - } - } -} - -static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, +static target_ulong h_client_architecture_support(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { target_ulong list = ppc64_phys_to_real(args[0]); target_ulong ov_table; - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_); CPUState *cs; - bool cpu_match = false; - unsigned old_compat_pvr = cpu_->compat_pvr; - unsigned compat_lvl = 0, compat_pvr = 0; - unsigned max_lvl = get_compat_level(cpu_->max_compat); - int counter; + bool explicit_match = false; /* Matched the CPU's real PVR */ + uint32_t max_compat = cpu->max_compat; + uint32_t best_compat = 0; + int i; sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates; - /* Parse PVR list */ - for (counter = 0; counter < 512; ++counter) { + /* + * We scan the supplied table of PVRs looking for two things + * 1. Is our real CPU PVR in the list? + * 2. What's the "best" listed logical PVR + */ + for (i = 0; i < 512; ++i) { uint32_t pvr, pvr_mask; pvr_mask = ldl_be_phys(&address_space_memory, list); - list += 4; - pvr = ldl_be_phys(&address_space_memory, list); - list += 4; - - trace_spapr_cas_pvr_try(pvr); - if (!max_lvl && - ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) { - cpu_match = true; - compat_pvr = 0; - } else if (pvr == cpu_->compat_pvr) { - cpu_match = true; - compat_pvr = cpu_->compat_pvr; - } else if (!cpu_match) { - cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &compat_pvr); - } - /* Terminator record */ + pvr = ldl_be_phys(&address_space_memory, list + 4); + list += 8; + if (~pvr_mask & pvr) { - break; + break; /* Terminator record */ } + + if ((cpu->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask)) { + explicit_match = true; + } else { + if (ppc_check_compat(cpu, pvr, best_compat, max_compat)) { + best_compat = pvr; + } + } + } + + if ((best_compat == 0) && (!explicit_match || max_compat)) { + /* We couldn't find a suitable compatibility mode, and either + * the guest doesn't support "raw" mode for this CPU, or raw + * mode is disabled because a maximum compat mode is set */ + return H_HARDWARE; } /* Parsing finished */ - trace_spapr_cas_pvr(cpu_->compat_pvr, cpu_match, - compat_pvr, pcc->pcr_mask); + trace_spapr_cas_pvr(cpu->compat_pvr, explicit_match, best_compat); /* Update CPUs */ - if (old_compat_pvr != compat_pvr) { + if (cpu->compat_pvr != best_compat) { CPU_FOREACH(cs) { SetCompatState s = { - .compat_pvr = compat_pvr, + .compat_pvr = best_compat, .err = NULL, }; diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 42b8ec0..f46995c 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -15,7 +15,7 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes" # hw/ppc/spapr_hcall.c spapr_cas_pvr_try(uint32_t pvr) "%x" -spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64 +spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=%x, explicit_match=%u, new=%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