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:
parent
83a7eefedc
commit
4a112585eb
@ -590,6 +590,13 @@ struct arm_cmn_hw_event {
|
||||
s8 dtc_idx[CMN_MAX_DTCS];
|
||||
u8 num_dns;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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 device_attribute attr;
|
||||
enum cmn_model model;
|
||||
@ -1336,9 +1354,34 @@ static const struct attribute_group *arm_cmn_attr_groups[] = {
|
||||
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)
|
||||
@ -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);
|
||||
cmn->dtc[i].cc_active = true;
|
||||
} else if (type == CMN_TYPE_WP) {
|
||||
int wp_idx = arm_cmn_wp_idx(event);
|
||||
u64 val = CMN_EVENT_WP_VAL(event);
|
||||
u64 mask = CMN_EVENT_WP_MASK(event);
|
||||
|
||||
for_each_hw_dn(hw, dn, i) {
|
||||
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(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];
|
||||
cmn->dtc[i].cc_active = false;
|
||||
} else if (type == CMN_TYPE_WP) {
|
||||
int wp_idx = arm_cmn_wp_idx(event);
|
||||
|
||||
for_each_hw_dn(hw, dn, i) {
|
||||
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(~0ULL, base + CMN_DTM_WPn_VAL(wp_idx));
|
||||
@ -1571,10 +1613,23 @@ struct arm_cmn_val {
|
||||
u8 dtm_count[CMN_MAX_DTMS];
|
||||
u8 occupid[CMN_MAX_DTMS][SEL_MAX];
|
||||
u8 wp[CMN_MAX_DTMS][4];
|
||||
u8 wp_combine[CMN_MAX_DTMS][2];
|
||||
int dtc_count[CMN_MAX_DTCS];
|
||||
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,
|
||||
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)
|
||||
continue;
|
||||
|
||||
wp_idx = arm_cmn_wp_idx(event);
|
||||
val->wp[dtm][wp_idx] = CMN_EVENT_WP_COMBINE(event) + 1;
|
||||
wp_idx = arm_cmn_val_find_free_wp_config(event, val, dtm);
|
||||
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;
|
||||
|
||||
arm_cmn_val_add_event(cmn, val, leader);
|
||||
|
||||
for_each_sibling_event(sibling, leader)
|
||||
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;
|
||||
|
||||
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)
|
||||
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)
|
||||
continue;
|
||||
|
||||
wp_idx = arm_cmn_wp_idx(event);
|
||||
if (val->wp[dtm][wp_idx])
|
||||
wp_idx = arm_cmn_val_find_free_wp_config(event, val, dtm);
|
||||
if (wp_idx < 0)
|
||||
goto done;
|
||||
|
||||
wp_cmb = val->wp[dtm][wp_idx ^ 1];
|
||||
if (wp_cmb && wp_cmb != CMN_EVENT_WP_COMBINE(event) + 1)
|
||||
if (wp_idx & 1 &&
|
||||
val->wp_combine[dtm][wp_idx >> 1] != !!CMN_EVENT_WP_COMBINE(event))
|
||||
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;
|
||||
unsigned int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
|
||||
|
||||
if (type == CMN_TYPE_WP)
|
||||
dtm->wp_event[arm_cmn_wp_idx(event)] = -1;
|
||||
if (type == CMN_TYPE_WP) {
|
||||
int wp_idx = arm_cmn_get_assigned_wp_idx(event, hw, i);
|
||||
|
||||
dtm->wp_event[wp_idx] = -1;
|
||||
}
|
||||
|
||||
if (hw->filter_sel > SEL_NONE)
|
||||
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);
|
||||
}
|
||||
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)
|
||||
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) {
|
||||
input_sel = CMN__PMEVCNT0_INPUT_SEL_XP + dtm_idx;
|
||||
} 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);
|
||||
|
||||
if (dtm->wp_event[wp_idx] >= 0)
|
||||
wp_idx = arm_cmn_find_free_wp_idx(dtm, event);
|
||||
if (wp_idx < 0)
|
||||
goto free_dtms;
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
} else {
|
||||
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id);
|
||||
|
Loading…
Reference in New Issue
Block a user