Commit 4a112585 authored by Ilkka Koskinen's avatar Ilkka Koskinen Committed by Will Deacon

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: default avatarIlkka Koskinen <ilkka@os.amperecomputing.com>
Link: https://lore.kernel.org/r/20240618005056.3092866-2-ilkka@os.amperecomputing.comSigned-off-by: default avatarWill Deacon <will@kernel.org>
parent 83a7eefe
......@@ -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)
{
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) + CMN_EVENT_WP_GRP(event);
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment