@@ -163,14 +163,15 @@ static void free_sampling_buffer(struct sf_buffer *sfb)
163
163
164
164
static int alloc_sample_data_block (unsigned long * sdbt , gfp_t gfp_flags )
165
165
{
166
- unsigned long sdb , * trailer ;
166
+ struct hws_trailer_entry * te ;
167
+ unsigned long sdb ;
167
168
168
169
/* Allocate and initialize sample-data-block */
169
170
sdb = get_zeroed_page (gfp_flags );
170
171
if (!sdb )
171
172
return - ENOMEM ;
172
- trailer = trailer_entry_ptr (sdb );
173
- * trailer = SDB_TE_ALERT_REQ_MASK ;
173
+ te = ( struct hws_trailer_entry * ) trailer_entry_ptr (sdb );
174
+ te -> header . a = 1 ;
174
175
175
176
/* Link SDB into the sample-data-block-table */
176
177
* sdbt = sdb ;
@@ -1206,7 +1207,7 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
1206
1207
"%s: Found unknown"
1207
1208
" sampling data entry: te->f %i"
1208
1209
" basic.def %#4x (%p)\n" , __func__ ,
1209
- te -> f , sample -> def , sample );
1210
+ te -> header . f , sample -> def , sample );
1210
1211
/* Sample slot is not yet written or other record.
1211
1212
*
1212
1213
* This condition can occur if the buffer was reused
@@ -1217,7 +1218,7 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
1217
1218
* that are not full. Stop processing if the first
1218
1219
* invalid format was detected.
1219
1220
*/
1220
- if (!te -> f )
1221
+ if (!te -> header . f )
1221
1222
break ;
1222
1223
}
1223
1224
@@ -1227,6 +1228,16 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
1227
1228
}
1228
1229
}
1229
1230
1231
+ static inline __uint128_t __cdsg (__uint128_t * ptr , __uint128_t old , __uint128_t new )
1232
+ {
1233
+ asm volatile (
1234
+ " cdsg %[old],%[new],%[ptr]\n"
1235
+ : [old ] "+d" (old ), [ptr ] "+QS" (* ptr )
1236
+ : [new ] "d" (new )
1237
+ : "memory" , "cc" );
1238
+ return old ;
1239
+ }
1240
+
1230
1241
/* hw_perf_event_update() - Process sampling buffer
1231
1242
* @event: The perf event
1232
1243
* @flush_all: Flag to also flush partially filled sample-data-blocks
@@ -1243,10 +1254,11 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
1243
1254
*/
1244
1255
static void hw_perf_event_update (struct perf_event * event , int flush_all )
1245
1256
{
1257
+ unsigned long long event_overflow , sampl_overflow , num_sdb ;
1258
+ union hws_trailer_header old , prev , new ;
1246
1259
struct hw_perf_event * hwc = & event -> hw ;
1247
1260
struct hws_trailer_entry * te ;
1248
1261
unsigned long * sdbt ;
1249
- unsigned long long event_overflow , sampl_overflow , num_sdb , te_flags ;
1250
1262
int done ;
1251
1263
1252
1264
/*
@@ -1266,25 +1278,25 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
1266
1278
te = (struct hws_trailer_entry * ) trailer_entry_ptr (* sdbt );
1267
1279
1268
1280
/* Leave loop if no more work to do (block full indicator) */
1269
- if (!te -> f ) {
1281
+ if (!te -> header . f ) {
1270
1282
done = 1 ;
1271
1283
if (!flush_all )
1272
1284
break ;
1273
1285
}
1274
1286
1275
1287
/* Check the sample overflow count */
1276
- if (te -> overflow )
1288
+ if (te -> header . overflow )
1277
1289
/* Account sample overflows and, if a particular limit
1278
1290
* is reached, extend the sampling buffer.
1279
1291
* For details, see sfb_account_overflows().
1280
1292
*/
1281
- sampl_overflow += te -> overflow ;
1293
+ sampl_overflow += te -> header . overflow ;
1282
1294
1283
1295
/* Timestamps are valid for full sample-data-blocks only */
1284
1296
debug_sprintf_event (sfdbg , 6 , "%s: sdbt %#lx "
1285
1297
"overflow %llu timestamp %#llx\n" ,
1286
- __func__ , (unsigned long )sdbt , te -> overflow ,
1287
- (te -> f ) ? trailer_timestamp (te ) : 0ULL );
1298
+ __func__ , (unsigned long )sdbt , te -> header . overflow ,
1299
+ (te -> header . f ) ? trailer_timestamp (te ) : 0ULL );
1288
1300
1289
1301
/* Collect all samples from a single sample-data-block and
1290
1302
* flag if an (perf) event overflow happened. If so, the PMU
@@ -1294,12 +1306,16 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
1294
1306
num_sdb ++ ;
1295
1307
1296
1308
/* Reset trailer (using compare-double-and-swap) */
1309
+ /* READ_ONCE() 16 byte header */
1310
+ prev .val = __cdsg (& te -> header .val , 0 , 0 );
1297
1311
do {
1298
- te_flags = te -> flags & ~SDB_TE_BUFFER_FULL_MASK ;
1299
- te_flags |= SDB_TE_ALERT_REQ_MASK ;
1300
- } while (!cmpxchg_double (& te -> flags , & te -> overflow ,
1301
- te -> flags , te -> overflow ,
1302
- te_flags , 0ULL ));
1312
+ old .val = prev .val ;
1313
+ new .val = prev .val ;
1314
+ new .f = 0 ;
1315
+ new .a = 1 ;
1316
+ new .overflow = 0 ;
1317
+ prev .val = __cdsg (& te -> header .val , old .val , new .val );
1318
+ } while (prev .val != old .val );
1303
1319
1304
1320
/* Advance to next sample-data-block */
1305
1321
sdbt ++ ;
@@ -1384,15 +1400,15 @@ static void aux_output_end(struct perf_output_handle *handle)
1384
1400
range_scan = AUX_SDB_NUM_ALERT (aux );
1385
1401
for (i = 0 , idx = aux -> head ; i < range_scan ; i ++ , idx ++ ) {
1386
1402
te = aux_sdb_trailer (aux , idx );
1387
- if (!( te -> flags & SDB_TE_BUFFER_FULL_MASK ) )
1403
+ if (!te -> header . f )
1388
1404
break ;
1389
1405
}
1390
1406
/* i is num of SDBs which are full */
1391
1407
perf_aux_output_end (handle , i << PAGE_SHIFT );
1392
1408
1393
1409
/* Remove alert indicators in the buffer */
1394
1410
te = aux_sdb_trailer (aux , aux -> alert_mark );
1395
- te -> flags &= ~ SDB_TE_ALERT_REQ_MASK ;
1411
+ te -> header . a = 0 ;
1396
1412
1397
1413
debug_sprintf_event (sfdbg , 6 , "%s: SDBs %ld range %ld head %ld\n" ,
1398
1414
__func__ , i , range_scan , aux -> head );
@@ -1437,9 +1453,9 @@ static int aux_output_begin(struct perf_output_handle *handle,
1437
1453
idx = aux -> empty_mark + 1 ;
1438
1454
for (i = 0 ; i < range_scan ; i ++ , idx ++ ) {
1439
1455
te = aux_sdb_trailer (aux , idx );
1440
- te -> flags &= ~( SDB_TE_BUFFER_FULL_MASK |
1441
- SDB_TE_ALERT_REQ_MASK ) ;
1442
- te -> overflow = 0 ;
1456
+ te -> header . f = 0 ;
1457
+ te -> header . a = 0 ;
1458
+ te -> header . overflow = 0 ;
1443
1459
}
1444
1460
/* Save the position of empty SDBs */
1445
1461
aux -> empty_mark = aux -> head + range - 1 ;
@@ -1448,7 +1464,7 @@ static int aux_output_begin(struct perf_output_handle *handle,
1448
1464
/* Set alert indicator */
1449
1465
aux -> alert_mark = aux -> head + range /2 - 1 ;
1450
1466
te = aux_sdb_trailer (aux , aux -> alert_mark );
1451
- te -> flags = te -> flags | SDB_TE_ALERT_REQ_MASK ;
1467
+ te -> header . a = 1 ;
1452
1468
1453
1469
/* Reset hardware buffer head */
1454
1470
head = AUX_SDB_INDEX (aux , aux -> head );
@@ -1475,25 +1491,28 @@ static int aux_output_begin(struct perf_output_handle *handle,
1475
1491
static bool aux_set_alert (struct aux_buffer * aux , unsigned long alert_index ,
1476
1492
unsigned long long * overflow )
1477
1493
{
1478
- unsigned long long orig_overflow , orig_flags , new_flags ;
1494
+ union hws_trailer_header old , prev , new ;
1479
1495
struct hws_trailer_entry * te ;
1480
1496
1481
1497
te = aux_sdb_trailer (aux , alert_index );
1498
+ /* READ_ONCE() 16 byte header */
1499
+ prev .val = __cdsg (& te -> header .val , 0 , 0 );
1482
1500
do {
1483
- orig_flags = te -> flags ;
1484
- * overflow = orig_overflow = te -> overflow ;
1485
- if (orig_flags & SDB_TE_BUFFER_FULL_MASK ) {
1501
+ old .val = prev .val ;
1502
+ new .val = prev .val ;
1503
+ * overflow = old .overflow ;
1504
+ if (old .f ) {
1486
1505
/*
1487
1506
* SDB is already set by hardware.
1488
1507
* Abort and try to set somewhere
1489
1508
* behind.
1490
1509
*/
1491
1510
return false;
1492
1511
}
1493
- new_flags = orig_flags | SDB_TE_ALERT_REQ_MASK ;
1494
- } while (! cmpxchg_double ( & te -> flags , & te -> overflow ,
1495
- orig_flags , orig_overflow ,
1496
- new_flags , 0ULL ) );
1512
+ new . a = 1 ;
1513
+ new . overflow = 0 ;
1514
+ prev . val = __cdsg ( & te -> header . val , old . val , new . val );
1515
+ } while ( prev . val != old . val );
1497
1516
return true;
1498
1517
}
1499
1518
@@ -1522,8 +1541,9 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
1522
1541
static bool aux_reset_buffer (struct aux_buffer * aux , unsigned long range ,
1523
1542
unsigned long long * overflow )
1524
1543
{
1525
- unsigned long long orig_overflow , orig_flags , new_flags ;
1526
1544
unsigned long i , range_scan , idx , idx_old ;
1545
+ union hws_trailer_header old , prev , new ;
1546
+ unsigned long long orig_overflow ;
1527
1547
struct hws_trailer_entry * te ;
1528
1548
1529
1549
debug_sprintf_event (sfdbg , 6 , "%s: range %ld head %ld alert %ld "
@@ -1554,17 +1574,20 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
1554
1574
idx_old = idx = aux -> empty_mark + 1 ;
1555
1575
for (i = 0 ; i < range_scan ; i ++ , idx ++ ) {
1556
1576
te = aux_sdb_trailer (aux , idx );
1577
+ /* READ_ONCE() 16 byte header */
1578
+ prev .val = __cdsg (& te -> header .val , 0 , 0 );
1557
1579
do {
1558
- orig_flags = te -> flags ;
1559
- orig_overflow = te -> overflow ;
1560
- new_flags = orig_flags & ~SDB_TE_BUFFER_FULL_MASK ;
1580
+ old .val = prev .val ;
1581
+ new .val = prev .val ;
1582
+ orig_overflow = old .overflow ;
1583
+ new .f = 0 ;
1584
+ new .overflow = 0 ;
1561
1585
if (idx == aux -> alert_mark )
1562
- new_flags |= SDB_TE_ALERT_REQ_MASK ;
1586
+ new . a = 1 ;
1563
1587
else
1564
- new_flags &= ~SDB_TE_ALERT_REQ_MASK ;
1565
- } while (!cmpxchg_double (& te -> flags , & te -> overflow ,
1566
- orig_flags , orig_overflow ,
1567
- new_flags , 0ULL ));
1588
+ new .a = 0 ;
1589
+ prev .val = __cdsg (& te -> header .val , old .val , new .val );
1590
+ } while (prev .val != old .val );
1568
1591
* overflow += orig_overflow ;
1569
1592
}
1570
1593
0 commit comments