// SPDX-License-Identifier: GPL-2.01/*2* Implement support for AMD Fam19h Branch Sampling feature3* Based on specifications published in AMD PPR Fam19 Model 014*5* Copyright 2021 Google LLC6* Contributed by Stephane Eranian <[email protected]>7*/8#include <linux/kernel.h>9#include <linux/jump_label.h>10#include <asm/msr.h>11#include <asm/cpufeature.h>1213#include "../perf_event.h"1415#define BRS_POISON 0xFFFFFFFFFFFFFFFEULL /* mark limit of valid entries */1617/* Debug Extension Configuration register layout */18union amd_debug_extn_cfg {19__u64 val;20struct {21__u64 rsvd0:2, /* reserved */22brsmen:1, /* branch sample enable */23rsvd4_3:2,/* reserved - must be 0x3 */24vb:1, /* valid branches recorded */25rsvd2:10, /* reserved */26msroff:4, /* index of next entry to write */27rsvd3:4, /* reserved */28pmc:3, /* #PMC holding the sampling event */29rsvd4:37; /* reserved */30};31};3233static inline unsigned int brs_from(int idx)34{35return MSR_AMD_SAMP_BR_FROM + 2 * idx;36}3738static inline unsigned int brs_to(int idx)39{40return MSR_AMD_SAMP_BR_FROM + 2 * idx + 1;41}4243static __always_inline void set_debug_extn_cfg(u64 val)44{45/* bits[4:3] must always be set to 11b */46native_wrmsrq(MSR_AMD_DBG_EXTN_CFG, val | 3ULL << 3);47}4849static __always_inline u64 get_debug_extn_cfg(void)50{51return native_rdmsrq(MSR_AMD_DBG_EXTN_CFG);52}5354static bool __init amd_brs_detect(void)55{56if (!cpu_feature_enabled(X86_FEATURE_BRS))57return false;5859switch (boot_cpu_data.x86) {60case 0x19: /* AMD Fam19h (Zen3) */61x86_pmu.lbr_nr = 16;6263/* No hardware filtering supported */64x86_pmu.lbr_sel_map = NULL;65x86_pmu.lbr_sel_mask = 0;66break;67default:68return false;69}7071return true;72}7374/*75* Current BRS implementation does not support branch type or privilege level76* filtering. Therefore, this function simply enforces these limitations. No need for77* a br_sel_map. Software filtering is not supported because it would not correlate well78* with a sampling period.79*/80static int amd_brs_setup_filter(struct perf_event *event)81{82u64 type = event->attr.branch_sample_type;8384/* No BRS support */85if (!x86_pmu.lbr_nr)86return -EOPNOTSUPP;8788/* Can only capture all branches, i.e., no filtering */89if ((type & ~PERF_SAMPLE_BRANCH_PLM_ALL) != PERF_SAMPLE_BRANCH_ANY)90return -EINVAL;9192return 0;93}9495static inline int amd_is_brs_event(struct perf_event *e)96{97return (e->hw.config & AMD64_RAW_EVENT_MASK) == AMD_FAM19H_BRS_EVENT;98}99100int amd_brs_hw_config(struct perf_event *event)101{102int ret = 0;103104/*105* Due to interrupt holding, BRS is not recommended in106* counting mode.107*/108if (!is_sampling_event(event))109return -EINVAL;110111/*112* Due to the way BRS operates by holding the interrupt until113* lbr_nr entries have been captured, it does not make sense114* to allow sampling on BRS with an event that does not match115* what BRS is capturing, i.e., retired taken branches.116* Otherwise the correlation with the event's period is even117* more loose:118*119* With retired taken branch:120* Effective P = P + 16 + X121* With any other event:122* Effective P = P + Y + X123*124* Where X is the number of taken branches due to interrupt125* skid. Skid is large.126*127* Where Y is the occurrences of the event while BRS is128* capturing the lbr_nr entries.129*130* By using retired taken branches, we limit the impact on the131* Y variable. We know it cannot be more than the depth of132* BRS.133*/134if (!amd_is_brs_event(event))135return -EINVAL;136137/*138* BRS implementation does not work with frequency mode139* reprogramming of the period.140*/141if (event->attr.freq)142return -EINVAL;143/*144* The kernel subtracts BRS depth from period, so it must145* be big enough.146*/147if (event->attr.sample_period <= x86_pmu.lbr_nr)148return -EINVAL;149150/*151* Check if we can allow PERF_SAMPLE_BRANCH_STACK152*/153ret = amd_brs_setup_filter(event);154155/* only set in case of success */156if (!ret)157event->hw.flags |= PERF_X86_EVENT_AMD_BRS;158159return ret;160}161162/* tos = top of stack, i.e., last valid entry written */163static inline int amd_brs_get_tos(union amd_debug_extn_cfg *cfg)164{165/*166* msroff: index of next entry to write so top-of-stack is one off167* if BRS is full then msroff is set back to 0.168*/169return (cfg->msroff ? cfg->msroff : x86_pmu.lbr_nr) - 1;170}171172/*173* make sure we have a sane BRS offset to begin with174* especially with kexec175*/176void amd_brs_reset(void)177{178if (!cpu_feature_enabled(X86_FEATURE_BRS))179return;180181/*182* Reset config183*/184set_debug_extn_cfg(0);185186/*187* Mark first entry as poisoned188*/189wrmsrq(brs_to(0), BRS_POISON);190}191192int __init amd_brs_init(void)193{194if (!amd_brs_detect())195return -EOPNOTSUPP;196197pr_cont("%d-deep BRS, ", x86_pmu.lbr_nr);198199return 0;200}201202void amd_brs_enable(void)203{204struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);205union amd_debug_extn_cfg cfg;206207/* Activate only on first user */208if (++cpuc->brs_active > 1)209return;210211cfg.val = 0; /* reset all fields */212cfg.brsmen = 1; /* enable branch sampling */213214/* Set enable bit */215set_debug_extn_cfg(cfg.val);216}217218void amd_brs_enable_all(void)219{220struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);221if (cpuc->lbr_users)222amd_brs_enable();223}224225void amd_brs_disable(void)226{227struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);228union amd_debug_extn_cfg cfg;229230/* Check if active (could be disabled via x86_pmu_disable_all()) */231if (!cpuc->brs_active)232return;233234/* Only disable for last user */235if (--cpuc->brs_active)236return;237238/*239* Clear the brsmen bit but preserve the others as they contain240* useful state such as vb and msroff241*/242cfg.val = get_debug_extn_cfg();243244/*245* When coming in on interrupt and BRS is full, then hw will have246* already stopped BRS, no need to issue wrmsr again247*/248if (cfg.brsmen) {249cfg.brsmen = 0;250set_debug_extn_cfg(cfg.val);251}252}253254void amd_brs_disable_all(void)255{256struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);257if (cpuc->lbr_users)258amd_brs_disable();259}260261static bool amd_brs_match_plm(struct perf_event *event, u64 to)262{263int type = event->attr.branch_sample_type;264int plm_k = PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_HV;265int plm_u = PERF_SAMPLE_BRANCH_USER;266267if (!(type & plm_k) && kernel_ip(to))268return 0;269270if (!(type & plm_u) && !kernel_ip(to))271return 0;272273return 1;274}275276/*277* Caller must ensure amd_brs_inuse() is true before calling278* return:279*/280void amd_brs_drain(void)281{282struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);283struct perf_event *event = cpuc->events[0];284struct perf_branch_entry *br = cpuc->lbr_entries;285union amd_debug_extn_cfg cfg;286u32 i, nr = 0, num, tos, start;287u32 shift = 64 - boot_cpu_data.x86_virt_bits;288289/*290* BRS event forced on PMC0,291* so check if there is an event.292* It is possible to have lbr_users > 0 but the event293* not yet scheduled due to long latency PMU irq294*/295if (!event)296goto empty;297298cfg.val = get_debug_extn_cfg();299300/* Sanity check [0-x86_pmu.lbr_nr] */301if (WARN_ON_ONCE(cfg.msroff >= x86_pmu.lbr_nr))302goto empty;303304/* No valid branch */305if (cfg.vb == 0)306goto empty;307308/*309* msr.off points to next entry to be written310* tos = most recent entry index = msr.off - 1311* BRS register buffer saturates, so we know we have312* start < tos and that we have to read from start to tos313*/314start = 0;315tos = amd_brs_get_tos(&cfg);316317num = tos - start + 1;318319/*320* BRS is only one pass (saturation) from MSROFF to depth-1321* MSROFF wraps to zero when buffer is full322*/323for (i = 0; i < num; i++) {324u32 brs_idx = tos - i;325u64 from, to;326327rdmsrq(brs_to(brs_idx), to);328329/* Entry does not belong to us (as marked by kernel) */330if (to == BRS_POISON)331break;332333/*334* Sign-extend SAMP_BR_TO to 64 bits, bits 61-63 are reserved.335* Necessary to generate proper virtual addresses suitable for336* symbolization337*/338to = (u64)(((s64)to << shift) >> shift);339340if (!amd_brs_match_plm(event, to))341continue;342343rdmsrq(brs_from(brs_idx), from);344345perf_clear_branch_entry_bitfields(br+nr);346347br[nr].from = from;348br[nr].to = to;349350nr++;351}352empty:353/* Record number of sampled branches */354cpuc->lbr_stack.nr = nr;355}356357/*358* Poison most recent entry to prevent reuse by next task359* required because BRS entry are not tagged by PID360*/361static void amd_brs_poison_buffer(void)362{363union amd_debug_extn_cfg cfg;364unsigned int idx;365366/* Get current state */367cfg.val = get_debug_extn_cfg();368369/* idx is most recently written entry */370idx = amd_brs_get_tos(&cfg);371372/* Poison target of entry */373wrmsrq(brs_to(idx), BRS_POISON);374}375376/*377* On context switch in, we need to make sure no samples from previous user378* are left in the BRS.379*380* On ctxswin, sched_in = true, called after the PMU has started381* On ctxswout, sched_in = false, called before the PMU is stopped382*/383void amd_pmu_brs_sched_task(struct perf_event_pmu_context *pmu_ctx,384struct task_struct *task, bool sched_in)385{386struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);387388/* no active users */389if (!cpuc->lbr_users)390return;391392/*393* On context switch in, we need to ensure we do not use entries394* from previous BRS user on that CPU, so we poison the buffer as395* a faster way compared to resetting all entries.396*/397if (sched_in)398amd_brs_poison_buffer();399}400401/*402* called from ACPI processor_idle.c or acpi_pad.c403* with interrupts disabled404*/405void noinstr perf_amd_brs_lopwr_cb(bool lopwr_in)406{407struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);408union amd_debug_extn_cfg cfg;409410/*411* on mwait in, we may end up in non C0 state.412* we must disable branch sampling to avoid holding the NMI413* for too long. We disable it in hardware but we414* keep the state in cpuc, so we can re-enable.415*416* The hardware will deliver the NMI if needed when brsmen cleared417*/418if (cpuc->brs_active) {419cfg.val = get_debug_extn_cfg();420cfg.brsmen = !lopwr_in;421set_debug_extn_cfg(cfg.val);422}423}424425DEFINE_STATIC_CALL_NULL(perf_lopwr_cb, perf_amd_brs_lopwr_cb);426EXPORT_STATIC_CALL_TRAMP_GPL(perf_lopwr_cb);427428void __init amd_brs_lopwr_init(void)429{430static_call_update(perf_lopwr_cb, perf_amd_brs_lopwr_cb);431}432433434