mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
Merge branch 'perf/m1-guest-events' of git://git.kernel.org/pub/scm/linux/kernel/git/oupton/linux into for-next/perf
Pull Apple-M1 PMU driver changes from Oliver Upton, which form a prefix of the series in the KVM/Arm tree that allows the PMU to be virtualised. Sort of, anyway. * 'perf/m1-guest-events' of git://git.kernel.org/pub/scm/linux/kernel/git/oupton/linux: drivers/perf: apple_m1: Support host/guest event filtering drivers/perf: apple_m1: Refactor event select/filter configuration
This commit is contained in:
commit
823437ed29
|
|
@ -37,6 +37,7 @@
|
|||
#define PMCR0_PMI_ENABLE_8_9 GENMASK(45, 44)
|
||||
|
||||
#define SYS_IMP_APL_PMCR1_EL1 sys_reg(3, 1, 15, 1, 0)
|
||||
#define SYS_IMP_APL_PMCR1_EL12 sys_reg(3, 1, 15, 7, 2)
|
||||
#define PMCR1_COUNT_A64_EL0_0_7 GENMASK(15, 8)
|
||||
#define PMCR1_COUNT_A64_EL1_0_7 GENMASK(23, 16)
|
||||
#define PMCR1_COUNT_A64_EL0_8_9 GENMASK(41, 40)
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ enum m1_pmu_events {
|
|||
*/
|
||||
M1_PMU_CFG_COUNT_USER = BIT(8),
|
||||
M1_PMU_CFG_COUNT_KERNEL = BIT(9),
|
||||
M1_PMU_CFG_COUNT_HOST = BIT(10),
|
||||
M1_PMU_CFG_COUNT_GUEST = BIT(11),
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -327,11 +329,10 @@ static void m1_pmu_disable_counter_interrupt(unsigned int index)
|
|||
__m1_pmu_enable_counter_interrupt(index, false);
|
||||
}
|
||||
|
||||
static void m1_pmu_configure_counter(unsigned int index, u8 event,
|
||||
bool user, bool kernel)
|
||||
static void __m1_pmu_configure_event_filter(unsigned int index, bool user,
|
||||
bool kernel, bool host)
|
||||
{
|
||||
u64 val, user_bit, kernel_bit;
|
||||
int shift;
|
||||
u64 clear, set, user_bit, kernel_bit;
|
||||
|
||||
switch (index) {
|
||||
case 0 ... 7:
|
||||
|
|
@ -346,19 +347,27 @@ static void m1_pmu_configure_counter(unsigned int index, u8 event,
|
|||
BUG();
|
||||
}
|
||||
|
||||
val = read_sysreg_s(SYS_IMP_APL_PMCR1_EL1);
|
||||
|
||||
clear = set = 0;
|
||||
if (user)
|
||||
val |= user_bit;
|
||||
set |= user_bit;
|
||||
else
|
||||
val &= ~user_bit;
|
||||
clear |= user_bit;
|
||||
|
||||
if (kernel)
|
||||
val |= kernel_bit;
|
||||
set |= kernel_bit;
|
||||
else
|
||||
val &= ~kernel_bit;
|
||||
clear |= kernel_bit;
|
||||
|
||||
write_sysreg_s(val, SYS_IMP_APL_PMCR1_EL1);
|
||||
if (host)
|
||||
sysreg_clear_set_s(SYS_IMP_APL_PMCR1_EL1, clear, set);
|
||||
else if (is_kernel_in_hyp_mode())
|
||||
sysreg_clear_set_s(SYS_IMP_APL_PMCR1_EL12, clear, set);
|
||||
}
|
||||
|
||||
static void __m1_pmu_configure_eventsel(unsigned int index, u8 event)
|
||||
{
|
||||
u64 clear = 0, set = 0;
|
||||
int shift;
|
||||
|
||||
/*
|
||||
* Counters 0 and 1 have fixed events. For anything else,
|
||||
|
|
@ -371,21 +380,32 @@ static void m1_pmu_configure_counter(unsigned int index, u8 event,
|
|||
break;
|
||||
case 2 ... 5:
|
||||
shift = (index - 2) * 8;
|
||||
val = read_sysreg_s(SYS_IMP_APL_PMESR0_EL1);
|
||||
val &= ~((u64)0xff << shift);
|
||||
val |= (u64)event << shift;
|
||||
write_sysreg_s(val, SYS_IMP_APL_PMESR0_EL1);
|
||||
clear |= (u64)0xff << shift;
|
||||
set |= (u64)event << shift;
|
||||
sysreg_clear_set_s(SYS_IMP_APL_PMESR0_EL1, clear, set);
|
||||
break;
|
||||
case 6 ... 9:
|
||||
shift = (index - 6) * 8;
|
||||
val = read_sysreg_s(SYS_IMP_APL_PMESR1_EL1);
|
||||
val &= ~((u64)0xff << shift);
|
||||
val |= (u64)event << shift;
|
||||
write_sysreg_s(val, SYS_IMP_APL_PMESR1_EL1);
|
||||
clear |= (u64)0xff << shift;
|
||||
set |= (u64)event << shift;
|
||||
sysreg_clear_set_s(SYS_IMP_APL_PMESR1_EL1, clear, set);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void m1_pmu_configure_counter(unsigned int index, unsigned long config_base)
|
||||
{
|
||||
bool kernel = config_base & M1_PMU_CFG_COUNT_KERNEL;
|
||||
bool guest = config_base & M1_PMU_CFG_COUNT_GUEST;
|
||||
bool host = config_base & M1_PMU_CFG_COUNT_HOST;
|
||||
bool user = config_base & M1_PMU_CFG_COUNT_USER;
|
||||
u8 evt = config_base & M1_PMU_CFG_EVENT;
|
||||
|
||||
__m1_pmu_configure_event_filter(index, user && host, kernel && host, true);
|
||||
__m1_pmu_configure_event_filter(index, user && guest, kernel && guest, false);
|
||||
__m1_pmu_configure_eventsel(index, evt);
|
||||
}
|
||||
|
||||
/* arm_pmu backend */
|
||||
static void m1_pmu_enable_event(struct perf_event *event)
|
||||
{
|
||||
|
|
@ -396,7 +416,7 @@ static void m1_pmu_enable_event(struct perf_event *event)
|
|||
user = event->hw.config_base & M1_PMU_CFG_COUNT_USER;
|
||||
kernel = event->hw.config_base & M1_PMU_CFG_COUNT_KERNEL;
|
||||
|
||||
m1_pmu_configure_counter(event->hw.idx, evt, user, kernel);
|
||||
m1_pmu_configure_counter(event->hw.idx, event->hw.config_base);
|
||||
m1_pmu_enable_counter(event->hw.idx);
|
||||
m1_pmu_enable_counter_interrupt(event->hw.idx);
|
||||
isb();
|
||||
|
|
@ -554,7 +574,7 @@ static int m1_pmu_set_event_filter(struct hw_perf_event *event,
|
|||
{
|
||||
unsigned long config_base = 0;
|
||||
|
||||
if (!attr->exclude_guest) {
|
||||
if (!attr->exclude_guest && !is_kernel_in_hyp_mode()) {
|
||||
pr_debug("ARM performance counters do not support mode exclusion\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -562,6 +582,10 @@ static int m1_pmu_set_event_filter(struct hw_perf_event *event,
|
|||
config_base |= M1_PMU_CFG_COUNT_KERNEL;
|
||||
if (!attr->exclude_user)
|
||||
config_base |= M1_PMU_CFG_COUNT_USER;
|
||||
if (!attr->exclude_host)
|
||||
config_base |= M1_PMU_CFG_COUNT_HOST;
|
||||
if (!attr->exclude_guest)
|
||||
config_base |= M1_PMU_CFG_COUNT_GUEST;
|
||||
|
||||
event->config_base = config_base;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user