From patchwork Fri Mar 19 23:01:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Patra X-Patchwork-Id: 12152085 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CA578C433E0 for ; Fri, 19 Mar 2021 23:01:51 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0BF1F6197B for ; Fri, 19 Mar 2021 23:01:51 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0BF1F6197B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=iak50TwC7z3GRCSkmsSU1q+iuOLzVhqhGdZjIc0I7xI=; b=IKHDP6VL3TJccJ+KMLowyG07k oJaTd3rHD0St/Jn0bXblt0eKZU2ta3N0oMJzCdt9wR9EEUo/xzPZdkm54Ubp/6IZcCKU+rRJqc1NG JKLLBIGqmPDHMuTeSRBdfBxSZt5/RgT0Xo8P54pMxBFin9E9pDL+3cJ9SG8IIFq7xfuCIkH75i6EA 4FFxqwB9hW28l6iIcdTr3TPGFLb87EYKcPFcKSGpo9k70dQeD5g9vOdyYOYClJwQdQHf3qo6T42v4 uOlQlmfCpj3skxi20OAnxs+tA7k+6Fk5NdaQXvk19hp15DEfWWqhzQrVy5gNfpwaeL1HeSnNIMs+v zwu4El8WQ==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7e-008IUy-4s; Fri, 19 Mar 2021 23:01:38 +0000 Received: from esa6.hgst.iphmx.com ([216.71.154.45]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7Y-008ISn-4H for linux-riscv@lists.infradead.org; Fri, 19 Mar 2021 23:01:34 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1616194893; x=1647730893; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=I27F+iUVnKqOMsuMJCcX8xkzk7/aFMoMG/XvpKNj1BE=; b=NYmpRdmzTvPjc5RT6IUXYkQ5/Gcispk/scj4ZCdQQiYoSxtr+R+c2bQ4 hHqMhjPc1qctaxSxCOzpG5JYb5oQOjzFqUTXq6iMw4Ete4EV8IwPmDKNa gQidekndwq5LzmLAXAS8L0jkO+hlU648KdAU5ek3UrFzj7nUqPXHWo24d r+K2NCrfNjHs+g3BrQsXwAz2D4sMyq0WOWYMsdfY0CTPlIsoCX6+z3DYg Ivn0Uz4SkHCbEQ9Ku1u4avG6w/DyWv7zcDpSgqidLWlZsJGD6Cb0n65JM xcVdmSxIIjjpQZzEiKrBCdvdMTzh2qwRdQ7i7t8H+SX5SEaRs1xkKunQ1 A==; IronPort-SDR: +DRrRu7/3U0Pw8rlxHFZoynfsv44dr5HfTDBEv0BUGhdCZ0j+GuC3pTKBSrldTHumqGea+UDKh wGygz7BgFNbLRmjhtDftslfET+4ljkId9NVn/5aRaagi2ciJ7xTiDvmILVOdGDltRGz5xW2H19 S+fgYrPg42YxRqc0/ZO7wMdril017sR/whQ5psKZ2bMoePh4UlqNovXfS420u0n01we8I3Q/Zr wCYG3IkCwh6xAqSZRhDrSQtC7nwc5NwVX4YKidv4XGH4XZzrn+3RbNgnPm/gC5UmJBvzYV8sFD lI4= X-IronPort-AV: E=Sophos;i="5.81,263,1610380800"; d="scan'208";a="163715802" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 20 Mar 2021 07:01:31 +0800 IronPort-SDR: ywsXxyYoFZC+tqXwl2Xl4hVts8ITt1Hp0USXrGEFUftZSWF1fYFAONznYK3XDIjl1LQ5XArws3 lF4fHLl9AHsuoNYYc0dL5S/keSe9hwg8KBUcO2nY7HL/k51RD+TunfeuxcjaVTwUB1MNykpsRV ev2JIjLVDmly7jPjRhWY+T/4NNyqktz11TjCs+dxx/zAl1ISZ31+qL5MUoqYKFYqtIhM3512YN aG7g4lLo2GcXAoYD7wdonIqv7Ph2nORjyoSLMrNmQ+hGeg/r4GZb9Vi+KkL02Lw6h7RBU0Hm+5 sg1ZBlw6lHlUp7x3AEr0WmBO Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Mar 2021 15:42:02 -0700 IronPort-SDR: wDvwfm7QwIA+a9VOxTikk1MWTIR009JdrjNGmunUU0iDLTTbpA9NkmGU2YggSRmt3/NOUbvhYf syzk8s6P2u6VPXw5F4wKxf3sgWsSHH8wj/U5ijxVX9h2xq8Z8GlNNXeEOYTIHjQg2vzOLauNtd qOgv6BkFNmb3kq614DU9CatAhHfd9mHZO+oYGCz2Who2mHc4EilEYnLWwKxv2fVIFu7qujBRaX SJhiPvawX+b7ybKwV/ncGQSuVflHEf8LArVHWM77xca9+AwI4Z/EN3hAt2ucNRwscOXe+g0gN+ G7A= WDCIronportException: Internal Received: from ind002560.ad.shared (HELO jedi-01.hgst.com) ([10.86.48.105]) by uls-op-cesaip02.wdc.com with ESMTP; 19 Mar 2021 16:01:30 -0700 From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Alexander Shishkin , Anup Patel , Ard Biesheuvel , Arnaldo Carvalho de Melo , Guo Ren , Kefeng Wang , linux-riscv@lists.infradead.org, Mark Rutland , Palmer Dabbelt , Paul Walmsley , Will Deacon Subject: [RFC 1/6] RISC-V: Remove the current perf implementation Date: Fri, 19 Mar 2021 16:01:01 -0700 Message-Id: <20210319230106.2186694-2-atish.patra@wdc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210319230106.2186694-1-atish.patra@wdc.com> References: <20210319230106.2186694-1-atish.patra@wdc.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210319_230132_862033_BB895BE6 X-CRM114-Status: GOOD ( 30.27 ) X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org 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. Signed-off-by: Atish Patra --- 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 85d626b8ce5e..fdbdba852137 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -351,19 +351,6 @@ config RISCV_ISA_C If you don't know what to do here, say Y. -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/perf_event.h index 062efd3a1d5d..dc6d5803c0e2 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 #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 3dc0abde988a..5f8f6290a0e1 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -45,7 +45,6 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o -obj-$(CONFIG_RISCV_BASE_PMU) += perf_event.o obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o obj-$(CONFIG_RISCV_SBI) += 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[] = { - [PERF_COUNT_HW_CPU_CYCLES] = RISCV_PMU_CYCLE, - [PERF_COUNT_HW_INSTRUCTIONS] = RISCV_PMU_INSTRET, - [PERF_COUNT_HW_CACHE_REFERENCES] = RISCV_OP_UNSUPP, - [PERF_COUNT_HW_CACHE_MISSES] = RISCV_OP_UNSUPP, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = RISCV_OP_UNSUPP, - [PERF_COUNT_HW_BRANCH_MISSES] = RISCV_OP_UNSUPP, - [PERF_COUNT_HW_BUS_CYCLES] = 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] = { - [C(L1D)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - }, - [C(L1I)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - }, - [C(LL)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - }, - [C(DTLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - }, - [C(ITLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - }, - [C(BPU)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP, - [C(RESULT_MISS)] = RISCV_OP_UNSUPP, - }, - }, -}; - -static int riscv_map_hw_event(u64 config) -{ - if (config >= 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 = -ENOENT; - int code; - - err = riscv_map_cache_decode(config, &type, &op, &result); - if (!riscv_pmu->cache_events || err) - return err; - - if (type >= PERF_COUNT_HW_CACHE_MAX || - op >= PERF_COUNT_HW_CACHE_OP_MAX || - result >= PERF_COUNT_HW_CACHE_RESULT_MAX) - return -EINVAL; - - code = (*riscv_pmu->cache_events)[type][op][result]; - if (code == RISCV_OP_UNSUPP) - return -EINVAL; - - return code; -} - -/* - * Low-level functions: reading/writing counters - */ - -static inline u64 read_counter(int idx) -{ - u64 val = 0; - - switch (idx) { - case RISCV_PMU_CYCLE: - val = csr_read(CSR_CYCLE); - break; - case RISCV_PMU_INSTRET: - val = 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 = &event->hw; - u64 prev_raw_count, new_raw_count; - u64 oldval; - int idx = hwc->idx; - u64 delta; - - do { - prev_raw_count = local64_read(&hwc->prev_count); - new_raw_count = read_counter(idx); - - oldval = local64_cmpxchg(&hwc->prev_count, prev_raw_count, - new_raw_count); - } while (oldval != prev_raw_count); - - /* - * delta is the value to update the counter we maintain in the kernel. - */ - delta = (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 = &event->hw; - - WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); - hwc->state |= PERF_HES_STOPPED; - - if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { - riscv_pmu->pmu->read(event); - hwc->state |= PERF_HES_UPTODATE; - } -} - -/* - * pmu->start: start the event. - */ -static void riscv_pmu_start(struct perf_event *event, int flags) -{ - struct hw_perf_event *hwc = &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 = 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 = this_cpu_ptr(&cpu_hw_events); - struct hw_perf_event *hwc = &event->hw; - - if (cpuc->n_events == 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 = hwc->config; - cpuc->events[hwc->idx] = event; - cpuc->n_events++; - - hwc->state = 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 = this_cpu_ptr(&cpu_hw_events); - struct hw_perf_event *hwc = &event->hw; - - cpuc->events[hwc->idx] = 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 = 0; - - mutex_lock(&pmc_reserve_mutex); - if (riscv_pmu->irq >= 0 && riscv_pmu->handle_irq) { - err = 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 >= 0) - free_irq(riscv_pmu->irq, NULL); - mutex_unlock(&pmc_reserve_mutex); -} - -/* - * Event Initialization/Finalization - */ - -static atomic_t riscv_active_events = ATOMIC_INIT(0); - -static void riscv_event_destroy(struct perf_event *event) -{ - if (atomic_dec_return(&riscv_active_events) == 0) - release_pmc_hardware(); -} - -static int riscv_event_init(struct perf_event *event) -{ - struct perf_event_attr *attr = &event->attr; - struct hw_perf_event *hwc = &event->hw; - int err; - int code; - - if (atomic_inc_return(&riscv_active_events) == 1) { - err = 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 = riscv_pmu->map_hw_event(attr->config); - break; - case PERF_TYPE_HW_CACHE: - code = riscv_pmu->map_cache_event(attr->config); - break; - case PERF_TYPE_RAW: - return -EOPNOTSUPP; - default: - return -ENOENT; - } - - event->destroy = 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 = code; - hwc->idx = -1; - - return 0; -} - -/* - * Initialization - */ - -static struct pmu min_pmu = { - .name = "riscv-base", - .event_init = riscv_event_init, - .add = riscv_pmu_add, - .del = riscv_pmu_del, - .start = riscv_pmu_start, - .stop = riscv_pmu_stop, - .read = riscv_pmu_read, -}; - -static const struct riscv_pmu riscv_base_pmu = { - .pmu = &min_pmu, - .max_events = ARRAY_SIZE(riscv_hw_event_map), - .map_hw_event = riscv_map_hw_event, - .hw_events = riscv_hw_event_map, - .map_cache_event = riscv_map_cache_event, - .cache_events = &riscv_cache_event_map, - .counter_width = 63, - .num_counters = RISCV_BASE_COUNTERS + 0, - .handle_irq = &riscv_base_pmu_handle_irq, - - /* This means this PMU has no IRQ. */ - .irq = -1, -}; - -static const struct of_device_id riscv_pmu_of_ids[] = { - {.compatible = "riscv,base-pmu", .data = &riscv_base_pmu}, - { /* sentinel value */ } -}; - -static int __init init_hw_perf_events(void) -{ - struct device_node *node = of_find_node_by_type(NULL, "pmu"); - const struct of_device_id *of_id; - - riscv_pmu = &riscv_base_pmu; - - if (node) { - of_id = of_match_node(riscv_pmu_of_ids, node); - - if (of_id) - riscv_pmu = 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); From patchwork Fri Mar 19 23:01:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Patra X-Patchwork-Id: 12152087 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 645E0C433C1 for ; Fri, 19 Mar 2021 23:01:54 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 85DAE6197B for ; Fri, 19 Mar 2021 23:01:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 85DAE6197B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=Un8D02gIgGcKGriU182T8ga5fztEBrCSbLryJNh07EI=; b=FiGNuVsvsPT+1HW+oTH4IKx+T yKqWor8/9Lq65aKQxka5xl3wdXICnWMvZndqnwY2iAG4fhKvi0DRxYAe6lsof64PZa5ODNaL3+8SX sobXUJbxEsOK4fReiOunLxA6yaLSm1OCrJzD9T6RSYX9uyMeSzKQPzvB1AUNzbBFCd/o4j2GHSXtC mRjei365BXObF+1vZih2cPJrNsOL9LG4/u+r+tmKl6aa/j3s0dDlHr+D4MjYg+m42OpnZ1sP+pnq2 S3SEWvw0Jfqn2s9jWnVbrRxjydto1V5938igj+uH107oVjp/Gh4uq1JmN15xD8MNqcnB1P8AhLXC3 +HpqtqBxw==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7f-008IVh-U8; Fri, 19 Mar 2021 23:01:41 +0000 Received: from esa6.hgst.iphmx.com ([216.71.154.45]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7Z-008ITD-Gx for linux-riscv@lists.infradead.org; Fri, 19 Mar 2021 23:01:36 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1616194894; x=1647730894; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XocJ1hDuH4ex8QRC/y2Fe2jp6AaWu+jTV16swTNZi6g=; b=eWRYdbWOEuwO6fVCJCRxUNskyk6A/0wq4UYxH+ym5QNw7JJxA4JUHPXe HJ/4LJWVZasBNG8Ly4qXGTaOaEoDR5YKellmTuHqhN6Id0shAnKyCX+hf y3T6wRY+IctPyW8Aw/5MalXdJMnJC2/mVVp5L+dZIOzB/hzB3Rky6U4CR GQLJ90dvJIeZ4T0MZ4evN66Otu65w8oK/P4GxzQWOtwi/SGuu5jjLzt9H nuJ32E2QhiaQ2529F/OByIiowaOXr1687PsnSb7wHFinqANUblvrXWdAv /c1kQDcuqd6L1vGUjdMpDBhukx02K1DythbNyBIFnlUl0qPYp9BLbI2wv A==; IronPort-SDR: pdtRMykNdEtT5b00I295JourO57ltHMFv1tHXiuhmuNTLuC7cNhewTSxCiRob654ZoPThmBnpm g8rV01m4k6myHhiBbxfimcc33s7mcKpH7qrz5bjZ82/Rmu65nhS/NyjMaH+J2AXrcGoW/2B1/D uQDPRw4KVdPCiVjIFBjigGnugu6GY716RP+E/gZgfxbtA9Kxtc1dNa3JV1TMZp+NYtG7xEQbAZ O/W6YXISnH2LBtWtUP2502pjWu355OKnVhzSyCBR8ZtCfeo5VBnEfmaESvQaOb9gFqHzgTL2u+ Ylw= X-IronPort-AV: E=Sophos;i="5.81,263,1610380800"; d="scan'208";a="163715804" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 20 Mar 2021 07:01:31 +0800 IronPort-SDR: ZvFgpqYd9URrKS8xtGow2QyS8JPR7N3yyBJvyNChZbbHzYcEaztRG8mRj6U7Z3CSYcL97g+JyC YQf75DFtPtYCFfAhlSMOLIKk5w0VZK255Q1fPdKjZZjTedjXbOZ2AMX81L/IYeK+DY6N+Wg0r5 qqokVGI/UauNfhhgSb0VC4WDfiy9xN1N8+yJPu/C1Nw7OaZZmZ7hzFWZ7Awzzi+TnTQkvU0oeW lkyKW4aZbg02DG8EpOwWnWFv4O5yfTOR98MUmutyV3jBAk0oqgVCAoA+Tmj+qZ6Q8xix0zy1kW YsIKICEuVajEYiLD8FsnMFTB Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Mar 2021 15:42:02 -0700 IronPort-SDR: VZy+zW7u+yifg45JsZ6vxe+eE6tbJIoMUoL7OOUF6h1FTweBuLIHAyMgeRDNwMEgMC8pg+fECo 1bBlPa1RQ5AMlckzn+olvIDNrfWa96fLZJj8gdlKZzwuNbuc0I1vnt3s2ifh4OUf2tdJAMkljd 0mm2+DPSkv8Do/m9b1hZDoDCHib6cW4eEpIbwTZT1jJhVt79wA+ZrMjzvg/DMo7P+TQA1Q/1PA klkBbnNqLEzee1FythgdbCGODjFS0mjeZEWj19P1+qoIhd0ZKlXmeiJenJ3ux/hZ4QDUqHK8UO UeU= WDCIronportException: Internal Received: from ind002560.ad.shared (HELO jedi-01.hgst.com) ([10.86.48.105]) by uls-op-cesaip02.wdc.com with ESMTP; 19 Mar 2021 16:01:31 -0700 From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Alexander Shishkin , Anup Patel , Ard Biesheuvel , Arnaldo Carvalho de Melo , Guo Ren , Kefeng Wang , linux-riscv@lists.infradead.org, Mark Rutland , Palmer Dabbelt , Paul Walmsley , Will Deacon Subject: [RFC 2/6] RISC-V: Add CSR encodings for all HPMCOUNTERS Date: Fri, 19 Mar 2021 16:01:02 -0700 Message-Id: <20210319230106.2186694-3-atish.patra@wdc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210319230106.2186694-1-atish.patra@wdc.com> References: <20210319230106.2186694-1-atish.patra@wdc.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210319_230134_555563_C5ECB269 X-CRM114-Status: UNSURE ( 9.32 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org Signed-off-by: Atish Patra --- 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 caadfc1d7487..7ce8df8f1683 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -89,9 +89,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 #define CSR_SSTATUS 0x100 #define CSR_SIE 0x104 From patchwork Fri Mar 19 23:01:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Patra X-Patchwork-Id: 12152091 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A6D4DC433DB for ; Fri, 19 Mar 2021 23:01:54 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 211306197F for ; Fri, 19 Mar 2021 23:01:54 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 211306197F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=8I8xnqSHYOXFaewOjWEsAmmLSS0ODcT/7QYUswAiT1g=; b=HSj12OrXDEypkahKFTFbkTGPl Yi2hTEkpbAdig1/D4MImNycwOClC1D+s9Jd+GaykXGv9s2TDOP2A8geQt4WUQfxJIgPxtRbRif80P I9Qljn890bDpb5xokb/+I/qGiXjXBD7jzETuDnIn3KLQbXFYTxMDwwlVgxZpb8QV83Cb6h1qLJhDd iOsWHXOJC47+Ak0o6lUY5KBzBwUUhp/XqkXLMwU1mWfXQo2TFl9Byd+NqK6/n/qQdr+1REHQ8FuKz mtgqr48hkbuWKtnj/d8joMuHtvsUbqJqZNp52KPUP9LjtKpsiGi88c2n06DuAHxB/rAx/yht9w3OH 7mKqwv6Ug==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7i-008IWA-4d; Fri, 19 Mar 2021 23:01:42 +0000 Received: from esa6.hgst.iphmx.com ([216.71.154.45]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7b-008ISd-At for linux-riscv@lists.infradead.org; Fri, 19 Mar 2021 23:01:37 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1616194896; x=1647730896; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eauJfQzZZQJrvKawBEc3kAASoZW3rJ3Tk0k3f4FpW1I=; b=aN/GcVWBAxjkpdMAAMaTXEbOHrPSqKuIeJXzXwO7F/8soavxaMXQSZlS m4azSF7HM7IRya8wrkBRyouPzJbZOV/EZGyqVCCdQ1rhL56UGo9opjHQR EWE5x1JpAgRX/qNEI8Qho7I9Tfy4zjSGXXN/QnJDXo3oAysLTIeQMf1I5 FfO8VsJav0tlpuNC1hEnwyaf1dcNE5Sb7FeI4KqkJNjK0S76uPfvLfhTZ q5p6pSF0+QF3WAWNM3R2pP2sCP6xHceuVSIMl/WgLmRhoBJ9v0IpQ3yfD hZoIF5bOKljt4sl8SrTYNRAL9trrW2AxyB2tzUcGtfbCGNMW1YDzApBG0 Q==; IronPort-SDR: xNERVBbf3eQsP+tZ+02boVavi82cd4lefFGwWe+XpUnj95cQ17RhBTqXVTFIKZuWus0LNlLBmc DL+WboYhmO6pedNyHWfd3y/94l/hM3UzfdEygtVHMPlSPJEWRtK5WhBvv4wu8H/Xj8eEPe/Zug zjqtGxMj2VwnkRhl4IEmU0/oFCc+nW/feUFECHBsjPMkoEbNww9SvEwX5j2gV7PSRiqiVLVrhM 7MkPO42/iNBQ6z2WE38qBPe8Zt/3VDb/oIKyJrmDDXKmJjHsFpOttypQxxQlAbJbWAUZDKqaGv QD0= X-IronPort-AV: E=Sophos;i="5.81,263,1610380800"; d="scan'208";a="163715807" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 20 Mar 2021 07:01:32 +0800 IronPort-SDR: KitI7F+BPnVM9DjgAE8AWTFvTpgZd6FHaney6/tMzh8aqfmpTjA6kHe68OA9DLM75ECQBWbvi/ mX8wAuYwpx8yV4roHyPoJ+H5YlSv93Hdfw/uQl+ZnBSAD5fezgpEi/BhoBrTyO3bEmq0M9s50W voTgEvAcLOpfTemQ7ZKhaRyofMDJ0atvpwLErZEYzCz7YZfr+2mtJ9uhX62fybVy3/yW2UwGiy YFHQcXhdNMnuANQ7etFADdxAV6VsBzkCDDP2vQfEHd23japmYrirR4plfTKJ+gmiLR4CYH8LJv mzC1J3WEhTTvoYU2EqZXsoTi Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Mar 2021 15:42:03 -0700 IronPort-SDR: /7Ii0SKo0kqTfvJf3I1KGz4OtT91SoExfKi60M07MyOR3xXxReFCOCuYssv8Po6EdmtmCfLet7 E12azLN2Z2zaOAerXmOwmN3i/ZYEzo+Qqu0cNtMXu698GJQAANnofZUTbyQHjRrq+o+dkOAZF5 nGHBIAfEgtXWYASp29Tiep+XHhPifoMQM2stK3OVDXjUeCnt/KS36fIpJ2KoXm3vPzRiErOD/c xmFGI4Hj3SER/JjtQnnWv1rSlIA2mfRHcHAdLu6kqa4lRdpUdDO+tT0nUngoCyhy78FMYidyxf m/Q= WDCIronportException: Internal Received: from ind002560.ad.shared (HELO jedi-01.hgst.com) ([10.86.48.105]) by uls-op-cesaip02.wdc.com with ESMTP; 19 Mar 2021 16:01:31 -0700 From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Alexander Shishkin , Anup Patel , Ard Biesheuvel , Arnaldo Carvalho de Melo , Guo Ren , Kefeng Wang , linux-riscv@lists.infradead.org, Mark Rutland , Palmer Dabbelt , Paul Walmsley , Will Deacon Subject: [RFC 3/6] RISC-V: Add a perf core platform driver Date: Fri, 19 Mar 2021 16:01:03 -0700 Message-Id: <20210319230106.2186694-4-atish.patra@wdc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210319230106.2186694-1-atish.patra@wdc.com> References: <20210319230106.2186694-1-atish.patra@wdc.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210319_230135_833530_C489A106 X-CRM114-Status: GOOD ( 36.94 ) X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org Implement a perf platform driver 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 using the core driver. Most of the common perf functionalities are kept in this core driver wile PMU specific driver can implement PMU specific features. For example, the SBI specific functionality will be implemented in the SBI specific driver. Signed-off-by: Atish Patra --- drivers/perf/Kconfig | 8 + drivers/perf/Makefile | 1 + drivers/perf/riscv_pmu.c | 385 +++++++++++++++++++++++++++++++++ include/linux/cpuhotplug.h | 1 + include/linux/perf/riscv_pmu.h | 59 +++++ 5 files changed, 454 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 77522e5efe11..fc42ab613ea0 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -56,6 +56,14 @@ config ARM_PMU Say y if you want to use CPU performance monitors on ARM-based systems. +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. + config ARM_PMU_ACPI depends on ARM_PMU && ACPI def_bool y diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index 5260b116c7da..76e5c50e24bb 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_FSL_IMX8_DDR_PMU) += fsl_imx8_ddr_perf.o obj-$(CONFIG_HISI_PMU) += hisilicon/ obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o +obj-$(CONFIG_RISCV_PMU) += riscv_pmu.o obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c new file mode 100644 index 000000000000..ce9d35069ac0 --- /dev/null +++ b/drivers/perf/riscv_pmu.c @@ -0,0 +1,385 @@ +// 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 +#include + +static unsigned long csr_read_num(int csr_num) +{ +#define switchcase_csr_read(__csr_num, __val) {\ + case __csr_num: \ + __val = 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 = 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_read_ctr_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); +} + +static unsigned long riscv_pmu_get_ctr_mask(struct perf_event *event) +{ + int cwidth; + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + + if (!rvpmu->get_ctr_width) + /** + * If the pmu driver doesn't support counter width, set it to default maximum + * allowed by the specification. + */ + cwidth = 63; + else { + if (hwc->idx == -1) + /* Handle init case where idx is not initialized yet */ + cwidth = rvpmu->get_ctr_width(0); + else + cwidth = rvpmu->get_ctr_width(hwc->idx); + } + + return GENMASK_ULL(cwidth, 0); +} + +static u64 riscv_pmu_event_update(struct perf_event *event) +{ + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u64 prev_raw_count, new_raw_count; + unsigned long cmask; + u64 oldval, delta; + + if (!rvpmu->read_ctr) + return 0; + + cmask = riscv_pmu_get_ctr_mask(event); + + do { + prev_raw_count = local64_read(&hwc->prev_count); + new_raw_count = rvpmu->read_ctr(event); + oldval = local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count); + } while (oldval != prev_raw_count); + + delta = (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 = &event->hw; + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + + WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); + + if (!(hwc->state & PERF_HES_STOPPED)) { + riscv_pmu_event_update(event); + if (rvpmu->stop_ctr) { + rvpmu->stop_ctr(event); + hwc->state |= PERF_HES_STOPPED; + } + hwc->state |= PERF_HES_UPTODATE; + } +} + +static int riscv_pmu_event_set_period(struct perf_event *event, u64 *init_val) +{ + struct hw_perf_event *hwc = &event->hw; + s64 left = local64_read(&hwc->period_left); + s64 period = hwc->sample_period; + u64 max_period; + int ret = 0; + unsigned long cmask = riscv_pmu_get_ctr_mask(event); + + max_period = cmask; + if (unlikely(left <= -period)) { + left = period; + local64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + + if (unlikely(left <= 0)) { + left += period; + local64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 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 = (max_period >> 1); + + local64_set(&hwc->prev_count, (u64)-left); + *init_val = (u64)(-left) & max_period; + perf_event_update_userpage(event); + + return ret; +} + +static void riscv_pmu_start(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + 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)); + + /* + * Set the counter to the period to the next interrupt here, + * if you have any. + */ + } + + hwc->state = 0; + riscv_pmu_event_set_period(event, &init_val); + rvpmu->start_ctr(event, init_val); + perf_event_update_userpage(event); +} + +static int riscv_pmu_add(struct perf_event *event, int flags) +{ + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events); + struct hw_perf_event *hwc = &event->hw; + int idx; + + idx = rvpmu->get_ctr_idx(event); + if (idx < 0) + return idx; + + hwc->idx = idx; + cpuc->events[idx] = event; + cpuc->n_events++; + hwc->state = 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 = to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events); + struct hw_perf_event *hwc = &event->hw; + + cpuc->events[hwc->idx] = NULL; + riscv_pmu_stop(event, PERF_EF_UPDATE); + cpuc->n_events--; + if (rvpmu->clear_ctr_idx) + rvpmu->clear_ctr_idx(event); + perf_event_update_userpage(event); + hwc->idx = -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 = &event->hw; + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + int mapped_event; + u64 event_config = 0; + unsigned long cmask; + + hwc->flags = 0; + mapped_event = rvpmu->map_event(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 = event_config; + hwc->idx = -1; + hwc->event_base = 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 = riscv_pmu_get_ctr_mask(event); + hwc->sample_period = cmask >> 1; + hwc->last_period = hwc->sample_period; + local64_set(&hwc->period_left, hwc->sample_period); + } + + return 0; +} + +static struct riscv_pmu *riscv_pmu_alloc(void) +{ + struct riscv_pmu *pmu; + int cpuid, i; + struct cpu_hw_events *cpuc; + + pmu = kzalloc(sizeof(*pmu), GFP_KERNEL); + if (!pmu) + goto out; + + pmu->hw_events = 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 = per_cpu_ptr(pmu->hw_events, cpuid); + cpuc->n_events = 0; + for (i = 0; i < RISCV_MAX_COUNTERS; i++) + cpuc->events[i] = NULL; + } + pmu->pmu = (struct pmu) { + .event_init = riscv_pmu_event_init, + .add = riscv_pmu_add, + .del = riscv_pmu_del, + .start = riscv_pmu_start, + .stop = riscv_pmu_stop, + .read = riscv_pmu_read, + }; + + return pmu; + +out_free_pmu: + kfree(pmu); +out: + return NULL; +} + +static int riscv_perf_starting_cpu(unsigned int cpu) +{ + /* Enable the access for TIME csr only from the user mode now */ + csr_write(CSR_SCOUNTEREN, 0x2); + + return 0; +} + +static int riscv_perf_dying_cpu(unsigned int cpu) +{ + /* Disable all counters access for user mode now */ + csr_write(CSR_SCOUNTEREN, 0x0); + + return 0; +} + +static int riscv_pmu_device_probe(struct platform_device *pdev) +{ + struct riscv_pmu *pmu = NULL; + + pmu = riscv_pmu_alloc(); + if (!pmu) + return -ENOMEM; + + cpuhp_setup_state(CPUHP_AP_PERF_RISCV_STARTING, + "perf/riscv/pmu:starting", + riscv_perf_starting_cpu, riscv_perf_dying_cpu); + perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW); + + return 0; +} + +static struct platform_driver riscv_pmu_driver = { + .probe = riscv_pmu_device_probe, + .driver = { + .name = RISCV_PMU_PDEV_NAME, + }, +}; + +static int __init riscv_pmu_driver_init(void) +{ + int ret; + struct platform_device *pdev; + + ret = platform_driver_register(&riscv_pmu_driver); + if (ret) + return ret; + + pdev = platform_device_register_simple(RISCV_PMU_PDEV_NAME, -1, NULL, 0); + if (IS_ERR(pdev)) { + platform_driver_unregister(&riscv_pmu_driver); + return PTR_ERR(pdev); + } + + return ret; +} +device_initcall(riscv_pmu_driver_init) diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index f14adb882338..4f0c08a93f3a 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -120,6 +120,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 new file mode 100644 index 000000000000..be7d63d075ff --- /dev/null +++ b/include/linux/perf/riscv_pmu.h @@ -0,0 +1,59 @@ +/* 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 128 +#define RISCV_OP_UNSUPP (-EOPNOTSUPP) +#define RISCV_PMU_PDEV_NAME "riscv-pmu" + +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 irq; + + int num_counters; + u64 (*read_ctr)(struct perf_event *event); + int (*get_ctr_idx)(struct perf_event *event); + int (*get_ctr_width)(int idx); + void (*clear_ctr_idx)(struct perf_event *event); + void (*start_ctr)(struct perf_event *event, u64 init_val); + void (*stop_ctr)(struct perf_event *event); + int (*map_event)(struct perf_event *event, u64 *config); + + struct cpu_hw_events __percpu *hw_events; +}; + +#define to_riscv_pmu(p) (container_of(p, struct riscv_pmu, pmu)) +unsigned long riscv_pmu_read_ctr_csr(unsigned long csr); + +#endif /* CONFIG_RISCV_PMU */ + +#endif /* _ASM_RISCV_PERF_EVENT_H */ From patchwork Fri Mar 19 23:01:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Patra X-Patchwork-Id: 12152089 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DC7ACC433E1 for ; Fri, 19 Mar 2021 23:01:54 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6CE4E6197E for ; Fri, 19 Mar 2021 23:01:54 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6CE4E6197E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=topj/H21NxJN5Vv0o7tJ5q9tjf0z/uLaSuCmXC3NfD8=; b=ZU2bwtOk5YGNYWMUUSBLFgZ1h nINeAJG8Epn2rhazJbLWwPYeeA8a+6Sa9QUimYNpiZ4V1w+i9Pvr2vkSx8hOHF2le3ObZaKDSiKVv I0ioiRnjqL3PAOvkljvAlKlPQJLbWWUPHbxM1wkyR0DUUA6wSN4crfHXSfFxcXrnZ6EJu2LP8luz6 Vj3vNu2vSVwKe7gcPi6baU06AkeI3mR+Zf/AY9qoYbKXF30QlMCpito4St35lZayuX/JRwOdBBfc1 +Z20RyrqB+pNCGu7BTsKmVQQmpooG98tlStfisbTQidkiUi2iCFLQEpeCBPfXIbf5NHrBubcwqECa x333xODtw==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7j-008IWl-M3; Fri, 19 Mar 2021 23:01:43 +0000 Received: from esa6.hgst.iphmx.com ([216.71.154.45]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7b-008ISn-Fx for linux-riscv@lists.infradead.org; Fri, 19 Mar 2021 23:01:37 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1616194896; x=1647730896; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WW4T5PmZJixjpQ7oYDcltpuHYHRByrMvxUXAAJYxp60=; b=PeAAARQD2ghYf3p5FuZpkFrHqEFGi9kDvxR6qJAM0jX1m16iA2wHoS6B 4Io47s85k2VlIofAFutDj0CDyo+JBbtdZ3pJRwkziqf0HdNQTO8HShzV5 rDN42vnGd1W8mTuenwrmnZCi1FqH0bH6AhobfxH9esYO+wh+B1PLO/g4s DEfylsmnrcDb1ENNRDexr/K+9gvjdI6H6TA1xpcd3xvVkL5uBuz+Zj7Os sw1W3fkERmWY7PaXanNJNPqPOkLJOFXrErDrLbqXUroMctZyM0xzLlhqR D5JXOhvzA8x5iFt83MNXlX5cKjcLunqS1RIx1MYyooFRltTOO7nFauKh/ g==; IronPort-SDR: fng8AgOO3rZc+d6CEJC5fnLt1zhLw86r1rFuSrRCXEX2C473EgyhhAsndQEKV7A5KbsbH7j/um R/OBRvWK0wK8cI6HmLss7DcO0ZAyBlS0uq03KZKkgX4GtCsOSt5OtPsaotk/gjtZE43VG5pbOj eXY5DiTu5EpmSofVvef0j3zc7MUrvSg7i6Uty0KFE/tih6HR7Fjs9fdxQ9srkF2u9t/LTgqwC7 7vzD6dIeZ/noh5/QLe2izsLq7SjzUjjpS1soffSeHMOGQI0zAruraVl7S4/Drm3xarKmuch235 HRA= X-IronPort-AV: E=Sophos;i="5.81,263,1610380800"; d="scan'208";a="163715808" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 20 Mar 2021 07:01:32 +0800 IronPort-SDR: DUMWuPxvXr+mkD4aquJsfWrofpk6/bX/tiQcvGAFQkiyBG7m2UQyQ3WsdfMEvRB+yBS+pwjVQK +Hi2aM6KtCGtSWLHwRJ7ob2N81ZKGDCBCeA1caDeCCnQaoezq/Hm7ClVjJvfQOjXu3ykiPw6AW 8T9Pi+tTrfz8Dk7wxbe9/wI4aJHQXbJvFymBx+RjaQ6UXrKnpIUVdiBpj3NaiXc7zMtXanGNG6 SbLSesOF7YdIcyg8JxERSSiDJ0RptsFvLZnBHiONdo/fvsYnfNVwTdxvbiHAj3xJ7fv4k7gmMZ jmqFC/Qx0bFoHW32fYpIEcJN Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Mar 2021 15:42:03 -0700 IronPort-SDR: Wzxg6dTWvlXDVFwHBFpFv7KYEUgDtJqCfCVCmnILYTkcJiQm/9Vf1LeMF+hJ3DjjQ8CHLwppie jnEEa1dDvXCdV/vX1/30mS9/uIvplw0MOKM4R+APESG4tqRg0o/hQNpHYZAAd2Sd2NI2dR3A/w 87bF/JfGwekVw1IKBgj1dAXpT/9e2cwXtcD2AQIlZle8PAzmcIA+5BUSyI5OE2Tu8yINOh8NNC HHkoJ4a2gl9vGtxCC30B8yhPTBQ62DCuNUxa4Q43P8NbmQPYQ5SYcZnoP1vMwwVpWUUV3soh31 ycY= WDCIronportException: Internal Received: from ind002560.ad.shared (HELO jedi-01.hgst.com) ([10.86.48.105]) by uls-op-cesaip02.wdc.com with ESMTP; 19 Mar 2021 16:01:32 -0700 From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Alexander Shishkin , Anup Patel , Ard Biesheuvel , Arnaldo Carvalho de Melo , Guo Ren , Kefeng Wang , linux-riscv@lists.infradead.org, Mark Rutland , Palmer Dabbelt , Paul Walmsley , Will Deacon Subject: [RFC 4/6] RISC-V: Add a simple platform driver for RISC-V legacy perf Date: Fri, 19 Mar 2021 16:01:04 -0700 Message-Id: <20210319230106.2186694-5-atish.patra@wdc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210319230106.2186694-1-atish.patra@wdc.com> References: <20210319230106.2186694-1-atish.patra@wdc.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210319_230136_205556_160E6308 X-CRM114-Status: GOOD ( 29.10 ) X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org 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. Signed-off-by: Atish Patra --- drivers/perf/Kconfig | 9 ++++ drivers/perf/Makefile | 3 ++ drivers/perf/riscv_pmu.c | 2 + drivers/perf/riscv_pmu_legacy.c | 88 +++++++++++++++++++++++++++++++++ include/linux/perf/riscv_pmu.h | 1 + 5 files changed, 103 insertions(+) create mode 100644 drivers/perf/riscv_pmu_legacy.c diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index fc42ab613ea0..1546a487d970 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -64,6 +64,15 @@ config RISCV_PMU Say y if you want to use CPU performance monitors on RISCV-based systems. +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 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 76e5c50e24bb..e8aa666a9d28 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -11,6 +11,9 @@ obj-$(CONFIG_HISI_PMU) += hisilicon/ obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o obj-$(CONFIG_RISCV_PMU) += riscv_pmu.o +ifeq ($(CONFIG_RISCV_PMU), y) +obj-$(CONFIG_RISCV_PMU_LEGACY) += riscv_pmu_legacy.o +endif obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c index ce9d35069ac0..838dca2ffca8 100644 --- a/drivers/perf/riscv_pmu.c +++ b/drivers/perf/riscv_pmu.c @@ -350,6 +350,8 @@ static int riscv_pmu_device_probe(struct platform_device *pdev) if (!pmu) return -ENOMEM; + riscv_pmu_legacy_init(pmu); + cpuhp_setup_state(CPUHP_AP_PERF_RISCV_STARTING, "perf/riscv/pmu:starting", riscv_perf_starting_cpu, riscv_perf_dying_cpu); diff --git a/drivers/perf/riscv_pmu_legacy.c b/drivers/perf/riscv_pmu_legacy.c new file mode 100644 index 000000000000..d75353824f4a --- /dev/null +++ b/drivers/perf/riscv_pmu_legacy.c @@ -0,0 +1,88 @@ +// 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 + +#define RISCV_PMU_LEGACY_CYCLE 0 +#define RISCV_PMU_LEGACY_INSTRET 1 +#define RISCV_PMU_LEGACY_NUM_CTR 2 + +static int pmu_legacy_get_ctr_idx(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + + if (event->attr.type != PERF_TYPE_HARDWARE) + return -EOPNOTSUPP; + if (attr->config == PERF_COUNT_HW_CPU_CYCLES) + return RISCV_PMU_LEGACY_CYCLE; + else if (attr->config == PERF_COUNT_HW_INSTRUCTIONS) + return RISCV_PMU_LEGACY_INSTRET; + else + return -EOPNOTSUPP; +} + +/* For legacy config & counter index are same */ +static int pmu_legacy_map_event(struct perf_event *event, u64 *config) +{ + return pmu_legacy_get_ctr_idx(event); +} + +static u64 pmu_legacy_read_ctr(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + u64 val; + + if (idx == RISCV_PMU_LEGACY_CYCLE) { + val = riscv_pmu_read_ctr_csr(CSR_CYCLE); + if (IS_ENABLED(CONFIG_32BIT)) + val = (u64)riscv_pmu_read_ctr_csr(CSR_CYCLEH) << 32 | val; + } else if (idx == RISCV_PMU_LEGACY_INSTRET) { + val = riscv_pmu_read_ctr_csr(CSR_INSTRET); + if (IS_ENABLED(CONFIG_32BIT)) + val = ((u64)riscv_pmu_read_ctr_csr(CSR_INSTRETH)) << 32 | val; + } else + return 0; + + return val; +} + +static void pmu_legacy_start_ctr(struct perf_event *event, u64 ival) +{ + struct hw_perf_event *hwc = &event->hw; + u64 initial_val = 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 useful + * will be removed in future. + */ +void riscv_pmu_legacy_init(struct riscv_pmu *pmu) +{ + pmu->num_counters = RISCV_PMU_LEGACY_NUM_CTR; + pmu->start_ctr = pmu_legacy_start_ctr; + pmu->stop_ctr = NULL; + pmu->map_event = pmu_legacy_map_event; + pmu->get_ctr_idx = pmu_legacy_get_ctr_idx; + pmu->get_ctr_width = NULL; + pmu->clear_ctr_idx = NULL; + pmu->read_ctr = pmu_legacy_read_ctr; +} diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index be7d63d075ff..3a02b496609d 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -53,6 +53,7 @@ struct riscv_pmu { #define to_riscv_pmu(p) (container_of(p, struct riscv_pmu, pmu)) unsigned long riscv_pmu_read_ctr_csr(unsigned long csr); +void riscv_pmu_legacy_init(struct riscv_pmu *pmu); #endif /* CONFIG_RISCV_PMU */ From patchwork Fri Mar 19 23:01:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Patra X-Patchwork-Id: 12152093 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UPPERCASE_50_75, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0AB6DC433DB for ; Fri, 19 Mar 2021 23:02:01 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 813A661970 for ; Fri, 19 Mar 2021 23:02:00 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 813A661970 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=brABH7nluJMpdDxNBrJ1lnHGYOB3r2S8/4iEm6jpRpc=; b=n779arV0iEtHuv6gJpIsxbETV DtZbX/ujCjJ05373VRkGeOGEkGFj854tb3uj1tgcRLSg8o0U8J4M3wHyfQULgv037Lz9PtNdhj2sX nXMFFdor2yGCboS/10Ee+4ad8kK79fsBgtjh0aAqorFRbkD1mq5rqhfxyMtPhzZRFytlX5Vf5SgnL pnFRzrWM1dmeX12ZA++BIJJcqqsVGbLB1U3qpLmu5vXkAZPB5W0g1NQ9NIsSaUGqQO2+1e+j5QHVN KXmZGRrRQg6lYAhiqpXQpoUpaCY4WBsDCGUlgi+afJ7Xm0mquctT5UykQQGHaBMFBaCIBUyRmq/j0 PfQUbEXBQ==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7m-008IXK-ED; Fri, 19 Mar 2021 23:01:46 +0000 Received: from esa6.hgst.iphmx.com ([216.71.154.45]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7d-008ITD-3q for linux-riscv@lists.infradead.org; Fri, 19 Mar 2021 23:01:39 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1616194898; x=1647730898; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bvhD1o7QLbuyiQ3irecBTTVFAEPFjiti9Nt3mhTF4+w=; b=Kly2dndeaY3xOjp+hse0f58u4bcfycoB9VMoM7+9XZuEIgzVnmKMrhGH nHT6bbjpQFwCcGqN8nVR3WzLCt1nNmHKEDfWt9Y+6TOWfR1+o9Bq1H9jT XdHU7kF6Fdyg+BSOjMQmFHB52t74TOgskGDPl+CpktIfDC1tm66ZEstZM jQcKXlSXvzwlz9jN7XT9NO+3xbFNCNXDMFRnroVp7wB4RzzIRc6edPJQx SBB6Gs18YQv0Fmfr0fBVtpwbueGxSp4s7bk9HFItfPIAwIBf5KsL1FVnb AygZ95jkAcbOam+gJmD9geQ9olPRQWicmmmh11NMei85Fe7BXLZHA5pOW Q==; IronPort-SDR: dN8kxg5otcF4+zukKe3HfyO5K7Pox+CVU1uY1o59DLY/dFbRMyO2XCvyuvifIxldZsfGTvvzd3 Vd8O1Y7rLctzp5E3Bt+odMYSVqniENlrf+rk9sBntljJ2OIkJNs+hVgHpSYNvwFHba6uzIksUt iLA1RACdKqNgOzCcohNasZNRGA/+UqwCsIHvCPTG3PdUtt9gIsdx0IngLnLt/f2BOFzTZWQIEn VBolNvx0aRWKMpX+3PngPhaYukxc9VR+ZpFS+PhQQ165WOaQeAFcx/ZsPh6p+UxltRyEdIU3pl zWM= X-IronPort-AV: E=Sophos;i="5.81,263,1610380800"; d="scan'208";a="163715809" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 20 Mar 2021 07:01:32 +0800 IronPort-SDR: IdijD8iRF2Lj/mPNg5A65ZC2K6icFq1wkgw7zGs3Ano/sD3lHjopd15dzq+htsQVX8/miMAgSV XuhFs9MZEsqvc8XgjVq1RrXAHMphMHpoU/38+D1WLqxaMUWt062W0BdEhHBFWJjDTquFhUhFcO hOHFiUhJIW0asmqqjXBcZlww3XtY7i8zD/EA5tdUOsvIdecs80aL7uj2yt0iIqm7HKpX/1N0hY Kd52ChULf7h5yE6NznycVZ228X0M2EwClMFi1ORiTTFnjXXH9dLcLcbVH0vf7JcS3jWJaeHBP7 GmzIR3bBJtxzNR3g8fecDh/8 Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Mar 2021 15:42:04 -0700 IronPort-SDR: a/RK+GO7gWzwO5+wEegWwV0E55vPwk0jaT865Ui5Ia9HugZOXXbuzQHyG5ClNQoLyY9ak/iR56 +XaxxVT85yXeyaAKq9sINCFC5b/GHxNzJm+Jcf+2UZW0tV3sS2lCmrGRb/Wpyvt2bgQYrg7R9L kNhKf2gJT9Amlv/BCgzi7LGP5xZjAqOxEXnsHHbirJLcttqlQqKeCT1y6mF/+V5s8W+jrblwbD 4d0UmGrkgNXhWALwHqCj3KzIk7AYvYIvUZ6hnJLvJxavA7265zMxueGZf03480Yd6ljxkxj7dm FGE= WDCIronportException: Internal Received: from ind002560.ad.shared (HELO jedi-01.hgst.com) ([10.86.48.105]) by uls-op-cesaip02.wdc.com with ESMTP; 19 Mar 2021 16:01:32 -0700 From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Alexander Shishkin , Anup Patel , Ard Biesheuvel , Arnaldo Carvalho de Melo , Guo Ren , Kefeng Wang , linux-riscv@lists.infradead.org, Mark Rutland , Palmer Dabbelt , Paul Walmsley , Will Deacon Subject: [RFC 5/6] RISC-V: Add RISC-V SBI PMU extension definitions Date: Fri, 19 Mar 2021 16:01:05 -0700 Message-Id: <20210319230106.2186694-6-atish.patra@wdc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210319230106.2186694-1-atish.patra@wdc.com> References: <20210319230106.2186694-1-atish.patra@wdc.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210319_230137_483726_017C71B5 X-CRM114-Status: GOOD ( 13.89 ) X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org This patch adds all the definitions defined by the SBI PMU extension. Signed-off-by: Atish Patra --- arch/riscv/include/asm/sbi.h | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 99895d9c3bdd..01b261bc6b68 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -27,6 +27,7 @@ enum sbi_ext_id { SBI_EXT_IPI = 0x735049, SBI_EXT_RFENCE = 0x52464E43, SBI_EXT_HSM = 0x48534D, + SBI_EXT_PMU = 0x504D55, }; enum sbi_ext_base_fid { @@ -70,6 +71,85 @@ enum sbi_hsm_hart_status { SBI_HSM_HART_STATUS_STOP_PENDING, }; + +enum sbi_ext_pmu_fid { + SBI_EXT_PMU_NUM_COUNTERS = 0, + SBI_EXT_PMU_COUNTER_GET_INFO, + SBI_EXT_PMU_COUNTER_CFG_MATCH, + SBI_EXT_PMU_COUNTER_FW_READ, + SBI_EXT_PMU_COUNTER_START, + SBI_EXT_PMU_COUNTER_STOP, +}; + +#define RISCV_PMU_RAW_EVENT_MASK 0x7FFFFFFF +#define RISCV_PMU_RAW_EVENT_IDX 0x20000 + +/* SBI PMU Hardware general events */ +enum sbi_pmu_hw_generic_events_t { + SBI_PMU_HW_NO_EVENT = 0, + SBI_PMU_HW_CPU_CYCLES, + SBI_PMU_HW_INSTRUCTIONS, + SBI_PMU_HW_CACHE_REFERENCES, + SBI_PMU_HW_CACHE_MISSES, + SBI_PMU_HW_BRANCH_INSTRUCTIONS, + SBI_PMU_HW_BRANCH_MISSES, + SBI_PMU_HW_BUS_CYCLES, + SBI_PMU_HW_STALLED_CYCLES_FRONTEND, + SBI_PMU_HW_STALLED_CYCLES_BACKEND, + SBI_PMU_HW_REF_CPU_CYCLES, + SBI_PMU_HW_MISALIGNED_LOAD, + SBI_PMU_HW_MISALIGNED_STORE, + + SBI_PMU_HW_GENERIC_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 = 0, + SBI_PMU_FW_MISALIGNED_STORE = 1, + SBI_PMU_FW_ACCESS_LOAD = 2, + SBI_PMU_FW_ACCESS_STORE = 3, + SBI_PMU_FW_ILLEGAL_INSN = 4, + SBI_PMU_FW_SET_TIMER = 5, + SBI_PMU_FW_IPI_SENT = 6, + SBI_PMU_FW_IPI_RECVD = 7, + SBI_PMU_FW_FENCE_I_SENT = 8, + SBI_PMU_FW_FENCE_I_RECVD = 9, + SBI_PMU_FW_SFENCE_VMA_SENT = 10, + SBI_PMU_FW_SFENCE_VMA_RCVD = 11, + SBI_PMU_FW_SFENCE_VMA_ASID_SENT = 12, + SBI_PMU_FW_SFENCE_VMA_ASID_RCVD = 13, + + SBI_PMU_FW_HFENCE_GVMA_SENT = 14, + SBI_PMU_FW_HFENCE_GVMA_RCVD = 15, + SBI_PMU_FW_HFENCE_GVMA_VMID_SENT = 16, + SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD = 17, + + SBI_PMU_FW_HFENCE_VVMA_SENT = 18, + SBI_PMU_FW_HFENCE_VVMA_RCVD = 19, + SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20, + SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21, + SBI_PMU_FW_MAX, +}; + +/* SBI PMU event types */ +enum sbi_pmu_event_type { + SBI_PMU_EVENT_TYPE_HW = 0x0, + SBI_PMU_EVENT_TYPE_CACHE = 0x1, + SBI_PMU_EVENT_TYPE_RAW = 0x2, + SBI_PMU_EVENT_TYPE_FW = 0xf, +}; + +/* SBI PMU event types */ +enum sbi_pmu_ctr_type { + SBI_PMU_CTR_TYPE_HW = 0x0, + SBI_PMU_CTR_TYPE_FW, +}; + #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f From patchwork Fri Mar 19 23:01:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Patra X-Patchwork-Id: 12152095 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D335EC433E0 for ; Fri, 19 Mar 2021 23:02:02 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 268896197E for ; Fri, 19 Mar 2021 23:02:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 268896197E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=4kpOSlzW9ir6KhesWhPJHOwBuOagY2z8Y+JpQUviok0=; b=R7mS0effONgVYoYvYbZc8N/na LepK0MmfKGztLV1Fu4ZuggzT6SMj3DfJNNujzh8ZJzZvCuHJDtG/4YJTIe7X3IRE55xrwPDqAxS8N vrdLcJ/5IzX4AENTvUPe5ZVtziYRqlGmMfEAmRqtH+LaiwNFRp3i3nRD9TPN8RVk2jZxNlYz2qKH8 INHq8eUmt59dT+AXxRrVgVS7RdtxJelLGYx74NO6IDjO56yxNGsvklEZEN0Q5tlasDhibxbiMY8tQ 6+nG3TNZTuY0CS6wWQ2/dOd6sHbK1vpxr1v2NboH1eSGLNsspIU7F8betWosuVMblNtzkoD+4isxw tmnVJ02+g==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7o-008IXz-2h; Fri, 19 Mar 2021 23:01:48 +0000 Received: from esa6.hgst.iphmx.com ([216.71.154.45]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNO7e-008ISd-Im for linux-riscv@lists.infradead.org; Fri, 19 Mar 2021 23:01:41 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1616194899; x=1647730899; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=IOebBZvKkCFckooW+fYGY6X91AqDA6DhwpSLB4faeIs=; b=moHecMGMQgxzYhm/sQM/99+b43k/j9ZZTGyfb9KKrcILi/JAR878j29y WAqMI71iNIqhZLzin/SRXHiYWK3VK4GAPPcj+EEGy/1qVUPeS4MFwcFif HV3BppQbsoqZPekg1MkeKmt7nmoOWVmzyHLdsXKElZSdlGQ6SGIemhiW5 L8pjOl8mL1d0fSgvrhoZi674g9qXKn3VXqDzLfKWMb/9DSKL6ZDM8rKqI MfP4JHacLM9cwbkJ42bgUAaklQTk6aR1EzT8nwdtFX2+86AQ3xqu8rKQf zHttErWnevpieKBhbLaM6JYuxHkqLczwiP0i8yLiYQ7S6IOvPUMXQ5UR9 A==; IronPort-SDR: JrO+bFojrGqn2q55IiFEKI1Eh+27AEXr8v2I7/ATU/sav6GOh15LwIBXChNeLNuIglepUdqd3v ZuBVMsa2mpCO6KCbdC5lAdW+sirdmS9mImVe+GH2UrWYG91zhdg8nOYZSewk8iTJIcGkw4n8dt rGqpj1GhDfljIWjR25B8Lwy03Y432F8vGXTyOO0WqMtsfHx+N7FkGTky4Z8jBtL+CgMLNs3r3r xWYJkjWAV+LCFFmu+ARHs4R8qcZM7RbYdE2AxaVweWRFQ0vgkKiWUpAVQGUOj5lqQcHayi3ubV CjQ= X-IronPort-AV: E=Sophos;i="5.81,263,1610380800"; d="scan'208";a="163715811" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 20 Mar 2021 07:01:33 +0800 IronPort-SDR: qQYuK/ORuO6gEGVwvN9Xw+gWoIA3pGRO4HfsX0wfLvtdgrk75HK0X12Q4ebKXAtACp7dTdFEMz TFKZiHa6pnJaUENWr9X0Th3i4T7mx1t5tuBaVmzIUD8IvVNCsWGFD9O/mkd08LylYiIZ6rFswp QftO+Fj3iDJXeCwDja8VpVT3/XZuTQqrbO5QQkklPqjtH/T7b8GbhcBcA8/VD0awpVxYe8q1NO vfimQZsYl1V6YoGj5zNryIEZPY8KNIfs2BQgq0WCSwZOr+OdwRqZu/cuKBJf/hrPkBcllYl3gQ oYZFUMQJv0DnHUvVrkncktq2 Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Mar 2021 15:42:04 -0700 IronPort-SDR: gVJWUzHFrCFBue/QX0eKoIWcQHQZlyAkYywiGPMSaCoIZQ8wmYwRpHb+ksQXw1/HtrXTmJQR+M oTsxfD7Bnjct/BhfflT+ghXAR9thr1dAYhgQt58zFmkDlBzM8+JUFr/ZUcBCrhH5+9vzXtug77 QflSrZnXhY3t+iZdqFbD3oOJePjACgGTTsxMpDPywqv5Y8yNOPccS36EB4cJMvqrOrR7B/xPyU SC30KVXIKs9Qz5FifikRqw99OVR9aLscNpkxGe51oJG3bydTrrfJ/ws/b83P3LC7K3Sufe57/E 2yY= WDCIronportException: Internal Received: from ind002560.ad.shared (HELO jedi-01.hgst.com) ([10.86.48.105]) by uls-op-cesaip02.wdc.com with ESMTP; 19 Mar 2021 16:01:33 -0700 From: Atish Patra To: linux-kernel@vger.kernel.org Cc: Atish Patra , Albert Ou , Alexander Shishkin , Anup Patel , Ard Biesheuvel , Arnaldo Carvalho de Melo , Guo Ren , Kefeng Wang , linux-riscv@lists.infradead.org, Mark Rutland , Palmer Dabbelt , Paul Walmsley , Will Deacon Subject: [RFC 6/6] RISC-V: Add perf platform driver based on SBI PMU extension Date: Fri, 19 Mar 2021 16:01:06 -0700 Message-Id: <20210319230106.2186694-7-atish.patra@wdc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210319230106.2186694-1-atish.patra@wdc.com> References: <20210319230106.2186694-1-atish.patra@wdc.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210319_230139_064941_6003237D X-CRM114-Status: GOOD ( 29.40 ) X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org 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 --- drivers/perf/Kconfig | 8 + drivers/perf/Makefile | 1 + drivers/perf/riscv_pmu.c | 12 +- drivers/perf/riscv_pmu_sbi.c | 464 +++++++++++++++++++++++++++++++++ include/linux/perf/riscv_pmu.h | 1 + 5 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 drivers/perf/riscv_pmu_sbi.c diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index 1546a487d970..2acb5feaab35 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -73,6 +73,14 @@ config RISCV_PMU_LEGACY implementation on RISC-V based systems. This only allows counting of cycle/instruction counter and will be removed in future. +config RISCV_PMU_SBI + depends on RISCV_PMU + 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. + config ARM_PMU_ACPI depends on ARM_PMU && ACPI def_bool y diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index e8aa666a9d28..7bcac4b5a983 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o obj-$(CONFIG_RISCV_PMU) += riscv_pmu.o ifeq ($(CONFIG_RISCV_PMU), y) obj-$(CONFIG_RISCV_PMU_LEGACY) += riscv_pmu_legacy.o +obj-$(CONFIG_RISCV_PMU_SBI) += riscv_pmu_sbi.o endif obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c index 838dca2ffca8..95e4ca07dd29 100644 --- a/drivers/perf/riscv_pmu.c +++ b/drivers/perf/riscv_pmu.c @@ -16,6 +16,8 @@ #include #include +#include + static unsigned long csr_read_num(int csr_num) { #define switchcase_csr_read(__csr_num, __val) {\ @@ -350,7 +352,15 @@ static int riscv_pmu_device_probe(struct platform_device *pdev) if (!pmu) return -ENOMEM; - riscv_pmu_legacy_init(pmu); + if (sbi_major_version() == 0 && + sbi_minor_version() == 3 && + sbi_probe_extension(SBI_EXT_PMU) > 0) { + pr_info("SBI PMU extension detected\n"); + riscv_pmu_sbi_init(pmu); + } else { + pr_info("Legacy PMU is in use as SBI PMU extension is not available\n"); + riscv_pmu_legacy_init(pmu); + } cpuhp_setup_state(CPUHP_AP_PERF_RISCV_STARTING, "perf/riscv/pmu:starting", diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c new file mode 100644 index 000000000000..1f27802bd0e9 --- /dev/null +++ b/drivers/perf/riscv_pmu_sbi.c @@ -0,0 +1,464 @@ +// 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. + */ + +#include + +#include + +union sbi_pmu_ctr_info { + unsigned long value; + struct { + unsigned long csr:12; + unsigned long width:6; +#if __riscv_xlen == 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 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 pmu_event_data pmu_hw_event_map[] = { + [PERF_COUNT_HW_CPU_CYCLES] = {.hw_gen_event = { + SBI_PMU_HW_CPU_CYCLES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_INSTRUCTIONS] = {.hw_gen_event = { + SBI_PMU_HW_INSTRUCTIONS, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_CACHE_REFERENCES] = {.hw_gen_event = { + SBI_PMU_HW_CACHE_REFERENCES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_CACHE_MISSES] = {.hw_gen_event = { + SBI_PMU_HW_CACHE_MISSES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = {.hw_gen_event = { + SBI_PMU_HW_BRANCH_INSTRUCTIONS, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_BRANCH_MISSES] = {.hw_gen_event = { + SBI_PMU_HW_BRANCH_MISSES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_BUS_CYCLES] = {.hw_gen_event = { + SBI_PMU_HW_BUS_CYCLES, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = {.hw_gen_event = { + SBI_PMU_HW_STALLED_CYCLES_FRONTEND, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = {.hw_gen_event = { + SBI_PMU_HW_STALLED_CYCLES_BACKEND, + SBI_PMU_EVENT_TYPE_HW, 0}}, + [PERF_COUNT_HW_REF_CPU_CYCLES] = {.hw_gen_event = { + SBI_PMU_HW_REF_CPU_CYCLES, + SBI_PMU_EVENT_TYPE_HW, 0}}, +}; + +#define C(x) PERF_COUNT_HW_CACHE_##x +static const struct pmu_event_data pmu_cache_event_map[PERF_COUNT_HW_CACHE_MAX] +[PERF_COUNT_HW_CACHE_OP_MAX] +[PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_READ), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_READ), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_WRITE), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_WRITE), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_PREFETCH), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_PREFETCH), C(L1D), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_READ), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), C(OP_READ), + C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_WRITE), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_WRITE), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_PREFETCH), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_PREFETCH), C(L1I), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_READ), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_READ), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_WRITE), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_WRITE), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_PREFETCH), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_PREFETCH), C(LL), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_READ), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_READ), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_WRITE), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_WRITE), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_PREFETCH), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_PREFETCH), C(DTLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_READ), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_READ), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_WRITE), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_WRITE), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_PREFETCH), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_PREFETCH), C(ITLB), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_READ), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_READ), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_WRITE), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_WRITE), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_PREFETCH), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_PREFETCH), C(BPU), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_READ), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_READ), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_WRITE), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_WRITE), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = {.hw_cache_event = {C(RESULT_ACCESS), + C(OP_PREFETCH), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + [C(RESULT_MISS)] = {.hw_cache_event = {C(RESULT_MISS), + C(OP_PREFETCH), C(NODE), SBI_PMU_EVENT_TYPE_CACHE, 0}}, + }, + }, +}; + +static int pmu_sbi_get_ctr_width(int idx) +{ + return pmu_ctr_list[idx].width; +} + +static int pmu_sbi_get_ctr_idx(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events); + struct sbiret ret; + int idx; + uint64_t cbase = 0; + uint64_t cmask = GENMASK_ULL(rvpmu->num_counters, 0); + + /* retrieve the available counter index */ + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, cmask, + hwc->event_base, hwc->config, 0, 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 = ret.value; + if (idx >= rvpmu->num_counters || !pmu_ctr_list[idx].value) + return -ENOENT; + + /* Additional sanity check for the counter id */ + if (!test_and_set_bit(idx, cpuc->used_event_ctrs)) + return idx; + else + return -ENOENT; +} + +static void pmu_sbi_clear_ctr_idx(struct perf_event *event) +{ + + struct hw_perf_event *hwc = &event->hw; + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events); + int idx = hwc->idx; + + clear_bit(idx, cpuc->used_event_ctrs); +} + +static int pmu_map_cache_event(u64 config) +{ + unsigned int cache_type, cache_op, cache_result, ret; + + cache_type = (config >> 0) & 0xff; + if (cache_type >= PERF_COUNT_HW_CACHE_MAX) + return -EINVAL; + + cache_op = (config >> 8) & 0xff; + if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) + return -EINVAL; + + cache_result = (config >> 16) & 0xff; + if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) + return -EINVAL; + + ret = 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 = event->attr.type; + u64 config = event->attr.config; + + if ((type == PERF_TYPE_RAW) && ((config >> 63) == 1)) + return true; + else + return false; +} + +static int pmu_sbi_map_event(struct perf_event *event, u64 *econfig) +{ + u32 type = event->attr.type; + u64 config = event->attr.config; + int bSoftware; + u64 raw_config_val; + int ret; + + switch (type) { + case PERF_TYPE_HARDWARE: + if (config >= PERF_COUNT_HW_MAX) + return -EINVAL; + ret = pmu_hw_event_map[event->attr.config].event_idx; + break; + case PERF_TYPE_HW_CACHE: + ret = pmu_map_cache_event(config); + break; + case PERF_TYPE_RAW: + bSoftware = config >> 63; + raw_config_val = config & RISCV_PMU_RAW_EVENT_MASK; + if (bSoftware) { + if (raw_config_val < SBI_PMU_FW_MAX) + ret = (raw_config_val & 0xFFFF) | + (SBI_PMU_EVENT_TYPE_FW << 16); + else + return -EINVAL; + } else { + ret = RISCV_PMU_RAW_EVENT_IDX; + *econfig = raw_config_val; + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static u64 pmu_sbi_read_ctr(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + struct sbiret ret; + union sbi_pmu_ctr_info info; + u64 val = 0; + + if (pmu_sbi_is_fw_event(event)) { + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_FW_READ, + hwc->idx, 0, 0, 0, 0, 0); + if (!ret.error) + val = ret.value; + } else { + info = pmu_ctr_list[idx]; + val = riscv_pmu_read_ctr_csr(info.csr); + if (IS_ENABLED(CONFIG_32BIT)) + val = ((u64)riscv_pmu_read_ctr_csr(info.csr + 0x80)) << 32 | val; + } + + return val; +} + +static void pmu_sbi_start_ctr(struct perf_event *event, u64 ival) +{ + struct sbiret ret; + struct hw_perf_event *hwc = &event->hw; + + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, hwc->idx, + ival, 0, 0, 0, 0); + if (ret.error) + pr_err("Starting counter idx %d failed with error %d\n", + hwc->idx, sbi_err_map_linux_errno(ret.error)); +} + +static void pmu_sbi_stop_ctr(struct perf_event *event) +{ + struct sbiret ret; + struct hw_perf_event *hwc = &event->hw; + struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); + struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events); + bool breset = false; + + if (cpuc->events[hwc->idx] == NULL) + breset = true; + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, hwc->idx, breset, 0, 0, 0, 0); + if (ret.error) + 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 = 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 = 0, num_fw_ctr = 0; + union sbi_pmu_ctr_info cinfo; + + pmu_ctr_list = kzalloc(sizeof(*pmu_ctr_list) * nctr, GFP_KERNEL); + if (!pmu_ctr_list) + return -ENOMEM; + + for (i = 0; i <= nctr; i++) { + ret = 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 = ret.value; + if (cinfo.type == SBI_PMU_CTR_TYPE_FW) + num_fw_ctr++; + else + num_hw_ctr++; + pmu_ctr_list[i].value = cinfo.value; + } + + pr_info("There are %d firmware & %d hardware counters available\n", + num_fw_ctr, num_hw_ctr); + + return 0; +} + +void riscv_pmu_sbi_init(struct riscv_pmu *pmu) +{ + int num_counters; + + num_counters = pmu_sbi_find_num_ctrs(); + if (num_counters < 0) { + pr_err("SBI PMU extension doesn't provide any counters\n"); + return; + } + + /* cache all the information about counters now */ + if (pmu_sbi_get_ctrinfo(num_counters)) + return; + + pmu->num_counters = num_counters; + pmu->start_ctr = pmu_sbi_start_ctr; + pmu->stop_ctr = pmu_sbi_stop_ctr; + pmu->map_event = pmu_sbi_map_event; + pmu->get_ctr_idx = pmu_sbi_get_ctr_idx; + pmu->get_ctr_width = pmu_sbi_get_ctr_width; + pmu->clear_ctr_idx = pmu_sbi_clear_ctr_idx; + pmu->read_ctr = pmu_sbi_read_ctr; +} diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 3a02b496609d..e54ba2a998c2 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -54,6 +54,7 @@ struct riscv_pmu { #define to_riscv_pmu(p) (container_of(p, struct riscv_pmu, pmu)) unsigned long riscv_pmu_read_ctr_csr(unsigned long csr); void riscv_pmu_legacy_init(struct riscv_pmu *pmu); +void riscv_pmu_sbi_init(struct riscv_pmu *pmu); #endif /* CONFIG_RISCV_PMU */