get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2173985/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2173985,
    "url": "http://patchwork.ozlabs.org/api/patches/2173985/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/kvm-riscv/patch/20251213150848.149729-4-jamestiotio@gmail.com/",
    "project": {
        "id": 70,
        "url": "http://patchwork.ozlabs.org/api/projects/70/?format=api",
        "name": "Linux KVM RISC-V",
        "link_name": "kvm-riscv",
        "list_id": "kvm-riscv.lists.infradead.org",
        "list_email": "kvm-riscv@lists.infradead.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "http://lists.infradead.org/pipermail/kvm-riscv/",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20251213150848.149729-4-jamestiotio@gmail.com>",
    "list_archive_url": null,
    "date": "2025-12-13T15:08:47",
    "name": "[kvm-unit-tests,3/4] lib: riscv: Add SBI PMU helper functions",
    "commit_ref": null,
    "pull_url": null,
    "state": "handled-elsewhere",
    "archived": false,
    "hash": "856405173f756498ba36f2b8f31b90585226e18a",
    "submitter": {
        "id": 85990,
        "url": "http://patchwork.ozlabs.org/api/people/85990/?format=api",
        "name": "James Raphael Tiovalen",
        "email": "jamestiotio@gmail.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/kvm-riscv/patch/20251213150848.149729-4-jamestiotio@gmail.com/mbox/",
    "series": [
        {
            "id": 485289,
            "url": "http://patchwork.ozlabs.org/api/series/485289/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/kvm-riscv/list/?series=485289",
            "date": "2025-12-13T15:08:44",
            "name": "riscv: sbi: Add support to test PMU extension",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/485289/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2173985/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2173985/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "\n <kvm-riscv-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n secure) header.d=lists.infradead.org header.i=@lists.infradead.org\n header.a=rsa-sha256 header.s=bombadil.20210309 header.b=W+DEeU7M;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20230601 header.b=R17BnS+v;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=none (no SPF record) smtp.mailfrom=lists.infradead.org\n (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org;\n envelope-from=kvm-riscv-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from bombadil.infradead.org (bombadil.infradead.org\n [IPv6:2607:7c80:54:3::133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4dT8qm4Y4Zz1xvn\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 14 Dec 2025 02:09:24 +1100 (AEDT)",
            "from localhost ([::1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1vURFG-00000001ifd-3szR;\n\tSat, 13 Dec 2025 15:09:20 +0000",
            "from mail-pl1-x62b.google.com ([2607:f8b0:4864:20::62b])\n\tby bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1vURFD-00000001ieG-0V0k\n\tfor kvm-riscv@lists.infradead.org;\n\tSat, 13 Dec 2025 15:09:16 +0000",
            "by mail-pl1-x62b.google.com with SMTP id\n d9443c01a7336-29f30233d8aso16368555ad.0\n        for <kvm-riscv@lists.infradead.org>;\n Sat, 13 Dec 2025 07:09:14 -0800 (PST)",
            "from JRT-PC.. ([111.94.32.24])\n        by smtp.gmail.com with ESMTPSA id\n d9443c01a7336-29eea016c6esm85494715ad.59.2025.12.13.07.09.12\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Sat, 13 Dec 2025 07:09:13 -0800 (PST)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20210309; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post:\n\tList-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:\n\tMessage-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=8nCWPz2Woq0DOZvUhpLZ5+DEs/cIa6NoukHi2UwLDxw=; b=W+DEeU7MlBZN6b\n\tpAFtV79sORdNiXyuHeEsbZPPLBnv9N6cVFb4eTLl8w6rYgELH8gSmKVPTywnKzor3hwCV4Hto7rzx\n\tJ94+Prjrw69QRrfEfG7P80ea126rCQaVRYQeF6AhsC81HCSEwLbYkqADs1R2KLBy9mVgn+bCm0aZ9\n\tiWerBKLOU5VU4TOOWL3FYenabKAdCV6BmiljAaV2kHVMirzjamTAEyNjtNjU2m1/8TsEEWx8XyRK/\n\tresqFOVkBsuCdGICaJ+agqHNANeFAij/mmpfcZFBG5wXpqhZWN0gnUcLbhs3bL3clbuxBx4Txftbt\n\txJ8UWEMb/ce5Q5ru9f6A==;",
            "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20230601; t=1765638554; x=1766243354;\n darn=lists.infradead.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=AmDAR6Bn9JvT49nuZwllh+G0QriEIJ4NSotf6lGYgHk=;\n        b=R17BnS+v85VmzA05bUQ1B31OqTCbdsLIFI8P4kMGuunx3NbEnYSSL//RgRdGXPvD6i\n         vigW0wpvXGoKhYApO/x7OhkDIRQzf7288/C2EJergktqDEGBtw5xkctHKsOoGjjmau9X\n         WBEFwpVR37iLbw6SOTpu5CfL+uI8tiEMsrPJJRPeLWiFP6j0YJLwns9fs6HCeLB7suBU\n         GbvwP9VNSGA7hvZzYK96heeWthv40h5Zzhpzb7H60zxSwHEf7pe1/EYWNOqmkrJzF7PV\n         +c6zYOobO69cIywklzyhzOaKoMy1s7Ixz87i32/9V1Iou7/O4/8MoHq7MLm0qAw0uTNQ\n         fLIA=="
        ],
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20230601; t=1765638554; x=1766243354;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=AmDAR6Bn9JvT49nuZwllh+G0QriEIJ4NSotf6lGYgHk=;\n        b=Oa38pl5Xz5566aM7cyWtETedKVER0agLf2BKmPhOJh9uJIdJT4VsXvRvTzn0uia8aX\n         dLM0DIAEwBI4MFDxlvUvTUfls/O0+IyBWK6ae/EVV/yJlXb5dnXTRmzZufvTv0ftIfUY\n         Ym5mUHn7sX7iVKY36zsjHlG1zm4bf+vCCJQDl8WY1duf43O4lnl6/qTDYEh48ZfyiMqy\n         Xt6CLeoYGQX1WJHlr6SRIDDqXhG9mq2wTa9AFdbbnD2MZZHDs1pOdsk4zjrHPeLm3pY6\n         QvJIzQgxHRwspJBpNcEX86cIqg6Kfe3aElBUiK1EfOf1fN+aOMmuhpy+Wl3golpgsPW8\n         5W9w==",
        "X-Forwarded-Encrypted": "i=1;\n AJvYcCWUcEBYMWlCB4u569LXPtW6p4TvXiQKX2mRr2QJ+1gujeZMqK017hCikC3jF4ECqA7uogC9vLWQ/k0=@lists.infradead.org",
        "X-Gm-Message-State": "AOJu0Yxm3IioL/yPwfdUVsEItbiWYHLAeRwpXI9WtJ+OfoycQBGZlTHK\n\t4ZA4PvK6Fp7re3Xe1uh9pFw8UZfciTaDOXwa8TMGx75qZtuKoRJ57Y6/",
        "X-Gm-Gg": "AY/fxX4qaFBA6YIbrEjM+8OkCrmPOeJB3oeKSiOVP3ROpd+/N18AIuE8yFSP3lIdokM\n\tKj7yzJTl4WL51jdyAhox+Q+L7Ckg2w7omcteasJYeXmx9HpZeekpMOXetjsSPSUngivndv0P8eE\n\tjpaomVR+XzPeJlDhoi8lb+SGdklPiqF+4D3kazXHrMGp8fE942U2nO5wnNqG16y7/jIjfqaBBkv\n\tWEoU4FHvJMMvyTHVoJ+olwhYbWSefaPA5fLHiFtSA2N18pXv+PU7ymqNLPW144rV0vdaFMU7QPE\n\tgL0EzJ1458sPKaXwEY4lmyueACmmvsqogfMOPSJ4OsPfz+bTGrd6WJzyoWi0NvDdJV22Na4aspJ\n\tnYx41y7MHyUwzIsRdsedM2P3DmylbBb0Xxrap8OSuvLOp4Fm8uHxUUGBp1hTUbIE/iF4CN9SEQL\n\t08zZ81CU98Tv/eyIo+",
        "X-Google-Smtp-Source": "\n AGHT+IFRYLtmyJngjzSbWKBjUVfP4Wi/Qy+oiDqp2kwr34xj2mRB5StpR9CMC0oxckv+BkwV32PM5w==",
        "X-Received": "by 2002:a17:902:c94a:b0:298:648a:f96a with SMTP id\n d9443c01a7336-29f23d409ffmr50790565ad.61.1765638554178;\n        Sat, 13 Dec 2025 07:09:14 -0800 (PST)",
        "From": "James Raphael Tiovalen <jamestiotio@gmail.com>",
        "To": "kvm@vger.kernel.org,\n\tkvm-riscv@lists.infradead.org",
        "Cc": "andrew.jones@linux.dev,\n\tatishp@rivosinc.com,\n\tJames Raphael Tiovalen <jamestiotio@gmail.com>",
        "Subject": "[kvm-unit-tests PATCH 3/4] lib: riscv: Add SBI PMU helper functions",
        "Date": "Sat, 13 Dec 2025 23:08:47 +0800",
        "Message-ID": "<20251213150848.149729-4-jamestiotio@gmail.com>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20251213150848.149729-1-jamestiotio@gmail.com>",
        "References": "<20251213150848.149729-1-jamestiotio@gmail.com>",
        "MIME-Version": "1.0",
        "X-CRM114-Version": "20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ",
        "X-CRM114-CacheID": "sfid-20251213_070915_326688_843FA981 ",
        "X-CRM114-Status": "GOOD (  18.75  )",
        "X-Spam-Score": "-2.1 (--)",
        "X-Spam-Report": "Spam detection software,\n running on the system \"bombadil.infradead.org\",\n has NOT identified this incoming email as spam.  The original\n message has been attached to this so you can view it or label\n similar future email.  If you have any questions, see\n the administrator of that system for details.\n Content preview:  Add some helper macros to handle event types and codes and\n    some helper functions to access the FDT. These will be used by the SBI\n tests.\n    Signed-off-by: James Raphael Tiovalen --- riscv/Makefile | 1 +\n lib/riscv/asm/pmu.h\n    | 167 +++++++++++++++++++++++++++++++++++++++++++ lib/riscv/pmu.c | 169\n +++++++++++++++++++++++++++++++++++++++++++\n    [...]\n Content analysis details:   (-2.1 points, 5.0 required)\n  pts rule name              description\n ---- ----------------------\n --------------------------------------------------\n -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/, no\n                             trust\n                             [2607:f8b0:4864:20:0:0:0:62b listed in]\n                             [list.dnswl.org]\n -0.0 SPF_PASS               SPF: sender matches SPF record\n  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record\n -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from\n author's\n                             domain\n -0.1 DKIM_VALID             Message has at least one valid DKIM or DK\n signature\n  0.1 DKIM_SIGNED            Message has a DKIM or DK signature,\n not necessarily valid\n -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from\n                             envelope-from domain\n -1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n                             [score: 0.0000]\n  0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail\n provider\n                             [jamestiotio(at)gmail.com]",
        "X-BeenThere": "kvm-riscv@lists.infradead.org",
        "X-Mailman-Version": "2.1.34",
        "Precedence": "list",
        "List-Id": "<kvm-riscv.lists.infradead.org>",
        "List-Unsubscribe": "<http://lists.infradead.org/mailman/options/kvm-riscv>,\n <mailto:kvm-riscv-request@lists.infradead.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.infradead.org/pipermail/kvm-riscv/>",
        "List-Post": "<mailto:kvm-riscv@lists.infradead.org>",
        "List-Help": "<mailto:kvm-riscv-request@lists.infradead.org?subject=help>",
        "List-Subscribe": "<http://lists.infradead.org/mailman/listinfo/kvm-riscv>,\n <mailto:kvm-riscv-request@lists.infradead.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Sender": "\"kvm-riscv\" <kvm-riscv-bounces@lists.infradead.org>",
        "Errors-To": "kvm-riscv-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org"
    },
    "content": "Add some helper macros to handle event types and codes and some helper\nfunctions to access the FDT. These will be used by the SBI tests.\n\nSigned-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>\n---\n riscv/Makefile      |   1 +\n lib/riscv/asm/pmu.h | 167 +++++++++++++++++++++++++++++++++++++++++++\n lib/riscv/pmu.c     | 169 ++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 337 insertions(+)\n create mode 100644 lib/riscv/asm/pmu.h\n create mode 100644 lib/riscv/pmu.c",
    "diff": "diff --git a/riscv/Makefile b/riscv/Makefile\nindex 64720c38..c0dd5465 100644\n--- a/riscv/Makefile\n+++ b/riscv/Makefile\n@@ -42,6 +42,7 @@ cflatobjs += lib/riscv/delay.o\n cflatobjs += lib/riscv/io.o\n cflatobjs += lib/riscv/isa.o\n cflatobjs += lib/riscv/mmu.o\n+cflatobjs += lib/riscv/pmu.o\n cflatobjs += lib/riscv/processor.o\n cflatobjs += lib/riscv/sbi.o\n cflatobjs += lib/riscv/setjmp.o\ndiff --git a/lib/riscv/asm/pmu.h b/lib/riscv/asm/pmu.h\nnew file mode 100644\nindex 00000000..8bb5e3e9\n--- /dev/null\n+++ b/lib/riscv/asm/pmu.h\n@@ -0,0 +1,167 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+#ifndef _ASMRISCV_PMU_H_\n+#define _ASMRISCV_PMU_H_\n+\n+#include <libcflat.h>\n+#include <asm/csr.h>\n+\n+#define SBI_PMU_HW_CTR_MAX\t\t\t\t32\n+\n+#define SBI_EXT_PMU_EVENT_IDX_TYPE_OFFSET\t\t16\n+#define SBI_EXT_PMU_EVENT_IDX_TYPE_MASK\t\t\t(0xF << SBI_EXT_PMU_EVENT_IDX_TYPE_OFFSET)\n+#define SBI_EXT_PMU_EVENT_IDX_CODE_MASK\t\t\t0xFFFF\n+\n+#define SBI_EXT_PMU_EVENT_HW_CACHE_OPS_RESULT\t\t0x1\n+#define SBI_EXT_PMU_EVENT_HW_CACHE_OPS_ID_MASK\t\t0x6\n+#define SBI_EXT_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET\t1\n+#define SBI_EXT_PMU_EVENT_HW_CACHE_ID_MASK\t\t0xFFF8\n+#define SBI_EXT_PMU_EVENT_HW_CACHE_ID_OFFSET\t\t3\n+\n+#define SBI_EXT_PMU_CFG_FLAG_SKIP_MATCH\t\t\t(1 << 0)\n+#define SBI_EXT_PMU_CFG_FLAG_CLEAR_VALUE\t\t(1 << 1)\n+#define SBI_EXT_PMU_CFG_FLAG_AUTO_START\t\t\t(1 << 2)\n+#define SBI_EXT_PMU_CFG_FLAG_SET_VUINH\t\t\t(1 << 3)\n+#define SBI_EXT_PMU_CFG_FLAG_SET_VSINH\t\t\t(1 << 4)\n+#define SBI_EXT_PMU_CFG_FLAG_SET_UINH\t\t\t(1 << 5)\n+#define SBI_EXT_PMU_CFG_FLAG_SET_SINH\t\t\t(1 << 6)\n+#define SBI_EXT_PMU_CFG_FLAG_SET_MINH\t\t\t(1 << 7)\n+\n+#define SBI_EXT_PMU_START_SET_INIT_VALUE\t\t(1 << 0)\n+#define SBI_EXT_PMU_START_FLAG_INIT_SNAPSHOT\t\t(1 << 1)\n+\n+#define SBI_EXT_PMU_STOP_FLAG_RESET\t\t\t(1 << 0)\n+#define SBI_EXT_PMU_STOP_FLAG_TAKE_SNAPSHOT\t\t(1 << 1)\n+\n+#define SBI_EXT_PMU_HPM_COUNTER_CASE(n)\t\t\t\\\n+\tcase CSR_HPMCOUNTER##n:\t\t\t\t\\\n+\t\treturn csr_read(CSR_HPMCOUNTER##n)\n+\n+enum sbi_ext_pmu_ctr_type {\n+\tSBI_EXT_PMU_CTR_TYPE_HW = 0,\n+\tSBI_EXT_PMU_CTR_TYPE_FW,\n+};\n+\n+union sbi_ext_pmu_ctr_info {\n+\tunsigned long value;\n+\tstruct {\n+\t\tunsigned long csr:12;\n+\t\tunsigned long width:6;\n+#if __riscv_xlen == 32\n+\t\tunsigned long reserved:13;\n+#else\n+\t\tunsigned long reserved:45;\n+#endif\n+\t\tunsigned long type:1;\n+\t};\n+};\n+\n+#define get_cidx_type(x) \\\n+\t(((x) & SBI_EXT_PMU_EVENT_IDX_TYPE_MASK) >> SBI_EXT_PMU_EVENT_IDX_TYPE_OFFSET)\n+\n+#define get_cidx_code(x) (x & SBI_EXT_PMU_EVENT_IDX_CODE_MASK)\n+\n+#define get_cidx_cache_id(x) \\\n+\t(((get_cidx_code(x)) & SBI_EXT_PMU_EVENT_HW_CACHE_ID_MASK) >> SBI_EXT_PMU_EVENT_HW_CACHE_ID_OFFSET)\n+\n+#define get_cidx_op_id(x) \\\n+\t(((get_cidx_code(x)) & SBI_EXT_PMU_EVENT_HW_CACHE_OPS_ID_MASK) >> SBI_EXT_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET)\n+\n+#define get_cidx_result_id(x) \\\n+\t((get_cidx_code(x)) & SBI_EXT_PMU_EVENT_HW_CACHE_OPS_RESULT)\n+\n+#define set_cidx_type(x, t) \\\n+\t((x) = ((((x) & ~SBI_EXT_PMU_EVENT_IDX_TYPE_MASK) | \\\n+\t\t((((unsigned long)(t)) << SBI_EXT_PMU_EVENT_IDX_TYPE_OFFSET) \\\n+\t\t& SBI_EXT_PMU_EVENT_IDX_TYPE_MASK))))\n+\n+#define set_cidx_code(x, c) \\\n+\t((x) = ((((x) & ~SBI_EXT_PMU_EVENT_IDX_CODE_MASK) | \\\n+\t\t(((unsigned long)(c)) & SBI_EXT_PMU_EVENT_IDX_CODE_MASK))))\n+\n+#define set_cidx_cache_id(x, id) \\\n+\t(set_cidx_code((x), (((get_cidx_code(x)) & ~SBI_EXT_PMU_EVENT_HW_CACHE_ID_MASK) | \\\n+\t\t((((unsigned long)(id)) << SBI_EXT_PMU_EVENT_HW_CACHE_ID_OFFSET) \\\n+\t\t& SBI_EXT_PMU_EVENT_HW_CACHE_ID_MASK))))\n+\n+#define set_cidx_op_id(x, op) \\\n+\t(set_cidx_code((x), (((get_cidx_code(x)) & ~SBI_EXT_PMU_EVENT_HW_CACHE_OPS_ID_MASK) | \\\n+\t\t((((unsigned long)(op)) << SBI_EXT_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET) \\\n+\t\t& SBI_EXT_PMU_EVENT_HW_CACHE_OPS_ID_MASK))))\n+\n+#define set_cidx_result_id(x, res) \\\n+\t(set_cidx_code((x), (((get_cidx_code(x)) & ~SBI_EXT_PMU_EVENT_HW_CACHE_OPS_RESULT) | \\\n+\t\t(((unsigned long)(res)) & SBI_EXT_PMU_EVENT_HW_CACHE_OPS_RESULT))))\n+\n+static inline uint64_t pmu_get_cycles(void)\n+{\n+\treturn csr_read(CSR_CYCLE);\n+}\n+\n+static inline uint64_t pmu_get_instret(void)\n+{\n+\treturn csr_read(CSR_INSTRET);\n+}\n+\n+static inline uint64_t pmu_get_counter(unsigned long csr)\n+{\n+\tswitch (csr) {\n+\tcase CSR_CYCLE:\n+\t\treturn pmu_get_cycles();\n+\tcase CSR_INSTRET:\n+\t\treturn pmu_get_instret();\n+\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(3);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(4);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(5);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(6);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(7);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(8);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(9);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(10);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(11);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(12);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(13);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(14);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(15);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(16);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(17);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(18);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(19);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(20);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(21);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(22);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(23);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(24);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(25);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(26);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(27);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(28);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(29);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(30);\n+\tSBI_EXT_PMU_HPM_COUNTER_CASE(31);\n+\n+\tdefault:\n+\t\t__builtin_unreachable();\n+\t}\n+}\n+\n+struct sbi_ext_pmu_hw_event {\n+\tuint32_t counters;\n+\tunsigned long start_idx;\n+\tunsigned long end_idx;\n+};\n+\n+struct sbi_ext_pmu_test_ctr {\n+\tint ctr_idx;\n+\tunsigned long eid;\n+};\n+\n+int sbi_ext_pmu_get_counters_for_hw_event(unsigned long event_idx);\n+int sbi_ext_pmu_get_first_counter_for_hw_event(unsigned long event_idx);\n+int sbi_ext_pmu_get_first_unsupported_hw_event(int ctr_idx);\n+struct sbi_ext_pmu_test_ctr sbi_ext_pmu_get_candidate_hw_counter_for_test(void);\n+void sbi_ext_pmu_add_hw_event_counter_map(u32 event_idx_start, u32 event_idx_end, u32 ctr_map, int i);\n+void fdt_pmu_setup(void);\n+void fdt_pmu_free(void);\n+\n+#endif /* _ASMRISCV_PMU_H_ */\ndiff --git a/lib/riscv/pmu.c b/lib/riscv/pmu.c\nnew file mode 100644\nindex 00000000..7bbd8221\n--- /dev/null\n+++ b/lib/riscv/pmu.c\n@@ -0,0 +1,169 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Copyright (C) 2025, James Raphael Tiovalen <jamestiotio@gmail.com>\n+ */\n+#include <alloc.h>\n+#include <libcflat.h>\n+#include <devicetree.h>\n+#include <asm/sbi.h>\n+#include <asm/pmu.h>\n+\n+static struct sbi_ext_pmu_hw_event *hw_event_map;\n+\n+int sbi_ext_pmu_get_counters_for_hw_event(unsigned long event_idx)\n+{\n+\tint i;\n+\n+\tif (!hw_event_map)\n+\t\treturn -1;\n+\n+\tfor (i = 0; i < SBI_PMU_HW_CTR_MAX; i++) {\n+\t\tif (hw_event_map[i].start_idx <= event_idx &&\n+\t\t    hw_event_map[i].end_idx >= event_idx) {\n+\t\t\treturn hw_event_map[i].counters;\n+\t\t}\n+\t}\n+\n+\treturn -1;\n+}\n+\n+int sbi_ext_pmu_get_first_counter_for_hw_event(unsigned long event_idx)\n+{\n+\tint i, counters = sbi_ext_pmu_get_counters_for_hw_event(event_idx);\n+\n+\tif (!hw_event_map || counters < 0)\n+\t\treturn -1;\n+\n+\tfor (i = CSR_HPMCOUNTER3 - CSR_CYCLE; i < SBI_PMU_HW_CTR_MAX; i++) {\n+\t\tif (counters & (1U << i))\n+\t\t\treturn i;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+void sbi_ext_pmu_add_hw_event_counter_map(u32 event_idx_start, u32 event_idx_end, u32 ctr_map, int i)\n+{\n+\tassert(event_idx_start <= event_idx_end);\n+\n+\thw_event_map[i].counters = ctr_map;\n+\thw_event_map[i].start_idx = event_idx_start;\n+\thw_event_map[i].end_idx = event_idx_end;\n+\n+\tassert(get_cidx_type(hw_event_map[i].start_idx) == SBI_EXT_PMU_EVENT_HW_GENERAL\n+\t       || get_cidx_type(hw_event_map[i].start_idx) == SBI_EXT_PMU_EVENT_HW_CACHE);\n+\tassert(get_cidx_type(hw_event_map[i].end_idx) == SBI_EXT_PMU_EVENT_HW_GENERAL\n+\t       || get_cidx_type(hw_event_map[i].end_idx) == SBI_EXT_PMU_EVENT_HW_CACHE);\n+}\n+\n+int sbi_ext_pmu_get_first_unsupported_hw_event(int ctr_idx)\n+{\n+\tint i, j, k;\n+\tunsigned long candidate_eid = {0};\n+\n+\tif (!hw_event_map)\n+\t\treturn -1;\n+\n+\tfor (i = SBI_EXT_PMU_HW_CPU_CYCLES; i <= SBI_EXT_PMU_HW_REF_CPU_CYCLES; i++) {\n+\t\tset_cidx_type(candidate_eid, SBI_EXT_PMU_EVENT_HW_GENERAL);\n+\t\tset_cidx_code(candidate_eid, i);\n+\n+\t\tif (sbi_ext_pmu_get_counters_for_hw_event(candidate_eid) < 0)\n+\t\t\treturn candidate_eid;\n+\t}\n+\n+\tfor (i = SBI_EXT_PMU_HW_CACHE_L1D; i <= SBI_EXT_PMU_HW_CACHE_NODE; i++) {\n+\t\tfor (j = SBI_EXT_PMU_HW_CACHE_OP_READ; j <= SBI_EXT_PMU_HW_CACHE_OP_PREFETCH; j++) {\n+\t\t\tfor (k = SBI_EXT_PMU_HW_CACHE_RESULT_ACCESS; k <= SBI_EXT_PMU_HW_CACHE_RESULT_MISS; k++) {\n+\t\t\t\tset_cidx_type(candidate_eid, SBI_EXT_PMU_EVENT_HW_CACHE);\n+\t\t\t\tset_cidx_cache_id(candidate_eid, i);\n+\t\t\t\tset_cidx_op_id(candidate_eid, j);\n+\t\t\t\tset_cidx_result_id(candidate_eid, k);\n+\n+\t\t\t\tif (sbi_ext_pmu_get_counters_for_hw_event(candidate_eid) < 0)\n+\t\t\t\t\treturn candidate_eid;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn -1;\n+}\n+\n+struct sbi_ext_pmu_test_ctr sbi_ext_pmu_get_candidate_hw_counter_for_test(void)\n+{\n+\tstruct sbi_ext_pmu_test_ctr test_ctr = {0};\n+\tint i, j, k, ctr_idx;\n+\n+\tif (!hw_event_map)\n+\t\treturn test_ctr;\n+\n+\tunsigned long candidate_eid = {0};\n+\n+\tfor (i = SBI_EXT_PMU_HW_CPU_CYCLES; i <= SBI_EXT_PMU_HW_REF_CPU_CYCLES; i++) {\n+\t\tset_cidx_type(candidate_eid, SBI_EXT_PMU_EVENT_HW_GENERAL);\n+\t\tset_cidx_code(candidate_eid, i);\n+\t\tctr_idx = sbi_ext_pmu_get_first_counter_for_hw_event(candidate_eid);\n+\n+\t\tif (ctr_idx >= 0) {\n+\t\t\ttest_ctr.ctr_idx = ctr_idx;\n+\t\t\ttest_ctr.eid = candidate_eid;\n+\t\t\treturn test_ctr;\n+\t\t}\n+\t}\n+\n+\tfor (i = SBI_EXT_PMU_HW_CACHE_L1D; i <= SBI_EXT_PMU_HW_CACHE_NODE; i++) {\n+\t\tfor (j = SBI_EXT_PMU_HW_CACHE_OP_READ; j <= SBI_EXT_PMU_HW_CACHE_OP_PREFETCH; j++) {\n+\t\t\tfor (k = SBI_EXT_PMU_HW_CACHE_RESULT_ACCESS; k <= SBI_EXT_PMU_HW_CACHE_RESULT_MISS; k++) {\n+\t\t\t\tset_cidx_type(candidate_eid, SBI_EXT_PMU_EVENT_HW_CACHE);\n+\t\t\t\tset_cidx_cache_id(candidate_eid, i);\n+\t\t\t\tset_cidx_op_id(candidate_eid, j);\n+\t\t\t\tset_cidx_result_id(candidate_eid, k);\n+\t\t\t\tctr_idx = sbi_ext_pmu_get_first_counter_for_hw_event(candidate_eid);\n+\n+\t\t\t\tif (ctr_idx >= 0) {\n+\t\t\t\t\ttest_ctr.ctr_idx = ctr_idx;\n+\t\t\t\t\ttest_ctr.eid = candidate_eid;\n+\t\t\t\t\treturn test_ctr;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn test_ctr;\n+}\n+\n+void fdt_pmu_setup(void)\n+{\n+\tconst void *fdt;\n+\tint i, pmu_offset, len;\n+\tconst u32 *event_ctr_map;\n+\tu32 event_idx_start, event_idx_end, ctr_map;\n+\n+\tassert_msg(dt_available(), \"ACPI not yet supported\");\n+\n+\tfdt = dt_fdt();\n+\n+\tpmu_offset = fdt_node_offset_by_compatible(fdt, -1, \"riscv,pmu\");\n+\tassert(pmu_offset >= 0);\n+\n+\tevent_ctr_map = fdt_getprop(fdt, pmu_offset, \"riscv,event-to-mhpmcounters\", &len);\n+\tif (event_ctr_map) {\n+\t\tlen = len / (sizeof(u32) * 3);\n+\t\thw_event_map = calloc(len, sizeof(struct sbi_ext_pmu_hw_event));\n+\t\tfor (i = 0; i < len; i++) {\n+\t\t\tevent_idx_start = fdt32_to_cpu(event_ctr_map[3 * i]);\n+\t\t\tevent_idx_end = fdt32_to_cpu(event_ctr_map[3 * i + 1]);\n+\t\t\tctr_map = fdt32_to_cpu(event_ctr_map[3 * i + 2]);\n+\t\t\tsbi_ext_pmu_add_hw_event_counter_map(event_idx_start, event_idx_end, ctr_map, i);\n+\t\t}\n+\t\treport_info(\"added %d hw event counter mappings\", len);\n+\t}\n+}\n+\n+void fdt_pmu_free(void)\n+{\n+\tif (hw_event_map) {\n+\t\tfree(hw_event_map);\n+\t\thw_event_map = NULL;\n+\t}\n+}\n",
    "prefixes": [
        "kvm-unit-tests",
        "3/4"
    ]
}