From nobody Fri Feb 27 22:08:45 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fN2Xg5yXKz6TPsB for ; Fri, 27 Feb 2026 22:08:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fN2Xg1LGFz3lld for ; Fri, 27 Feb 2026 22:08:51 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772230131; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hlCOIGhuG1XGKutVgxVT68aBhwyKDc6ajwdM1tw57gw=; b=yXGG39cxmqKTsy6KD3kxRpWgKSbVRfIb3lZTQpbNiiQYmnDkHxiSCO4ZoGyOlPCq/KWYgT 9/0dIuV7CMW8xuu+inYW6ElNdC8FaGX/uTRpmQWaaooLQMYp5/+eM6eLP/hZcLW0QnZjay /hibVTOhAc1jEvexsOmVi3tNEi2Nsdg/rQhFLdGAS25y5ycxS6N5u5WZCEs6RLeAfrH8JV MgzaiGv0nDLrtBKIGwWGYh7PvmY3TaDYOoihib13n59XRGKEP6MfKfCP7/F5nq2eoStQeS 3qSst0zMkczSwl3tjRH6UdJtHIgg7I8maBL05VjVygkrclDedX/C/1q4raYnkg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1772230131; a=rsa-sha256; cv=none; b=PteHiVN6EhgclskIFwYGTHLpeStdjwjNSb/uvsOdjQ9UzIYw511opD9Zlx5h/FwtNRvAwp N7mdjfp7kibQtsZaTHLxJMP6WvDal3rg1bdfDGD2o7lzJygV7vsDHW8VA+kD4f8jqerqCE MbisZOvHri0a7RV+LXsFjFo0tQVjDVrvJtMjv8tV+vY/6eb0tItofAcgSi87U0A8BvscI1 4t2p6AyUIUrcAy7C4tOyOC3x/SpvEfXLeT1A8dt4jc5vfkH5cXRzKYNwQDGDftSnjnSZY0 fiRmcWZCZ3dGrcQlnPcMYvuKbFcVR2z1T+XT1HYgKxawgINMBZReKgnPGPFNUg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772230131; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hlCOIGhuG1XGKutVgxVT68aBhwyKDc6ajwdM1tw57gw=; b=FKR2+THnb5u2l6OVKwtOLGpwiMUfWe+wUNeImkCy+j5GCQ+EMrSgekAMbl6Vy2KzuxYipt 1cfrT1Zg4guAmHsCWX2ACaMCnVYUiro5OHSHZA0aF0UjLlbj9aMBcXi88tz6lsFk5mPozB 2iFnpq9Udz6Vm0/0AoLdP+sQzCrPQCsj9/+o5klQKHO9wW3xElCMU4HWFd4YO79C4Ul8IA ndvNT38AjVeM7eqXg0fQI7sf3UYhmcNZ6QcK6zzmkhNmtCpYGCZEgmei15A0FjUr/ztgLX h2fNf5DdH5XG+rBRjqB0fQic+C78wrRiLz5UaIQ5QaJER2GTY2Asqbl7Oy1drw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fN2Xg0lqczcSB for ; Fri, 27 Feb 2026 22:08:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 342b2 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 27 Feb 2026 22:08:45 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Ali Mashtizadeh From: Warner Losh Subject: git: 00c0a1f0bf6c - main - hwpmc: Fix PMC flags for AMD Zen cores List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 00c0a1f0bf6c07e63384a389060dfc10924c0ed6 Auto-Submitted: auto-generated Date: Fri, 27 Feb 2026 22:08:45 +0000 Message-Id: <69a215ed.342b2.2e815130@gitrepo.freebsd.org> The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=00c0a1f0bf6c07e63384a389060dfc10924c0ed6 commit 00c0a1f0bf6c07e63384a389060dfc10924c0ed6 Author: Ali Mashtizadeh AuthorDate: 2026-02-21 19:07:26 +0000 Commit: Warner Losh CommitDate: 2026-02-27 21:19:40 +0000 hwpmc: Fix PMC flags for AMD Zen cores The PMC flags available for DF and L3 counters were not all implemented. More importantly, the field encodings for the L3 counters changed in an incompatible way between Family 17h and Family 19h. Similarly, the field encodings for the DF coutners changed between Family 19h and 1Ah. I also added the precise retire flag for the 3rd core counter. Lastly, I added a warning in the jevent parser because ignoring the unknown fields results in counters incorrectly programmed. We should not just ignore that. Sponsored by: Netflix Reviewed by: imp Pull Request: https://github.com/freebsd/freebsd-src/pull/2040 --- lib/libpmc/libpmc_pmu_util.c | 71 ++++++++++++++++++++++++++++--- lib/libpmc/pmu-events/jevents.c | 40 +++++++++++++++++- lib/libpmc/pmu-events/json.c | 14 +++++++ lib/libpmc/pmu-events/json.h | 1 + sys/dev/hwpmc/hwpmc_amd.c | 19 ++++++++- sys/dev/hwpmc/hwpmc_amd.h | 93 +++++++++++++++++++++++++++++------------ 6 files changed, 204 insertions(+), 34 deletions(-) diff --git a/lib/libpmc/libpmc_pmu_util.c b/lib/libpmc/libpmc_pmu_util.c index de642aa71a18..0832ab32e2f1 100644 --- a/lib/libpmc/libpmc_pmu_util.c +++ b/lib/libpmc/libpmc_pmu_util.c @@ -121,6 +121,24 @@ pmu_events_mfr(void) return (mfr); } +static int +pmu_events_x86_family(void) +{ + char buf[PMC_CPUID_LEN]; + size_t s = sizeof(buf); + char *cpuid, *family; + + if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, + (void *)NULL, 0) == -1) + return (-1); + cpuid = &buf[0]; + + strsep(&cpuid, "-"); + family = strsep(&cpuid, "-"); + + return (strtol(family, NULL, 10)); +} + /* * The Intel fixed mode counters are: * "inst_retired.any", @@ -208,6 +226,10 @@ struct pmu_event_desc { uint64_t ped_offcore_rsp; uint64_t ped_l3_thread; uint64_t ped_l3_slice; + uint32_t ped_sourceid; + uint32_t ped_coreid; + uint32_t ped_allsources; + uint32_t ped_allcores; uint32_t ped_event; uint32_t ped_frontend; uint32_t ped_ldlat; @@ -347,6 +369,14 @@ pmu_parse_event(struct pmu_event_desc *ped, const char *eventin) ped->ped_l3_thread = strtol(value, NULL, 16); else if (strcmp(key, "l3_slice_mask") == 0) ped->ped_l3_slice = strtol(value, NULL, 16); + else if (strcmp(key, "sourceid") == 0) + ped->ped_sourceid = strtol(value, NULL, 16); + else if (strcmp(key, "coreid") == 0) + ped->ped_coreid = strtol(value, NULL, 16); + else if (strcmp(key, "allcores") == 0) + ped->ped_allcores = strtol(value, NULL, 10); + else if (strcmp(key, "allsources") == 0) + ped->ped_allsources = strtol(value, NULL, 10); else { debug = getenv("PMUDEBUG"); if (debug != NULL && strcmp(debug, "true") == 0 && value != NULL) @@ -486,20 +516,23 @@ static int pmc_pmu_amd_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, struct pmu_event_desc *ped) { + int cpu_family; struct pmc_md_amd_op_pmcallocate *amd; const struct pmu_event *pe; int idx = -1; + cpu_family = pmu_events_x86_family(); + amd = &pm->pm_md.pm_amd; if (ped->ped_umask > 0) { pm->pm_caps |= PMC_CAP_QUALIFIER; - amd->pm_amd_config |= AMD_PMC_TO_UNITMASK(ped->ped_umask); } pm->pm_class = PMC_CLASS_K8; pe = pmu_event_get(NULL, event_name, &idx); if (pe->pmu == NULL) { amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event); + amd->pm_amd_config |= AMD_PMC_TO_UNITMASK(ped->ped_umask); amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_CORE; if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == @@ -515,14 +548,42 @@ pmc_pmu_amd_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, amd->pm_amd_config |= AMD_PMC_INVERT; if (pm->pm_caps & PMC_CAP_INTERRUPT) amd->pm_amd_config |= AMD_PMC_INT; + if (pm->pm_caps & PMC_CAP_PRECISE) + amd->pm_amd_config |= AMD_PMC_PRECISERETIRE; } else if (strcmp("amd_l3", pe->pmu) == 0) { - amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event); + amd->pm_amd_config |= AMD_PMC_L3_TO_EVENTMASK(ped->ped_event); + amd->pm_amd_config |= AMD_PMC_L3_TO_UNITMASK(ped->ped_umask); amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_L3_CACHE; - amd->pm_amd_config |= AMD_PMC_TO_L3SLICE(ped->ped_l3_slice); - amd->pm_amd_config |= AMD_PMC_TO_L3CORE(ped->ped_l3_thread); + if (cpu_family <= 0x17) { + amd->pm_amd_config |= + AMD_PMC_L31_TO_SLICE(ped->ped_l3_slice); + amd->pm_amd_config |= + AMD_PMC_L31_TO_CORE(ped->ped_l3_thread); + } else { + amd->pm_amd_config |= + AMD_PMC_L32_TO_THREAD(ped->ped_l3_thread); + amd->pm_amd_config |= + AMD_PMC_L32_TO_SOURCEID(ped->ped_sourceid); + amd->pm_amd_config |= + AMD_PMC_L32_TO_COREID(ped->ped_coreid); + if (ped->ped_allcores) + amd->pm_amd_config |= AMD_PMC_L32_ALLCORES; + if (ped->ped_allsources) + amd->pm_amd_config |= AMD_PMC_L32_ALLSOURCES; + } } else if (strcmp("amd_df", pe->pmu) == 0) { - amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK_DF(ped->ped_event); amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_DATA_FABRIC; + if (cpu_family <= 19) { + amd->pm_amd_config |= + AMD_PMC_DF1_TO_EVENTMASK(ped->ped_event); + amd->pm_amd_config |= + AMD_PMC_DF1_TO_UNITMASK(ped->ped_umask); + } else { + amd->pm_amd_config |= + AMD_PMC_DF2_TO_EVENTMASK(ped->ped_event); + amd->pm_amd_config |= + AMD_PMC_DF2_TO_UNITMASK(ped->ped_umask); + } } else { printf("PMC pmu '%s' is not supported!\n", pe->pmu); return (EOPNOTSUPP); diff --git a/lib/libpmc/pmu-events/jevents.c b/lib/libpmc/pmu-events/jevents.c index 628ed26c6f9d..4e4f53a0c0d0 100644 --- a/lib/libpmc/pmu-events/jevents.c +++ b/lib/libpmc/pmu-events/jevents.c @@ -560,6 +560,10 @@ static int json_events(const char *fn, jsmntok_t *obj = tok++; bool configcode_present = false; char *umask = NULL; + char *allcores = NULL; + char *allslices = NULL; + char *sliceid = NULL; + char *threadmask = NULL; char *cmask = NULL; char *inv = NULL; char *any = NULL; @@ -585,6 +589,22 @@ static int json_events(const char *fn, /* match_field */ if (json_streq(map, field, "UMask") && nz) { addfield(map, &umask, "", "umask=", val); + } else if (json_streq(map, field, "EnAllCores") && nz) { + addfield(map, &allcores, "", "allcores=", val); + } else if (json_streq(map, field, "EnAllSlices") && nz) { + addfield(map, &allslices, "", "allslices=", val); + } else if (json_streq(map, field, "SliceId") && nz) { + /* + * We use sourceid because there's a + * descripency where the JSON from linux calls + * it a SliceId, which is not the name used by + * AMD in the PPRs. The field name from Family + * 19h and below that calls it slicemask see + * the references in hwpmc_amd.h. + */ + addfield(map, &sliceid, "", "sourceid=", val); + } else if (json_streq(map, field, "ThreadMask") && nz) { + addfield(map, &threadmask, "", "l3_thread_mask=", val); } else if (json_streq(map, field, "CounterMask") && nz) { addfield(map, &cmask, "", "cmask=", val); } else if (json_streq(map, field, "Invert") && nz) { @@ -675,8 +695,14 @@ static int json_events(const char *fn, addfield(map, &arch_std, "", "", val); for (s = arch_std; *s; s++) *s = tolower(*s); + } else { + /* + * We shouldn't ignore unknown fields that + * makes the counter invalid! + */ + json_copystr(map, field, buf, sizeof(buf)); + fprintf(stderr, "Unknown field '%s'!\n", buf); } - /* ignore unknown fields */ } if (precise && je.desc && !strstr(je.desc, "(Precise Event)")) { if (json_streq(map, precise, "2")) @@ -707,6 +733,14 @@ static int json_events(const char *fn, addfield(map, &event, ",", period, NULL); if (umask) addfield(map, &event, ",", umask, NULL); + if (allcores) + addfield(map, &event, ",", allcores, NULL); + if (allslices) + addfield(map, &event, ",", allslices, NULL); + if (sliceid) + addfield(map, &event, ",", sliceid, NULL); + if (threadmask) + addfield(map, &event, ",", threadmask, NULL); if (je.desc && extra_desc) addfield(map, &je.desc, " ", extra_desc, NULL); @@ -737,6 +771,10 @@ static int json_events(const char *fn, err = func(data, &je); free_strings: free(umask); + free(allcores); + free(allslices); + free(sliceid); + free(threadmask); free(cmask); free(inv); free(any); diff --git a/lib/libpmc/pmu-events/json.c b/lib/libpmc/pmu-events/json.c index 89cafbc04fb6..66eaf0a74ba6 100644 --- a/lib/libpmc/pmu-events/json.c +++ b/lib/libpmc/pmu-events/json.c @@ -160,3 +160,17 @@ int json_streq(char *map, jsmntok_t *t, const char *s) unsigned len = json_len(t); return len == strlen(s) && !strncasecmp(map + t->start, s, len); } + +int json_copystr(char *map, jsmntok_t *t, char *s, int len) +{ + int jlen; + + jlen = json_len(t); + if (jlen > len) + jlen = len - 1; + + memcpy(s, map + t->start, jlen); + s[jlen] = '\0'; + + return (jlen); +} diff --git a/lib/libpmc/pmu-events/json.h b/lib/libpmc/pmu-events/json.h index 278ebd32cfb6..89b9c2fba617 100644 --- a/lib/libpmc/pmu-events/json.h +++ b/lib/libpmc/pmu-events/json.h @@ -9,6 +9,7 @@ int json_line(char *map, jsmntok_t *t); const char *json_name(jsmntok_t *t); int json_streq(char *map, jsmntok_t *t, const char *s); int json_len(jsmntok_t *t); +int json_copystr(char *map, jsmntok_t *t, char *s, int len); extern int verbose; diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c index 801b75b39595..b34cbffcffa8 100644 --- a/sys/dev/hwpmc/hwpmc_amd.c +++ b/sys/dev/hwpmc/hwpmc_amd.c @@ -347,6 +347,10 @@ amd_allocate_pmc(int cpu __unused, int ri, struct pmc *pm, caps = pm->pm_caps; + if (((caps & PMC_CAP_PRECISE) != 0) && + ((pd->pd_caps & PMC_CAP_PRECISE) == 0)) + return (EINVAL); + PMCDBG2(MDP, ALL, 1,"amd-allocate ri=%d caps=0x%x", ri, caps); /* Validate sub-class. */ @@ -360,6 +364,9 @@ amd_allocate_pmc(int cpu __unused, int ri, struct pmc *pm, return (0); } + /* + * Everything below this is for supporting older processors. + */ pe = a->pm_ev; /* map ev to the correct event mask code */ @@ -817,6 +824,14 @@ pmc_amd_initialize(void) "K8-%d", i); d->pm_descr.pd_class = PMC_CLASS_K8; d->pm_descr.pd_caps = AMD_PMC_CAPS; + /* + * Zen 5 can precisely count retire events. + * + * Refer to PPR Vol 1 for AMD Family 1Ah Model 02h C1 57238 + * Rev. 0.24 September 29, 2024. + */ + if ((family >= 0x1a) && (i == 2)) + d->pm_descr.pd_caps |= PMC_CAP_PRECISE; d->pm_descr.pd_width = 48; if ((amd_feature2 & AMDID2_PCXC) != 0) { d->pm_evsel = AMD_PMC_CORE_BASE + 2 * i; @@ -836,7 +851,7 @@ pmc_amd_initialize(void) snprintf(d->pm_descr.pd_name, PMC_NAME_MAX, "K8-L3-%d", i); d->pm_descr.pd_class = PMC_CLASS_K8; - d->pm_descr.pd_caps = AMD_PMC_CAPS; + d->pm_descr.pd_caps = AMD_PMC_L3_CAPS; d->pm_descr.pd_width = 48; d->pm_evsel = AMD_PMC_L3_BASE + 2 * i; d->pm_perfctr = AMD_PMC_L3_BASE + 2 * i + 1; @@ -852,7 +867,7 @@ pmc_amd_initialize(void) snprintf(d->pm_descr.pd_name, PMC_NAME_MAX, "K8-DF-%d", i); d->pm_descr.pd_class = PMC_CLASS_K8; - d->pm_descr.pd_caps = AMD_PMC_CAPS; + d->pm_descr.pd_caps = AMD_PMC_DF_CAPS; d->pm_descr.pd_width = 48; d->pm_evsel = AMD_PMC_DF_BASE + 2 * i; d->pm_perfctr = AMD_PMC_DF_BASE + 2 * i + 1; diff --git a/sys/dev/hwpmc/hwpmc_amd.h b/sys/dev/hwpmc/hwpmc_amd.h index be484a1111a2..6d8ab8203942 100644 --- a/sys/dev/hwpmc/hwpmc_amd.h +++ b/sys/dev/hwpmc/hwpmc_amd.h @@ -62,21 +62,10 @@ #define AMD_PMC_CORE_DEFAULT 6 #define AMD_PMC_CORE_MAX 16 -/* L3 */ -#define AMD_PMC_L3_BASE 0xC0010230 -#define AMD_PMC_L3_DEFAULT 6 -#define AMD_PMC_L3_MAX 6 - -/* DF */ -#define AMD_PMC_DF_BASE 0xC0010240 -#define AMD_PMC_DF_DEFAULT 4 -#define AMD_PMC_DF_MAX 64 - -#define AMD_NPMCS_K8 4 -#define AMD_NPMCS_MAX (AMD_PMC_CORE_MAX + AMD_PMC_L3_MAX + \ - AMD_PMC_DF_MAX) - #define AMD_PMC_COUNTERMASK 0xFF000000 +#define AMD_PMC_PRECISERETIRE (1ULL << 43) /* Only valid for PERF_CTL2 */ +#define AMD_PMC_HOST (1ULL << 41) +#define AMD_PMC_GUEST (1ULL << 40) #define AMD_PMC_TO_COUNTER(x) (((x) << 24) & AMD_PMC_COUNTERMASK) #define AMD_PMC_INVERT (1 << 23) #define AMD_PMC_ENABLE (1 << 22) @@ -85,24 +74,13 @@ #define AMD_PMC_EDGE (1 << 18) #define AMD_PMC_OS (1 << 17) #define AMD_PMC_USR (1 << 16) -#define AMD_PMC_L3SLICEMASK (0x000F000000000000) -#define AMD_PMC_L3COREMASK (0xFF00000000000000) -#define AMD_PMC_TO_L3SLICE(x) (((x) << 48) & AMD_PMC_L3SLICEMASK) -#define AMD_PMC_TO_L3CORE(x) (((x) << 56) & AMD_PMC_L3COREMASK) - -#define AMD_PMC_UNITMASK_M 0x10 -#define AMD_PMC_UNITMASK_O 0x08 -#define AMD_PMC_UNITMASK_E 0x04 -#define AMD_PMC_UNITMASK_S 0x02 -#define AMD_PMC_UNITMASK_I 0x01 -#define AMD_PMC_UNITMASK_MOESI 0x1F #define AMD_PMC_UNITMASK 0xFF00 #define AMD_PMC_EVENTMASK 0xF000000FF #define AMD_PMC_TO_UNITMASK(x) (((x) << 8) & AMD_PMC_UNITMASK) #define AMD_PMC_TO_EVENTMASK(x) (((x) & 0xFF) | (((uint64_t)(x) & 0xF00) << 24)) -#define AMD_PMC_TO_EVENTMASK_DF(x) (((x) & 0xFF) | (((uint64_t)(x) & 0x0F00) << 24)) | (((uint64_t)(x) & 0x3000) << 47) + #define AMD_VALID_BITS (AMD_PMC_COUNTERMASK | AMD_PMC_INVERT | \ AMD_PMC_ENABLE | AMD_PMC_INT | AMD_PMC_PC | AMD_PMC_EDGE | \ AMD_PMC_OS | AMD_PMC_USR | AMD_PMC_UNITMASK | AMD_PMC_EVENTMASK) @@ -111,6 +89,69 @@ PMC_CAP_SYSTEM | PMC_CAP_EDGE | PMC_CAP_THRESHOLD | \ PMC_CAP_READ | PMC_CAP_WRITE | PMC_CAP_INVERT | PMC_CAP_QUALIFIER) +/* L3 */ +#define AMD_PMC_L3_BASE 0xC0010230 +#define AMD_PMC_L3_DEFAULT 6 +#define AMD_PMC_L3_MAX 6 + +/* + * L3 counters change their encoding slightly between Family 17h and Family 19h + * processors. + * + * Refer to the following documents for the L3 fields: + * PPR for AMD Family 17h Model 20h A1 55772-A1 Rev. 3.08 April 14, 2021 + * PPR for AMD Family 19h Model 51h A1 56569-A1 Rev. 3.03 September 21, 2021 + * PPR for AMD Family 1Ah Model 02h C1 57238 Rev. 0.24 September 29, 2024 + */ +#define AMD_PMC_L31_SLICEMASK (0x000F000000000000ULL) +#define AMD_PMC_L31_COREMASK (0xFF00000000000000ULL) + +#define AMD_PMC_L31_TO_SLICE(x) (((uint64_t)(x) << 48) & AMD_PMC_L31_SLICEMASK) +#define AMD_PMC_L31_TO_CORE(x) (((uint64_t)(x) << 56) & AMD_PMC_L31_COREMASK) + +#define AMD_PMC_L32_THREADMASK (0x0F00000000000000ULL) +#define AMD_PMC_L32_SOURCEMASK (0x0007000000000000ULL) +#define AMD_PMC_L32_ALLCORES (1ULL << 47) +#define AMD_PMC_L32_ALLSOURCES (1ULL << 46) +#define AMD_PMC_L32_COREMASK (0x00001C0000000000ULL) + +#define AMD_PMC_L32_TO_THREAD(x) (((uint64_t)(x) << 56) & AMD_PMC_L32_THREADMASK) +#define AMD_PMC_L32_TO_SOURCEID(x) (((uint64_t)(x) << 48) & AMD_PMC_L32_SOURCEMASK) +#define AMD_PMC_L32_TO_COREID(x) (((uint64_t)(x) << 42) & AMD_PMC_L32_COREMASK) + +#define AMD_PMC_L3_TO_UNITMASK(x) (((x) << 8) & AMD_PMC_UNITMASK) +#define AMD_PMC_L3_TO_EVENTMASK(x) ((x) & 0xFF) + +#define AMD_PMC_L3_CAPS (PMC_CAP_READ | PMC_CAP_WRITE | \ + PMC_CAP_QUALIFIER | PMC_CAP_DOMWIDE) + +/* DF */ +#define AMD_PMC_DF_BASE 0xC0010240 +#define AMD_PMC_DF_DEFAULT 4 +#define AMD_PMC_DF_MAX 64 + +#define AMD_PMC_DF_CAPS (PMC_CAP_READ | PMC_CAP_WRITE | \ + PMC_CAP_QUALIFIER | PMC_CAP_DOMWIDE) + +/* + * DF counters change their encoding between Family 19h and Family 1Ah + * processors. + * + * Refer to the same documents as the L3 counters. + */ +#define AMD_PMC_DF1_TO_EVENTMASK(x) (((x) & 0xFF) | \ + (((uint64_t)(x) & 0x0F00) << 24) | (((uint64_t)(x) & 0x3000) << 47)) +#define AMD_PMC_DF1_TO_UNITMASK(x) (((x) & 0xFF) << 8) + +#define AMD_PMC_DF2_TO_EVENTMASK(x) (((x) & 0xFF) | \ + (((uint64_t)(x) & 0x7F00) << 24)) +#define AMD_PMC_DF2_TO_UNITMASK(x) ((((x) & 0xFF) << 8) | \ + (((uint64_t)(x) & 0x0F00) << 16)) + +#define AMD_NPMCS_K8 4 +#define AMD_NPMCS_MAX (AMD_PMC_CORE_MAX + AMD_PMC_L3_MAX + \ + AMD_PMC_DF_MAX) + #define AMD_PMC_IS_STOPPED(evsel) ((rdmsr((evsel)) & AMD_PMC_ENABLE) == 0) #define AMD_PMC_HAS_OVERFLOWED(pmc) ((rdpmc(pmc) & (1ULL << 47)) == 0)