From: Mikael Pettersson perfctr seqlocks 4/4: ppc32 changes - use write_perfseq_begin/end in perfctr_cpu_suspend/resume/sample to indicate that the state has changed - in mmap:ed state, redefine samplecnt field as the sequence number Signed-off-by: Mikael Pettersson Signed-off-by: Andrew Morton --- drivers/perfctr/ppc.c | 8 ++++++-- include/asm-ppc/perfctr.h | 10 ++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff -puN drivers/perfctr/ppc.c~perfctr-seqlocks-for-mmaped-state-ppc32 drivers/perfctr/ppc.c --- 25/drivers/perfctr/ppc.c~perfctr-seqlocks-for-mmaped-state-ppc32 2005-05-26 22:57:44.000000000 -0700 +++ 25-akpm/drivers/perfctr/ppc.c 2005-05-26 22:57:44.000000000 -0700 @@ -697,6 +697,7 @@ void perfctr_cpu_suspend(struct perfctr_ unsigned int i, cstatus, nractrs; struct perfctr_low_ctrs now; + write_perfseq_begin(&state->user.sequence); if (perfctr_cstatus_has_mmcr0_quirk(state->user.cstatus)) { unsigned int mmcr0 = mfspr(SPRN_MMCR0); mtspr(SPRN_MMCR0, mmcr0 | MMCR0_FC); @@ -712,10 +713,12 @@ void perfctr_cpu_suspend(struct perfctr_ nractrs = perfctr_cstatus_nractrs(cstatus); for(i = 0; i < nractrs; ++i) state->user.pmc[i].sum += now.pmc[i] - state->user.pmc[i].start; + write_perfseq_end(&state->user.sequence); } void perfctr_cpu_resume(struct perfctr_cpu_state *state) { + write_perfseq_begin(&state->user.sequence); if (perfctr_cstatus_has_ictrs(state->user.cstatus)) perfctr_cpu_iresume(state); if (perfctr_cstatus_has_mmcr0_quirk(state->user.cstatus)) @@ -733,7 +736,7 @@ void perfctr_cpu_resume(struct perfctr_c for(i = 0; i < nrctrs; ++i) state->user.pmc[i].start = now.pmc[i]; } - ++state->user.samplecnt; + write_perfseq_end(&state->user.sequence); } void perfctr_cpu_sample(struct perfctr_cpu_state *state) @@ -741,6 +744,7 @@ void perfctr_cpu_sample(struct perfctr_c unsigned int i, cstatus, nractrs; struct perfctr_low_ctrs now; + write_perfseq_begin(&state->user.sequence); perfctr_cpu_read_counters(state, &now); cstatus = state->user.cstatus; if (perfctr_cstatus_has_tsc(cstatus)) { @@ -752,7 +756,7 @@ void perfctr_cpu_sample(struct perfctr_c state->user.pmc[i].sum += now.pmc[i] - state->user.pmc[i].start; state->user.pmc[i].start = now.pmc[i]; } - ++state->user.samplecnt; + write_perfseq_end(&state->user.sequence); } static void perfctr_cpu_clear_counters(void) diff -puN include/asm-ppc/perfctr.h~perfctr-seqlocks-for-mmaped-state-ppc32 include/asm-ppc/perfctr.h --- 25/include/asm-ppc/perfctr.h~perfctr-seqlocks-for-mmaped-state-ppc32 2005-05-26 22:57:44.000000000 -0700 +++ 25-akpm/include/asm-ppc/perfctr.h 2005-05-26 22:57:44.000000000 -0700 @@ -21,12 +21,10 @@ struct perfctr_cpu_control_header { struct perfctr_cpu_state_user { __u32 cstatus; - /* 'samplecnt' is incremented every time the 'start' - fields have been updated by a sampling operation. - Unfortunately the PPC timebase (tsc_start) has too - low frequency for it to be a reliable context-switch - indicator for user-space. */ - __u32 samplecnt; + /* This is a sequence counter to ensure atomic reads by + * userspace. The mechanism is identical to that used for + * seqcount_t in include/linux/seqlock.h. */ + __u32 sequence; __u64 tsc_start; __u64 tsc_sum; struct { _