On Tue, 24 May 2011, Michael Hope wrote:

> On Tue, May 24, 2011 at 10:33 AM, Michael Casadevall
> <mcasadev...@ubuntu.com> wrote:
> > On 05/19/2011 10:56 AM, David Gilbert wrote:
> >> On 19 May 2011 16:49, Ken Werner <k...@linux.vnet.ibm.com> wrote:
> >>> On 05/19/2011 12:40 PM, David Rusling wrote:
> >>>>
> >>>> Is this going to end up in a blueprint?   This is the last loose end of
> >>>> SMP / atomic memory operations work and I'd like to see it happen
> >>>
> >>> Hi,
> >>>
> >>> Yep, there is one (kind of a skeleton) in place at:
> >>> https://blueprints.launchpad.net/linaro-toolchain-misc/+spec/64-bit-sync-primitives
> >>
> >> Which I'll be filling out in the next few days.
> >>
> >> Dave
> >
> > Is there a timeline for this feature? It's been requested by members of
> > the ARM Server Club to have this implemented, and its important that
> > this makes it into the Ubuntu 11.10 release.
> > Michael
> 
> Hi Michael.  The topics for this planning cycle are listed here:
>  https://wiki.linaro.org/Cycles/1111/TechnicalTopics/Toolchain
> 
> 64 bit sync primitives are medium priority so they will be achieved in
> the next six months.
> 
> A draft of what is in whos queue is at:
>  https://wiki.linaro.org/Cycles/1111/TechnicalTopics/Toolchain/Planning
> 
> The primitives are second in Dave's queue so should be started in the
> next three months.

FWIW, here's what the kernel part might look like, i.e. for 
compatibility with pre ARMv6k systems (beware, only compile tested):

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index e8d8856..53830a7 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -383,7 +383,7 @@ ENDPROC(__pabt_svc)
        .endm
 
        .macro  kuser_cmpxchg_check
-#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
 #ifndef CONFIG_MMU
 #warning "NPTL on non MMU needs fixing"
 #else
@@ -392,7 +392,7 @@ ENDPROC(__pabt_svc)
        @ perform a quick test inline since it should be false
        @ 99.9999% of the time.  The rest is done out of line.
        cmp     r2, #TASK_SIZE
-       blhs    kuser_cmpxchg_fixup
+       blhs    kuser_cmpxchg64_fixup
 #endif
 #endif
        .endm
@@ -797,6 +797,139 @@ __kuser_helper_start:
 /*
  * Reference prototype:
  *
+ *     int __kernel_cmpxchgd64(int64_t *oldval, int64_t *newval, int64_t *ptr)
+ *
+ * Input:
+ *
+ *     r0 = pointer to oldval
+ *     r1 = pointer to newval
+ *     r2 = pointer to target value
+ *     lr = return address
+ *
+ * Output:
+ *
+ *     r0 = returned value (zero or non-zero)
+ *     C flag = set if r0 == 0, clear if r0 != 0
+ *
+ * Clobbered:
+ *
+ *     r3, flags
+ *
+ * Definition and user space usage example:
+ *
+ *     typedef int (__kernel_cmpxchg64_t)(const int64_t *oldval,
+ *                                        const int64_t *newval,
+ *                                        volatile int64_t *ptr);
+ *     #define __kernel_cmpxchg64 (*(__kernel_cmpxchg64_t *)0xffff0f60)
+ *
+ * Atomically store newval in *ptr if *ptr is equal to oldval for user space.
+ * Return zero if *ptr was changed or non-zero if no exchange happened.
+ * The C flag is also set if *ptr was changed to allow for assembly
+ * optimization in the calling code.
+ *
+ * Notes:
+ *
+ *    - This routine already includes memory barriers as needed.
+ *
+ *    - Due to the length of some sequences, this spans 2 regular kuser
+ *      "slots" so 0xffff0f80 is not used as a valid entry point.
+ */
+
+__kuser_cmpxchg64:                             @ 0xffff0f60
+
+#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+
+       /*
+        * Poor you.  No fast solution possible...
+        * The kernel itself must perform the operation.
+        * A special ghost syscall is used for that (see traps.c).
+        */
+       stmfd   sp!, {r7, lr}
+       ldr     r7, 1f                  @ it's 20 bits
+       swi     __ARM_NR_cmpxchg64
+       ldmfd   sp!, {r7, pc}
+1:     .word   __ARM_NR_cmpxchg64
+
+#elif defined(CONFIG_CPU_32v6K)
+
+       stmfd   sp!, {r4, r5, r6, r7}
+       ldrd    r4, r5, [r0]                    @ load old val
+       ldrd    r6, r7, [r1]                    @ load new val
+       smp_dmb arm
+1:     ldrexd  r0, r1, [r2]                    @ load current val
+       eors    r3, r0, r4                      @ compare with oldval (1)
+       eoreqs  r3, r1, r5                      @ compare with oldval (2)
+       strexdeq r3, r6, r7, [r2]               @ store newval if eq
+       teqeq   r3, #1                          @ success?
+       beq     1b                              @ if no then retry
+       smp_dmb arm
+       rsbs    r0, r3, #0                      @ set returned val and C flag
+       ldmfd   sp!, {r4, r5, r6, r7}
+       usr_ret lr
+
+#elif !defined(CONFIG_SMP)
+
+#ifdef CONFIG_MMU
+
+       /*
+        * The only thing that can break atomicity in this cmpxchg64
+        * implementation is either an IRQ or a data abort exception
+        * causing another process/thread to be scheduled in the middle
+        * of the critical sequence.  To prevent this, code is added to
+        * the IRQ and data abort exception handlers to set the pc back
+        * to the beginning of the critical section if it is found to be
+        * within that critical section (see kuser_cmpxchg_fixup64).
+        */
+       stmfd   sp!, {r4, r5, r6, lr}
+       ldmia   r0, {r4, r5}                    @ load old val
+       ldmia   r1, {r6, lr}                    @ load new val
+1:     ldmia   r2, {r0, r1}                    @ load current val
+       eors    r3, r0, r4                      @ compare with oldval (1)
+       eoreqs  r3, r1, r5                      @ compare with oldval (2)
+2:     stmeqia r2, {r6, lr}                    @ store newval if eq
+       rsbs    r0, r3, #0                      @ set return val and C flag
+       ldmfd   sp!, {r4, r5, r6, pc}
+
+       .text
+kuser_cmpxchg64_fixup:
+       @ Called from kuser_cmpxchg_fixup.
+       @ r2 = address of interrupted insn (must be preserved).
+       @ sp = saved regs. r7 and r8 are clobbered.
+       @ 1b = first critical insn, 2b = last critical insn.
+       @ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b.
+       mov     r7, #0xffff0fff
+       sub     r7, r7, #(0xffff0fff - (0xffff0f60 + (1b - __kuser_cmpxchg64)))
+       subs    r8, r2, r7
+       rsbcss  r8, r8, #(2b - 1b)
+       strcs   r7, [sp, #S_PC]
+#if __LINUX_ARM_ARCH__ < 6
+       b       kuser_cmpxchg32_fixup
+#else
+       mov     pc, lr
+#endif
+       .previous
+
+#else
+#warning "NPTL on non MMU needs fixing"
+       mov     r0, #-1
+       adds    r0, r0, #0
+       usr_ret lr
+#endif
+
+#else
+#error "incoherent kernel configuration"
+#endif
+
+       /* pad to next slot */
+       .rept   (16 - (. - __kuser_cmpxchg64)/4)
+       .word   0
+       .endr
+
+       .align  5
+
+/*
+ * Reference prototype:
+ *
  *     void __kernel_memory_barrier(void)
  *
  * Input:
@@ -921,7 +1054,7 @@ __kuser_cmpxchg:                           @ 0xffff0fc0
        usr_ret lr
 
        .text
-kuser_cmpxchg_fixup:
+kuser_cmpxchg32_fixup:
        @ Called from kuser_cmpxchg_check macro.
        @ r2 = address of interrupted insn (must be preserved).
        @ sp = saved regs. r7 and r8 are clobbered.
_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to