162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/export.h> 362306a36Sopenharmony_ci#include <linux/types.h> 462306a36Sopenharmony_ci#include <linux/bits.h> 562306a36Sopenharmony_ci#include "probe.h" 662306a36Sopenharmony_ci 762306a36Sopenharmony_cistatic umode_t 862306a36Sopenharmony_cinot_visible(struct kobject *kobj, struct attribute *attr, int i) 962306a36Sopenharmony_ci{ 1062306a36Sopenharmony_ci return 0; 1162306a36Sopenharmony_ci} 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * Accepts msr[] array with non populated entries as long as either 1562306a36Sopenharmony_ci * msr[i].msr is 0 or msr[i].grp is NULL. Note that the default sysfs 1662306a36Sopenharmony_ci * visibility is visible when group->is_visible callback is set. 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ciunsigned long 1962306a36Sopenharmony_ciperf_msr_probe(struct perf_msr *msr, int cnt, bool zero, void *data) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci unsigned long avail = 0; 2262306a36Sopenharmony_ci unsigned int bit; 2362306a36Sopenharmony_ci u64 val; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (cnt >= BITS_PER_LONG) 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci for (bit = 0; bit < cnt; bit++) { 2962306a36Sopenharmony_ci if (!msr[bit].no_check) { 3062306a36Sopenharmony_ci struct attribute_group *grp = msr[bit].grp; 3162306a36Sopenharmony_ci u64 mask; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* skip entry with no group */ 3462306a36Sopenharmony_ci if (!grp) 3562306a36Sopenharmony_ci continue; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci grp->is_visible = not_visible; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* skip unpopulated entry */ 4062306a36Sopenharmony_ci if (!msr[bit].msr) 4162306a36Sopenharmony_ci continue; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (msr[bit].test && !msr[bit].test(bit, data)) 4462306a36Sopenharmony_ci continue; 4562306a36Sopenharmony_ci /* Virt sucks; you cannot tell if a R/O MSR is present :/ */ 4662306a36Sopenharmony_ci if (rdmsrl_safe(msr[bit].msr, &val)) 4762306a36Sopenharmony_ci continue; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci mask = msr[bit].mask; 5062306a36Sopenharmony_ci if (!mask) 5162306a36Sopenharmony_ci mask = ~0ULL; 5262306a36Sopenharmony_ci /* Disable zero counters if requested. */ 5362306a36Sopenharmony_ci if (!zero && !(val & mask)) 5462306a36Sopenharmony_ci continue; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci grp->is_visible = NULL; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci avail |= BIT(bit); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return avail; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(perf_msr_probe); 64