s390/cpum_sf: Atomically reset trailer entry fields of sample-data-blocks
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Thu, 12 Dec 2013 16:26:51 +0000 (17:26 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 16 Dec 2013 13:37:57 +0000 (14:37 +0100)
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>
arch/s390/include/asm/cpu_mf.h
arch/s390/kernel/perf_cpum_sf.c

index d707abc26157de7ae6d11a642b8df40184ddec27..b0b3059b8d6428f72c3a4ffdd38cd5229f140ed7 100644 (file)
@@ -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;   /*                                   */
index ea1656073dac6f3ed7f626555599b3b41eb2d522..9202f28588949f09fe30c6edf2abe06fddc355d4 100644 (file)
@@ -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++;