From nobody Sat Oct 25 13:20:50 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1521233399265144.62986954143423; Fri, 16 Mar 2018 13:49:59 -0700 (PDT) Received: from localhost ([::1]:59551 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ewwIY-0003rr-F4 for importer@patchew.org; Fri, 16 Mar 2018 16:49:58 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44793) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eww1r-0006Gb-CR for qemu-devel@nongnu.org; Fri, 16 Mar 2018 16:32:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eww1p-0003sC-Dk for qemu-devel@nongnu.org; Fri, 16 Mar 2018 16:32:43 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:56880) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eww1i-0003ip-Vl; Fri, 16 Mar 2018 16:32:35 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id D064F60F6E; Fri, 16 Mar 2018 20:32:23 +0000 (UTC) Received: from mossypile.qualcomm.com (global_nat1_iad_fw.qualcomm.com [129.46.232.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: alindsay@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 1BBE960FAA; Fri, 16 Mar 2018 20:32:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1521232354; bh=bDOC/lX/98tdhEA9hw6VJ3HJJAPQSysJ6XMIwyMzcho=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L7W9+iEGiLXeZupZLyTiWyjiQ94mQdTLkGBj9A6ghpa3HmONzwswC6KiG8CnsLVeI BrrwyCCp7oEuGpfjCvsdu/5u3mAy8aYy4/SjKkPus2qFQcT8C9D/Sfs6YnQmtM1sUP w9GTs7ocG6UQEH1pq+hi6Yn72xN98Fyjf18yWKaU= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1521232342; bh=bDOC/lX/98tdhEA9hw6VJ3HJJAPQSysJ6XMIwyMzcho=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RFtqw9F76pedz7J2PivrVNuJ7M+qswcZBgGbc7j5GZX+WMOgAaX8frqZ8TgE0mVW6 HwtLybUaCkU9Xw7Cn62YaW6KnEnjZl3FS5UbXPrLjfhRveoDfyI3S2J/XmMsr+Bi/T sVxKva2vQqI5zEg4nv751DlakKec3mWzG1ha1jdw= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 1BBE960FAA Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=alindsay@codeaurora.org From: Aaron Lindsay To: qemu-arm@nongnu.org, Peter Maydell , Alistair Francis , Wei Huang , Peter Crosthwaite Date: Fri, 16 Mar 2018 16:31:17 -0400 Message-Id: <1521232280-13089-20-git-send-email-alindsay@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1521232280-13089-1-git-send-email-alindsay@codeaurora.org> References: <1521232280-13089-1-git-send-email-alindsay@codeaurora.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 198.145.29.96 Subject: [Qemu-devel] [PATCH v3 19/22] target/arm: Finish implementation of PM[X]EVCNTR and PM[X]EVTYPER 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: Michael Spradling , qemu-devel@nongnu.org, Digant Desai Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add arrays to hold the registers, the definitions themselves, access functions, and add logic to reset counters when PMCR.P is set. Signed-off-by: Aaron Lindsay --- target/arm/cpu.h | 7 +- target/arm/helper.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++= ---- 2 files changed, 207 insertions(+), 19 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 19f005d..7a74966 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -454,8 +454,9 @@ typedef struct CPUARMState { uint64_t oslsr_el1; /* OS Lock Status */ uint64_t mdcr_el2; uint64_t mdcr_el3; - /* If the counter is enabled, this stores the last time the counter - * was reset. Otherwise it stores the counter value + /* If the pmccntr and pmevcntr counters are enabled, they store the + * offset the last time the counter was reset. Otherwise they stor= e the + * counter value. */ uint64_t c15_ccnt; /* ccnt_cached_cycles is used to hold the last cycle count when @@ -463,6 +464,8 @@ typedef struct CPUARMState { * PMU operations which require this. */ uint64_t ccnt_cached_cycles; + uint64_t c14_pmevcntr[31]; + uint64_t c14_pmevtyper[31]; uint64_t pmccfiltr_el0; /* Performance Monitor Filter Register */ uint64_t vpidr_el2; /* Virtualization Processor ID Register */ uint64_t vmpidr_el2; /* Virtualization Multiprocessor ID Register = */ diff --git a/target/arm/helper.c b/target/arm/helper.c index 6a4f900..2fa8308 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -906,6 +906,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] =3D { #define PMCRN_SHIFT 11 #define PMCRD 0x8 #define PMCRC 0x4 +#define PMCRP 0x2 #define PMCRE 0x1 =20 #define PMXEVTYPER_P 0x80000000 @@ -931,7 +932,7 @@ typedef struct pm_event { bool (*supported)(CPUARMState *); /* Retrieve the current count of the underlying event. The programmed * counters hold a difference from the return value from this function= */ - uint64_t (*get_count)(CPUARMState *); + uint64_t (*get_count)(CPUARMState *, uint64_t cycles); } pm_event; =20 #define SUPPORTED_EVENT_SENTINEL UINT16_MAX @@ -1054,6 +1055,21 @@ static inline bool pmu_counter_enabled(CPUARMState *= env, uint8_t counter) return false; } =20 + if (counter !=3D 31) { + /* If not checking PMCCNTR, ensure the counter is setup to an even= t we + * support */ + uint16_t event =3D env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_E= VTCOUNT; + if (event > 0x3f) { + return false; /* We only support common architectural and + microarchitectural events */ + } + + uint16_t event_idx =3D supported_event_map[event]; + if (event_idx =3D=3D SUPPORTED_EVENT_SENTINEL) { + return false; + } + } + return true; } =20 @@ -1149,14 +1165,37 @@ void pmccntr_op_finish(CPUARMState *env, uint64_t p= rev_cycles) } } =20 +static void pmu_sync_counter(CPUARMState *env, uint8_t counter, uint64_t c= ycles) +{ + if (pmu_counter_enabled(env, counter) && + !pmu_counter_filtered(env, env->cp15.c14_pmevtyper[counter])) { + + uint16_t event =3D env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_E= VTCOUNT; + uint16_t event_idx =3D supported_event_map[event]; + + uint64_t count =3D pm_events[event_idx].get_count(env, cycles); + env->cp15.c14_pmevcntr[counter] =3D + count - env->cp15.c14_pmevcntr[counter]; + } +} + uint64_t pmu_op_start(CPUARMState *env) { - return pmccntr_op_start(env); + uint64_t saved_cycles =3D pmccntr_op_start(env); + unsigned int i; + for (i =3D 0; i < PMU_NUM_COUNTERS(env); i++) { + pmu_sync_counter(env, i, saved_cycles); + } + return saved_cycles; } =20 void pmu_op_finish(CPUARMState *env, uint64_t prev_cycles) { pmccntr_op_finish(env, prev_cycles); + unsigned int i; + for (i =3D 0; i < PMU_NUM_COUNTERS(env); i++) { + pmu_sync_counter(env, i, prev_cycles); + } } =20 void pmu_pre_el_change(ARMCPU *cpu, void *ignored) @@ -1179,6 +1218,13 @@ static void pmcr_write(CPUARMState *env, const ARMCP= RegInfo *ri, env->cp15.c15_ccnt =3D 0; } =20 + if (value & PMCRP) { + unsigned int i; + for (i =3D 0; i < PMU_NUM_COUNTERS(env); i++) { + env->cp15.c14_pmevcntr[i] =3D 0; + } + } + /* only the DP, X, D and E bits are writable */ env->cp15.c9_pmcr &=3D ~0x39; env->cp15.c9_pmcr |=3D (value & 0x39); @@ -1294,30 +1340,127 @@ static void pmovsset_write(CPUARMState *env, const= ARMCPRegInfo *ri, env->cp15.c9_pmovsr |=3D value; } =20 -static void pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) +static void pmevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value, const uint8_t counter) { + if (counter =3D=3D 0x1f) { + pmccfiltr_write(env, ri, value); + } else if (counter < PMU_NUM_COUNTERS(env)) { + uint64_t cycles =3D 0; +#ifndef CONFIG_USER_ONLY + cycles =3D muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + ARM_CPU_FREQ, NANOSECONDS_PER_SECOND); +#endif + pmu_sync_counter(env, counter, cycles); + env->cp15.c14_pmevtyper[counter] =3D value & 0xfe0003ff; + pmu_sync_counter(env, counter, cycles); + } /* Attempts to access PMXEVTYPER are CONSTRAINED UNPREDICTABLE when * PMSELR value is equal to or greater than the number of implemented * counters, but not equal to 0x1f. We opt to behave as a RAZ/WI. */ - if (env->cp15.c9_pmselr =3D=3D 0x1f) { - pmccfiltr_write(env, ri, value); +} + +static uint64_t pmevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri, + const uint8_t counter) +{ + if (counter =3D=3D 0x1f) { + return env->cp15.pmccfiltr_el0; + } else if (counter < PMU_NUM_COUNTERS(env)) { + return env->cp15.c14_pmevtyper[counter]; + } else { + /* We opt to behave as a RAZ/WI when attempts to access PMXEVTYPER + * are CONSTRAINED UNPREDICTABLE. See comments in pmevtyper_write(). + */ + return 0; } } =20 +static void pmevtyper_writefn(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + pmevtyper_write(env, ri, value, counter); +} + +static uint64_t pmevtyper_readfn(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + return pmevtyper_read(env, ri, counter); +} + +static void pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmevtyper_write(env, ri, value, env->cp15.c9_pmselr & 31); +} + static uint64_t pmxevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri) { - /* We opt to behave as a RAZ/WI when attempts to access PMXEVTYPER - * are CONSTRAINED UNPREDICTABLE. See comments in pmxevtyper_write(). - */ - if (env->cp15.c9_pmselr =3D=3D 0x1f) { - return env->cp15.pmccfiltr_el0; + return pmevtyper_read(env, ri, env->cp15.c9_pmselr & 31); +} + +static void pmevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value, uint8_t counter) +{ + if (counter < PMU_NUM_COUNTERS(env)) { + uint64_t cycles =3D 0; +#ifndef CONFIG_USER_ONLY + cycles =3D muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + ARM_CPU_FREQ, NANOSECONDS_PER_SECOND); +#endif + env->cp15.c14_pmevcntr[counter] =3D value; + pmu_sync_counter(env, counter, cycles); + } + /* We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR + * are CONSTRAINED UNPREDICTABLE. */ +} + +static uint64_t pmevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint8_t counter) +{ + if (counter < PMU_NUM_COUNTERS(env)) { + uint64_t ret; + uint64_t cycles =3D 0; +#ifndef CONFIG_USER_ONLY + cycles =3D muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + ARM_CPU_FREQ, NANOSECONDS_PER_SECOND); +#endif + pmu_sync_counter(env, counter, cycles); + ret =3D env->cp15.c14_pmevcntr[counter]; + pmu_sync_counter(env, counter, cycles); + return ret; } else { + /* We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR + * are CONSTRAINED UNPREDICTABLE. */ return 0; } } =20 +static void pmevcntr_writefn(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + pmevcntr_write(env, ri, value, counter); +} + +static uint64_t pmevcntr_readfn(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + return pmevcntr_read(env, ri, counter); +} + +static void pmxevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmevcntr_write(env, ri, value, env->cp15.c9_pmselr & 31); +} + +static uint64_t pmxevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return pmevcntr_read(env, ri, env->cp15.c9_pmselr & 31); +} + static void pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { @@ -1504,16 +1647,23 @@ static const ARMCPRegInfo v7_cp_reginfo[] =3D { .fieldoffset =3D offsetof(CPUARMState, cp15.pmccfiltr_el0), .resetvalue =3D 0, }, { .name =3D "PMXEVTYPER", .cp =3D 15, .crn =3D 9, .crm =3D 13, .opc1 = =3D 0, .opc2 =3D 1, - .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW, .accessfn =3D pmreg_acc= ess, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .accessfn =3D pmreg_access, .writefn =3D pmxevtyper_write, .readfn =3D pmxevtyper_read }, { .name =3D "PMXEVTYPER_EL0", .state =3D ARM_CP_STATE_AA64, .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 13, .opc2 =3D 1, - .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW, .accessfn =3D pmreg_acc= ess, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .accessfn =3D pmreg_access, .writefn =3D pmxevtyper_write, .readfn =3D pmxevtyper_read }, - /* Unimplemented, RAZ/WI. */ { .name =3D "PMXEVCNTR", .cp =3D 15, .crn =3D 9, .crm =3D 13, .opc1 = =3D 0, .opc2 =3D 2, - .access =3D PL0_RW, .type =3D ARM_CP_CONST, .resetvalue =3D 0, - .accessfn =3D pmreg_access_xevcntr }, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .accessfn =3D pmreg_access_xevcntr, + .writefn =3D pmxevcntr_write, .readfn =3D pmxevcntr_read }, + { .name =3D "PMXEVCNTR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 13, .opc2 =3D 2, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .accessfn =3D pmreg_access_xevcntr, + .writefn =3D pmxevcntr_write, .readfn =3D pmxevcntr_read }, { .name =3D "PMUSERENR", .cp =3D 15, .crn =3D 9, .crm =3D 14, .opc1 = =3D 0, .opc2 =3D 0, .access =3D PL0_R | PL1_RW, .accessfn =3D access_tpm, .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmuserenr), @@ -4204,7 +4354,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] =3D { #endif /* The only field of MDCR_EL2 that has a defined architectural reset v= alue * is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N; but= we - * don't impelment any PMU event counters, so using zero as a reset + * don't implement any PMU event counters, so using zero as a reset * value for MDCR_EL2 is okay */ { .name =3D "MDCR_EL2", .state =3D ARM_CP_STATE_BOTH, @@ -5016,6 +5166,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, v7ve_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_V7)) { + unsigned int i; /* v7 performance monitor control register: same implementor * field as main ID register, and we implement only the cycle * count register. @@ -5040,6 +5191,40 @@ void register_cp_regs_for_features(ARMCPU *cpu) }; define_one_arm_cp_reg(cpu, &pmcr); define_one_arm_cp_reg(cpu, &pmcr64); + for (i =3D 0; i < 31; i++) { + char *pmevcntr_name =3D g_strdup_printf("PMEVCNTR%d", i); + char *pmevcntr_el0_name =3D g_strdup_printf("PMEVCNTR%d_EL0", = i); + char *pmevtyper_name =3D g_strdup_printf("PMEVTYPER%d", i); + char *pmevtyper_el0_name =3D g_strdup_printf("PMEVTYPER%d_EL0"= , i); + ARMCPRegInfo pmev_regs[] =3D { + { .name =3D pmevcntr_name, .cp =3D 15, .crn =3D 15, + .crm =3D 8 | (3 & (i >> 3)), .opc1 =3D 0, .opc2 =3D i & = 7, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .readfn =3D pmevcntr_readfn, .writefn =3D pmevcntr_write= fn, + .accessfn =3D pmreg_access }, + { .name =3D pmevcntr_el0_name, .state =3D ARM_CP_STATE_AA6= 4, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 15, .crm =3D 8 | (3 &= (i >> 3)), + .opc2 =3D i & 7, .access =3D PL0_RW, .accessfn =3D pmreg= _access, + .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .readfn =3D pmevcntr_readfn, .writefn =3D pmevcntr_write= fn }, + { .name =3D pmevtyper_name, .cp =3D 15, .crn =3D 15, + .crm =3D 12 | (3 & (i >> 3)), .opc1 =3D 0, .opc2 =3D i &= 7, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .readfn =3D pmevtyper_readfn, .writefn =3D pmevtyper_wri= tefn, + .accessfn =3D pmreg_access }, + { .name =3D pmevtyper_el0_name, .state =3D ARM_CP_STATE_AA= 64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 15, .crm =3D 12 | (3 = & (i >> 3)), + .opc2 =3D i & 7, .access =3D PL0_RW, .accessfn =3D pmreg= _access, + .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .readfn =3D pmevtyper_readfn, .writefn =3D pmevtyper_wri= tefn }, + REGINFO_SENTINEL + }; + define_arm_cp_regs(cpu, pmev_regs); + g_free(pmevcntr_name); + g_free(pmevcntr_el0_name); + g_free(pmevtyper_name); + g_free(pmevtyper_el0_name); + } #endif ARMCPRegInfo clidr =3D { .name =3D "CLIDR", .state =3D ARM_CP_STATE_BOTH, --=20 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, = Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.