From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B3938C433FE for ; Sat, 19 Feb 2022 00:47:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240471AbiBSArj (ORCPT ); Fri, 18 Feb 2022 19:47:39 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:39192 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240452AbiBSAre (ORCPT ); Fri, 18 Feb 2022 19:47:34 -0500 Received: from mail-ot1-x32c.google.com (mail-ot1-x32c.google.com [IPv6:2607:f8b0:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 68D93276D79 for ; Fri, 18 Feb 2022 16:47:16 -0800 (PST) Received: by mail-ot1-x32c.google.com with SMTP id k9-20020a056830242900b005ad25f8ebfdso3087896ots.7 for ; Fri, 18 Feb 2022 16:47:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=szWXfgdRJjtXGuXkkbx8mVqectdJ9zQfO94sHTyTbqY=; b=BtInRdQN/+c9BBs2GcrRhY+lUMx6LBhnq1MvczrVKUGb3ZByGjdqz3WgLgYw7LQC3D eW4ZamyzZuEurFRWC9PEMIAv8720us+OjggWQmJr6q7d+tmnBZ84tLs5gKJU6eG2f98n wqRjzMmIKFMfQ0cJdTuECum3vvqRvw8JoDZTaX51FyqkFP8rrYX3ZCcii2ODTLaaEJUZ X77lDb2lHMn8Jmhv2q6vsiMPTr6iIew/db/wd4gm+vBKLtaTAKZBEk7pYU2rHVDlR3uq t2Wow0cJfBVSxwQb3vQgaWUq85TlxNobhkaKZz+MFUj8ZEwWtsXctwrWr3/yecgeLQQJ fSNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=szWXfgdRJjtXGuXkkbx8mVqectdJ9zQfO94sHTyTbqY=; b=wFEF1Ont+fW7ItPX2FVDoa0ybQWRzn9Sisurfw8biTt1G2nHVP4BGGD8hYEMkZIQwU y/m2TNViYalfHgcdm4mbT3IMDFhMWFbj063GINiuCMxb+6FqWlJGNsEAeMlhYjBUJ+2k udO7SBZ5VbOwAY7+3KqQPUcZydOrD63tSZ0BvvE89mj9pzflsUxvXREGL/w8dKyZMQuB Np5tcE719rtyXN/MfNDgBLsAPfpl8tPwSSBrhXh7oe84hUJ0foBVtNTi2MWan/i+qbHp aM97pfns6K6j1MlmcmfG6LsHfheox2BQUf/tzHqaudE3nmQOcSS2VCis5TSXEc91/QmA 9Frg== X-Gm-Message-State: AOAM5337VdFTjwPW97cPvVBAHCuERsxmokzyp71Y+oiqeB/ombSWAUa6 gmDK3NpT/pRwWMi3+i+xsPNsVxjIv/tkkYAI X-Google-Smtp-Source: ABdhPJxAaoMOyVKrj7i6Ehjj35CKt0J27KkhnvgMrtBjEWtsk4bjo4zSvZ7iz63auj/aQS87UmAqdQ== X-Received: by 2002:a9d:2da5:0:b0:5ad:fa9:832 with SMTP id g34-20020a9d2da5000000b005ad0fa90832mr3339109otb.250.1645231635280; Fri, 18 Feb 2022 16:47:15 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:14 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Anup Patel , Atish Patra , Albert Ou , Atish Patra , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 1/9] RISC-V: Remove the current perf implementation Date: Fri, 18 Feb 2022 16:46:52 -0800 Message-Id: <20220219004700.1973682-2-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra The current perf implementation in RISC-V is not very useful as it can not count any events other than cycle/instructions. Moreover, perf record can not be used or the events can not be started or stopped. Remove the implementation now for a better platform driver in future that will implement most of the missing functionality. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- arch/riscv/Kconfig | 13 - arch/riscv/include/asm/perf_event.h | 72 ----- arch/riscv/kernel/Makefile | 1 - arch/riscv/kernel/perf_event.c | 485 ---------------------------- 4 files changed, 571 deletions(-) delete mode 100644 arch/riscv/kernel/perf_event.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 5adcbd9b5e88..00cc3d4c77d1 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -333,19 +333,6 @@ config RISCV_ISA_C =20 If you don't know what to do here, say Y. =20 -menu "supported PMU type" - depends on PERF_EVENTS - -config RISCV_BASE_PMU - bool "Base Performance Monitoring Unit" - def_bool y - help - A base PMU that serves as a reference implementation and has limited - feature of perf. It can run on any RISC-V machines so serves as the - fallback, but this option can also be disable to reduce kernel size. - -endmenu - config FPU bool "FPU support" default y diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/p= erf_event.h index 062efd3a1d5d..d42c901f9a97 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h @@ -9,77 +9,5 @@ #define _ASM_RISCV_PERF_EVENT_H =20 #include -#include -#include - -#ifdef CONFIG_RISCV_BASE_PMU -#define RISCV_BASE_COUNTERS 2 - -/* - * The RISCV_MAX_COUNTERS parameter should be specified. - */ - -#define RISCV_MAX_COUNTERS 2 - -/* - * These are the indexes of bits in counteren register *minus* 1, - * except for cycle. It would be coherent if it can directly mapped - * to counteren bit definition, but there is a *time* register at - * counteren[1]. Per-cpu structure is scarce resource here. - * - * According to the spec, an implementation can support counter up to - * mhpmcounter31, but many high-end processors has at most 6 general - * PMCs, we give the definition to MHPMCOUNTER8 here. - */ -#define RISCV_PMU_CYCLE 0 -#define RISCV_PMU_INSTRET 1 -#define RISCV_PMU_MHPMCOUNTER3 2 -#define RISCV_PMU_MHPMCOUNTER4 3 -#define RISCV_PMU_MHPMCOUNTER5 4 -#define RISCV_PMU_MHPMCOUNTER6 5 -#define RISCV_PMU_MHPMCOUNTER7 6 -#define RISCV_PMU_MHPMCOUNTER8 7 - -#define RISCV_OP_UNSUPP (-EOPNOTSUPP) - -struct cpu_hw_events { - /* # currently enabled events*/ - int n_events; - /* currently enabled events */ - struct perf_event *events[RISCV_MAX_COUNTERS]; - /* vendor-defined PMU data */ - void *platform; -}; - -struct riscv_pmu { - struct pmu *pmu; - - /* generic hw/cache events table */ - const int *hw_events; - const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX]; - /* method used to map hw/cache events */ - int (*map_hw_event)(u64 config); - int (*map_cache_event)(u64 config); - - /* max generic hw events in map */ - int max_events; - /* number total counters, 2(base) + x(general) */ - int num_counters; - /* the width of the counter */ - int counter_width; - - /* vendor-defined PMU features */ - void *platform; - - irqreturn_t (*handle_irq)(int irq_num, void *dev); - int irq; -}; - -#endif -#ifdef CONFIG_PERF_EVENTS #define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs -#endif - #endif /* _ASM_RISCV_PERF_EVENT_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 612556faa527..fb63b462ff85 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -51,7 +51,6 @@ obj-$(CONFIG_MODULE_SECTIONS) +=3D module-sections.o obj-$(CONFIG_FUNCTION_TRACER) +=3D mcount.o ftrace.o obj-$(CONFIG_DYNAMIC_FTRACE) +=3D mcount-dyn.o =20 -obj-$(CONFIG_RISCV_BASE_PMU) +=3D perf_event.o obj-$(CONFIG_PERF_EVENTS) +=3D perf_callchain.o obj-$(CONFIG_HAVE_PERF_REGS) +=3D perf_regs.o obj-$(CONFIG_RISCV_SBI) +=3D sbi.o diff --git a/arch/riscv/kernel/perf_event.c b/arch/riscv/kernel/perf_event.c deleted file mode 100644 index c835f0362d94..000000000000 --- a/arch/riscv/kernel/perf_event.c +++ /dev/null @@ -1,485 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2008 Thomas Gleixner - * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2009 Jaswinder Singh Rajput - * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra - * Copyright (C) 2009 Intel Corporation, - * Copyright (C) 2009 Google, Inc., Stephane Eranian - * Copyright 2014 Tilera Corporation. All Rights Reserved. - * Copyright (C) 2018 Andes Technology Corporation - * - * Perf_events support for RISC-V platforms. - * - * Since the spec. (as of now, Priv-Spec 1.10) does not provide enough - * functionality for perf event to fully work, this file provides - * the very basic framework only. - * - * For platform portings, please check Documentations/riscv/pmu.txt. - * - * The Copyright line includes x86 and tile ones. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const struct riscv_pmu *riscv_pmu __read_mostly; -static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); - -/* - * Hardware & cache maps and their methods - */ - -static const int riscv_hw_event_map[] =3D { - [PERF_COUNT_HW_CPU_CYCLES] =3D RISCV_PMU_CYCLE, - [PERF_COUNT_HW_INSTRUCTIONS] =3D RISCV_PMU_INSTRET, - [PERF_COUNT_HW_CACHE_REFERENCES] =3D RISCV_OP_UNSUPP, - [PERF_COUNT_HW_CACHE_MISSES] =3D RISCV_OP_UNSUPP, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =3D RISCV_OP_UNSUPP, - [PERF_COUNT_HW_BRANCH_MISSES] =3D RISCV_OP_UNSUPP, - [PERF_COUNT_HW_BUS_CYCLES] =3D RISCV_OP_UNSUPP, -}; - -#define C(x) PERF_COUNT_HW_CACHE_##x -static const int riscv_cache_event_map[PERF_COUNT_HW_CACHE_MAX] -[PERF_COUNT_HW_CACHE_OP_MAX] -[PERF_COUNT_HW_CACHE_RESULT_MAX] =3D { - [C(L1D)] =3D { - [C(OP_READ)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - }, - [C(L1I)] =3D { - [C(OP_READ)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - }, - [C(LL)] =3D { - [C(OP_READ)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - }, - [C(DTLB)] =3D { - [C(OP_READ)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - }, - [C(ITLB)] =3D { - [C(OP_READ)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - }, - [C(BPU)] =3D { - [C(OP_READ)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] =3D { - [C(RESULT_ACCESS)] =3D RISCV_OP_UNSUPP, - [C(RESULT_MISS)] =3D RISCV_OP_UNSUPP, - }, - }, -}; - -static int riscv_map_hw_event(u64 config) -{ - if (config >=3D riscv_pmu->max_events) - return -EINVAL; - - return riscv_pmu->hw_events[config]; -} - -static int riscv_map_cache_decode(u64 config, unsigned int *type, - unsigned int *op, unsigned int *result) -{ - return -ENOENT; -} - -static int riscv_map_cache_event(u64 config) -{ - unsigned int type, op, result; - int err =3D -ENOENT; - int code; - - err =3D riscv_map_cache_decode(config, &type, &op, &result); - if (!riscv_pmu->cache_events || err) - return err; - - if (type >=3D PERF_COUNT_HW_CACHE_MAX || - op >=3D PERF_COUNT_HW_CACHE_OP_MAX || - result >=3D PERF_COUNT_HW_CACHE_RESULT_MAX) - return -EINVAL; - - code =3D (*riscv_pmu->cache_events)[type][op][result]; - if (code =3D=3D RISCV_OP_UNSUPP) - return -EINVAL; - - return code; -} - -/* - * Low-level functions: reading/writing counters - */ - -static inline u64 read_counter(int idx) -{ - u64 val =3D 0; - - switch (idx) { - case RISCV_PMU_CYCLE: - val =3D csr_read(CSR_CYCLE); - break; - case RISCV_PMU_INSTRET: - val =3D csr_read(CSR_INSTRET); - break; - default: - WARN_ON_ONCE(idx < 0 || idx > RISCV_MAX_COUNTERS); - return -EINVAL; - } - - return val; -} - -static inline void write_counter(int idx, u64 value) -{ - /* currently not supported */ - WARN_ON_ONCE(1); -} - -/* - * pmu->read: read and update the counter - * - * Other architectures' implementation often have a xxx_perf_event_update - * routine, which can return counter values when called in the IRQ, but - * return void when being called by the pmu->read method. - */ -static void riscv_pmu_read(struct perf_event *event) -{ - struct hw_perf_event *hwc =3D &event->hw; - u64 prev_raw_count, new_raw_count; - u64 oldval; - int idx =3D hwc->idx; - u64 delta; - - do { - prev_raw_count =3D local64_read(&hwc->prev_count); - new_raw_count =3D read_counter(idx); - - oldval =3D local64_cmpxchg(&hwc->prev_count, prev_raw_count, - new_raw_count); - } while (oldval !=3D prev_raw_count); - - /* - * delta is the value to update the counter we maintain in the kernel. - */ - delta =3D (new_raw_count - prev_raw_count) & - ((1ULL << riscv_pmu->counter_width) - 1); - local64_add(delta, &event->count); - /* - * Something like local64_sub(delta, &hwc->period_left) here is - * needed if there is an interrupt for perf. - */ -} - -/* - * State transition functions: - * - * stop()/start() & add()/del() - */ - -/* - * pmu->stop: stop the counter - */ -static void riscv_pmu_stop(struct perf_event *event, int flags) -{ - struct hw_perf_event *hwc =3D &event->hw; - - WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); - hwc->state |=3D PERF_HES_STOPPED; - - if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { - riscv_pmu->pmu->read(event); - hwc->state |=3D PERF_HES_UPTODATE; - } -} - -/* - * pmu->start: start the event. - */ -static void riscv_pmu_start(struct perf_event *event, int flags) -{ - struct hw_perf_event *hwc =3D &event->hw; - - if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) - return; - - if (flags & PERF_EF_RELOAD) { - WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE)); - - /* - * Set the counter to the period to the next interrupt here, - * if you have any. - */ - } - - hwc->state =3D 0; - perf_event_update_userpage(event); - - /* - * Since we cannot write to counters, this serves as an initialization - * to the delta-mechanism in pmu->read(); otherwise, the delta would be - * wrong when pmu->read is called for the first time. - */ - local64_set(&hwc->prev_count, read_counter(hwc->idx)); -} - -/* - * pmu->add: add the event to PMU. - */ -static int riscv_pmu_add(struct perf_event *event, int flags) -{ - struct cpu_hw_events *cpuc =3D this_cpu_ptr(&cpu_hw_events); - struct hw_perf_event *hwc =3D &event->hw; - - if (cpuc->n_events =3D=3D riscv_pmu->num_counters) - return -ENOSPC; - - /* - * We don't have general conunters, so no binding-event-to-counter - * process here. - * - * Indexing using hwc->config generally not works, since config may - * contain extra information, but here the only info we have in - * hwc->config is the event index. - */ - hwc->idx =3D hwc->config; - cpuc->events[hwc->idx] =3D event; - cpuc->n_events++; - - hwc->state =3D PERF_HES_UPTODATE | PERF_HES_STOPPED; - - if (flags & PERF_EF_START) - riscv_pmu->pmu->start(event, PERF_EF_RELOAD); - - return 0; -} - -/* - * pmu->del: delete the event from PMU. - */ -static void riscv_pmu_del(struct perf_event *event, int flags) -{ - struct cpu_hw_events *cpuc =3D this_cpu_ptr(&cpu_hw_events); - struct hw_perf_event *hwc =3D &event->hw; - - cpuc->events[hwc->idx] =3D NULL; - cpuc->n_events--; - riscv_pmu->pmu->stop(event, PERF_EF_UPDATE); - perf_event_update_userpage(event); -} - -/* - * Interrupt: a skeletion for reference. - */ - -static DEFINE_MUTEX(pmc_reserve_mutex); - -static irqreturn_t riscv_base_pmu_handle_irq(int irq_num, void *dev) -{ - return IRQ_NONE; -} - -static int reserve_pmc_hardware(void) -{ - int err =3D 0; - - mutex_lock(&pmc_reserve_mutex); - if (riscv_pmu->irq >=3D 0 && riscv_pmu->handle_irq) { - err =3D request_irq(riscv_pmu->irq, riscv_pmu->handle_irq, - IRQF_PERCPU, "riscv-base-perf", NULL); - } - mutex_unlock(&pmc_reserve_mutex); - - return err; -} - -static void release_pmc_hardware(void) -{ - mutex_lock(&pmc_reserve_mutex); - if (riscv_pmu->irq >=3D 0) - free_irq(riscv_pmu->irq, NULL); - mutex_unlock(&pmc_reserve_mutex); -} - -/* - * Event Initialization/Finalization - */ - -static atomic_t riscv_active_events =3D ATOMIC_INIT(0); - -static void riscv_event_destroy(struct perf_event *event) -{ - if (atomic_dec_return(&riscv_active_events) =3D=3D 0) - release_pmc_hardware(); -} - -static int riscv_event_init(struct perf_event *event) -{ - struct perf_event_attr *attr =3D &event->attr; - struct hw_perf_event *hwc =3D &event->hw; - int err; - int code; - - if (atomic_inc_return(&riscv_active_events) =3D=3D 1) { - err =3D reserve_pmc_hardware(); - - if (err) { - pr_warn("PMC hardware not available\n"); - atomic_dec(&riscv_active_events); - return -EBUSY; - } - } - - switch (event->attr.type) { - case PERF_TYPE_HARDWARE: - code =3D riscv_pmu->map_hw_event(attr->config); - break; - case PERF_TYPE_HW_CACHE: - code =3D riscv_pmu->map_cache_event(attr->config); - break; - case PERF_TYPE_RAW: - return -EOPNOTSUPP; - default: - return -ENOENT; - } - - event->destroy =3D riscv_event_destroy; - if (code < 0) { - event->destroy(event); - return code; - } - - /* - * idx is set to -1 because the index of a general event should not be - * decided until binding to some counter in pmu->add(). - * - * But since we don't have such support, later in pmu->add(), we just - * use hwc->config as the index instead. - */ - hwc->config =3D code; - hwc->idx =3D -1; - - return 0; -} - -/* - * Initialization - */ - -static struct pmu min_pmu =3D { - .name =3D "riscv-base", - .event_init =3D riscv_event_init, - .add =3D riscv_pmu_add, - .del =3D riscv_pmu_del, - .start =3D riscv_pmu_start, - .stop =3D riscv_pmu_stop, - .read =3D riscv_pmu_read, -}; - -static const struct riscv_pmu riscv_base_pmu =3D { - .pmu =3D &min_pmu, - .max_events =3D ARRAY_SIZE(riscv_hw_event_map), - .map_hw_event =3D riscv_map_hw_event, - .hw_events =3D riscv_hw_event_map, - .map_cache_event =3D riscv_map_cache_event, - .cache_events =3D &riscv_cache_event_map, - .counter_width =3D 63, - .num_counters =3D RISCV_BASE_COUNTERS + 0, - .handle_irq =3D &riscv_base_pmu_handle_irq, - - /* This means this PMU has no IRQ. */ - .irq =3D -1, -}; - -static const struct of_device_id riscv_pmu_of_ids[] =3D { - {.compatible =3D "riscv,base-pmu", .data =3D &riscv_base_pmu}, - { /* sentinel value */ } -}; - -static int __init init_hw_perf_events(void) -{ - struct device_node *node =3D of_find_node_by_type(NULL, "pmu"); - const struct of_device_id *of_id; - - riscv_pmu =3D &riscv_base_pmu; - - if (node) { - of_id =3D of_match_node(riscv_pmu_of_ids, node); - - if (of_id) - riscv_pmu =3D of_id->data; - of_node_put(node); - } - - perf_pmu_register(riscv_pmu->pmu, "cpu", PERF_TYPE_RAW); - return 0; -} -arch_initcall(init_hw_perf_events); --=20 2.30.2 From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 02EF8C4332F for ; Sat, 19 Feb 2022 00:47:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240482AbiBSArq (ORCPT ); Fri, 18 Feb 2022 19:47:46 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:39266 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240456AbiBSArf (ORCPT ); Fri, 18 Feb 2022 19:47:35 -0500 Received: from mail-ot1-x32c.google.com (mail-ot1-x32c.google.com [IPv6:2607:f8b0:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EF82B27790E for ; Fri, 18 Feb 2022 16:47:17 -0800 (PST) Received: by mail-ot1-x32c.google.com with SMTP id b17-20020a9d4791000000b005a17fc2dfc1so3100169otf.1 for ; Fri, 18 Feb 2022 16:47:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=r7d4QHjy8919ZRO4h3tQp6Y7b0B32ou2+EpX+fwfcw0=; b=H5zVwRUMuUl8xTvBteU92vszT+9z+34Em7K2/0F2cVdhe0MoDgAQaqvP3mHRucqsWp rA2/izndo3IyBWZRwfiyt0nMsK9oCF3q/PDCTZ7m461ySLC+BRbsXVJ9vvSpevCmys17 BzedNLS9HgvioOxo3gTMvDW2TcYNY36UzgBtLV3f/A4qqW9ootmfEk5ecFf2IikTXC25 jTy96vlOIVJATC/ScT1HAhMvCVCEa3lw98zuuu13suvXTaUaL7XtLrr4VhmnDWGqvkr2 v0UcTqFs/ZAKjUbYY8Zslth24mIZs8u+vkQdhNF5Ot51dvdpjOAwQpmfwo1WZX3o7XfK 4YBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=r7d4QHjy8919ZRO4h3tQp6Y7b0B32ou2+EpX+fwfcw0=; b=zvCJ8w1ZrPZJbIGsQadRFjzv819d4F1JClJ42f2kyby6E3XHuxNXX3nHL1Qhio6SDj lmDL95OdnV/PRx60WNVsCtJFNNoUbCMRuIaHWjoodETA4osiGP7CU14nq3L2NUbNVzBe jo/DJ/LaFGrQQVrOQYkEe0UqRVWurA1K5FzbZH9tNeT/QH5JFJDxZE1aBuggRZUjLbnU KdSfLmobw8kYtVZIbYnSwIhLqtMrlKcInkMtkitH2hBu+/eexmCcgpIKNQ1cm9G3VNGJ vtwprCz887xaXc0Y+sWqPDrvo5Cq3D4X67vb335oqCgZq0QeKb/uzZzPy7jWcP69r0vx A6iw== X-Gm-Message-State: AOAM530rj0ZEDvvZV+KXqsnuBbwUA8CIGFJiZ1QhcKyS63cllev8Pv17 nR9PCG4+d5aAwqkmf/uNziZ85xeB7iXfXrFq X-Google-Smtp-Source: ABdhPJz6BmwRNZxitWawKhsyA+xW3K3g0bNI73vzKxIaOxa8TFDi5IWy52wKfsY2ar7Rhy8z+SQNqw== X-Received: by 2002:a05:6830:43a9:b0:5a4:9dbb:645d with SMTP id s41-20020a05683043a900b005a49dbb645dmr3244988otv.138.1645231637078; Fri, 18 Feb 2022 16:47:17 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:16 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Anup Patel , Atish Patra , Albert Ou , Atish Patra , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 2/9] RISC-V: Add CSR encodings for all HPMCOUNTERS Date: Fri, 18 Feb 2022 16:46:53 -0800 Message-Id: <20220219004700.1973682-3-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra Linux kernel can directly read these counters as the HPMCOUNTERS CSRs are accessible in S-mode. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- arch/riscv/include/asm/csr.h | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index ae711692eec9..ce493df11177 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -150,9 +150,67 @@ #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 #define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f #define CSR_CYCLEH 0xc80 #define CSR_TIMEH 0xc81 #define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f =20 #define CSR_SSTATUS 0x100 #define CSR_SIE 0x104 --=20 2.30.2 From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50479C433F5 for ; Sat, 19 Feb 2022 00:47:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240490AbiBSArt (ORCPT ); Fri, 18 Feb 2022 19:47:49 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:39380 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240462AbiBSArh (ORCPT ); Fri, 18 Feb 2022 19:47:37 -0500 Received: from mail-oo1-xc2a.google.com (mail-oo1-xc2a.google.com [IPv6:2607:f8b0:4864:20::c2a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DE9A6276D5D for ; Fri, 18 Feb 2022 16:47:19 -0800 (PST) Received: by mail-oo1-xc2a.google.com with SMTP id d134-20020a4a528c000000b00319244f4b04so5585622oob.8 for ; Fri, 18 Feb 2022 16:47:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=PBtZQAf02ylyCGOb57FDlVNWaZJ7REmGhJEP6Z5aqyM=; b=5R3pJG9Q29rF2Xph0z7OeQUGHvS4la26m5MYQf8LwF9fiA7bGxVhISl8kmTtSFyaJZ YqcyThqbG4vb/WunSbaXykHoImTDm5BndOTFm6+iUBuCUaoMD6S6DLAuBkx7KTGfbjDw e4zmAH28F9jIpQKoQZK6l8xe3wKUxkVvbote4xECUp6Op7/o1G+voHOYyKcFuxz5HA6k XoSJMVNY3fsKDHPV9NHupQcmHu072gmuDjwYprM4tRXhFR99RyoO5unOXgMxj4dW3JN0 T55UCgOQwd8Lzicjoo8VMsht7lkvA89cdJ493IfITj3qNrqCjcNDiSbAJDfXvf99T/cO ri1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=PBtZQAf02ylyCGOb57FDlVNWaZJ7REmGhJEP6Z5aqyM=; b=cV6n0K8ebtHoVe6LYccxw9Jf3VIzLqeuTZLWHtwkWPAyDrzbleaFtEXXz7EFdCN5tp a8vwjMEkqk7NNIFjLjm7XdIvIq9bani92+bwBWKY72MsSDBN7o5l5iadTrRHILIY0IgG biLuUdL0XC091z9Keq4u/m1V9iI8IvbI0gZszR+fom83iVbuq2uXxSb+xEDLbK2NTLd9 htVzc9v3EdP61x0RFwFvMebgaIjIDx2uN0+4r0XMH/MtCAymp4zasdRGX2lwRueYKpPD rlZPssmB01BYGP8bFX+fHV71eCXmYv9Pj4ccrY4OYed+t28NItYC/Ny7yvedEsltDWgN gbEw== X-Gm-Message-State: AOAM533vXT3H9OURFavE8TIjEyvAhRzGfZQ6vaKwXu7iVXdqNHKzx49j H4T1Gtg6LEgRa2y95QrLzogzZW34oOc/Dw2p X-Google-Smtp-Source: ABdhPJys03cZCZe7wHhV27uqrBntJP1UDpo7imQ9xOMhE5WqkVBa4HWGBoa0XMeAvPkMWPJidOlPoQ== X-Received: by 2002:a4a:3845:0:b0:2e9:b01:6257 with SMTP id o5-20020a4a3845000000b002e90b016257mr3144442oof.78.1645231638795; Fri, 18 Feb 2022 16:47:18 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:18 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Anup Patel , Atish Patra , Albert Ou , Atish Patra , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 3/9] RISC-V: Add a perf core library for pmu drivers Date: Fri, 18 Feb 2022 16:46:54 -0800 Message-Id: <20220219004700.1973682-4-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra Implement a perf core library that can support all the essential perf features in future. It can also accommodate any type of PMU implementation in future. Currently, both SBI based perf driver and legacy driver implemented uses the library. Most of the common perf functionalities are kept in this core library wile PMU specific driver can implement PMU specific features. For example, the SBI specific functionality will be implemented in the SBI specific driver. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- drivers/perf/Kconfig | 10 + drivers/perf/Makefile | 1 + drivers/perf/riscv_pmu.c | 322 +++++++++++++++++++++++++++++++++ include/linux/perf/riscv_pmu.h | 65 +++++++ 4 files changed, 398 insertions(+) create mode 100644 drivers/perf/riscv_pmu.c create mode 100644 include/linux/perf/riscv_pmu.h diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index e1a0c44bc686..dbc0e3f98be9 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -56,6 +56,16 @@ config ARM_PMU Say y if you want to use CPU performance monitors on ARM-based systems. =20 +config RISCV_PMU + depends on RISCV + bool "RISC-V PMU framework" + default y + help + Say y if you want to use CPU performance monitors on RISCV-based + systems. This provides the core PMU framework that abstracts common + PMU functionalities in a core library so that different PMU drivers + can reuse it. + config ARM_PMU_ACPI depends on ARM_PMU && ACPI def_bool y diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index 2db5418d5b0a..09082dea154b 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_FSL_IMX8_DDR_PMU) +=3D fsl_imx8_ddr_perf.o obj-$(CONFIG_HISI_PMU) +=3D hisilicon/ obj-$(CONFIG_QCOM_L2_PMU) +=3D qcom_l2_pmu.o obj-$(CONFIG_QCOM_L3_PMU) +=3D qcom_l3_pmu.o +obj-$(CONFIG_RISCV_PMU) +=3D riscv_pmu.o obj-$(CONFIG_THUNDERX2_PMU) +=3D thunderx2_pmu.o obj-$(CONFIG_XGENE_PMU) +=3D xgene_pmu.o obj-$(CONFIG_ARM_SPE_PMU) +=3D arm_spe_pmu.o diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c new file mode 100644 index 000000000000..590a5789c128 --- /dev/null +++ b/drivers/perf/riscv_pmu.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V performance counter support. + * + * Copyright (C) 2021 Western Digital Corporation or its affiliates. + * + * This implementation is based on old RISC-V perf and ARM perf event code + * which are in turn based on sparc64 and x86 code. + */ + +#include +#include +#include +#include +#include +#include + +static unsigned long csr_read_num(int csr_num) +{ +#define switchcase_csr_read(__csr_num, __val) {\ + case __csr_num: \ + __val =3D csr_read(__csr_num); \ + break; } +#define switchcase_csr_read_2(__csr_num, __val) {\ + switchcase_csr_read(__csr_num + 0, __val) \ + switchcase_csr_read(__csr_num + 1, __val)} +#define switchcase_csr_read_4(__csr_num, __val) {\ + switchcase_csr_read_2(__csr_num + 0, __val) \ + switchcase_csr_read_2(__csr_num + 2, __val)} +#define switchcase_csr_read_8(__csr_num, __val) {\ + switchcase_csr_read_4(__csr_num + 0, __val) \ + switchcase_csr_read_4(__csr_num + 4, __val)} +#define switchcase_csr_read_16(__csr_num, __val) {\ + switchcase_csr_read_8(__csr_num + 0, __val) \ + switchcase_csr_read_8(__csr_num + 8, __val)} +#define switchcase_csr_read_32(__csr_num, __val) {\ + switchcase_csr_read_16(__csr_num + 0, __val) \ + switchcase_csr_read_16(__csr_num + 16, __val)} + + unsigned long ret =3D 0; + + switch (csr_num) { + switchcase_csr_read_32(CSR_CYCLE, ret) + switchcase_csr_read_32(CSR_CYCLEH, ret) + default : + break; + } + + return ret; +#undef switchcase_csr_read_32 +#undef switchcase_csr_read_16 +#undef switchcase_csr_read_8 +#undef switchcase_csr_read_4 +#undef switchcase_csr_read_2 +#undef switchcase_csr_read +} + +/* + * Read the CSR of a corresponding counter. + */ +unsigned long riscv_pmu_ctr_read_csr(unsigned long csr) +{ + if (csr < CSR_CYCLE || csr > CSR_HPMCOUNTER31H || + (csr > CSR_HPMCOUNTER31 && csr < CSR_CYCLEH)) { + pr_err("Invalid performance counter csr %lx\n", csr); + return -EINVAL; + } + + return csr_read_num(csr); +} + +u64 riscv_pmu_ctr_get_width_mask(struct perf_event *event) +{ + int cwidth; + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + struct hw_perf_event *hwc =3D &event->hw; + + if (!rvpmu->ctr_get_width) + /** + * If the pmu driver doesn't support counter width, set it to default + * maximum allowed by the specification. + */ + cwidth =3D 63; + else { + if (hwc->idx =3D=3D -1) + /* Handle init case where idx is not initialized yet */ + cwidth =3D rvpmu->ctr_get_width(0); + else + cwidth =3D rvpmu->ctr_get_width(hwc->idx); + } + + return GENMASK_ULL(cwidth, 0); +} + +u64 riscv_pmu_event_update(struct perf_event *event) +{ + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + struct hw_perf_event *hwc =3D &event->hw; + u64 prev_raw_count, new_raw_count; + unsigned long cmask; + u64 oldval, delta; + + if (!rvpmu->ctr_read) + return 0; + + cmask =3D riscv_pmu_ctr_get_width_mask(event); + + do { + prev_raw_count =3D local64_read(&hwc->prev_count); + new_raw_count =3D rvpmu->ctr_read(event); + oldval =3D local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count); + } while (oldval !=3D prev_raw_count); + + delta =3D (new_raw_count - prev_raw_count) & cmask; + local64_add(delta, &event->count); + local64_sub(delta, &hwc->period_left); + + return delta; +} + +static void riscv_pmu_stop(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc =3D &event->hw; + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + + WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); + + if (!(hwc->state & PERF_HES_STOPPED)) { + if (rvpmu->ctr_stop) { + rvpmu->ctr_stop(event, 0); + hwc->state |=3D PERF_HES_STOPPED; + } + riscv_pmu_event_update(event); + hwc->state |=3D PERF_HES_UPTODATE; + } +} + +int riscv_pmu_event_set_period(struct perf_event *event) +{ + struct hw_perf_event *hwc =3D &event->hw; + s64 left =3D local64_read(&hwc->period_left); + s64 period =3D hwc->sample_period; + int overflow =3D 0; + uint64_t max_period =3D riscv_pmu_ctr_get_width_mask(event); + + if (unlikely(left <=3D -period)) { + left =3D period; + local64_set(&hwc->period_left, left); + hwc->last_period =3D period; + overflow =3D 1; + } + + if (unlikely(left <=3D 0)) { + left +=3D period; + local64_set(&hwc->period_left, left); + hwc->last_period =3D period; + overflow =3D 1; + } + + /* + * Limit the maximum period to prevent the counter value + * from overtaking the one we are about to program. In + * effect we are reducing max_period to account for + * interrupt latency (and we are being very conservative). + */ + if (left > (max_period >> 1)) + left =3D (max_period >> 1); + + local64_set(&hwc->prev_count, (u64)-left); + perf_event_update_userpage(event); + + return overflow; +} + +static void riscv_pmu_start(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc =3D &event->hw; + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + uint64_t max_period =3D riscv_pmu_ctr_get_width_mask(event); + u64 init_val; + + if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) + return; + + if (flags & PERF_EF_RELOAD) + WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE)); + + hwc->state =3D 0; + riscv_pmu_event_set_period(event); + init_val =3D local64_read(&hwc->prev_count) & max_period; + rvpmu->ctr_start(event, init_val); + perf_event_update_userpage(event); +} + +static int riscv_pmu_add(struct perf_event *event, int flags) +{ + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc =3D this_cpu_ptr(rvpmu->hw_events); + struct hw_perf_event *hwc =3D &event->hw; + int idx; + + idx =3D rvpmu->ctr_get_idx(event); + if (idx < 0) + return idx; + + hwc->idx =3D idx; + cpuc->events[idx] =3D event; + cpuc->n_events++; + hwc->state =3D PERF_HES_UPTODATE | PERF_HES_STOPPED; + if (flags & PERF_EF_START) + riscv_pmu_start(event, PERF_EF_RELOAD); + + /* Propagate our changes to the userspace mapping. */ + perf_event_update_userpage(event); + + return 0; +} + +static void riscv_pmu_del(struct perf_event *event, int flags) +{ + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc =3D this_cpu_ptr(rvpmu->hw_events); + struct hw_perf_event *hwc =3D &event->hw; + + riscv_pmu_stop(event, PERF_EF_UPDATE); + cpuc->events[hwc->idx] =3D NULL; + /* The firmware need to reset the counter mapping */ + if (rvpmu->ctr_stop) + rvpmu->ctr_stop(event, RISCV_PMU_STOP_FLAG_RESET); + cpuc->n_events--; + if (rvpmu->ctr_clear_idx) + rvpmu->ctr_clear_idx(event); + perf_event_update_userpage(event); + hwc->idx =3D -1; +} + +static void riscv_pmu_read(struct perf_event *event) +{ + riscv_pmu_event_update(event); +} + +static int riscv_pmu_event_init(struct perf_event *event) +{ + struct hw_perf_event *hwc =3D &event->hw; + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + int mapped_event; + u64 event_config =3D 0; + uint64_t cmask; + + hwc->flags =3D 0; + mapped_event =3D rvpmu->event_map(event, &event_config); + if (mapped_event < 0) { + pr_debug("event %x:%llx not supported\n", event->attr.type, + event->attr.config); + return mapped_event; + } + + /* + * idx is set to -1 because the index of a general event should not be + * decided until binding to some counter in pmu->add(). + * config will contain the information about counter CSR + * the idx will contain the counter index + */ + hwc->config =3D event_config; + hwc->idx =3D -1; + hwc->event_base =3D mapped_event; + + if (!is_sampling_event(event)) { + /* + * For non-sampling runs, limit the sample_period to half + * of the counter width. That way, the new counter value + * is far less likely to overtake the previous one unless + * you have some serious IRQ latency issues. + */ + cmask =3D riscv_pmu_ctr_get_width_mask(event); + hwc->sample_period =3D cmask >> 1; + hwc->last_period =3D hwc->sample_period; + local64_set(&hwc->period_left, hwc->sample_period); + } + + return 0; +} + +struct riscv_pmu *riscv_pmu_alloc(void) +{ + struct riscv_pmu *pmu; + int cpuid, i; + struct cpu_hw_events *cpuc; + + pmu =3D kzalloc(sizeof(*pmu), GFP_KERNEL); + if (!pmu) + goto out; + + pmu->hw_events =3D alloc_percpu_gfp(struct cpu_hw_events, GFP_KERNEL); + if (!pmu->hw_events) { + pr_info("failed to allocate per-cpu PMU data.\n"); + goto out_free_pmu; + } + + for_each_possible_cpu(cpuid) { + cpuc =3D per_cpu_ptr(pmu->hw_events, cpuid); + cpuc->n_events =3D 0; + for (i =3D 0; i < RISCV_MAX_COUNTERS; i++) + cpuc->events[i] =3D NULL; + } + pmu->pmu =3D (struct pmu) { + .event_init =3D riscv_pmu_event_init, + .add =3D riscv_pmu_add, + .del =3D riscv_pmu_del, + .start =3D riscv_pmu_start, + .stop =3D riscv_pmu_stop, + .read =3D riscv_pmu_read, + }; + + return pmu; + +out_free_pmu: + kfree(pmu); +out: + return NULL; +} diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h new file mode 100644 index 000000000000..0d8979765d79 --- /dev/null +++ b/include/linux/perf/riscv_pmu.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 SiFive + * Copyright (C) 2018 Andes Technology Corporation + * Copyright (C) 2021 Western Digital Corporation or its affiliates. + * + */ + +#ifndef _ASM_RISCV_PERF_EVENT_H +#define _ASM_RISCV_PERF_EVENT_H + +#include +#include +#include + +#ifdef CONFIG_RISCV_PMU + +/* + * The RISCV_MAX_COUNTERS parameter should be specified. + */ + +#define RISCV_MAX_COUNTERS 64 +#define RISCV_OP_UNSUPP (-EOPNOTSUPP) +#define RISCV_PMU_PDEV_NAME "riscv-pmu" + +#define RISCV_PMU_STOP_FLAG_RESET 1 + +struct cpu_hw_events { + /* currently enabled events */ + int n_events; + /* currently enabled events */ + struct perf_event *events[RISCV_MAX_COUNTERS]; + /* currently enabled counters */ + DECLARE_BITMAP(used_event_ctrs, RISCV_MAX_COUNTERS); +}; + +struct riscv_pmu { + struct pmu pmu; + char *name; + + irqreturn_t (*handle_irq)(int irq_num, void *dev); + + int num_counters; + u64 (*ctr_read)(struct perf_event *event); + int (*ctr_get_idx)(struct perf_event *event); + int (*ctr_get_width)(int idx); + void (*ctr_clear_idx)(struct perf_event *event); + void (*ctr_start)(struct perf_event *event, u64 init_val); + void (*ctr_stop)(struct perf_event *event, unsigned long flag); + int (*event_map)(struct perf_event *event, u64 *config); + + struct cpu_hw_events __percpu *hw_events; + struct hlist_node node; +}; + +#define to_riscv_pmu(p) (container_of(p, struct riscv_pmu, pmu)) +unsigned long riscv_pmu_ctr_read_csr(unsigned long csr); +int riscv_pmu_event_set_period(struct perf_event *event); +uint64_t riscv_pmu_ctr_get_width_mask(struct perf_event *event); +u64 riscv_pmu_event_update(struct perf_event *event); +struct riscv_pmu *riscv_pmu_alloc(void); + +#endif /* CONFIG_RISCV_PMU */ + +#endif /* _ASM_RISCV_PERF_EVENT_H */ --=20 2.30.2 From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 55FF9C433FE for ; Sat, 19 Feb 2022 00:47:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240493AbiBSAry (ORCPT ); Fri, 18 Feb 2022 19:47:54 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:39474 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240469AbiBSArj (ORCPT ); Fri, 18 Feb 2022 19:47:39 -0500 Received: from mail-oi1-x22c.google.com (mail-oi1-x22c.google.com [IPv6:2607:f8b0:4864:20::22c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6E543277908 for ; Fri, 18 Feb 2022 16:47:21 -0800 (PST) Received: by mail-oi1-x22c.google.com with SMTP id j2so4886126oie.7 for ; Fri, 18 Feb 2022 16:47:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=KzmhLvVz31vDzGMMY34u4TS6n0xBB5tfzWyXF9F+lho=; b=lXvzgeIW84VjTgJdYCIo+dLzmZaCO3ZzkPgwOEmtn6VOoYrBHo3GnjIJE/IeXP4uJL Mw7a2fbyTQ3BmDYQaL8wdMtX427VtK1mEbNnxslkVbeirG6RYxrR+mZx0kqRGfeD06oE 5csQBlItRhfzxNNLlUxHHLtvr8hUo1mrbA3/r/6Fet8/bvXVyd9ORXx5TsJthNdj5mB7 oPfM3fvRozywtHc5soKa+F4ncy5ncOPX2ssZXiA6u5nBK2nwvyTBOEaFvE9NjKi/vS1W SvbCwGUU1mShVd+gywPr9V874Y2pc01lYedWj6DkSI+iyUh8/ve14o4bcncWlIwIQXZG lmtA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=KzmhLvVz31vDzGMMY34u4TS6n0xBB5tfzWyXF9F+lho=; b=QQE3AxBbtDYiy0VaKWBASdmul0H1dplmIL4Y27bxCzf2msocu2pMydmJJCnBKvxhvf 6LO8I+EN9jGXXL7GTasu/mNEtlwkBBxGy1eyx9FJmPJzjmDc08uGMI2uddmbaZSEKVKO rlZPu0Rb9NMon4XNnF6FtphFAFJskU9Bf0mj0TDo3gahz0JaaxAT2pwTqM8utDcU7jT3 02EZWYZsyO+spxa699fnDjZVwmQ7Mpi4+4MPsrTbmHnzPhhpD2YQzQndLDWSAPg+qkL7 UVPoYGV9RyohlRZvqnoc968HPsRuRy5Afl4rdH6qL0kEggrZD85HJmEoMejv2YKLULLA 2J9w== X-Gm-Message-State: AOAM531i42dxwaQFZzDxizbw0lN16HYCuCHwUqL0CqDswZMKRLNy7sR+ jZrlYVs9uSHprxwSZpDUfaISK5/8mwk+AgL0 X-Google-Smtp-Source: ABdhPJyDev9Pc4oxIWxXyasAoZdwJfZr5R8goDRj6aWEX0l9J2Hc/U9mVA0sJ3SeJtP1S4bjHUy+/A== X-Received: by 2002:a05:6808:2029:b0:2d0:8e1a:14f3 with SMTP id q41-20020a056808202900b002d08e1a14f3mr6444328oiw.257.1645231640482; Fri, 18 Feb 2022 16:47:20 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:20 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Anup Patel , Atish Patra , Albert Ou , Atish Patra , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 4/9] RISC-V: Add a simple platform driver for RISC-V legacy perf Date: Fri, 18 Feb 2022 16:46:55 -0800 Message-Id: <20220219004700.1973682-5-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra The old RISC-V perf implementation allowed counting of only cycle/instruction counters using perf. Restore that feature by implementing a simple platform driver under a separate config to provide backward compatibility. Any existing software stack will continue to work as it is. However, it provides an easy way out in future where we can remove the legacy driver. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- drivers/perf/Kconfig | 10 +++ drivers/perf/Makefile | 1 + drivers/perf/riscv_pmu_legacy.c | 142 ++++++++++++++++++++++++++++++++ include/linux/perf/riscv_pmu.h | 6 ++ 4 files changed, 159 insertions(+) create mode 100644 drivers/perf/riscv_pmu_legacy.c diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index dbc0e3f98be9..386162ad858a 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -66,6 +66,16 @@ config RISCV_PMU PMU functionalities in a core library so that different PMU drivers can reuse it. =20 +config RISCV_PMU_LEGACY + depends on RISCV_PMU + bool "RISC-V legacy PMU implementation" + default y + help + Say y if you want to use the legacy CPU performance monitor + implementation on RISC-V based systems. This only allows counting + of cycle/instruction counter and doesn't support counter overflow, + or programmable counters. It will be removed in future. + config ARM_PMU_ACPI depends on ARM_PMU && ACPI def_bool y diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index 09082dea154b..c3d3268d495b 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_HISI_PMU) +=3D hisilicon/ obj-$(CONFIG_QCOM_L2_PMU) +=3D qcom_l2_pmu.o obj-$(CONFIG_QCOM_L3_PMU) +=3D qcom_l3_pmu.o obj-$(CONFIG_RISCV_PMU) +=3D riscv_pmu.o +obj-$(CONFIG_RISCV_PMU_LEGACY) +=3D riscv_pmu_legacy.o obj-$(CONFIG_THUNDERX2_PMU) +=3D thunderx2_pmu.o obj-$(CONFIG_XGENE_PMU) +=3D xgene_pmu.o obj-$(CONFIG_ARM_SPE_PMU) +=3D arm_spe_pmu.o diff --git a/drivers/perf/riscv_pmu_legacy.c b/drivers/perf/riscv_pmu_legac= y.c new file mode 100644 index 000000000000..342778782359 --- /dev/null +++ b/drivers/perf/riscv_pmu_legacy.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V performance counter support. + * + * Copyright (C) 2021 Western Digital Corporation or its affiliates. + * + * This implementation is based on old RISC-V perf and ARM perf event code + * which are in turn based on sparc64 and x86 code. + */ + +#include +#include +#include + +#define RISCV_PMU_LEGACY_CYCLE 0 +#define RISCV_PMU_LEGACY_INSTRET 1 +#define RISCV_PMU_LEGACY_NUM_CTR 2 + +static bool pmu_init_done; + +static int pmu_legacy_ctr_get_idx(struct perf_event *event) +{ + struct perf_event_attr *attr =3D &event->attr; + + if (event->attr.type !=3D PERF_TYPE_HARDWARE) + return -EOPNOTSUPP; + if (attr->config =3D=3D PERF_COUNT_HW_CPU_CYCLES) + return RISCV_PMU_LEGACY_CYCLE; + else if (attr->config =3D=3D PERF_COUNT_HW_INSTRUCTIONS) + return RISCV_PMU_LEGACY_INSTRET; + else + return -EOPNOTSUPP; +} + +/* For legacy config & counter index are same */ +static int pmu_legacy_event_map(struct perf_event *event, u64 *config) +{ + return pmu_legacy_ctr_get_idx(event); +} + +static u64 pmu_legacy_read_ctr(struct perf_event *event) +{ + struct hw_perf_event *hwc =3D &event->hw; + int idx =3D hwc->idx; + u64 val; + + if (idx =3D=3D RISCV_PMU_LEGACY_CYCLE) { + val =3D riscv_pmu_ctr_read_csr(CSR_CYCLE); + if (IS_ENABLED(CONFIG_32BIT)) + val =3D (u64)riscv_pmu_ctr_read_csr(CSR_CYCLEH) << 32 | val; + } else if (idx =3D=3D RISCV_PMU_LEGACY_INSTRET) { + val =3D riscv_pmu_ctr_read_csr(CSR_INSTRET); + if (IS_ENABLED(CONFIG_32BIT)) + val =3D ((u64)riscv_pmu_ctr_read_csr(CSR_INSTRETH)) << 32 | val; + } else + return 0; + + return val; +} + +static void pmu_legacy_ctr_start(struct perf_event *event, u64 ival) +{ + struct hw_perf_event *hwc =3D &event->hw; + u64 initial_val =3D pmu_legacy_read_ctr(event); + + /** + * The legacy method doesn't really have a start/stop method. + * It also can not update the counter with a initial value. + * But we still need to set the prev_count so that read() can compute + * the delta. Just use the current counter value to set the prev_count. + */ + local64_set(&hwc->prev_count, initial_val); +} + +/** + * This is just a simple implementation to allow legacy implementations + * compatible with new RISC-V PMU driver framework. + * This driver only allows reading two counters i.e CYCLE & INSTRET. + * However, it can not start or stop the counter. Thus, it is not very use= ful + * will be removed in future. + */ +static void pmu_legacy_init(struct riscv_pmu *pmu) +{ + pr_info("Legacy PMU implementation is available\n"); + + pmu->num_counters =3D RISCV_PMU_LEGACY_NUM_CTR; + pmu->ctr_start =3D pmu_legacy_ctr_start; + pmu->ctr_stop =3D NULL; + pmu->event_map =3D pmu_legacy_event_map; + pmu->ctr_get_idx =3D pmu_legacy_ctr_get_idx; + pmu->ctr_get_width =3D NULL; + pmu->ctr_clear_idx =3D NULL; + pmu->ctr_read =3D pmu_legacy_read_ctr; + + perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW); +} + +static int pmu_legacy_device_probe(struct platform_device *pdev) +{ + struct riscv_pmu *pmu =3D NULL; + + pmu =3D riscv_pmu_alloc(); + if (!pmu) + return -ENOMEM; + pmu_legacy_init(pmu); + + return 0; +} + +static struct platform_driver pmu_legacy_driver =3D { + .probe =3D pmu_legacy_device_probe, + .driver =3D { + .name =3D RISCV_PMU_LEGACY_PDEV_NAME, + }, +}; + +static int __init riscv_pmu_legacy_devinit(void) +{ + int ret; + struct platform_device *pdev; + + if (likely(pmu_init_done)) + return 0; + + ret =3D platform_driver_register(&pmu_legacy_driver); + if (ret) + return ret; + + pdev =3D platform_device_register_simple(RISCV_PMU_LEGACY_PDEV_NAME, -1, = NULL, 0); + if (IS_ERR(pdev)) { + platform_driver_unregister(&pmu_legacy_driver); + return PTR_ERR(pdev); + } + + return ret; +} +late_initcall(riscv_pmu_legacy_devinit); + +void riscv_pmu_legacy_skip_init(void) +{ + pmu_init_done =3D true; +} diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 0d8979765d79..9140c491fc54 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -22,6 +22,7 @@ #define RISCV_MAX_COUNTERS 64 #define RISCV_OP_UNSUPP (-EOPNOTSUPP) #define RISCV_PMU_PDEV_NAME "riscv-pmu" +#define RISCV_PMU_LEGACY_PDEV_NAME "riscv-pmu-legacy" =20 #define RISCV_PMU_STOP_FLAG_RESET 1 =20 @@ -58,6 +59,11 @@ unsigned long riscv_pmu_ctr_read_csr(unsigned long csr); int riscv_pmu_event_set_period(struct perf_event *event); uint64_t riscv_pmu_ctr_get_width_mask(struct perf_event *event); u64 riscv_pmu_event_update(struct perf_event *event); +#ifdef CONFIG_RISCV_PMU_LEGACY +void riscv_pmu_legacy_skip_init(void); +#else +static inline void riscv_pmu_legacy_skip_init(void) {}; +#endif struct riscv_pmu *riscv_pmu_alloc(void); =20 #endif /* CONFIG_RISCV_PMU */ --=20 2.30.2 From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 174F3C433FE for ; Sat, 19 Feb 2022 00:47:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240497AbiBSAr5 (ORCPT ); Fri, 18 Feb 2022 19:47:57 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:39578 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240473AbiBSArl (ORCPT ); Fri, 18 Feb 2022 19:47:41 -0500 Received: from mail-oo1-xc31.google.com (mail-oo1-xc31.google.com [IPv6:2607:f8b0:4864:20::c31]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 30EB327790E for ; Fri, 18 Feb 2022 16:47:23 -0800 (PST) Received: by mail-oo1-xc31.google.com with SMTP id e19-20020a4ab993000000b0031a98fe3a9dso5617809oop.6 for ; Fri, 18 Feb 2022 16:47:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=0j+T9VasmFWeUqsBn6L9ZQ6Qv99DW8ONEhzwQtqDRFk=; b=W8CSVN8s2dohlJRB1FJ3HVV8VwnSRlGhMP6LtrFCLiIEGxdMl6y1QizrlloOoEq4EJ 9sfkO7VeAFs2DZ+JK9Fvrm50z13bYgJIQTGS+dAyTvKWOAJMWOY9aqEDWQERIFDNE5wU kfDcPpOyMPmtGl+WsPmyQMPZWtRaI4LcZAXQo8lKEo27Uw1oIHR6EEVDjE6tUe4eIKEf nN/BFYhE92v9nsecjzw7nwN9zzRBzAH72HGRz5MUVmg6PYcgtm//WgyKMbmwnXD0Cp6B bvBoR7vDYQWJD4ctKuNVrowu9dh3YYHUtBep71QqYwihFr/ZwOh1SOkcr7QDv2Bleqkb J4ng== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0j+T9VasmFWeUqsBn6L9ZQ6Qv99DW8ONEhzwQtqDRFk=; b=1b5fnZUJ5xKjoc/yA2VH/IfItqUEBOdZWfl2sOIbMyicDWpOOWF9SntzKPair5dCqz Rw+4iP6wh9YuFm3so6SimpSIWYe6pyCpV/61jshVFQ7htqY0uNFII29b5mU9eVWJi5IL 4xkitaN8/gf5urheyo3PJY1PeC4Pr879BtTLdp7wkCGusiQ1fZvLjUO1RJ4LSkmL8Dgl ZJ35Xp7OM2hx90q2DKedr9eh/uKIr4uIvYdww6R7ENviPJzXW8ALqiWIeF+QOY870sMO qfqTBk002JMVbVRKmqiKSO+UP8+b8qEHLLIo8iW57I0efIK3EJTCtJoWK9McZBOynY+0 bmxw== X-Gm-Message-State: AOAM530zCtD/1LzrwVSseXmARrw4OyOqSS4BIqxBU3f//rDF3Qcl7iQP BHIncWb+ejK71oUpxFPbRm3gqB7cpVokkztf X-Google-Smtp-Source: ABdhPJxAyxuLwuTuXTKj3/VOQR+djzq+LeVnxLMGFdxcc2wCuga4DKoazdnFlrq/5iDDL20rw7Ctjg== X-Received: by 2002:a4a:7601:0:b0:2e0:3c62:4787 with SMTP id t1-20020a4a7601000000b002e03c624787mr3070173ooc.11.1645231642263; Fri, 18 Feb 2022 16:47:22 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:21 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Anup Patel , Atish Patra , Albert Ou , Atish Patra , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 5/9] RISC-V: Add RISC-V SBI PMU extension definitions Date: Fri, 18 Feb 2022 16:46:56 -0800 Message-Id: <20220219004700.1973682-6-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra This patch adds all the definitions defined by the SBI PMU extension. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- arch/riscv/include/asm/sbi.h | 95 ++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index d1c37479d828..4a430ae60eaa 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -29,6 +29,7 @@ enum sbi_ext_id { SBI_EXT_RFENCE =3D 0x52464E43, SBI_EXT_HSM =3D 0x48534D, SBI_EXT_SRST =3D 0x53525354, + SBI_EXT_PMU =3D 0x504D55, =20 /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START =3D 0x08000000, @@ -95,6 +96,98 @@ enum sbi_srst_reset_reason { SBI_SRST_RESET_REASON_SYS_FAILURE, }; =20 +enum sbi_ext_pmu_fid { + SBI_EXT_PMU_NUM_COUNTERS =3D 0, + SBI_EXT_PMU_COUNTER_GET_INFO, + SBI_EXT_PMU_COUNTER_CFG_MATCH, + SBI_EXT_PMU_COUNTER_START, + SBI_EXT_PMU_COUNTER_STOP, + SBI_EXT_PMU_COUNTER_FW_READ, +}; + +#define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(55, 0) +#define RISCV_PMU_RAW_EVENT_IDX 0x20000 + +/** General pmu event codes specified in SBI PMU extension */ +enum sbi_pmu_hw_generic_events_t { + SBI_PMU_HW_NO_EVENT =3D 0, + SBI_PMU_HW_CPU_CYCLES =3D 1, + SBI_PMU_HW_INSTRUCTIONS =3D 2, + SBI_PMU_HW_CACHE_REFERENCES =3D 3, + SBI_PMU_HW_CACHE_MISSES =3D 4, + SBI_PMU_HW_BRANCH_INSTRUCTIONS =3D 5, + SBI_PMU_HW_BRANCH_MISSES =3D 6, + SBI_PMU_HW_BUS_CYCLES =3D 7, + SBI_PMU_HW_STALLED_CYCLES_FRONTEND =3D 8, + SBI_PMU_HW_STALLED_CYCLES_BACKEND =3D 9, + SBI_PMU_HW_REF_CPU_CYCLES =3D 10, + + SBI_PMU_HW_GENERAL_MAX, +}; + +/** + * Special "firmware" events provided by the firmware, even if the hardware + * does not support performance events. These events are encoded as a raw + * event type in Linux kernel perf framework. + */ +enum sbi_pmu_fw_generic_events_t { + SBI_PMU_FW_MISALIGNED_LOAD =3D 0, + SBI_PMU_FW_MISALIGNED_STORE =3D 1, + SBI_PMU_FW_ACCESS_LOAD =3D 2, + SBI_PMU_FW_ACCESS_STORE =3D 3, + SBI_PMU_FW_ILLEGAL_INSN =3D 4, + SBI_PMU_FW_SET_TIMER =3D 5, + SBI_PMU_FW_IPI_SENT =3D 6, + SBI_PMU_FW_IPI_RECVD =3D 7, + SBI_PMU_FW_FENCE_I_SENT =3D 8, + SBI_PMU_FW_FENCE_I_RECVD =3D 9, + SBI_PMU_FW_SFENCE_VMA_SENT =3D 10, + SBI_PMU_FW_SFENCE_VMA_RCVD =3D 11, + SBI_PMU_FW_SFENCE_VMA_ASID_SENT =3D 12, + SBI_PMU_FW_SFENCE_VMA_ASID_RCVD =3D 13, + + SBI_PMU_FW_HFENCE_GVMA_SENT =3D 14, + SBI_PMU_FW_HFENCE_GVMA_RCVD =3D 15, + SBI_PMU_FW_HFENCE_GVMA_VMID_SENT =3D 16, + SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD =3D 17, + + SBI_PMU_FW_HFENCE_VVMA_SENT =3D 18, + SBI_PMU_FW_HFENCE_VVMA_RCVD =3D 19, + SBI_PMU_FW_HFENCE_VVMA_ASID_SENT =3D 20, + SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD =3D 21, + SBI_PMU_FW_MAX, +}; + +/* SBI PMU event types */ +enum sbi_pmu_event_type { + SBI_PMU_EVENT_TYPE_HW =3D 0x0, + SBI_PMU_EVENT_TYPE_CACHE =3D 0x1, + SBI_PMU_EVENT_TYPE_RAW =3D 0x2, + SBI_PMU_EVENT_TYPE_FW =3D 0xf, +}; + +/* SBI PMU event types */ +enum sbi_pmu_ctr_type { + SBI_PMU_CTR_TYPE_HW =3D 0x0, + SBI_PMU_CTR_TYPE_FW, +}; + +/* Flags defined for config matching function */ +#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0) +#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1) +#define SBI_PMU_CFG_FLAG_AUTO_START (1 << 2) +#define SBI_PMU_CFG_FLAG_SET_VUINH (1 << 3) +#define SBI_PMU_CFG_FLAG_SET_VSNH (1 << 4) +#define SBI_PMU_CFG_FLAG_SET_UINH (1 << 5) +#define SBI_PMU_CFG_FLAG_SET_SINH (1 << 6) +#define SBI_PMU_CFG_FLAG_SET_MINH (1 << 7) + +/* Flags defined for counter start function */ +#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0) + +/* Flags defined for counter stop function */ +#define SBI_PMU_STOP_FLAG_RESET (1 << 0) + #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f @@ -108,6 +201,8 @@ enum sbi_srst_reset_reason { #define SBI_ERR_DENIED -4 #define SBI_ERR_INVALID_ADDRESS -5 #define SBI_ERR_ALREADY_AVAILABLE -6 +#define SBI_ERR_ALREADY_STARTED -7 +#define SBI_ERR_ALREADY_STOPPED -8 =20 extern unsigned long sbi_spec_version; struct sbiret { --=20 2.30.2 From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 039CEC433F5 for ; Sat, 19 Feb 2022 00:47:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240516AbiBSAr7 (ORCPT ); Fri, 18 Feb 2022 19:47:59 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:40510 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240492AbiBSArw (ORCPT ); Fri, 18 Feb 2022 19:47:52 -0500 Received: from mail-oo1-xc32.google.com (mail-oo1-xc32.google.com [IPv6:2607:f8b0:4864:20::c32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 344A427791B for ; Fri, 18 Feb 2022 16:47:25 -0800 (PST) Received: by mail-oo1-xc32.google.com with SMTP id 189-20020a4a03c6000000b003179d7b30d8so5627883ooi.2 for ; Fri, 18 Feb 2022 16:47:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=VGIzIWcYkIdrmW35zeks5wJrTjRccg/bi+P4cXlmL0g=; b=W/W+IoP+iKxq6WWEUtHGQcSwcYCa+NHFbogQdYbW6yW0WVcRY03JnGGvPu2/jfoZ/V 70SyCo6qlPM0yEuCgEVoY0PbBcQFC2pogeb68mJrfd2UxNLoBGkW1R+MjFzq9hcsUSg9 Cr5+E+nbPLzEBjAEYexu0Hw+S+UMBQL3FtYbUZO+FPZSVdQrl9WZHhX7T0Bx3QugG/2p 4EMMurLkFC8AJhX+RLSjDF4MWQXGXhTG21K+xANA3r1C/GEL4s6evZC6LBkZzkqHe8XE GompvOmJImFBWTq9ipjyZo+zbcqOhnxEN4EGfloIihLNlonRBDI1k0KMeIGPjNmP/B9r h9FA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=VGIzIWcYkIdrmW35zeks5wJrTjRccg/bi+P4cXlmL0g=; b=Wxa9hc7K430XEQJiJk5xEMSd/SqFvab1MyRK0IXYPtOSEbsiHxSSnoHrlnjgB7m105 xvOEcAHyJhkwV+BluJst83k/xIMlGTIJL4/SUg329lcxEJhvb7LWIX2fQO3COyOHyyxN 1x3cdYP4aztMl9TEM7bfFJurILUBj5FxE1mrGPAr/zl6OzbW6W/fCyZpI48J7P507ly0 zm/ZKKBCTTdR2wqxugUbwTAol2He288c8HgpTi7SshxlfiYXcDDJwIgFX0TjxydCoByl Wz6Diidk3u46bJ9wCuJnwokZ0hHsvEhtYkSyjB4a7QKF1izRqaXReooP0DpJMQ9ILOPe 7iDg== X-Gm-Message-State: AOAM532KDN6IwMDCq/1PeJ7mfMWjbHXInV75JlaPOC0sZCz0/iKkNHD8 mL7es7W99LCNWC5cObS7mRdB9HZHp3l+o14U X-Google-Smtp-Source: ABdhPJyk8CcA95tsMx7JmGGg6jk2i6oJAVLho3yQIpPtDKTc1jzqQkSHUnq24ntLjCTfSg2oML+nmw== X-Received: by 2002:a05:6870:e60b:b0:d2:bcb7:8641 with SMTP id q11-20020a056870e60b00b000d2bcb78641mr3883348oag.327.1645231644016; Fri, 18 Feb 2022 16:47:24 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:23 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Atish Patra , Anup Patel , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 6/9] RISC-V: Add perf platform driver based on SBI PMU extension Date: Fri, 18 Feb 2022 16:46:57 -0800 Message-Id: <20220219004700.1973682-7-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra RISC-V SBI specification added a PMU extension that allows to configure start/stop any pmu counter. The RISC-V perf can use most of the generic perf features except interrupt overflow and event filtering based on privilege mode which will be added in future. It also allows to monitor a handful of firmware counters that can provide insights into firmware activity during a performance analysis. Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- drivers/perf/Kconfig | 10 + drivers/perf/Makefile | 1 + drivers/perf/riscv_pmu.c | 2 + drivers/perf/riscv_pmu_sbi.c | 578 +++++++++++++++++++++++++++++++++ include/linux/cpuhotplug.h | 1 + include/linux/perf/riscv_pmu.h | 6 +- 6 files changed, 596 insertions(+), 2 deletions(-) create mode 100644 drivers/perf/riscv_pmu_sbi.c diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index 386162ad858a..5645b5615c14 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -76,6 +76,16 @@ config RISCV_PMU_LEGACY of cycle/instruction counter and doesn't support counter overflow, or programmable counters. It will be removed in future. =20 +config RISCV_PMU_SBI + depends on RISCV_PMU && RISCV_SBI + bool "RISC-V PMU based on SBI PMU extension" + default y + help + Say y if you want to use the CPU performance monitor + using SBI PMU extension on RISC-V based systems. This option provides + full perf feature support i.e. counter overflow, privilege mode + filtering, counter configuration. + config ARM_PMU_ACPI depends on ARM_PMU && ACPI def_bool y diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index c3d3268d495b..f149735166e1 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_QCOM_L2_PMU) +=3D qcom_l2_pmu.o obj-$(CONFIG_QCOM_L3_PMU) +=3D qcom_l3_pmu.o obj-$(CONFIG_RISCV_PMU) +=3D riscv_pmu.o obj-$(CONFIG_RISCV_PMU_LEGACY) +=3D riscv_pmu_legacy.o +obj-$(CONFIG_RISCV_PMU_SBI) +=3D riscv_pmu_sbi.o obj-$(CONFIG_THUNDERX2_PMU) +=3D thunderx2_pmu.o obj-$(CONFIG_XGENE_PMU) +=3D xgene_pmu.o obj-$(CONFIG_ARM_SPE_PMU) +=3D arm_spe_pmu.o diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c index 590a5789c128..b2b8d2074ed0 100644 --- a/drivers/perf/riscv_pmu.c +++ b/drivers/perf/riscv_pmu.c @@ -15,6 +15,8 @@ #include #include =20 +#include + static unsigned long csr_read_num(int csr_num) { #define switchcase_csr_read(__csr_num, __val) {\ diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c new file mode 100644 index 000000000000..815d5c509c64 --- /dev/null +++ b/drivers/perf/riscv_pmu_sbi.c @@ -0,0 +1,578 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V performance counter support. + * + * Copyright (C) 2021 Western Digital Corporation or its affiliates. + * + * This code is based on ARM perf event code which is in turn based on + * sparc64 and x86 code. + */ + +#define pr_fmt(fmt) "riscv-pmu-sbi: " fmt + +#include +#include +#include + +#include + +union sbi_pmu_ctr_info { + unsigned long value; + struct { + unsigned long csr:12; + unsigned long width:6; +#if __riscv_xlen =3D=3D 32 + unsigned long reserved:13; +#else + unsigned long reserved:45; +#endif + unsigned long type:1; + }; +}; + +/** + * RISC-V doesn't have hetergenous harts yet. This need to be part of + * per_cpu in case of harts with different pmu counters + */ +static union sbi_pmu_ctr_info *pmu_ctr_list; + +struct sbi_pmu_event_data { + union { + union { + struct hw_gen_event { + uint32_t event_code:16; + uint32_t event_type:4; + uint32_t reserved:12; + } hw_gen_event; + struct hw_cache_event { + uint32_t result_id:1; + uint32_t op_id:2; + uint32_t cache_id:13; + uint32_t event_type:4; + uint32_t reserved:12; + } hw_cache_event; + }; + uint32_t event_idx; + }; +}; + +static const struct sbi_pmu_event_data pmu_hw_event_map[] =3D { + [PERF_COUNT_HW_CPU_CYCLES] =3D {.hw_gen_event =3D { + SBI_PMU_HW_CPU_CYCLES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_INSTRUCTIONS] =3D {.hw_gen_event =3D { + SBI_PMU_HW_INSTRUCTIONS, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_CACHE_REFERENCES] =3D {.hw_gen_event =3D { + SBI_PMU_HW_CACHE_REFERENCES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_CACHE_MISSES] =3D {.hw_gen_event =3D { + SBI_PMU_HW_CACHE_MISSES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =3D {.hw_gen_event =3D { + SBI_PMU_HW_BRANCH_INSTRUCTIONS, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_BRANCH_MISSES] =3D {.hw_gen_event =3D { + SBI_PMU_HW_BRANCH_MISSES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_BUS_CYCLES] =3D {.hw_gen_event =3D { + SBI_PMU_HW_BUS_CYCLES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =3D {.hw_gen_event =3D { + SBI_PMU_HW_STALLED_CYCLES_FRONTEND, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =3D {.hw_gen_event =3D { + SBI_PMU_HW_STALLED_CYCLES_BACKEND, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_REF_CPU_CYCLES] =3D {.hw_gen_event =3D { + SBI_PMU_HW_REF_CPU_CYCLES, + SBI_PMU_EVENT_TYPE_HW, 0}}, +}; + +#define C(x) PERF_COUNT_HW_CACHE_##x +static const struct sbi_pmu_event_data pmu_cache_event_map[PERF_COUNT_HW_C= ACHE_MAX] +[PERF_COUNT_HW_CACHE_OP_MAX] +[PERF_COUNT_HW_CACHE_RESULT_MAX] =3D { + [C(L1D)] =3D { + [C(OP_READ)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_READ), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_READ), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_WRITE), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_WRITE), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_PREFETCH), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_PREFETCH), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(L1I)] =3D { + [C(OP_READ)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_READ), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), C(OP_READ), + C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_WRITE), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_WRITE), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_PREFETCH), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_PREFETCH), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(LL)] =3D { + [C(OP_READ)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_READ), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_READ), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_WRITE), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_WRITE), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_PREFETCH), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_PREFETCH), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(DTLB)] =3D { + [C(OP_READ)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_READ), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_READ), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_WRITE), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_WRITE), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_PREFETCH), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_PREFETCH), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(ITLB)] =3D { + [C(OP_READ)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_READ), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_READ), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_WRITE), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_WRITE), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_PREFETCH), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_PREFETCH), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(BPU)] =3D { + [C(OP_READ)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_READ), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_READ), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_WRITE), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_WRITE), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_PREFETCH), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_PREFETCH), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(NODE)] =3D { + [C(OP_READ)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_READ), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_READ), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_WRITE), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_WRITE), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] =3D { + [C(RESULT_ACCESS)] =3D {.hw_cache_event =3D {C(RESULT_ACCESS), + C(OP_PREFETCH), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] =3D {.hw_cache_event =3D {C(RESULT_MISS), + C(OP_PREFETCH), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, +}; + +static int pmu_sbi_ctr_get_width(int idx) +{ + return pmu_ctr_list[idx].width; +} + +static bool pmu_sbi_ctr_is_fw(int cidx) +{ + union sbi_pmu_ctr_info *info; + + info =3D &pmu_ctr_list[cidx]; + if (!info) + return false; + + return (info->type =3D=3D SBI_PMU_CTR_TYPE_FW) ? true : false; +} + +static int pmu_sbi_ctr_get_idx(struct perf_event *event) +{ + struct hw_perf_event *hwc =3D &event->hw; + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc =3D this_cpu_ptr(rvpmu->hw_events); + struct sbiret ret; + int idx; + uint64_t cbase =3D 0; + uint64_t cmask =3D GENMASK_ULL(rvpmu->num_counters - 1, 0); + unsigned long cflags =3D 0; + + if (event->attr.exclude_kernel) + cflags |=3D SBI_PMU_CFG_FLAG_SET_SINH; + if (event->attr.exclude_user) + cflags |=3D SBI_PMU_CFG_FLAG_SET_UINH; + + /* retrieve the available counter index */ + ret =3D sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, cmas= k, + cflags, hwc->event_base, hwc->config, 0); + if (ret.error) { + pr_debug("Not able to find a counter for event %lx config %llx\n", + hwc->event_base, hwc->config); + return sbi_err_map_linux_errno(ret.error); + } + + idx =3D ret.value; + if (idx >=3D rvpmu->num_counters || !pmu_ctr_list[idx].value) + return -ENOENT; + + /* Additional sanity check for the counter id */ + if (pmu_sbi_ctr_is_fw(idx)) { + if (!test_and_set_bit(idx, cpuc->used_fw_ctrs)) + return idx; + } else { + if (!test_and_set_bit(idx, cpuc->used_hw_ctrs)) + return idx; + } + + return -ENOENT; +} + +static void pmu_sbi_ctr_clear_idx(struct perf_event *event) +{ + + struct hw_perf_event *hwc =3D &event->hw; + struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc =3D this_cpu_ptr(rvpmu->hw_events); + int idx =3D hwc->idx; + + if (pmu_sbi_ctr_is_fw(idx)) + clear_bit(idx, cpuc->used_fw_ctrs); + else + clear_bit(idx, cpuc->used_hw_ctrs); +} + +static int pmu_event_find_cache(u64 config) +{ + unsigned int cache_type, cache_op, cache_result, ret; + + cache_type =3D (config >> 0) & 0xff; + if (cache_type >=3D PERF_COUNT_HW_CACHE_MAX) + return -EINVAL; + + cache_op =3D (config >> 8) & 0xff; + if (cache_op >=3D PERF_COUNT_HW_CACHE_OP_MAX) + return -EINVAL; + + cache_result =3D (config >> 16) & 0xff; + if (cache_result >=3D PERF_COUNT_HW_CACHE_RESULT_MAX) + return -EINVAL; + + ret =3D pmu_cache_event_map[cache_type][cache_op][cache_result].event_idx; + + return ret; +} + +static bool pmu_sbi_is_fw_event(struct perf_event *event) +{ + u32 type =3D event->attr.type; + u64 config =3D event->attr.config; + + if ((type =3D=3D PERF_TYPE_RAW) && ((config >> 63) =3D=3D 1)) + return true; + else + return false; +} + +static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) +{ + u32 type =3D event->attr.type; + u64 config =3D event->attr.config; + int bSoftware; + u64 raw_config_val; + int ret; + + switch (type) { + case PERF_TYPE_HARDWARE: + if (config >=3D PERF_COUNT_HW_MAX) + return -EINVAL; + ret =3D pmu_hw_event_map[event->attr.config].event_idx; + break; + case PERF_TYPE_HW_CACHE: + ret =3D pmu_event_find_cache(config); + break; + case PERF_TYPE_RAW: + /* + * As per SBI specification, the upper 16 bits must be unused for + * a raw event. Use the MSB (63b) to distinguish between hardware + * raw event and firmware events. + */ + bSoftware =3D config >> 63; + raw_config_val =3D config & RISCV_PMU_RAW_EVENT_MASK; + if (bSoftware) { + if (raw_config_val < SBI_PMU_FW_MAX) + ret =3D (raw_config_val & 0xFFFF) | + (SBI_PMU_EVENT_TYPE_FW << 16); + else + return -EINVAL; + } else { + ret =3D RISCV_PMU_RAW_EVENT_IDX; + *econfig =3D raw_config_val; + } + break; + default: + ret =3D -EINVAL; + break; + } + + return ret; +} + +static u64 pmu_sbi_ctr_read(struct perf_event *event) +{ + struct hw_perf_event *hwc =3D &event->hw; + int idx =3D hwc->idx; + struct sbiret ret; + union sbi_pmu_ctr_info info; + u64 val =3D 0; + + if (pmu_sbi_is_fw_event(event)) { + ret =3D sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_FW_READ, + hwc->idx, 0, 0, 0, 0, 0); + if (!ret.error) + val =3D ret.value; + } else { + info =3D pmu_ctr_list[idx]; + val =3D riscv_pmu_ctr_read_csr(info.csr); + if (IS_ENABLED(CONFIG_32BIT)) + val =3D ((u64)riscv_pmu_ctr_read_csr(info.csr + 0x80)) << 31 | val; + } + + return val; +} + +static void pmu_sbi_ctr_start(struct perf_event *event, u64 ival) +{ + struct sbiret ret; + struct hw_perf_event *hwc =3D &event->hw; + unsigned long flag =3D SBI_PMU_START_FLAG_SET_INIT_VALUE; + + ret =3D sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, hwc->idx, + 1, flag, ival, ival >> 32, 0); + if (ret.error && (ret.error !=3D SBI_ERR_ALREADY_STARTED)) + pr_err("Starting counter idx %d failed with error %d\n", + hwc->idx, sbi_err_map_linux_errno(ret.error)); +} + +static void pmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag) +{ + struct sbiret ret; + struct hw_perf_event *hwc =3D &event->hw; + + ret =3D sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, hwc->idx, 1, fla= g, 0, 0, 0); + if (ret.error && (ret.error !=3D SBI_ERR_ALREADY_STOPPED) && + flag !=3D SBI_PMU_STOP_FLAG_RESET) + pr_err("Stopping counter idx %d failed with error %d\n", + hwc->idx, sbi_err_map_linux_errno(ret.error)); +} + +static int pmu_sbi_find_num_ctrs(void) +{ + struct sbiret ret; + + ret =3D sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_NUM_COUNTERS, 0, 0, 0, 0, 0, 0= ); + if (!ret.error) + return ret.value; + else + return sbi_err_map_linux_errno(ret.error); +} + +static int pmu_sbi_get_ctrinfo(int nctr) +{ + struct sbiret ret; + int i, num_hw_ctr =3D 0, num_fw_ctr =3D 0; + union sbi_pmu_ctr_info cinfo; + + pmu_ctr_list =3D kcalloc(nctr, sizeof(*pmu_ctr_list), GFP_KERNEL); + if (!pmu_ctr_list) + return -ENOMEM; + + for (i =3D 0; i <=3D nctr; i++) { + ret =3D sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_GET_INFO, i, 0, 0, 0,= 0, 0); + if (ret.error) + /* The logical counter ids are not expected to be contiguous */ + continue; + cinfo.value =3D ret.value; + if (cinfo.type =3D=3D SBI_PMU_CTR_TYPE_FW) + num_fw_ctr++; + else + num_hw_ctr++; + pmu_ctr_list[i].value =3D cinfo.value; + } + + pr_info("%d firmware and %d hardware counters\n", num_fw_ctr, num_hw_ctr); + + return 0; +} + +static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct riscv_pmu *pmu =3D hlist_entry_safe(node, struct riscv_pmu, node); + + /* Enable the access for TIME csr only from the user mode now */ + csr_write(CSR_SCOUNTEREN, 0x2); + + /* Stop all the counters so that they can be enabled from perf */ + sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, + 0, GENMASK_ULL(pmu->num_counters - 1, 0), 0, 0, 0, 0); + + return 0; +} + +static int pmu_sbi_dying_cpu(unsigned int cpu, struct hlist_node *node) +{ + /* Disable all counters access for user mode now */ + csr_write(CSR_SCOUNTEREN, 0x0); + + return 0; +} + +static int pmu_sbi_device_probe(struct platform_device *pdev) +{ + struct riscv_pmu *pmu =3D NULL; + int num_counters; + int ret; + + pr_info("SBI PMU extension is available\n"); + pmu =3D riscv_pmu_alloc(); + if (!pmu) + return -ENOMEM; + + num_counters =3D pmu_sbi_find_num_ctrs(); + if (num_counters < 0) { + pr_err("SBI PMU extension doesn't provide any counters\n"); + return -ENODEV; + } + + /* cache all the information about counters now */ + if (pmu_sbi_get_ctrinfo(num_counters)) + return -ENODEV; + + pmu->num_counters =3D num_counters; + pmu->ctr_start =3D pmu_sbi_ctr_start; + pmu->ctr_stop =3D pmu_sbi_ctr_stop; + pmu->event_map =3D pmu_sbi_event_map; + pmu->ctr_get_idx =3D pmu_sbi_ctr_get_idx; + pmu->ctr_get_width =3D pmu_sbi_ctr_get_width; + pmu->ctr_clear_idx =3D pmu_sbi_ctr_clear_idx; + pmu->ctr_read =3D pmu_sbi_ctr_read; + + ret =3D cpuhp_state_add_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node= ); + if (ret) + return ret; + + ret =3D perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW); + if (ret) { + cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node); + return ret; + } + + return 0; +} + +static struct platform_driver pmu_sbi_driver =3D { + .probe =3D pmu_sbi_device_probe, + .driver =3D { + .name =3D RISCV_PMU_PDEV_NAME, + }, +}; + +static int __init pmu_sbi_devinit(void) +{ + int ret; + struct platform_device *pdev; + + if (sbi_spec_version < sbi_mk_version(0, 3) || + sbi_probe_extension(SBI_EXT_PMU) <=3D 0) { + return 0; + } + + ret =3D cpuhp_setup_state_multi(CPUHP_AP_PERF_RISCV_STARTING, + "perf/riscv/pmu:starting", + pmu_sbi_starting_cpu, pmu_sbi_dying_cpu); + if (ret) { + pr_err("CPU hotplug notifier could not be registered: %d\n", + ret); + return ret; + } + + ret =3D platform_driver_register(&pmu_sbi_driver); + if (ret) + return ret; + + pdev =3D platform_device_register_simple(RISCV_PMU_PDEV_NAME, -1, NULL, 0= ); + if (IS_ERR(pdev)) { + platform_driver_unregister(&pmu_sbi_driver); + return PTR_ERR(pdev); + } + + /* Notify legacy implementation that SBI pmu is available*/ + riscv_pmu_legacy_skip_init(); + + return ret; +} +device_initcall(pmu_sbi_devinit) diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 411a428ace4d..51c7e4929df7 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -165,6 +165,7 @@ enum cpuhp_state { CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING, CPUHP_AP_PERF_ARM_ACPI_STARTING, CPUHP_AP_PERF_ARM_STARTING, + CPUHP_AP_PERF_RISCV_STARTING, CPUHP_AP_ARM_L2X0_STARTING, CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING, CPUHP_AP_ARM_ARCH_TIMER_STARTING, diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 9140c491fc54..0f226948c0ca 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -31,8 +31,10 @@ struct cpu_hw_events { int n_events; /* currently enabled events */ struct perf_event *events[RISCV_MAX_COUNTERS]; - /* currently enabled counters */ - DECLARE_BITMAP(used_event_ctrs, RISCV_MAX_COUNTERS); + /* currently enabled hardware counters */ + DECLARE_BITMAP(used_hw_ctrs, RISCV_MAX_COUNTERS); + /* currently enabled firmware counters */ + DECLARE_BITMAP(used_fw_ctrs, RISCV_MAX_COUNTERS); }; =20 struct riscv_pmu { --=20 2.30.2 From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 820B1C433EF for ; Sat, 19 Feb 2022 00:47:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238710AbiBSAsL (ORCPT ); Fri, 18 Feb 2022 19:48:11 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:40524 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240496AbiBSArw (ORCPT ); Fri, 18 Feb 2022 19:47:52 -0500 Received: from mail-oo1-xc31.google.com (mail-oo1-xc31.google.com [IPv6:2607:f8b0:4864:20::c31]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B524E27792B for ; Fri, 18 Feb 2022 16:47:26 -0800 (PST) Received: by mail-oo1-xc31.google.com with SMTP id x6-20020a4a4106000000b003193022319cso5609888ooa.4 for ; Fri, 18 Feb 2022 16:47:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=nd4vYxhtOAlUcUpptoKmnAI88shl1K2lARFMdYN/LgM=; b=NVVK+u+2VjbDv29XdP0Dvb/TIjxLj7ZpRacQuSgFesWinC0Hx+VEtVXW73NItWYsAA am3PJZbm9N09vc2km7JE3VACBfixCGDY6wYiAxuzckhQI6dJLNRubzEASRQJ4mhiqqVv PnMFsbBGeRPBzLx8rRvCP5Rw5N2yFDR4ebVJ1KLVhPoJq6EuuH4GBCeHRLrxXXe3yv9P vrwQbfs0h+c0bVIAm8VGhPUuXekGpknOW6hOvUoq0dAyYpD6Ouv5KKwe3C41RBFPEJqv FOuQfzwkK1E+O1hzFA0I6bAE2Ki2D4P1iyWrjrJLJei87P/BXA33sgwULF54A8Ep4Wat +bUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=nd4vYxhtOAlUcUpptoKmnAI88shl1K2lARFMdYN/LgM=; b=GvagdpS/i2rz56oLk+704nLo/Eu0TLvZiWHH/clR+AwWvZ94egq2tVmVB2MIgk0/Ng 2yeE+LzmwRzt9zlUNSx/UzU1foAmOblunid0z5PP1z0Yj5j7GmqAck242sAzJ7MVbPZH 0UY6tcoAvvgiSCMI/+++r1qnZZSxhy0r0xdJNuyPim/MB2ts6sl/omJpY+Nk8TldO99s +TVek73mJrnrkNC2BQ9AAUbaCrbU+bzXkwT2qDp6A+S2axa9zCBwcTiFGfrqwDKCN1PF J4ePsRDmm7eEhQz3+84GpThk4QwSIuwmiImOKRoWb5Ie6WtV/EKZ/4od4xKSZVyueF3T GrgQ== X-Gm-Message-State: AOAM530rGTAdjrjGkLtk9oGZzCeZgOhRqOCs7RxpHBlWEgWauOkKPUMs AzwJc2LaotCNAGOL5WeRP288rMziR/gLc36H X-Google-Smtp-Source: ABdhPJz49tLu9krZGg7hBtKQ/28otwliM6uBgDz2MPXK3bVqvHaUkOBpMGxeOO0JpMAOv/vJdyrM9w== X-Received: by 2002:a05:6870:1015:b0:ce:c0c9:5d2 with SMTP id 21-20020a056870101500b000cec0c905d2mr5174837oai.36.1645231645708; Fri, 18 Feb 2022 16:47:25 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:25 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Atish Patra , Anup Patel , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 7/9] RISC-V: Add sscofpmf extension support Date: Fri, 18 Feb 2022 16:46:58 -0800 Message-Id: <20220219004700.1973682-8-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra The sscofpmf extension allows counter overflow and filtering for programmable counters. Enable the perf driver to handle the overflow interrupt. The overflow interrupt is a hart local interrupt. Thus, per cpu overflow interrupts are setup as a child under the root INTC irq domain. Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- arch/riscv/include/asm/csr.h | 8 +- arch/riscv/include/asm/hwcap.h | 1 + arch/riscv/kernel/cpu.c | 1 + arch/riscv/kernel/cpufeature.c | 2 + drivers/perf/riscv_pmu_sbi.c | 222 ++++++++++++++++++++++++++++++++- include/linux/perf/riscv_pmu.h | 2 + 6 files changed, 230 insertions(+), 6 deletions(-) diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index ce493df11177..8b2e48077731 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -65,6 +65,7 @@ #define IRQ_S_EXT 9 #define IRQ_VS_EXT 10 #define IRQ_M_EXT 11 +#define IRQ_PMU_OVF 13 =20 /* Exception causes */ #define EXC_INST_MISALIGNED 0 @@ -212,6 +213,8 @@ #define CSR_HPMCOUNTER30H 0xc9e #define CSR_HPMCOUNTER31H 0xc9f =20 +#define CSR_SSCOUNTOVF 0xda0 + #define CSR_SSTATUS 0x100 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 @@ -298,7 +301,10 @@ # define RV_IRQ_SOFT IRQ_S_SOFT # define RV_IRQ_TIMER IRQ_S_TIMER # define RV_IRQ_EXT IRQ_S_EXT -#endif /* CONFIG_RISCV_M_MODE */ +# define RV_IRQ_PMU IRQ_PMU_OVF +# define SIP_LCOFIP (_AC(0x1, UL) << IRQ_PMU_OVF) + +#endif /* !CONFIG_RISCV_M_MODE */ =20 /* IE/IP (Supervisor/Machine Interrupt Enable/Pending) flags */ #define IE_SIE (_AC(0x1, UL) << RV_IRQ_SOFT) diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index 691fc9c8099b..0734e42f74f2 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -51,6 +51,7 @@ extern unsigned long elf_hwcap; * available logical extension id. */ enum riscv_isa_ext_id { + RISCV_ISA_EXT_SSCOFPMF =3D RISCV_ISA_EXT_BASE, RISCV_ISA_EXT_ID_MAX =3D RISCV_ISA_EXT_MAX, }; =20 diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index ced7e5be8641..2b212b10a5a8 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -71,6 +71,7 @@ int riscv_of_parent_hartid(struct device_node *node) } =20 static struct riscv_isa_ext_data isa_ext_arr[] =3D { + __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), __RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX), }; =20 diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index cb9c9e0aab31..eabf82ac53ea 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -187,6 +187,8 @@ void __init riscv_fill_hwcap(void) if (!ext_long) { this_hwcap |=3D isa2hwcap[(unsigned char)(*ext)]; set_bit(*ext - 'a', this_isa); + } else { + SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF); } #undef SET_ISA_EXT_MAP } diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 815d5c509c64..a1317a483512 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -13,8 +13,13 @@ #include #include #include +#include +#include +#include +#include =20 #include +#include =20 union sbi_pmu_ctr_info { unsigned long value; @@ -35,6 +40,7 @@ union sbi_pmu_ctr_info { * per_cpu in case of harts with different pmu counters */ static union sbi_pmu_ctr_info *pmu_ctr_list; +static unsigned int riscv_pmu_irq; =20 struct sbi_pmu_event_data { union { @@ -469,33 +475,229 @@ static int pmu_sbi_get_ctrinfo(int nctr) return 0; } =20 +static inline void pmu_sbi_stop_all(struct riscv_pmu *pmu) +{ + /** + * No need to check the error because we are disabling all the counters + * which may include counters that are not enabled yet. + */ + sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, + 0, GENMASK_ULL(pmu->num_counters - 1, 0), 0, 0, 0, 0); +} + +static inline void pmu_sbi_stop_hw_ctrs(struct riscv_pmu *pmu) +{ + struct cpu_hw_events *cpu_hw_evt =3D this_cpu_ptr(pmu->hw_events); + + /* No need to check the error here as we can't do anything about the erro= r */ + sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, 0, + cpu_hw_evt->used_hw_ctrs[0], 0, 0, 0, 0); +} + +/** + * This function starts all the used counters in two step approach. + * Any counter that did not overflow can be start in a single step + * while the overflowed counters need to be started with updated initializ= ation + * value. + */ +static inline void pmu_sbi_start_overflow_mask(struct riscv_pmu *pmu, + unsigned long ctr_ovf_mask) +{ + int idx =3D 0; + struct cpu_hw_events *cpu_hw_evt =3D this_cpu_ptr(pmu->hw_events); + struct perf_event *event; + unsigned long flag =3D SBI_PMU_START_FLAG_SET_INIT_VALUE; + unsigned long ctr_start_mask =3D 0; + uint64_t max_period; + struct hw_perf_event *hwc; + u64 init_val =3D 0; + + ctr_start_mask =3D cpu_hw_evt->used_hw_ctrs[0] & ~ctr_ovf_mask; + + /* Start all the counters that did not overflow in a single shot */ + sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, 0, ctr_start_mask, + 0, 0, 0, 0); + + /* Reinitialize and start all the counter that overflowed */ + while (ctr_ovf_mask) { + if (ctr_ovf_mask & 0x01) { + event =3D cpu_hw_evt->events[idx]; + hwc =3D &event->hw; + max_period =3D riscv_pmu_ctr_get_width_mask(event); + init_val =3D local64_read(&hwc->prev_count) & max_period; + sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, idx, 1, + flag, init_val, 0, 0); + } + ctr_ovf_mask =3D ctr_ovf_mask >> 1; + idx++; + } +} + +static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev) +{ + struct perf_sample_data data; + struct pt_regs *regs; + struct hw_perf_event *hw_evt; + union sbi_pmu_ctr_info *info; + int lidx, hidx, fidx; + struct riscv_pmu *pmu; + struct perf_event *event; + unsigned long overflow; + unsigned long overflowed_ctrs =3D 0; + struct cpu_hw_events *cpu_hw_evt =3D dev; + + if (WARN_ON_ONCE(!cpu_hw_evt)) + return IRQ_NONE; + + /* Firmware counter don't support overflow yet */ + fidx =3D find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS); + event =3D cpu_hw_evt->events[fidx]; + if (!event) { + csr_clear(CSR_SIP, SIP_LCOFIP); + return IRQ_NONE; + } + + pmu =3D to_riscv_pmu(event->pmu); + pmu_sbi_stop_hw_ctrs(pmu); + + /* Overflow status register should only be read after counter are stopped= */ + overflow =3D csr_read(CSR_SSCOUNTOVF); + + /** + * Overflow interrupt pending bit should only be cleared after stopping + * all the counters to avoid any race condition. + */ + csr_clear(CSR_SIP, SIP_LCOFIP); + + /* No overflow bit is set */ + if (!overflow) + return IRQ_NONE; + + regs =3D get_irq_regs(); + + for_each_set_bit(lidx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) { + struct perf_event *event =3D cpu_hw_evt->events[lidx]; + + /* Skip if invalid event or user did not request a sampling */ + if (!event || !is_sampling_event(event)) + continue; + + info =3D &pmu_ctr_list[lidx]; + /* Do a sanity check */ + if (!info || info->type !=3D SBI_PMU_CTR_TYPE_HW) + continue; + + /* compute hardware counter index */ + hidx =3D info->csr - CSR_CYCLE; + /* check if the corresponding bit is set in sscountovf */ + if (!(overflow & (1 << hidx))) + continue; + + /* + * Keep a track of overflowed counters so that they can be started + * with updated initial value. + */ + overflowed_ctrs |=3D 1 << lidx; + hw_evt =3D &event->hw; + riscv_pmu_event_update(event); + perf_sample_data_init(&data, 0, hw_evt->last_period); + if (riscv_pmu_event_set_period(event)) { + /* + * Unlike other ISAs, RISC-V don't have to disable interrupts + * to avoid throttling here. As per the specification, the + * interrupt remains disabled until the OF bit is set. + * Interrupts are enabled again only during the start. + * TODO: We will need to stop the guest counters once + * virtualization support is added. + */ + perf_event_overflow(event, &data, regs); + } + } + pmu_sbi_start_overflow_mask(pmu, overflowed_ctrs); + + return IRQ_HANDLED; +} + static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node) { struct riscv_pmu *pmu =3D hlist_entry_safe(node, struct riscv_pmu, node); + struct cpu_hw_events *cpu_hw_evt =3D this_cpu_ptr(pmu->hw_events); =20 /* Enable the access for TIME csr only from the user mode now */ csr_write(CSR_SCOUNTEREN, 0x2); =20 /* Stop all the counters so that they can be enabled from perf */ - sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, - 0, GENMASK_ULL(pmu->num_counters - 1, 0), 0, 0, 0, 0); + pmu_sbi_stop_all(pmu); + + if (riscv_isa_extension_available(NULL, SSCOFPMF)) { + cpu_hw_evt->irq =3D riscv_pmu_irq; + csr_clear(CSR_IP, BIT(RV_IRQ_PMU)); + csr_set(CSR_IE, BIT(RV_IRQ_PMU)); + enable_percpu_irq(riscv_pmu_irq, IRQ_TYPE_NONE); + } =20 return 0; } =20 static int pmu_sbi_dying_cpu(unsigned int cpu, struct hlist_node *node) { + if (riscv_isa_extension_available(NULL, SSCOFPMF)) { + disable_percpu_irq(riscv_pmu_irq); + csr_clear(CSR_IE, BIT(RV_IRQ_PMU)); + } + /* Disable all counters access for user mode now */ csr_write(CSR_SCOUNTEREN, 0x0); =20 return 0; } =20 +static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_devic= e *pdev) +{ + int ret; + struct cpu_hw_events __percpu *hw_events =3D pmu->hw_events; + struct device_node *cpu, *child; + struct irq_domain *domain =3D NULL; + + if (!riscv_isa_extension_available(NULL, SSCOFPMF)) + return -EOPNOTSUPP; + + for_each_of_cpu_node(cpu) { + child =3D of_get_compatible_child(cpu, "riscv,cpu-intc"); + if (!child) { + pr_err("Failed to find INTC node\n"); + return -ENODEV; + } + domain =3D irq_find_host(child); + of_node_put(child); + if (domain) + break; + } + if (!domain) { + pr_err("Failed to find INTC IRQ root domain\n"); + return -ENODEV; + } + + riscv_pmu_irq =3D irq_create_mapping(domain, RV_IRQ_PMU); + if (!riscv_pmu_irq) { + pr_err("Failed to map PMU interrupt for node\n"); + return -ENODEV; + } + + ret =3D request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu= ", hw_events); + if (ret) { + pr_err("registering percpu irq failed [%d]\n", ret); + return ret; + } + + return 0; +} + static int pmu_sbi_device_probe(struct platform_device *pdev) { struct riscv_pmu *pmu =3D NULL; int num_counters; - int ret; + int ret =3D -ENODEV; =20 pr_info("SBI PMU extension is available\n"); pmu =3D riscv_pmu_alloc(); @@ -505,13 +707,19 @@ static int pmu_sbi_device_probe(struct platform_devic= e *pdev) num_counters =3D pmu_sbi_find_num_ctrs(); if (num_counters < 0) { pr_err("SBI PMU extension doesn't provide any counters\n"); - return -ENODEV; + goto out_free; } =20 /* cache all the information about counters now */ if (pmu_sbi_get_ctrinfo(num_counters)) - return -ENODEV; + goto out_free; =20 + ret =3D pmu_sbi_setup_irqs(pmu, pdev); + if (ret < 0) { + pr_info("Perf sampling/filtering is not supported as sscof extension is = not available\n"); + pmu->pmu.capabilities |=3D PERF_PMU_CAP_NO_INTERRUPT; + pmu->pmu.capabilities |=3D PERF_PMU_CAP_NO_EXCLUDE; + } pmu->num_counters =3D num_counters; pmu->ctr_start =3D pmu_sbi_ctr_start; pmu->ctr_stop =3D pmu_sbi_ctr_stop; @@ -532,6 +740,10 @@ static int pmu_sbi_device_probe(struct platform_device= *pdev) } =20 return 0; + +out_free: + kfree(pmu); + return ret; } =20 static struct platform_driver pmu_sbi_driver =3D { diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 0f226948c0ca..46f9b6fe306e 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -29,6 +29,8 @@ struct cpu_hw_events { /* currently enabled events */ int n_events; + /* Counter overflow interrupt */ + int irq; /* currently enabled events */ struct perf_event *events[RISCV_MAX_COUNTERS]; /* currently enabled hardware counters */ --=20 2.30.2 From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 282E9C433F5 for ; Sat, 19 Feb 2022 00:47:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240524AbiBSAsD (ORCPT ); Fri, 18 Feb 2022 19:48:03 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:40532 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240498AbiBSArw (ORCPT ); Fri, 18 Feb 2022 19:47:52 -0500 Received: from mail-oi1-x22e.google.com (mail-oi1-x22e.google.com [IPv6:2607:f8b0:4864:20::22e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9AFA5278280 for ; Fri, 18 Feb 2022 16:47:28 -0800 (PST) Received: by mail-oi1-x22e.google.com with SMTP id ay7so4875476oib.8 for ; Fri, 18 Feb 2022 16:47:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=jDfjdd5QvoMIvAgiJmvJKZ7Z4Plwg6BPMXyfZ+uY2oQ=; b=rSWElPPAAV/8oZ7K7A+3n23TbYEU4TOoNRpAAB1eZKQ8IIuAu/H1hJh8AI/7wiZj56 vGddnwdzJIKsSEREmI845CyCoZda+afAGfZPERUIdDdKAEPsn62EGwVGdy1m5s7zO1bc pR46KHk4WFVkthpS3z5lTLuYO9RW2UJsxxEagSvGrdqyxX8m1NynJ/2+GZ7TCqiWyqdM i3pPJnHnKAsTnU5R3Y6zLT1eaqqJjSkr3ml5XU2R6JgkgjjcotctGySL/llHwQDFgUzX uZADWN1kj0cuUzarcK1kZDGN+ORVygBpoxlQ3djCiVsGvUXTynOsqrMss73oTxE0UHMh BjHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=jDfjdd5QvoMIvAgiJmvJKZ7Z4Plwg6BPMXyfZ+uY2oQ=; b=C+3Kmlfl08XJRTkYu8MRo0734BJNQb0hV4/NFSBfEEv9Ess1xHPPg8q1+ch8EnsabI C8mGWGbIGiTs9aTvGlq80UFp3hR1hjzX/+Ca82ju2gvR0x0zMl3aBsHUHMPDstwJbrw6 XJmTywcY2CLtD4aTMlGyogRhVQPhCm28SAR9KsdKnsfWdbAgyaXorNI6OK8zOdTTEkGN 1/pYgnamc8QuA9f+1XH5BuQyRv2GSuLDwd040zaSdWUJqVA6bIR0smPZvvkWBld5RCbT tlShSLETOMNxc4VtMcT143tLJ0UYS2JzrW+SoTifQjGx/xq6V9j2Z8ZHuka00OCr2S9w i7Lg== X-Gm-Message-State: AOAM533041n0LOX8rF85VWNW4Mj7iIfU6SCb8CKc9DoVV1zW62PiKDnE Rh1k7XRQr8LFuM1qKixXb6dEQ7zQreLRzPL6 X-Google-Smtp-Source: ABdhPJyEUjqGS4+dDHQtra5YXjyGLUROgshy+1M2zQOq2bLYjDgIbvc7OByOgrQ3sheHBQi4Qt87Gg== X-Received: by 2002:aca:5d57:0:b0:2ca:b411:1189 with SMTP id r84-20020aca5d57000000b002cab4111189mr6065602oib.77.1645231647396; Fri, 18 Feb 2022 16:47:27 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:26 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Anup Patel , Atish Patra , Albert Ou , Atish Patra , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 8/9] Documentation: riscv: Remove the old documentation Date: Fri, 18 Feb 2022 16:46:59 -0800 Message-Id: <20220219004700.1973682-9-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra The existing pmu documentation describes the limitation of perf infrastructure in RISC-V ISA and limited feature set of perf in RISC-V. However, SBI PMU extension and sscofpmf extension(ISA extension) allows to implement most of the required features of perf. Remove the old documentation which is not accurate anymore. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- Documentation/riscv/pmu.rst | 255 ------------------------------------ 1 file changed, 255 deletions(-) delete mode 100644 Documentation/riscv/pmu.rst diff --git a/Documentation/riscv/pmu.rst b/Documentation/riscv/pmu.rst deleted file mode 100644 index acb216b99c26..000000000000 --- a/Documentation/riscv/pmu.rst +++ /dev/null @@ -1,255 +0,0 @@ -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D -Supporting PMUs on RISC-V platforms -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - -Alan Kao , Mar 2018 - -Introduction ------------- - -As of this writing, perf_event-related features mentioned in The RISC-V ISA -Privileged Version 1.10 are as follows: -(please check the manual for more details) - -* [m|s]counteren -* mcycle[h], cycle[h] -* minstret[h], instret[h] -* mhpeventx, mhpcounterx[h] - -With such function set only, porting perf would require a lot of work, due= to -the lack of the following general architectural performance monitoring fea= tures: - -* Enabling/Disabling counters - Counters are just free-running all the time in our case. -* Interrupt caused by counter overflow - No such feature in the spec. -* Interrupt indicator - It is not possible to have many interrupt ports for all counters, so an - interrupt indicator is required for software to tell which counter has - just overflowed. -* Writing to counters - There will be an SBI to support this since the kernel cannot modify the - counters [1]. Alternatively, some vendor considers to implement - hardware-extension for M-S-U model machines to write counters directly. - -This document aims to provide developers a quick guide on supporting their -PMUs in the kernel. The following sections briefly explain perf' mechanism -and todos. - -You may check previous discussions here [1][2]. Also, it might be helpful -to check the appendix for related kernel structures. - - -1. Initialization ------------------ - -*riscv_pmu* is a global pointer of type *struct riscv_pmu*, which contains -various methods according to perf's internal convention and PMU-specific -parameters. One should declare such instance to represent the PMU. By de= fault, -*riscv_pmu* points to a constant structure *riscv_base_pmu*, which has very -basic support to a baseline QEMU model. - -Then he/she can either assign the instance's pointer to *riscv_pmu* so that -the minimal and already-implemented logic can be leveraged, or invent his/= her -own *riscv_init_platform_pmu* implementation. - -In other words, existing sources of *riscv_base_pmu* merely provide a -reference implementation. Developers can flexibly decide how many parts t= hey -can leverage, and in the most extreme case, they can customize every funct= ion -according to their needs. - - -2. Event Initialization ------------------------ - -When a user launches a perf command to monitor some events, it is first -interpreted by the userspace perf tool into multiple *perf_event_open* -system calls, and then each of them calls to the body of *event_init* -member function that was assigned in the previous step. In *riscv_base_pm= u*'s -case, it is *riscv_event_init*. - -The main purpose of this function is to translate the event provided by us= er -into bitmap, so that HW-related control registers or counters can directly= be -manipulated. The translation is based on the mappings and methods provide= d in -*riscv_pmu*. - -Note that some features can be done in this stage as well: - -(1) interrupt setting, which is stated in the next section; -(2) privilege level setting (user space only, kernel space only, both); -(3) destructor setting. Normally it is sufficient to apply *riscv_destroy= _event*; -(4) tweaks for non-sampling events, which will be utilized by functions su= ch as - *perf_adjust_period*, usually something like the follows:: - - if (!is_sampling_event(event)) { - hwc->sample_period =3D x86_pmu.max_period; - hwc->last_period =3D hwc->sample_period; - local64_set(&hwc->period_left, hwc->sample_period); - } - -In the case of *riscv_base_pmu*, only (3) is provided for now. - - -3. Interrupt ------------- - -3.1. Interrupt Initialization - -This often occurs at the beginning of the *event_init* method. In common -practice, this should be a code segment like:: - - int x86_reserve_hardware(void) - { - int err =3D 0; - - if (!atomic_inc_not_zero(&pmc_refcount)) { - mutex_lock(&pmc_reserve_mutex); - if (atomic_read(&pmc_refcount) =3D=3D 0) { - if (!reserve_pmc_hardware()) - err =3D -EBUSY; - else - reserve_ds_buffers(); - } - if (!err) - atomic_inc(&pmc_refcount); - mutex_unlock(&pmc_reserve_mutex); - } - - return err; - } - -And the magic is in *reserve_pmc_hardware*, which usually does atomic -operations to make implemented IRQ accessible from some global function po= inter. -*release_pmc_hardware* serves the opposite purpose, and it is used in event -destructors mentioned in previous section. - -(Note: From the implementations in all the architectures, the *reserve/rel= ease* -pair are always IRQ settings, so the *pmc_hardware* seems somehow misleadi= ng. -It does NOT deal with the binding between an event and a physical counter, -which will be introduced in the next section.) - -3.2. IRQ Structure - -Basically, a IRQ runs the following pseudo code:: - - for each hardware counter that triggered this overflow - - get the event of this counter - - // following two steps are defined as *read()*, - // check the section Reading/Writing Counters for details. - count the delta value since previous interrupt - update the event->count (# event occurs) by adding delta, and - event->hw.period_left by subtracting delta - - if the event overflows - sample data - set the counter appropriately for the next overflow - - if the event overflows again - too frequently, throttle this event - fi - fi - - end for - -However as of this writing, none of the RISC-V implementations have design= ed an -interrupt for perf, so the details are to be completed in the future. - -4. Reading/Writing Counters ---------------------------- - -They seem symmetric but perf treats them quite differently. For reading, = there -is a *read* interface in *struct pmu*, but it serves more than just readin= g. -According to the context, the *read* function not only reads the content o= f the -counter (event->count), but also updates the left period to the next inter= rupt -(event->hw.period_left). - -But the core of perf does not need direct write to counters. Writing coun= ters -is hidden behind the abstraction of 1) *pmu->start*, literally start count= ing so one -has to set the counter to a good value for the next interrupt; 2) inside t= he IRQ -it should set the counter to the same resonable value. - -Reading is not a problem in RISC-V but writing would need some effort, sin= ce -counters are not allowed to be written by S-mode. - - -5. add()/del()/start()/stop() ------------------------------ - -Basic idea: add()/del() adds/deletes events to/from a PMU, and start()/sto= p() -starts/stop the counter of some event in the PMU. All of them take the sa= me -arguments: *struct perf_event *event* and *int flag*. - -Consider perf as a state machine, then you will find that these functions = serve -as the state transition process between those states. -Three states (event->hw.state) are defined: - -* PERF_HES_STOPPED: the counter is stopped -* PERF_HES_UPTODATE: the event->count is up-to-date -* PERF_HES_ARCH: arch-dependent usage ... we don't need this for now - -A normal flow of these state transitions are as follows: - -* A user launches a perf event, resulting in calling to *event_init*. -* When being context-switched in, *add* is called by the perf core, with a= flag - PERF_EF_START, which means that the event should be started after it is = added. - At this stage, a general event is bound to a physical counter, if any. - The state changes to PERF_HES_STOPPED and PERF_HES_UPTODATE, because it = is now - stopped, and the (software) event count does not need updating. - - - *start* is then called, and the counter is enabled. - With flag PERF_EF_RELOAD, it writes an appropriate value to the counte= r (check - previous section for detail). - Nothing is written if the flag does not contain PERF_EF_RELOAD. - The state now is reset to none, because it is neither stopped nor upda= ted - (the counting already started) - -* When being context-switched out, *del* is called. It then checks out al= l the - events in the PMU and calls *stop* to update their counts. - - - *stop* is called by *del* - and the perf core with flag PERF_EF_UPDATE, and it often shares the sa= me - subroutine as *read* with the same logic. - The state changes to PERF_HES_STOPPED and PERF_HES_UPTODATE, again. - - - Life cycle of these two pairs: *add* and *del* are called repeatedly as - tasks switch in-and-out; *start* and *stop* is also called when the pe= rf core - needs a quick stop-and-start, for instance, when the interrupt period = is being - adjusted. - -Current implementation is sufficient for now and can be easily extended to -features in the future. - -A. Related Structures ---------------------- - -* struct pmu: include/linux/perf_event.h -* struct riscv_pmu: arch/riscv/include/asm/perf_event.h - - Both structures are designed to be read-only. - - *struct pmu* defines some function pointer interfaces, and most of them = take - *struct perf_event* as a main argument, dealing with perf events accordi= ng to - perf's internal state machine (check kernel/events/core.c for details). - - *struct riscv_pmu* defines PMU-specific parameters. The naming follows = the - convention of all other architectures. - -* struct perf_event: include/linux/perf_event.h -* struct hw_perf_event - - The generic structure that represents perf events, and the hardware-rela= ted - details. - -* struct riscv_hw_events: arch/riscv/include/asm/perf_event.h - - The structure that holds the status of events, has two fixed members: - the number of events and the array of the events. - -References ----------- - -[1] https://github.com/riscv/riscv-linux/pull/124 - -[2] https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/f19T= mCNP6yA --=20 2.30.2 From nobody Sat Jun 27 21:23:35 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 97D0FC433EF for ; Sat, 19 Feb 2022 00:47:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240527AbiBSAsI (ORCPT ); Fri, 18 Feb 2022 19:48:08 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:40544 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240501AbiBSArw (ORCPT ); Fri, 18 Feb 2022 19:47:52 -0500 Received: from mail-oi1-x22b.google.com (mail-oi1-x22b.google.com [IPv6:2607:f8b0:4864:20::22b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 06574278284 for ; Fri, 18 Feb 2022 16:47:30 -0800 (PST) Received: by mail-oi1-x22b.google.com with SMTP id k2so1125045oia.2 for ; Fri, 18 Feb 2022 16:47:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=c/0FNgv5lUN8jWi4HV9B3F/rz6WuSHsRs+ZuBRv8FFI=; b=ZiY0wwJ0SqisQuu6ArfKe03xg+2W+PovMKQyGMyksKruK698BV0tgUOmJQQczbB4Xy es5RPo++t4bQEgF6wzMapiJTWPReNgRTwNNnnpyDJCfbCrFvTWOcPHowU1Vwl23ky6QG DLN4/uaRUwaGd6Uiy3y+l0wMQJpMBa9ezEV3oMztup72dpEC+uY7NTrt5/fnJI8q9SwT XepPFmnUClJGgK/xmhL+gQhVMQdh5nP1IFVL0PN3g01vJ0kc/FXov1ooooas1J6O8XfN UX3AvR6/Kpz7g0WdEIyp4lPJ9SKAa2nSDYRPLrxuhBE571zxzuyKjTZXPQkW8/0ZFDVF Btqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=c/0FNgv5lUN8jWi4HV9B3F/rz6WuSHsRs+ZuBRv8FFI=; b=WCTwSz9wrCE0hVvwW8r9bcr6KS64qMGHNaq+ByIjKHZAhydXwCyJ+NnQ72GORRBDvk 8/W4QsmB7KvqVQ4ci1zisW2y7lmvfhS0DkxjAVM/uOZttymgLJfk88VY4a5WJ7kgPjf/ NjmrR0Nn4l07QSv5gZOdMGvTywdt24OyjX83mq1lzwZo7ut+t2wS7bGW4vsl2lvDCbCQ 2hjVbRH8ZzFOvGryR/4th7aQ+0gO3JRgThX29MmRYBRa4dJCBNIF8ei+pkBgqIfDqhdY iBY2sLTgbyMwV1OrUYYIvyrRy9yE+oAGqsNBU+NDPrYGEgC72s3EwplLCZ9CR72GVSz2 vpGw== X-Gm-Message-State: AOAM530WzezfVV6/qFaJ/O5xdVtZHZFjPLQUAb79+rkJ0Ga1aSt6oFxj xcSdAJrhIZhMK2+oWImjgew4s3TD0OsxiwE+ X-Google-Smtp-Source: ABdhPJzRQen7NvHhjcQNsc8zdzkieqqweNi8Zrd2NfXxhR0scCdRCj2ZIJPPYhXkW27QcvKyFYXfyg== X-Received: by 2002:a05:6808:190f:b0:2d4:b3c0:193a with SMTP id bf15-20020a056808190f00b002d4b3c0193amr1760730oib.229.1645231649091; Fri, 18 Feb 2022 16:47:29 -0800 (PST) Received: from rivos-atish.. (adsl-70-228-75-190.dsl.akrnoh.ameritech.net. [70.228.75.190]) by smtp.gmail.com with ESMTPSA id n11sm11360794oal.1.2022.02.18.16.47.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Feb 2022 16:47:28 -0800 (PST) From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Atish Patra , Anup Patel , Damien Le Moal , devicetree@vger.kernel.org, Jisheng Zhang , Krzysztof Kozlowski , linux-riscv@lists.infradead.org, Palmer Dabbelt , Paul Walmsley , Rob Herring Subject: [v6 9/9] MAINTAINERS: Add entry for RISC-V PMU drivers Date: Fri, 18 Feb 2022 16:47:00 -0800 Message-Id: <20220219004700.1973682-10-atishp@rivosinc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220219004700.1973682-1-atishp@rivosinc.com> References: <20220219004700.1973682-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Atish Patra Add myself and Anup as maintainer for RISC-V PMU drivers. Signed-off-by: Atish Patra Signed-off-by: Atish Patra Tested-by: Nikita Shubin --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fca970a46e77..101a07728d5f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16596,6 +16596,15 @@ S: Maintained F: drivers/mtd/nand/raw/r852.c F: drivers/mtd/nand/raw/r852.h =20 +RISC-V PMU DRIVERS +M: Atish Patra +R: Anup Patel +L: linux-riscv@lists.infradead.org +S: Supported +F: drivers/perf/riscv_pmu.c +F: drivers/perf/riscv_pmu_legacy.c +F: drivers/perf/riscv_pmu_sbi.c + RISC-V ARCHITECTURE M: Paul Walmsley M: Palmer Dabbelt --=20 2.30.2