aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2013-12-12 11:26:51 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-12-16 08:37:57 -0500
commitfcc77f507333776eaa336ab4ff49c23422f53703 (patch)
tree5b1e158fc3da9b865d1bdbb89b7cb23936e6cb57 /arch/s390/kernel
parent69f239ed335a4b03265cae3ca930f3f166e42e35 (diff)
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 <brueckner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/perf_cpum_sf.c12
1 files changed, 8 insertions, 4 deletions
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)
953 struct hw_perf_event *hwc = &event->hw; 953 struct hw_perf_event *hwc = &event->hw;
954 struct hws_trailer_entry *te; 954 struct hws_trailer_entry *te;
955 unsigned long *sdbt; 955 unsigned long *sdbt;
956 unsigned long long event_overflow, sampl_overflow, num_sdb; 956 unsigned long long event_overflow, sampl_overflow, num_sdb, te_flags;
957 int done; 957 int done;
958 958
959 sdbt = (unsigned long *) TEAR_REG(hwc); 959 sdbt = (unsigned long *) TEAR_REG(hwc);
@@ -990,9 +990,13 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
990 hw_collect_samples(event, sdbt, &event_overflow); 990 hw_collect_samples(event, sdbt, &event_overflow);
991 num_sdb++; 991 num_sdb++;
992 992
993 /* Reset trailer */ 993 /* Reset trailer (using compare-double-and-swap) */
994 xchg(&te->overflow, 0); 994 do {
995 xchg((unsigned char *) te, 0x40); 995 te_flags = te->flags & ~SDB_TE_BUFFER_FULL_MASK;
996 te_flags |= SDB_TE_ALERT_REQ_MASK;
997 } while (!cmpxchg_double(&te->flags, &te->overflow,
998 te->flags, te->overflow,
999 te_flags, 0ULL));
996 1000
997 /* Advance to next sample-data-block */ 1001 /* Advance to next sample-data-block */
998 sdbt++; 1002 sdbt++;