@@ -281,16 +281,13 @@ struct arm_cmn_node {
281
281
u16 id , logid ;
282
282
enum cmn_node_type type ;
283
283
284
- int dtm ;
285
- union {
286
- /* DN/HN-F/CXHA */
287
- struct {
288
- u8 val : 4 ;
289
- u8 count : 4 ;
290
- } occupid [SEL_MAX ];
291
- /* XP */
292
- u8 dtc ;
293
- };
284
+ u8 dtm ;
285
+ s8 dtc ;
286
+ /* DN/HN-F/CXHA */
287
+ struct {
288
+ u8 val : 4 ;
289
+ u8 count : 4 ;
290
+ } occupid [SEL_MAX ];
294
291
union {
295
292
u8 event [4 ];
296
293
__le32 event_sel ;
@@ -540,12 +537,12 @@ static int arm_cmn_map_show(struct seq_file *s, void *data)
540
537
541
538
seq_puts (s , "\n |" );
542
539
for (x = 0 ; x < cmn -> mesh_x ; x ++ ) {
543
- u8 dtc = cmn -> xps [xp_base + x ].dtc ;
540
+ s8 dtc = cmn -> xps [xp_base + x ].dtc ;
544
541
545
- if (dtc & ( dtc - 1 ) )
542
+ if (dtc < 0 )
546
543
seq_puts (s , " DTC ?? |" );
547
544
else
548
- seq_printf (s , " DTC %ld |" , __ffs ( dtc ) );
545
+ seq_printf (s , " DTC %d |" , dtc );
549
546
}
550
547
seq_puts (s , "\n |" );
551
548
for (x = 0 ; x < cmn -> mesh_x ; x ++ )
@@ -589,8 +586,7 @@ static void arm_cmn_debugfs_init(struct arm_cmn *cmn, int id) {}
589
586
struct arm_cmn_hw_event {
590
587
struct arm_cmn_node * dn ;
591
588
u64 dtm_idx [4 ];
592
- unsigned int dtc_idx ;
593
- u8 dtcs_used ;
589
+ s8 dtc_idx [CMN_MAX_DTCS ];
594
590
u8 num_dns ;
595
591
u8 dtm_offset ;
596
592
bool wide_sel ;
@@ -600,6 +596,10 @@ struct arm_cmn_hw_event {
600
596
#define for_each_hw_dn (hw , dn , i ) \
601
597
for (i = 0, dn = hw->dn; i < hw->num_dns; i++, dn++)
602
598
599
+ /* @i is the DTC number, @idx is the counter index on that DTC */
600
+ #define for_each_hw_dtc_idx (hw , i , idx ) \
601
+ for (int i = 0, idx; i < CMN_MAX_DTCS; i++) if ((idx = hw->dtc_idx[i]) >= 0)
602
+
603
603
static struct arm_cmn_hw_event * to_cmn_hw (struct perf_event * event )
604
604
{
605
605
BUILD_BUG_ON (sizeof (struct arm_cmn_hw_event ) > offsetof(struct hw_perf_event , target ));
@@ -1429,12 +1429,11 @@ static void arm_cmn_init_counter(struct perf_event *event)
1429
1429
{
1430
1430
struct arm_cmn * cmn = to_cmn (event -> pmu );
1431
1431
struct arm_cmn_hw_event * hw = to_cmn_hw (event );
1432
- unsigned int i , pmevcnt = CMN_DT_PMEVCNT (hw -> dtc_idx );
1433
1432
u64 count ;
1434
1433
1435
- for ( i = 0 ; hw -> dtcs_used & ( 1U << i ); i ++ ) {
1436
- writel_relaxed (CMN_COUNTER_INIT , cmn -> dtc [i ].base + pmevcnt );
1437
- cmn -> dtc [i ].counters [hw -> dtc_idx ] = event ;
1434
+ for_each_hw_dtc_idx ( hw , i , idx ) {
1435
+ writel_relaxed (CMN_COUNTER_INIT , cmn -> dtc [i ].base + CMN_DT_PMEVCNT ( idx ) );
1436
+ cmn -> dtc [i ].counters [idx ] = event ;
1438
1437
}
1439
1438
1440
1439
count = arm_cmn_read_dtm (cmn , hw , false);
@@ -1447,11 +1446,9 @@ static void arm_cmn_event_read(struct perf_event *event)
1447
1446
struct arm_cmn_hw_event * hw = to_cmn_hw (event );
1448
1447
u64 delta , new , prev ;
1449
1448
unsigned long flags ;
1450
- unsigned int i ;
1451
1449
1452
- if (hw -> dtc_idx == CMN_DT_NUM_COUNTERS ) {
1453
- i = __ffs (hw -> dtcs_used );
1454
- delta = arm_cmn_read_cc (cmn -> dtc + i );
1450
+ if (CMN_EVENT_TYPE (event ) == CMN_TYPE_DTC ) {
1451
+ delta = arm_cmn_read_cc (cmn -> dtc + hw -> dtc_idx [0 ]);
1455
1452
local64_add (delta , & event -> count );
1456
1453
return ;
1457
1454
}
@@ -1461,8 +1458,8 @@ static void arm_cmn_event_read(struct perf_event *event)
1461
1458
delta = new - prev ;
1462
1459
1463
1460
local_irq_save (flags );
1464
- for ( i = 0 ; hw -> dtcs_used & ( 1U << i ); i ++ ) {
1465
- new = arm_cmn_read_counter (cmn -> dtc + i , hw -> dtc_idx );
1461
+ for_each_hw_dtc_idx ( hw , i , idx ) {
1462
+ new = arm_cmn_read_counter (cmn -> dtc + i , idx );
1466
1463
delta += new << 16 ;
1467
1464
}
1468
1465
local_irq_restore (flags );
@@ -1518,7 +1515,7 @@ static void arm_cmn_event_start(struct perf_event *event, int flags)
1518
1515
int i ;
1519
1516
1520
1517
if (type == CMN_TYPE_DTC ) {
1521
- i = __ffs ( hw -> dtcs_used ) ;
1518
+ i = hw -> dtc_idx [ 0 ] ;
1522
1519
writeq_relaxed (CMN_CC_INIT , cmn -> dtc [i ].base + CMN_DT_PMCCNTR );
1523
1520
cmn -> dtc [i ].cc_active = true;
1524
1521
} else if (type == CMN_TYPE_WP ) {
@@ -1549,7 +1546,7 @@ static void arm_cmn_event_stop(struct perf_event *event, int flags)
1549
1546
int i ;
1550
1547
1551
1548
if (type == CMN_TYPE_DTC ) {
1552
- i = __ffs ( hw -> dtcs_used ) ;
1549
+ i = hw -> dtc_idx [ 0 ] ;
1553
1550
cmn -> dtc [i ].cc_active = false;
1554
1551
} else if (type == CMN_TYPE_WP ) {
1555
1552
int wp_idx = arm_cmn_wp_idx (event );
@@ -1735,12 +1732,19 @@ static int arm_cmn_event_init(struct perf_event *event)
1735
1732
hw -> dn = arm_cmn_node (cmn , type );
1736
1733
if (!hw -> dn )
1737
1734
return - EINVAL ;
1735
+
1736
+ memset (hw -> dtc_idx , -1 , sizeof (hw -> dtc_idx ));
1738
1737
for (dn = hw -> dn ; dn -> type == type ; dn ++ ) {
1739
1738
if (bynodeid && dn -> id != nodeid ) {
1740
1739
hw -> dn ++ ;
1741
1740
continue ;
1742
1741
}
1743
1742
hw -> num_dns ++ ;
1743
+ if (dn -> dtc < 0 )
1744
+ memset (hw -> dtc_idx , 0 , cmn -> num_dtcs );
1745
+ else
1746
+ hw -> dtc_idx [dn -> dtc ] = 0 ;
1747
+
1744
1748
if (bynodeid )
1745
1749
break ;
1746
1750
}
@@ -1752,12 +1756,6 @@ static int arm_cmn_event_init(struct perf_event *event)
1752
1756
nodeid , nid .x , nid .y , nid .port , nid .dev , type );
1753
1757
return - EINVAL ;
1754
1758
}
1755
- /*
1756
- * Keep assuming non-cycles events count in all DTC domains; turns out
1757
- * it's hard to make a worthwhile optimisation around this, short of
1758
- * going all-in with domain-local counter allocation as well.
1759
- */
1760
- hw -> dtcs_used = (1U << cmn -> num_dtcs ) - 1 ;
1761
1759
1762
1760
return arm_cmn_validate_group (cmn , event );
1763
1761
}
@@ -1783,46 +1781,48 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
1783
1781
}
1784
1782
memset (hw -> dtm_idx , 0 , sizeof (hw -> dtm_idx ));
1785
1783
1786
- for ( i = 0 ; hw -> dtcs_used & ( 1U << i ); i ++ )
1787
- cmn -> dtc [i ].counters [hw -> dtc_idx ] = NULL ;
1784
+ for_each_hw_dtc_idx ( hw , j , idx )
1785
+ cmn -> dtc [j ].counters [idx ] = NULL ;
1788
1786
}
1789
1787
1790
1788
static int arm_cmn_event_add (struct perf_event * event , int flags )
1791
1789
{
1792
1790
struct arm_cmn * cmn = to_cmn (event -> pmu );
1793
1791
struct arm_cmn_hw_event * hw = to_cmn_hw (event );
1794
- struct arm_cmn_dtc * dtc = & cmn -> dtc [0 ];
1795
1792
struct arm_cmn_node * dn ;
1796
1793
enum cmn_node_type type = CMN_EVENT_TYPE (event );
1797
- unsigned int i , dtc_idx , input_sel ;
1794
+ unsigned int input_sel , i = 0 ;
1798
1795
1799
1796
if (type == CMN_TYPE_DTC ) {
1800
- i = 0 ;
1801
1797
while (cmn -> dtc [i ].cycles )
1802
1798
if (++ i == cmn -> num_dtcs )
1803
1799
return - ENOSPC ;
1804
1800
1805
1801
cmn -> dtc [i ].cycles = event ;
1806
- hw -> dtc_idx = CMN_DT_NUM_COUNTERS ;
1807
- hw -> dtcs_used = 1U << i ;
1802
+ hw -> dtc_idx [0 ] = i ;
1808
1803
1809
1804
if (flags & PERF_EF_START )
1810
1805
arm_cmn_event_start (event , 0 );
1811
1806
return 0 ;
1812
1807
}
1813
1808
1814
1809
/* Grab a free global counter first... */
1815
- dtc_idx = 0 ;
1816
- while (dtc -> counters [dtc_idx ])
1817
- if (++ dtc_idx == CMN_DT_NUM_COUNTERS )
1818
- return - ENOSPC ;
1819
-
1820
- hw -> dtc_idx = dtc_idx ;
1810
+ for_each_hw_dtc_idx (hw , j , idx ) {
1811
+ if (j > 0 ) {
1812
+ idx = hw -> dtc_idx [0 ];
1813
+ } else {
1814
+ idx = 0 ;
1815
+ while (cmn -> dtc [j ].counters [idx ])
1816
+ if (++ idx == CMN_DT_NUM_COUNTERS )
1817
+ goto free_dtms ;
1818
+ }
1819
+ hw -> dtc_idx [j ] = idx ;
1820
+ }
1821
1821
1822
1822
/* ...then the local counters to feed it. */
1823
1823
for_each_hw_dn (hw , dn , i ) {
1824
1824
struct arm_cmn_dtm * dtm = & cmn -> dtms [dn -> dtm ] + hw -> dtm_offset ;
1825
- unsigned int dtm_idx , shift ;
1825
+ unsigned int dtm_idx , shift , d = 0 ;
1826
1826
u64 reg ;
1827
1827
1828
1828
dtm_idx = 0 ;
@@ -1841,11 +1841,11 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
1841
1841
1842
1842
tmp = dtm -> wp_event [wp_idx ^ 1 ];
1843
1843
if (tmp >= 0 && CMN_EVENT_WP_COMBINE (event ) !=
1844
- CMN_EVENT_WP_COMBINE (dtc -> counters [tmp ]))
1844
+ CMN_EVENT_WP_COMBINE (cmn -> dtc [ d ]. counters [tmp ]))
1845
1845
goto free_dtms ;
1846
1846
1847
1847
input_sel = CMN__PMEVCNT0_INPUT_SEL_WP + wp_idx ;
1848
- dtm -> wp_event [wp_idx ] = dtc_idx ;
1848
+ dtm -> wp_event [wp_idx ] = hw -> dtc_idx [ d ] ;
1849
1849
writel_relaxed (cfg , dtm -> base + CMN_DTM_WPn_CONFIG (wp_idx ));
1850
1850
} else {
1851
1851
struct arm_cmn_nodeid nid = arm_cmn_nid (cmn , dn -> id );
@@ -1865,7 +1865,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
1865
1865
dtm -> input_sel [dtm_idx ] = input_sel ;
1866
1866
shift = CMN__PMEVCNTn_GLOBAL_NUM_SHIFT (dtm_idx );
1867
1867
dtm -> pmu_config_low &= ~(CMN__PMEVCNT0_GLOBAL_NUM << shift );
1868
- dtm -> pmu_config_low |= FIELD_PREP (CMN__PMEVCNT0_GLOBAL_NUM , dtc_idx ) << shift ;
1868
+ dtm -> pmu_config_low |= FIELD_PREP (CMN__PMEVCNT0_GLOBAL_NUM , hw -> dtc_idx [ d ] ) << shift ;
1869
1869
dtm -> pmu_config_low |= CMN__PMEVCNT_PAIRED (dtm_idx );
1870
1870
reg = (u64 )le32_to_cpu (dtm -> pmu_config_high ) << 32 | dtm -> pmu_config_low ;
1871
1871
writeq_relaxed (reg , dtm -> base + CMN_DTM_PMU_CONFIG );
@@ -1893,7 +1893,7 @@ static void arm_cmn_event_del(struct perf_event *event, int flags)
1893
1893
arm_cmn_event_stop (event , PERF_EF_UPDATE );
1894
1894
1895
1895
if (type == CMN_TYPE_DTC )
1896
- cmn -> dtc [__ffs ( hw -> dtcs_used ) ].cycles = NULL ;
1896
+ cmn -> dtc [hw -> dtc_idx [ 0 ] ].cycles = NULL ;
1897
1897
else
1898
1898
arm_cmn_event_clear (cmn , event , hw -> num_dns );
1899
1899
}
@@ -2074,7 +2074,6 @@ static int arm_cmn_init_dtcs(struct arm_cmn *cmn)
2074
2074
{
2075
2075
struct arm_cmn_node * dn , * xp ;
2076
2076
int dtc_idx = 0 ;
2077
- u8 dtcs_present = (1 << cmn -> num_dtcs ) - 1 ;
2078
2077
2079
2078
cmn -> dtc = devm_kcalloc (cmn -> dev , cmn -> num_dtcs , sizeof (cmn -> dtc [0 ]), GFP_KERNEL );
2080
2079
if (!cmn -> dtc )
@@ -2084,23 +2083,26 @@ static int arm_cmn_init_dtcs(struct arm_cmn *cmn)
2084
2083
2085
2084
cmn -> xps = arm_cmn_node (cmn , CMN_TYPE_XP );
2086
2085
2086
+ if (cmn -> part == PART_CMN600 && cmn -> num_dtcs > 1 ) {
2087
+ /* We do at least know that a DTC's XP must be in that DTC's domain */
2088
+ dn = arm_cmn_node (cmn , CMN_TYPE_DTC );
2089
+ for (int i = 0 ; i < cmn -> num_dtcs ; i ++ )
2090
+ arm_cmn_node_to_xp (cmn , dn + i )-> dtc = i ;
2091
+ }
2092
+
2087
2093
for (dn = cmn -> dns ; dn -> type ; dn ++ ) {
2088
- if (dn -> type == CMN_TYPE_XP ) {
2089
- dn -> dtc &= dtcs_present ;
2094
+ if (dn -> type == CMN_TYPE_XP )
2090
2095
continue ;
2091
- }
2092
2096
2093
2097
xp = arm_cmn_node_to_xp (cmn , dn );
2098
+ dn -> dtc = xp -> dtc ;
2094
2099
dn -> dtm = xp -> dtm ;
2095
2100
if (cmn -> multi_dtm )
2096
2101
dn -> dtm += arm_cmn_nid (cmn , dn -> id ).port / 2 ;
2097
2102
2098
2103
if (dn -> type == CMN_TYPE_DTC ) {
2099
- int err ;
2100
- /* We do at least know that a DTC's XP must be in that DTC's domain */
2101
- if (xp -> dtc == 0xf )
2102
- xp -> dtc = 1 << dtc_idx ;
2103
- err = arm_cmn_init_dtc (cmn , dn , dtc_idx ++ );
2104
+ int err = arm_cmn_init_dtc (cmn , dn , dtc_idx ++ );
2105
+
2104
2106
if (err )
2105
2107
return err ;
2106
2108
}
@@ -2258,9 +2260,9 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
2258
2260
cmn -> mesh_x = xp -> logid ;
2259
2261
2260
2262
if (cmn -> part == PART_CMN600 )
2261
- xp -> dtc = 0xf ;
2263
+ xp -> dtc = -1 ;
2262
2264
else
2263
- xp -> dtc = 1 << arm_cmn_dtc_domain (cmn , xp_region );
2265
+ xp -> dtc = arm_cmn_dtc_domain (cmn , xp_region );
2264
2266
2265
2267
xp -> dtm = dtm - cmn -> dtms ;
2266
2268
arm_cmn_init_dtm (dtm ++ , xp , 0 );
0 commit comments