From: Hendrik Brueckner Date: Thu, 12 Dec 2013 16:26:51 +0000 (+0100) Subject: s390/cpum_sf: Atomically reset trailer entry fields of sample-data-blocks X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=fcc77f507333776eaa336ab4ff49c23422f53703;p=linux-beck.git s390/cpum_sf: Atomically reset trailer entry fields of sample-data-blocks Ensure to reset the sample-data-block full indicator and the overflow counter at the same time. This must be done atomically because the sampling hardware is still active while full sample-data-block is processed. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky --- diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index d707abc26157..b0b3059b8d64 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -115,10 +115,15 @@ struct hws_data_entry { } __packed; struct hws_trailer_entry { - unsigned int f:1; /* 0 - Block Full Indicator */ - unsigned int a:1; /* 1 - Alert request control */ - unsigned int t:1; /* 2 - Timestamp format */ - unsigned long long:61; /* 3 - 63: Reserved */ + 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 long long:61; /* 3 - 63: Reserved */ + }; + unsigned long long flags; /* 0 - 63: All indicators */ + }; unsigned long long overflow; /* 64 - sample Overflow count */ unsigned long long timestamp; /* 16 - time-stamp */ unsigned long long timestamp1; /* */ diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index ea1656073dac..9202f2858894 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -953,7 +953,7 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all) struct hw_perf_event *hwc = &event->hw; struct hws_trailer_entry *te; unsigned long *sdbt; - unsigned long long event_overflow, sampl_overflow, num_sdb; + unsigned long long event_overflow, sampl_overflow, num_sdb, te_flags; int done; sdbt = (unsigned long *) TEAR_REG(hwc); @@ -990,9 +990,13 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all) hw_collect_samples(event, sdbt, &event_overflow); num_sdb++; - /* Reset trailer */ - xchg(&te->overflow, 0); - xchg((unsigned char *) te, 0x40); + /* Reset trailer (using compare-double-and-swap) */ + 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)); /* Advance to next sample-data-block */ sdbt++;