[RFC][PATCH 08/12] s390: Replace cmpxchg_double() with cmpxchg128()

From: Peter Zijlstra
Date: Mon Dec 19 2022 - 10:46:23 EST


In order to depricate cmpxchg_double(), replace all its usage with
cmpxchg128().

Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
---
arch/s390/include/asm/cpu_mf.h | 29 ++++++++++++-----
arch/s390/kernel/perf_cpum_sf.c | 65 +++++++++++++++++++++++++---------------
2 files changed, 63 insertions(+), 31 deletions(-)

--- a/arch/s390/include/asm/cpu_mf.h
+++ b/arch/s390/include/asm/cpu_mf.h
@@ -131,19 +131,32 @@ struct hws_combined_entry {
struct hws_diag_entry diag; /* Diagnostic-sampling data entry */
} __packed;

+union hws_flags_and_overflow {
+ struct {
+ unsigned long flags;
+ unsigned long overflow;
+ };
+ u128 full;
+};
+
struct hws_trailer_entry {
union {
struct {
- unsigned int f:1; /* 0 - Block Full Indicator */
- unsigned int a:1; /* 1 - Alert request control */
- unsigned int t:1; /* 2 - Timestamp format */
- unsigned int :29; /* 3 - 31: Reserved */
- unsigned int bsdes:16; /* 32-47: size of basic SDE */
- unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */
+ union {
+ struct {
+ unsigned int f:1; /* 0 - Block Full Indicator */
+ unsigned int a:1; /* 1 - Alert request control */
+ unsigned int t:1; /* 2 - Timestamp format */
+ unsigned int :29; /* 3 - 31: Reserved */
+ unsigned int bsdes:16; /* 32-47: size of basic SDE */
+ unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */
+ };
+ unsigned long long flags; /* 0 - 63: All indicators */
+ };
+ unsigned long long overflow; /* 64 - sample Overflow count */
};
- unsigned long long flags; /* 0 - 63: All indicators */
+ union hws_flags_and_overflow flags_and_overflow;
};
- unsigned long long overflow; /* 64 - sample Overflow count */
unsigned char timestamp[16]; /* 16 - 31 timestamp */
unsigned long long reserved1; /* 32 -Reserved */
unsigned long long reserved2; /* */
--- a/arch/s390/kernel/perf_cpum_sf.c
+++ b/arch/s390/kernel/perf_cpum_sf.c
@@ -1227,6 +1227,8 @@ static void hw_collect_samples(struct pe
}
}

+typedef union hws_flags_and_overflow fao_t;
+
/* hw_perf_event_update() - Process sampling buffer
* @event: The perf event
* @flush_all: Flag to also flush partially filled sample-data-blocks
@@ -1243,10 +1245,11 @@ static void hw_collect_samples(struct pe
*/
static void hw_perf_event_update(struct perf_event *event, int flush_all)
{
+ unsigned long long event_overflow, sampl_overflow, num_sdb;
struct hw_perf_event *hwc = &event->hw;
struct hws_trailer_entry *te;
+ fao_t old_fao, new_fao;
unsigned long *sdbt;
- unsigned long long event_overflow, sampl_overflow, num_sdb, te_flags;
int done;

/*
@@ -1294,12 +1297,16 @@ static void hw_perf_event_update(struct
num_sdb++;

/* Reset trailer (using compare-double-and-swap) */
+ old_fao = te->flags_and_overflow;
do {
- te_flags = te->flags & ~SDB_TE_BUFFER_FULL_MASK;
- te_flags |= SDB_TE_ALERT_REQ_MASK;
- } while (!cmpxchg_double(&te->flags, &te->overflow,
- te->flags, te->overflow,
- te_flags, 0ULL));
+ new_fao = (fao_t){
+ .flags = old_fao.flags,
+ .overflow = 0,
+ };
+ new_fao.flags &= ~SDB_TE_BUFFER_FULL_MASK;
+ new_fao.flags |= SDB_TE_ALERT_REQ_MASK;
+ } while (!try_cmpxchg128(&te->flags_and_overflow.full,
+ &old_fao.full, new_fao.full));

/* Advance to next sample-data-block */
sdbt++;
@@ -1475,14 +1482,19 @@ static int aux_output_begin(struct perf_
static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
unsigned long long *overflow)
{
- unsigned long long orig_overflow, orig_flags, new_flags;
struct hws_trailer_entry *te;
+ fao_t old_fao, new_fao;

te = aux_sdb_trailer(aux, alert_index);
+
+ old_fao = te->flags_and_overflow;
do {
- orig_flags = te->flags;
- *overflow = orig_overflow = te->overflow;
- if (orig_flags & SDB_TE_BUFFER_FULL_MASK) {
+ new_fao = (fao_t){
+ .flags = old_fao.flags,
+ .overflow = 0,
+ };
+ *overflow = old_fao.overflow;
+ if (new_fao.flags & SDB_TE_BUFFER_FULL_MASK) {
/*
* SDB is already set by hardware.
* Abort and try to set somewhere
@@ -1490,10 +1502,11 @@ static bool aux_set_alert(struct aux_buf
*/
return false;
}
- new_flags = orig_flags | SDB_TE_ALERT_REQ_MASK;
- } while (!cmpxchg_double(&te->flags, &te->overflow,
- orig_flags, orig_overflow,
- new_flags, 0ULL));
+ new_fao.flags |= SDB_TE_ALERT_REQ_MASK;
+
+ } while (!try_cmpxchg128(&te->flags_and_overflow.full,
+ &old_fao.full, new_fao.full));
+
return true;
}

@@ -1522,9 +1535,10 @@ static bool aux_set_alert(struct aux_buf
static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
unsigned long long *overflow)
{
- unsigned long long orig_overflow, orig_flags, new_flags;
unsigned long i, range_scan, idx, idx_old;
+ unsigned long long orig_overflow;
struct hws_trailer_entry *te;
+ fao_t old_fao, new_fao;

debug_sprintf_event(sfdbg, 6, "%s: range %ld head %ld alert %ld "
"empty %ld\n", __func__, range, aux->head,
@@ -1554,17 +1568,22 @@ static bool aux_reset_buffer(struct aux_
idx_old = idx = aux->empty_mark + 1;
for (i = 0; i < range_scan; i++, idx++) {
te = aux_sdb_trailer(aux, idx);
+
+ old_fao = te->flags_and_overflow;
do {
- orig_flags = te->flags;
- orig_overflow = te->overflow;
- new_flags = orig_flags & ~SDB_TE_BUFFER_FULL_MASK;
+ new_fao = (fao_t){
+ .flags = old_fao.flags,
+ .overflow = 0,
+ };
+ orig_overflow = old_fao.overflow;
+ new_fao.flags &= ~SDB_TE_BUFFER_FULL_MASK;
if (idx == aux->alert_mark)
- new_flags |= SDB_TE_ALERT_REQ_MASK;
+ new_fao.flags |= SDB_TE_ALERT_REQ_MASK;
else
- new_flags &= ~SDB_TE_ALERT_REQ_MASK;
- } while (!cmpxchg_double(&te->flags, &te->overflow,
- orig_flags, orig_overflow,
- new_flags, 0ULL));
+ new_fao.flags &= ~SDB_TE_ALERT_REQ_MASK;
+ } while (!try_cmpxchg128(&te->flags_and_overflow.full,
+ &old_fao.full, new_fao.full));
+
*overflow += orig_overflow;
}