1

perf/arm-cmn: Decouple wp_config registers from filter group number

Previously, wp_config0/2 registers were used for primary match group and
wp_config1/3 registers for secondary match group. In order to support
tertiary match group, this patch decouples the registers and the groups.

Signed-off-by: Ilkka Koskinen <ilkka@os.amperecomputing.com>
Link: https://lore.kernel.org/r/20240618005056.3092866-2-ilkka@os.amperecomputing.com
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
Ilkka Koskinen 2024-06-17 17:50:55 -07:00 committed by Will Deacon
parent 83a7eefedc
commit 4a112585eb

View File

@ -590,6 +590,13 @@ struct arm_cmn_hw_event {
s8 dtc_idx[CMN_MAX_DTCS]; s8 dtc_idx[CMN_MAX_DTCS];
u8 num_dns; u8 num_dns;
u8 dtm_offset; u8 dtm_offset;
/*
* WP config registers are divided to UP and DOWN events. We need to
* keep to track only one of them.
*/
DECLARE_BITMAP(wp_idx, CMN_MAX_XPS);
bool wide_sel; bool wide_sel;
enum cmn_filter_select filter_sel; enum cmn_filter_select filter_sel;
}; };
@ -617,6 +624,17 @@ static unsigned int arm_cmn_get_index(u64 x[], unsigned int pos)
return (x[pos / 32] >> ((pos % 32) * 2)) & 3; return (x[pos / 32] >> ((pos % 32) * 2)) & 3;
} }
static void arm_cmn_set_wp_idx(unsigned long *wp_idx, unsigned int pos, bool val)
{
if (val)
set_bit(pos, wp_idx);
}
static unsigned int arm_cmn_get_wp_idx(unsigned long *wp_idx, unsigned int pos)
{
return test_bit(pos, wp_idx);
}
struct arm_cmn_event_attr { struct arm_cmn_event_attr {
struct device_attribute attr; struct device_attribute attr;
enum cmn_model model; enum cmn_model model;
@ -1336,9 +1354,34 @@ static const struct attribute_group *arm_cmn_attr_groups[] = {
NULL NULL
}; };
static int arm_cmn_wp_idx(struct perf_event *event) static int arm_cmn_find_free_wp_idx(struct arm_cmn_dtm *dtm,
struct perf_event *event)
{ {
return CMN_EVENT_EVENTID(event) + CMN_EVENT_WP_GRP(event); int wp_idx = CMN_EVENT_EVENTID(event);
if (dtm->wp_event[wp_idx] >= 0)
if (dtm->wp_event[++wp_idx] >= 0)
return -ENOSPC;
return wp_idx;
}
static int arm_cmn_get_assigned_wp_idx(struct perf_event *event,
struct arm_cmn_hw_event *hw,
unsigned int pos)
{
return CMN_EVENT_EVENTID(event) + arm_cmn_get_wp_idx(hw->wp_idx, pos);
}
static void arm_cmn_claim_wp_idx(struct arm_cmn_dtm *dtm,
struct perf_event *event,
unsigned int dtc, int wp_idx,
unsigned int pos)
{
struct arm_cmn_hw_event *hw = to_cmn_hw(event);
dtm->wp_event[wp_idx] = hw->dtc_idx[dtc];
arm_cmn_set_wp_idx(hw->wp_idx, pos, wp_idx - CMN_EVENT_EVENTID(event));
} }
static u32 arm_cmn_wp_config(struct perf_event *event) static u32 arm_cmn_wp_config(struct perf_event *event)
@ -1520,12 +1563,12 @@ static void arm_cmn_event_start(struct perf_event *event, int flags)
writeq_relaxed(CMN_CC_INIT, cmn->dtc[i].base + CMN_DT_PMCCNTR); writeq_relaxed(CMN_CC_INIT, cmn->dtc[i].base + CMN_DT_PMCCNTR);
cmn->dtc[i].cc_active = true; cmn->dtc[i].cc_active = true;
} else if (type == CMN_TYPE_WP) { } else if (type == CMN_TYPE_WP) {
int wp_idx = arm_cmn_wp_idx(event);
u64 val = CMN_EVENT_WP_VAL(event); u64 val = CMN_EVENT_WP_VAL(event);
u64 mask = CMN_EVENT_WP_MASK(event); u64 mask = CMN_EVENT_WP_MASK(event);
for_each_hw_dn(hw, dn, i) { for_each_hw_dn(hw, dn, i) {
void __iomem *base = dn->pmu_base + CMN_DTM_OFFSET(hw->dtm_offset); void __iomem *base = dn->pmu_base + CMN_DTM_OFFSET(hw->dtm_offset);
int wp_idx = arm_cmn_get_assigned_wp_idx(event, hw, i);
writeq_relaxed(val, base + CMN_DTM_WPn_VAL(wp_idx)); writeq_relaxed(val, base + CMN_DTM_WPn_VAL(wp_idx));
writeq_relaxed(mask, base + CMN_DTM_WPn_MASK(wp_idx)); writeq_relaxed(mask, base + CMN_DTM_WPn_MASK(wp_idx));
@ -1550,10 +1593,9 @@ static void arm_cmn_event_stop(struct perf_event *event, int flags)
i = hw->dtc_idx[0]; i = hw->dtc_idx[0];
cmn->dtc[i].cc_active = false; cmn->dtc[i].cc_active = false;
} else if (type == CMN_TYPE_WP) { } else if (type == CMN_TYPE_WP) {
int wp_idx = arm_cmn_wp_idx(event);
for_each_hw_dn(hw, dn, i) { for_each_hw_dn(hw, dn, i) {
void __iomem *base = dn->pmu_base + CMN_DTM_OFFSET(hw->dtm_offset); void __iomem *base = dn->pmu_base + CMN_DTM_OFFSET(hw->dtm_offset);
int wp_idx = arm_cmn_get_assigned_wp_idx(event, hw, i);
writeq_relaxed(0, base + CMN_DTM_WPn_MASK(wp_idx)); writeq_relaxed(0, base + CMN_DTM_WPn_MASK(wp_idx));
writeq_relaxed(~0ULL, base + CMN_DTM_WPn_VAL(wp_idx)); writeq_relaxed(~0ULL, base + CMN_DTM_WPn_VAL(wp_idx));
@ -1571,10 +1613,23 @@ struct arm_cmn_val {
u8 dtm_count[CMN_MAX_DTMS]; u8 dtm_count[CMN_MAX_DTMS];
u8 occupid[CMN_MAX_DTMS][SEL_MAX]; u8 occupid[CMN_MAX_DTMS][SEL_MAX];
u8 wp[CMN_MAX_DTMS][4]; u8 wp[CMN_MAX_DTMS][4];
u8 wp_combine[CMN_MAX_DTMS][2];
int dtc_count[CMN_MAX_DTCS]; int dtc_count[CMN_MAX_DTCS];
bool cycles; bool cycles;
}; };
static int arm_cmn_val_find_free_wp_config(struct perf_event *event,
struct arm_cmn_val *val, int dtm)
{
int wp_idx = CMN_EVENT_EVENTID(event);
if (val->wp[dtm][wp_idx])
if (val->wp[dtm][++wp_idx])
return -ENOSPC;
return wp_idx;
}
static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val, static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
struct perf_event *event) struct perf_event *event)
{ {
@ -1606,8 +1661,9 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
if (type != CMN_TYPE_WP) if (type != CMN_TYPE_WP)
continue; continue;
wp_idx = arm_cmn_wp_idx(event); wp_idx = arm_cmn_val_find_free_wp_config(event, val, dtm);
val->wp[dtm][wp_idx] = CMN_EVENT_WP_COMBINE(event) + 1; val->wp[dtm][wp_idx] = 1;
val->wp_combine[dtm][wp_idx >> 1] += !!CMN_EVENT_WP_COMBINE(event);
} }
} }
@ -1631,6 +1687,7 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
return -ENOMEM; return -ENOMEM;
arm_cmn_val_add_event(cmn, val, leader); arm_cmn_val_add_event(cmn, val, leader);
for_each_sibling_event(sibling, leader) for_each_sibling_event(sibling, leader)
arm_cmn_val_add_event(cmn, val, sibling); arm_cmn_val_add_event(cmn, val, sibling);
@ -1645,7 +1702,7 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
goto done; goto done;
for_each_hw_dn(hw, dn, i) { for_each_hw_dn(hw, dn, i) {
int wp_idx, wp_cmb, dtm = dn->dtm, sel = hw->filter_sel; int wp_idx, dtm = dn->dtm, sel = hw->filter_sel;
if (val->dtm_count[dtm] == CMN_DTM_NUM_COUNTERS) if (val->dtm_count[dtm] == CMN_DTM_NUM_COUNTERS)
goto done; goto done;
@ -1657,12 +1714,12 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
if (type != CMN_TYPE_WP) if (type != CMN_TYPE_WP)
continue; continue;
wp_idx = arm_cmn_wp_idx(event); wp_idx = arm_cmn_val_find_free_wp_config(event, val, dtm);
if (val->wp[dtm][wp_idx]) if (wp_idx < 0)
goto done; goto done;
wp_cmb = val->wp[dtm][wp_idx ^ 1]; if (wp_idx & 1 &&
if (wp_cmb && wp_cmb != CMN_EVENT_WP_COMBINE(event) + 1) val->wp_combine[dtm][wp_idx >> 1] != !!CMN_EVENT_WP_COMBINE(event))
goto done; goto done;
} }
@ -1773,8 +1830,11 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
struct arm_cmn_dtm *dtm = &cmn->dtms[hw->dn[i].dtm] + hw->dtm_offset; struct arm_cmn_dtm *dtm = &cmn->dtms[hw->dn[i].dtm] + hw->dtm_offset;
unsigned int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i); unsigned int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
if (type == CMN_TYPE_WP) if (type == CMN_TYPE_WP) {
dtm->wp_event[arm_cmn_wp_idx(event)] = -1; int wp_idx = arm_cmn_get_assigned_wp_idx(event, hw, i);
dtm->wp_event[wp_idx] = -1;
}
if (hw->filter_sel > SEL_NONE) if (hw->filter_sel > SEL_NONE)
hw->dn[i].occupid[hw->filter_sel].count--; hw->dn[i].occupid[hw->filter_sel].count--;
@ -1783,6 +1843,7 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
writel_relaxed(dtm->pmu_config_low, dtm->base + CMN_DTM_PMU_CONFIG); writel_relaxed(dtm->pmu_config_low, dtm->base + CMN_DTM_PMU_CONFIG);
} }
memset(hw->dtm_idx, 0, sizeof(hw->dtm_idx)); memset(hw->dtm_idx, 0, sizeof(hw->dtm_idx));
memset(hw->wp_idx, 0, sizeof(hw->wp_idx));
for_each_hw_dtc_idx(hw, j, idx) for_each_hw_dtc_idx(hw, j, idx)
cmn->dtc[j].counters[idx] = NULL; cmn->dtc[j].counters[idx] = NULL;
@ -1836,10 +1897,11 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
if (type == CMN_TYPE_XP) { if (type == CMN_TYPE_XP) {
input_sel = CMN__PMEVCNT0_INPUT_SEL_XP + dtm_idx; input_sel = CMN__PMEVCNT0_INPUT_SEL_XP + dtm_idx;
} else if (type == CMN_TYPE_WP) { } else if (type == CMN_TYPE_WP) {
int tmp, wp_idx = arm_cmn_wp_idx(event); int tmp, wp_idx;
u32 cfg = arm_cmn_wp_config(event); u32 cfg = arm_cmn_wp_config(event);
if (dtm->wp_event[wp_idx] >= 0) wp_idx = arm_cmn_find_free_wp_idx(dtm, event);
if (wp_idx < 0)
goto free_dtms; goto free_dtms;
tmp = dtm->wp_event[wp_idx ^ 1]; tmp = dtm->wp_event[wp_idx ^ 1];
@ -1848,7 +1910,8 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
goto free_dtms; goto free_dtms;
input_sel = CMN__PMEVCNT0_INPUT_SEL_WP + wp_idx; input_sel = CMN__PMEVCNT0_INPUT_SEL_WP + wp_idx;
dtm->wp_event[wp_idx] = hw->dtc_idx[d];
arm_cmn_claim_wp_idx(dtm, event, d, wp_idx, i);
writel_relaxed(cfg, dtm->base + CMN_DTM_WPn_CONFIG(wp_idx)); writel_relaxed(cfg, dtm->base + CMN_DTM_WPn_CONFIG(wp_idx));
} else { } else {
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id); struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id);