@@ -590,6 +590,13 @@ struct arm_cmn_hw_event {
590
590
s8 dtc_idx [CMN_MAX_DTCS ];
591
591
u8 num_dns ;
592
592
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
+
593
600
bool wide_sel ;
594
601
enum cmn_filter_select filter_sel ;
595
602
};
@@ -617,6 +624,17 @@ static unsigned int arm_cmn_get_index(u64 x[], unsigned int pos)
617
624
return (x [pos / 32 ] >> ((pos % 32 ) * 2 )) & 3 ;
618
625
}
619
626
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
+
620
638
struct arm_cmn_event_attr {
621
639
struct device_attribute attr ;
622
640
enum cmn_model model ;
@@ -1336,9 +1354,34 @@ static const struct attribute_group *arm_cmn_attr_groups[] = {
1336
1354
NULL
1337
1355
};
1338
1356
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 )
1340
1372
{
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 ));
1342
1385
}
1343
1386
1344
1387
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)
1520
1563
writeq_relaxed (CMN_CC_INIT , cmn -> dtc [i ].base + CMN_DT_PMCCNTR );
1521
1564
cmn -> dtc [i ].cc_active = true;
1522
1565
} else if (type == CMN_TYPE_WP ) {
1523
- int wp_idx = arm_cmn_wp_idx (event );
1524
1566
u64 val = CMN_EVENT_WP_VAL (event );
1525
1567
u64 mask = CMN_EVENT_WP_MASK (event );
1526
1568
1527
1569
for_each_hw_dn (hw , dn , i ) {
1528
1570
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 );
1529
1572
1530
1573
writeq_relaxed (val , base + CMN_DTM_WPn_VAL (wp_idx ));
1531
1574
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)
1550
1593
i = hw -> dtc_idx [0 ];
1551
1594
cmn -> dtc [i ].cc_active = false;
1552
1595
} else if (type == CMN_TYPE_WP ) {
1553
- int wp_idx = arm_cmn_wp_idx (event );
1554
-
1555
1596
for_each_hw_dn (hw , dn , i ) {
1556
1597
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 );
1557
1599
1558
1600
writeq_relaxed (0 , base + CMN_DTM_WPn_MASK (wp_idx ));
1559
1601
writeq_relaxed (~0ULL , base + CMN_DTM_WPn_VAL (wp_idx ));
@@ -1571,10 +1613,23 @@ struct arm_cmn_val {
1571
1613
u8 dtm_count [CMN_MAX_DTMS ];
1572
1614
u8 occupid [CMN_MAX_DTMS ][SEL_MAX ];
1573
1615
u8 wp [CMN_MAX_DTMS ][4 ];
1616
+ u8 wp_combine [CMN_MAX_DTMS ][2 ];
1574
1617
int dtc_count [CMN_MAX_DTCS ];
1575
1618
bool cycles ;
1576
1619
};
1577
1620
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
+
1578
1633
static void arm_cmn_val_add_event (struct arm_cmn * cmn , struct arm_cmn_val * val ,
1579
1634
struct perf_event * event )
1580
1635
{
@@ -1606,8 +1661,9 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
1606
1661
if (type != CMN_TYPE_WP )
1607
1662
continue ;
1608
1663
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 );
1611
1667
}
1612
1668
}
1613
1669
@@ -1631,6 +1687,7 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
1631
1687
return - ENOMEM ;
1632
1688
1633
1689
arm_cmn_val_add_event (cmn , val , leader );
1690
+
1634
1691
for_each_sibling_event (sibling , leader )
1635
1692
arm_cmn_val_add_event (cmn , val , sibling );
1636
1693
@@ -1645,7 +1702,7 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
1645
1702
goto done ;
1646
1703
1647
1704
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 ;
1649
1706
1650
1707
if (val -> dtm_count [dtm ] == CMN_DTM_NUM_COUNTERS )
1651
1708
goto done ;
@@ -1657,12 +1714,12 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
1657
1714
if (type != CMN_TYPE_WP )
1658
1715
continue ;
1659
1716
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 )
1662
1719
goto done ;
1663
1720
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 ))
1666
1723
goto done ;
1667
1724
}
1668
1725
@@ -1773,8 +1830,11 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
1773
1830
struct arm_cmn_dtm * dtm = & cmn -> dtms [hw -> dn [i ].dtm ] + hw -> dtm_offset ;
1774
1831
unsigned int dtm_idx = arm_cmn_get_index (hw -> dtm_idx , i );
1775
1832
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
+ }
1778
1838
1779
1839
if (hw -> filter_sel > SEL_NONE )
1780
1840
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,
1783
1843
writel_relaxed (dtm -> pmu_config_low , dtm -> base + CMN_DTM_PMU_CONFIG );
1784
1844
}
1785
1845
memset (hw -> dtm_idx , 0 , sizeof (hw -> dtm_idx ));
1846
+ memset (hw -> wp_idx , 0 , sizeof (hw -> wp_idx ));
1786
1847
1787
1848
for_each_hw_dtc_idx (hw , j , idx )
1788
1849
cmn -> dtc [j ].counters [idx ] = NULL ;
@@ -1836,10 +1897,11 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
1836
1897
if (type == CMN_TYPE_XP ) {
1837
1898
input_sel = CMN__PMEVCNT0_INPUT_SEL_XP + dtm_idx ;
1838
1899
} else if (type == CMN_TYPE_WP ) {
1839
- int tmp , wp_idx = arm_cmn_wp_idx ( event ) ;
1900
+ int tmp , wp_idx ;
1840
1901
u32 cfg = arm_cmn_wp_config (event );
1841
1902
1842
- if (dtm -> wp_event [wp_idx ] >= 0 )
1903
+ wp_idx = arm_cmn_find_free_wp_idx (dtm , event );
1904
+ if (wp_idx < 0 )
1843
1905
goto free_dtms ;
1844
1906
1845
1907
tmp = dtm -> wp_event [wp_idx ^ 1 ];
@@ -1848,7 +1910,8 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
1848
1910
goto free_dtms ;
1849
1911
1850
1912
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 );
1852
1915
writel_relaxed (cfg , dtm -> base + CMN_DTM_WPn_CONFIG (wp_idx ));
1853
1916
} else {
1854
1917
struct arm_cmn_nodeid nid = arm_cmn_nid (cmn , dn -> id );
0 commit comments