Skip to content

Commit 4a11258

Browse files
ilkka-koskinenwilldeacon
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 83a7eef commit 4a11258

File tree

1 file changed

+80
-17
lines changed

1 file changed

+80
-17
lines changed

drivers/perf/arm-cmn.c

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,13 @@ struct arm_cmn_hw_event {
590590
s8 dtc_idx[CMN_MAX_DTCS];
591591
u8 num_dns;
592592
u8 dtm_offset;
593+
594+
/*
595+
* WP config registers are divided to UP and DOWN events. We need to
596+
* keep to track only one of them.
597+
*/
598+
DECLARE_BITMAP(wp_idx, CMN_MAX_XPS);
599+
593600
bool wide_sel;
594601
enum cmn_filter_select filter_sel;
595602
};
@@ -617,6 +624,17 @@ static unsigned int arm_cmn_get_index(u64 x[], unsigned int pos)
617624
return (x[pos / 32] >> ((pos % 32) * 2)) & 3;
618625
}
619626

627+
static void arm_cmn_set_wp_idx(unsigned long *wp_idx, unsigned int pos, bool val)
628+
{
629+
if (val)
630+
set_bit(pos, wp_idx);
631+
}
632+
633+
static unsigned int arm_cmn_get_wp_idx(unsigned long *wp_idx, unsigned int pos)
634+
{
635+
return test_bit(pos, wp_idx);
636+
}
637+
620638
struct arm_cmn_event_attr {
621639
struct device_attribute attr;
622640
enum cmn_model model;
@@ -1336,9 +1354,34 @@ static const struct attribute_group *arm_cmn_attr_groups[] = {
13361354
NULL
13371355
};
13381356

1339-
static int arm_cmn_wp_idx(struct perf_event *event)
1357+
static int arm_cmn_find_free_wp_idx(struct arm_cmn_dtm *dtm,
1358+
struct perf_event *event)
1359+
{
1360+
int wp_idx = CMN_EVENT_EVENTID(event);
1361+
1362+
if (dtm->wp_event[wp_idx] >= 0)
1363+
if (dtm->wp_event[++wp_idx] >= 0)
1364+
return -ENOSPC;
1365+
1366+
return wp_idx;
1367+
}
1368+
1369+
static int arm_cmn_get_assigned_wp_idx(struct perf_event *event,
1370+
struct arm_cmn_hw_event *hw,
1371+
unsigned int pos)
13401372
{
1341-
return CMN_EVENT_EVENTID(event) + CMN_EVENT_WP_GRP(event);
1373+
return CMN_EVENT_EVENTID(event) + arm_cmn_get_wp_idx(hw->wp_idx, pos);
1374+
}
1375+
1376+
static void arm_cmn_claim_wp_idx(struct arm_cmn_dtm *dtm,
1377+
struct perf_event *event,
1378+
unsigned int dtc, int wp_idx,
1379+
unsigned int pos)
1380+
{
1381+
struct arm_cmn_hw_event *hw = to_cmn_hw(event);
1382+
1383+
dtm->wp_event[wp_idx] = hw->dtc_idx[dtc];
1384+
arm_cmn_set_wp_idx(hw->wp_idx, pos, wp_idx - CMN_EVENT_EVENTID(event));
13421385
}
13431386

13441387
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)
15201563
writeq_relaxed(CMN_CC_INIT, cmn->dtc[i].base + CMN_DT_PMCCNTR);
15211564
cmn->dtc[i].cc_active = true;
15221565
} else if (type == CMN_TYPE_WP) {
1523-
int wp_idx = arm_cmn_wp_idx(event);
15241566
u64 val = CMN_EVENT_WP_VAL(event);
15251567
u64 mask = CMN_EVENT_WP_MASK(event);
15261568

15271569
for_each_hw_dn(hw, dn, i) {
15281570
void __iomem *base = dn->pmu_base + CMN_DTM_OFFSET(hw->dtm_offset);
1571+
int wp_idx = arm_cmn_get_assigned_wp_idx(event, hw, i);
15291572

15301573
writeq_relaxed(val, base + CMN_DTM_WPn_VAL(wp_idx));
15311574
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)
15501593
i = hw->dtc_idx[0];
15511594
cmn->dtc[i].cc_active = false;
15521595
} else if (type == CMN_TYPE_WP) {
1553-
int wp_idx = arm_cmn_wp_idx(event);
1554-
15551596
for_each_hw_dn(hw, dn, i) {
15561597
void __iomem *base = dn->pmu_base + CMN_DTM_OFFSET(hw->dtm_offset);
1598+
int wp_idx = arm_cmn_get_assigned_wp_idx(event, hw, i);
15571599

15581600
writeq_relaxed(0, base + CMN_DTM_WPn_MASK(wp_idx));
15591601
writeq_relaxed(~0ULL, base + CMN_DTM_WPn_VAL(wp_idx));
@@ -1571,10 +1613,23 @@ struct arm_cmn_val {
15711613
u8 dtm_count[CMN_MAX_DTMS];
15721614
u8 occupid[CMN_MAX_DTMS][SEL_MAX];
15731615
u8 wp[CMN_MAX_DTMS][4];
1616+
u8 wp_combine[CMN_MAX_DTMS][2];
15741617
int dtc_count[CMN_MAX_DTCS];
15751618
bool cycles;
15761619
};
15771620

1621+
static int arm_cmn_val_find_free_wp_config(struct perf_event *event,
1622+
struct arm_cmn_val *val, int dtm)
1623+
{
1624+
int wp_idx = CMN_EVENT_EVENTID(event);
1625+
1626+
if (val->wp[dtm][wp_idx])
1627+
if (val->wp[dtm][++wp_idx])
1628+
return -ENOSPC;
1629+
1630+
return wp_idx;
1631+
}
1632+
15781633
static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
15791634
struct perf_event *event)
15801635
{
@@ -1606,8 +1661,9 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
16061661
if (type != CMN_TYPE_WP)
16071662
continue;
16081663

1609-
wp_idx = arm_cmn_wp_idx(event);
1610-
val->wp[dtm][wp_idx] = CMN_EVENT_WP_COMBINE(event) + 1;
1664+
wp_idx = arm_cmn_val_find_free_wp_config(event, val, dtm);
1665+
val->wp[dtm][wp_idx] = 1;
1666+
val->wp_combine[dtm][wp_idx >> 1] += !!CMN_EVENT_WP_COMBINE(event);
16111667
}
16121668
}
16131669

@@ -1631,6 +1687,7 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
16311687
return -ENOMEM;
16321688

16331689
arm_cmn_val_add_event(cmn, val, leader);
1690+
16341691
for_each_sibling_event(sibling, leader)
16351692
arm_cmn_val_add_event(cmn, val, sibling);
16361693

@@ -1645,7 +1702,7 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
16451702
goto done;
16461703

16471704
for_each_hw_dn(hw, dn, i) {
1648-
int wp_idx, wp_cmb, dtm = dn->dtm, sel = hw->filter_sel;
1705+
int wp_idx, dtm = dn->dtm, sel = hw->filter_sel;
16491706

16501707
if (val->dtm_count[dtm] == CMN_DTM_NUM_COUNTERS)
16511708
goto done;
@@ -1657,12 +1714,12 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
16571714
if (type != CMN_TYPE_WP)
16581715
continue;
16591716

1660-
wp_idx = arm_cmn_wp_idx(event);
1661-
if (val->wp[dtm][wp_idx])
1717+
wp_idx = arm_cmn_val_find_free_wp_config(event, val, dtm);
1718+
if (wp_idx < 0)
16621719
goto done;
16631720

1664-
wp_cmb = val->wp[dtm][wp_idx ^ 1];
1665-
if (wp_cmb && wp_cmb != CMN_EVENT_WP_COMBINE(event) + 1)
1721+
if (wp_idx & 1 &&
1722+
val->wp_combine[dtm][wp_idx >> 1] != !!CMN_EVENT_WP_COMBINE(event))
16661723
goto done;
16671724
}
16681725

@@ -1773,8 +1830,11 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
17731830
struct arm_cmn_dtm *dtm = &cmn->dtms[hw->dn[i].dtm] + hw->dtm_offset;
17741831
unsigned int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
17751832

1776-
if (type == CMN_TYPE_WP)
1777-
dtm->wp_event[arm_cmn_wp_idx(event)] = -1;
1833+
if (type == CMN_TYPE_WP) {
1834+
int wp_idx = arm_cmn_get_assigned_wp_idx(event, hw, i);
1835+
1836+
dtm->wp_event[wp_idx] = -1;
1837+
}
17781838

17791839
if (hw->filter_sel > SEL_NONE)
17801840
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,
17831843
writel_relaxed(dtm->pmu_config_low, dtm->base + CMN_DTM_PMU_CONFIG);
17841844
}
17851845
memset(hw->dtm_idx, 0, sizeof(hw->dtm_idx));
1846+
memset(hw->wp_idx, 0, sizeof(hw->wp_idx));
17861847

17871848
for_each_hw_dtc_idx(hw, j, idx)
17881849
cmn->dtc[j].counters[idx] = NULL;
@@ -1836,10 +1897,11 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
18361897
if (type == CMN_TYPE_XP) {
18371898
input_sel = CMN__PMEVCNT0_INPUT_SEL_XP + dtm_idx;
18381899
} else if (type == CMN_TYPE_WP) {
1839-
int tmp, wp_idx = arm_cmn_wp_idx(event);
1900+
int tmp, wp_idx;
18401901
u32 cfg = arm_cmn_wp_config(event);
18411902

1842-
if (dtm->wp_event[wp_idx] >= 0)
1903+
wp_idx = arm_cmn_find_free_wp_idx(dtm, event);
1904+
if (wp_idx < 0)
18431905
goto free_dtms;
18441906

18451907
tmp = dtm->wp_event[wp_idx ^ 1];
@@ -1848,7 +1910,8 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
18481910
goto free_dtms;
18491911

18501912
input_sel = CMN__PMEVCNT0_INPUT_SEL_WP + wp_idx;
1851-
dtm->wp_event[wp_idx] = hw->dtc_idx[d];
1913+
1914+
arm_cmn_claim_wp_idx(dtm, event, d, wp_idx, i);
18521915
writel_relaxed(cfg, dtm->base + CMN_DTM_WPn_CONFIG(wp_idx));
18531916
} else {
18541917
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id);

0 commit comments

Comments
 (0)