in arm_spe_pmu.c [935:1046]
static void __arm_spe_pmu_dev_probe(void *info)
{
int fld;
u64 reg;
struct arm_spe_pmu *spe_pmu = info;
struct device *dev = &spe_pmu->pdev->dev;
fld = cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64DFR0_EL1),
ID_AA64DFR0_PMSVER_SHIFT);
if (!fld) {
dev_err(dev,
"unsupported ID_AA64DFR0_EL1.PMSVer [%d] on CPU %d\n",
fld, smp_processor_id());
return;
}
spe_pmu->pmsver = (u16)fld;
/* Read PMBIDR first to determine whether or not we have access */
reg = read_sysreg_s(SYS_PMBIDR_EL1);
if (reg & BIT(SYS_PMBIDR_EL1_P_SHIFT)) {
dev_err(dev,
"profiling buffer owned by higher exception level\n");
return;
}
/* Minimum alignment. If it's out-of-range, then fail the probe */
fld = reg >> SYS_PMBIDR_EL1_ALIGN_SHIFT & SYS_PMBIDR_EL1_ALIGN_MASK;
spe_pmu->align = 1 << fld;
if (spe_pmu->align > SZ_2K) {
dev_err(dev, "unsupported PMBIDR.Align [%d] on CPU %d\n",
fld, smp_processor_id());
return;
}
/* It's now safe to read PMSIDR and figure out what we've got */
reg = read_sysreg_s(SYS_PMSIDR_EL1);
if (reg & BIT(SYS_PMSIDR_EL1_FE_SHIFT))
spe_pmu->features |= SPE_PMU_FEAT_FILT_EVT;
if (reg & BIT(SYS_PMSIDR_EL1_FT_SHIFT))
spe_pmu->features |= SPE_PMU_FEAT_FILT_TYP;
if (reg & BIT(SYS_PMSIDR_EL1_FL_SHIFT))
spe_pmu->features |= SPE_PMU_FEAT_FILT_LAT;
if (reg & BIT(SYS_PMSIDR_EL1_ARCHINST_SHIFT))
spe_pmu->features |= SPE_PMU_FEAT_ARCH_INST;
if (reg & BIT(SYS_PMSIDR_EL1_LDS_SHIFT))
spe_pmu->features |= SPE_PMU_FEAT_LDS;
if (reg & BIT(SYS_PMSIDR_EL1_ERND_SHIFT))
spe_pmu->features |= SPE_PMU_FEAT_ERND;
/* This field has a spaced out encoding, so just use a look-up */
fld = reg >> SYS_PMSIDR_EL1_INTERVAL_SHIFT & SYS_PMSIDR_EL1_INTERVAL_MASK;
switch (fld) {
case 0:
spe_pmu->min_period = 256;
break;
case 2:
spe_pmu->min_period = 512;
break;
case 3:
spe_pmu->min_period = 768;
break;
case 4:
spe_pmu->min_period = 1024;
break;
case 5:
spe_pmu->min_period = 1536;
break;
case 6:
spe_pmu->min_period = 2048;
break;
case 7:
spe_pmu->min_period = 3072;
break;
default:
dev_warn(dev, "unknown PMSIDR_EL1.Interval [%d]; assuming 8\n",
fld);
fallthrough;
case 8:
spe_pmu->min_period = 4096;
}
/* Maximum record size. If it's out-of-range, then fail the probe */
fld = reg >> SYS_PMSIDR_EL1_MAXSIZE_SHIFT & SYS_PMSIDR_EL1_MAXSIZE_MASK;
spe_pmu->max_record_sz = 1 << fld;
if (spe_pmu->max_record_sz > SZ_2K || spe_pmu->max_record_sz < 16) {
dev_err(dev, "unsupported PMSIDR_EL1.MaxSize [%d] on CPU %d\n",
fld, smp_processor_id());
return;
}
fld = reg >> SYS_PMSIDR_EL1_COUNTSIZE_SHIFT & SYS_PMSIDR_EL1_COUNTSIZE_MASK;
switch (fld) {
default:
dev_warn(dev, "unknown PMSIDR_EL1.CountSize [%d]; assuming 2\n",
fld);
fallthrough;
case 2:
spe_pmu->counter_sz = 12;
}
dev_info(dev,
"probed for CPUs %*pbl [max_record_sz %u, align %u, features 0x%llx]\n",
cpumask_pr_args(&spe_pmu->supported_cpus),
spe_pmu->max_record_sz, spe_pmu->align, spe_pmu->features);
spe_pmu->features |= SPE_PMU_FEAT_DEV_PROBED;
}