| // SPDX-License-Identifier: GPL-2.0 | |
| #include <linux/export.h> | |
| #include <linux/types.h> | |
| #include <linux/bits.h> | |
| #include "probe.h" | |
| static umode_t | |
| not_visible(struct kobject *kobj, struct attribute *attr, int i) | |
| { | |
| return 0; | |
| } | |
| /* | |
| * Accepts msr[] array with non populated entries as long as either | |
| * msr[i].msr is 0 or msr[i].grp is NULL. Note that the default sysfs | |
| * visibility is visible when group->is_visible callback is set. | |
| */ | |
| unsigned long | |
| perf_msr_probe(struct perf_msr *msr, int cnt, bool zero, void *data) | |
| { | |
| unsigned long avail = 0; | |
| unsigned int bit; | |
| u64 val; | |
| if (cnt >= BITS_PER_LONG) | |
| return 0; | |
| for (bit = 0; bit < cnt; bit++) { | |
| if (!msr[bit].no_check) { | |
| struct attribute_group *grp = msr[bit].grp; | |
| u64 mask; | |
| /* skip entry with no group */ | |
| if (!grp) | |
| continue; | |
| grp->is_visible = not_visible; | |
| /* skip unpopulated entry */ | |
| if (!msr[bit].msr) | |
| continue; | |
| if (msr[bit].test && !msr[bit].test(bit, data)) | |
| continue; | |
| /* Virt sucks; you cannot tell if a R/O MSR is present :/ */ | |
| if (rdmsrl_safe(msr[bit].msr, &val)) | |
| continue; | |
| mask = msr[bit].mask; | |
| if (!mask) | |
| mask = ~0ULL; | |
| /* Disable zero counters if requested. */ | |
| if (!zero && !(val & mask)) | |
| continue; | |
| grp->is_visible = NULL; | |
| } | |
| avail |= BIT(bit); | |
| } | |
| return avail; | |
| } | |
| EXPORT_SYMBOL_GPL(perf_msr_probe); |