diff mbox series

[3/9] xen/ppc: Implement atomic.h

Message ID 8035b9659a5930c00802dd36ab52574695d6b419.1691016993.git.sanastasio@raptorengineering.com (mailing list archive)
State Superseded
Headers show
Series ppc: Enable full Xen build | expand

Commit Message

Shawn Anastasio Aug. 2, 2023, 11:02 p.m. UTC
Implement atomic.h for PPC, based off of the original Xen 3.2
implementation.

Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>
---
 xen/arch/ppc/include/asm/atomic.h | 387 ++++++++++++++++++++++++++++++
 xen/arch/ppc/include/asm/memory.h |  34 +++
 2 files changed, 421 insertions(+)
 create mode 100644 xen/arch/ppc/include/asm/atomic.h
 create mode 100644 xen/arch/ppc/include/asm/memory.h

Comments

Jan Beulich Aug. 7, 2023, 4:13 p.m. UTC | #1
On 03.08.2023 01:02, Shawn Anastasio wrote:
> Implement atomic.h for PPC, based off of the original Xen 3.2
> implementation.

Since likely that originally came from Linux, did you cross check that
Linux hasn't gained any bug fixes in the meantime?

Other than this just a couple of nits; I'm not really qualified to
review in particular the inline assembly here, I'm afraid.

> --- /dev/null
> +++ b/xen/arch/ppc/include/asm/atomic.h
> @@ -0,0 +1,387 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * PowerPC64 atomic operations
> + *
> + * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
> + * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
> + * Copyright Raptor Engineering LLC
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +
> +#ifndef _ASM_PPC64_ATOMIC_H_
> +#define _ASM_PPC64_ATOMIC_H_

To fit the name, no "64" please.

> +#include <xen/atomic.h>
> +
> +#include <asm/memory.h>
> +#include <asm/system.h>
> +
> +static inline int atomic_read(const atomic_t *v)
> +{
> +    return *(volatile int *)&v->counter;
> +}
> +
> +static inline int _atomic_read(atomic_t v)
> +{
> +    return v.counter;
> +}
> +
> +static inline void atomic_set(atomic_t *v, int i)
> +{
> +    v->counter = i;
> +}
> +
> +static inline void _atomic_set(atomic_t *v, int i)
> +{
> +    v->counter = i;
> +}
> +
> +void __bad_atomic_read(const volatile void *p, void *res);
> +void __bad_atomic_size(void);
> +
> +#define build_atomic_read(name, insn, type)                                    \
> +    static inline type name(const volatile type *addr)                         \
> +    {                                                                          \
> +        type ret;                                                              \
> +        asm volatile ( insn "%U1%X1 %0,%1" : "=r"(ret) : "m<>"(*addr) );       \

As I think I had mentioned before, asm() contraints want a blank between
closing quote and opend paren. I.e. like this

        asm volatile ( insn "%U1%X1 %0,%1" : "=r" (ret) : "m<>" (*addr) );

> +#define read_atomic(p)                                                         \
> +    ({                                                                         \
> +        union {                                                                \
> +            typeof(*(p)) val;                                                  \
> +            char c[0];                                                         \
> +        } x_;                                                                  \
> +        read_atomic_size(p, x_.c, sizeof(*(p)));                               \
> +        x_.val;                                                                \
> +    })
> +
> +#define write_atomic(p, x)                                                     \
> +    do                                                                         \
> +    {                                                                          \
> +        typeof(*(p)) x_ = (x);                                                 \
> +        write_atomic_size(p, &x_, sizeof(*(p)));                               \
> +    } while ( 0 )

Up to here you use underscore-suffixed locals, but then ...

> +#define add_sized(p, x)                                                        \
> +    ({                                                                         \
> +        typeof(*(p)) __x = (x);                                                \

... you have even two prefixing underscores here.

> +        switch ( sizeof(*(p)) )                                                \
> +        {                                                                      \
> +        case 1:                                                                \
> +            add_u8_sized((uint8_t *) (p), __x);                                \
> +            break;                                                             \
> +        case 2:                                                                \
> +            add_u16_sized((uint16_t *) (p), __x);                              \
> +            break;                                                             \
> +        case 4:                                                                \
> +            add_u32_sized((uint32_t *) (p), __x);                              \
> +            break;                                                             \
> +        default:                                                               \
> +            __bad_atomic_size();                                               \
> +            break;                                                             \
> +        }                                                                      \
> +    })
> +
> +static inline void atomic_add(int a, atomic_t *v)
> +{
> +    int t;
> +
> +    asm volatile ( "1: lwarx %0,0,%3\n"
> +                   "add %0,%2,%0\n"
> +                   "stwcx. %0,0,%3\n"
> +                   "bne- 1b"
> +                   : "=&r"(t), "=m"(v->counter)
> +                   : "r"(a), "r"(&v->counter), "m"(v->counter) : "cc" );

"+m" and then drop the last input?

> +static inline int atomic_dec_if_positive(atomic_t *v)
> +{
> +    int t;
> +
> +    asm volatile(PPC_ATOMIC_ENTRY_BARRIER
> +                 "1:    lwarx    %0,0,%1        # atomic_dec_if_positive\n"
> +                 "addic.    %0,%0,-1\n"
> +                 "blt-    2f\n"
> +                 "stwcx.    %0,0,%1\n"
> +                 "bne-    1b\n"
> +                 PPC_ATOMIC_EXIT_BARRIER
> +                 "2:" : "=&r"(t)
> +                 : "r"(&v->counter) : "cc", "memory");

Missing blanks near the parentheses. Would also be nice if the padding
blanks actually vertically aligned the operands.

> +    return t;
> +}
> +
> +static inline atomic_t atomic_compareandswap(atomic_t old, atomic_t new,
> +                                             atomic_t *v)
> +{
> +    atomic_t rc;
> +    rc.counter = __cmpxchg(&v->counter, old.counter, new.counter, sizeof(int));
> +    return rc;
> +}
> +
> +#define arch_cmpxchg(ptr, o, n)                                                \
> +    ({                                                                         \
> +        __typeof__(*(ptr)) _o_ = (o);                                          \
> +        __typeof__(*(ptr)) _n_ = (n);                                          \

Problematic leading underscores again.

> +        (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long) _o_,             \
> +                                       (unsigned long) _n_, sizeof(*(ptr)));   \
> +    })
> +
> +static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
> +{
> +    return arch_cmpxchg(&v->counter, old, new);
> +}
> +
> +#define ATOMIC_OP(op, insn, suffix, sign) \
> +    static inline void atomic_##op(int a, atomic_t *v)                           \
> +    {                                                                            \
> +        int t;                                                                   \
> +        asm volatile ( "1: lwarx %0,0,%3\n"                                      \
> +                       insn "%I2" suffix " %0,%0,%2\n"                         \
> +                       "stwcx. %0,0,%3 \n"                                       \
> +                       "bne- 1b\n"                                               \
> +                       : "=&r"(t), "+m"(v->counter)                              \
> +                       : "r" #sign(a), "r"(&v->counter)                          \
> +                       : "cc" );                                                 \
> +    }
> +
> +ATOMIC_OP(and, "and", ".", K)
> +
> +static inline int atomic_sub_and_test(int i, atomic_t *v)
> +{
> +    return atomic_sub_return(i, v) == 0;
> +}
> +
> +static inline int atomic_inc_and_test(atomic_t *v)
> +{
> +    return atomic_add_return(1, v) == 0;
> +}
> +
> +static inline int atomic_dec_and_test(atomic_t *v)
> +{
> +    return atomic_sub_return(1, v) == 0;
> +}
> +
> +static inline int atomic_add_negative(int i, atomic_t *v)
> +{
> +    return atomic_add_return(i, v) < 0;
> +}
> +
> +static inline int __atomic_add_unless(atomic_t *v, int a, int u)
> +{
> +	int c, old;
> +
> +	c = atomic_read(v);
> +	while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)

Btw, no real need to parenthesize v in cases like this one. Otoh a needs
parenthesizing.

Jan
Shawn Anastasio Aug. 8, 2023, 7:19 p.m. UTC | #2
On 8/7/23 11:13 AM, Jan Beulich wrote:
> On 03.08.2023 01:02, Shawn Anastasio wrote:
>> Implement atomic.h for PPC, based off of the original Xen 3.2
>> implementation.
> 
> Since likely that originally came from Linux, did you cross check that
> Linux hasn't gained any bug fixes in the meantime?

I did -- the atomic barrier instructions used by linux have changed
since this code was originally written, so I've updated them to be
inline with modern linux.

> Other than this just a couple of nits; I'm not really qualified to
> review in particular the inline assembly here, I'm afraid.
> 
>> --- /dev/null
>> +++ b/xen/arch/ppc/include/asm/atomic.h
>> @@ -0,0 +1,387 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * PowerPC64 atomic operations
>> + *
>> + * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
>> + * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
>> + * Copyright Raptor Engineering LLC
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _ASM_PPC64_ATOMIC_H_
>> +#define _ASM_PPC64_ATOMIC_H_
> 
> To fit the name, no "64" please.

Will fix.

>> +#include <xen/atomic.h>
>> +
>> +#include <asm/memory.h>
>> +#include <asm/system.h>
>> +
>> +static inline int atomic_read(const atomic_t *v)
>> +{
>> +    return *(volatile int *)&v->counter;
>> +}
>> +
>> +static inline int _atomic_read(atomic_t v)
>> +{
>> +    return v.counter;
>> +}
>> +
>> +static inline void atomic_set(atomic_t *v, int i)
>> +{
>> +    v->counter = i;
>> +}
>> +
>> +static inline void _atomic_set(atomic_t *v, int i)
>> +{
>> +    v->counter = i;
>> +}
>> +
>> +void __bad_atomic_read(const volatile void *p, void *res);
>> +void __bad_atomic_size(void);
>> +
>> +#define build_atomic_read(name, insn, type)                                    \
>> +    static inline type name(const volatile type *addr)                         \
>> +    {                                                                          \
>> +        type ret;                                                              \
>> +        asm volatile ( insn "%U1%X1 %0,%1" : "=r"(ret) : "m<>"(*addr) );       \
> 
> As I think I had mentioned before, asm() contraints want a blank between
> closing quote and opend paren. I.e. like this
> 
>         asm volatile ( insn "%U1%X1 %0,%1" : "=r" (ret) : "m<>" (*addr) );
> 

My mistake, I went through and hand-formatted all of this code to try to
be inline with Xen's style but forgot about the constraints.

As an aside, I don't suppose there is an automatic formatter somewhere
that I've missed? I found an old clang-format fork that claims to add
support for Xen's formatting[1] but it seems to only handle a subset of
Xen's rules so I haven't found it very useful.

[1] https://github.com/NastyaVicodin/llvm-project/commits/main

>> +#define read_atomic(p)                                                         \
>> +    ({                                                                         \
>> +        union {                                                                \
>> +            typeof(*(p)) val;                                                  \
>> +            char c[0];                                                         \
>> +        } x_;                                                                  \
>> +        read_atomic_size(p, x_.c, sizeof(*(p)));                               \
>> +        x_.val;                                                                \
>> +    })
>> +
>> +#define write_atomic(p, x)                                                     \
>> +    do                                                                         \
>> +    {                                                                          \
>> +        typeof(*(p)) x_ = (x);                                                 \
>> +        write_atomic_size(p, &x_, sizeof(*(p)));                               \
>> +    } while ( 0 )
> 
> Up to here you use underscore-suffixed locals, but then ...
> 
>> +#define add_sized(p, x)                                                        \
>> +    ({                                                                         \
>> +        typeof(*(p)) __x = (x);                                                \
> 
> ... you have even two prefixing underscores here.
> 

The definitions of these macros were directly copied from elsewhere in
Xen (x86 and arm). I can change them all to use underscore-suffixed
local naming here, though.

>> +        switch ( sizeof(*(p)) )                                                \
>> +        {                                                                      \
>> +        case 1:                                                                \
>> +            add_u8_sized((uint8_t *) (p), __x);                                \
>> +            break;                                                             \
>> +        case 2:                                                                \
>> +            add_u16_sized((uint16_t *) (p), __x);                              \
>> +            break;                                                             \
>> +        case 4:                                                                \
>> +            add_u32_sized((uint32_t *) (p), __x);                              \
>> +            break;                                                             \
>> +        default:                                                               \
>> +            __bad_atomic_size();                                               \
>> +            break;                                                             \
>> +        }                                                                      \
>> +    })
>> +
>> +static inline void atomic_add(int a, atomic_t *v)
>> +{
>> +    int t;
>> +
>> +    asm volatile ( "1: lwarx %0,0,%3\n"
>> +                   "add %0,%2,%0\n"
>> +                   "stwcx. %0,0,%3\n"
>> +                   "bne- 1b"
>> +                   : "=&r"(t), "=m"(v->counter)
>> +                   : "r"(a), "r"(&v->counter), "m"(v->counter) : "cc" );
> 
> "+m" and then drop the last input?
> 

Yes, that makes sense. Not sure why it was originally written that way
but I'll change it.

>> +static inline int atomic_dec_if_positive(atomic_t *v)
>> +{
>> +    int t;
>> +
>> +    asm volatile(PPC_ATOMIC_ENTRY_BARRIER
>> +                 "1:    lwarx    %0,0,%1        # atomic_dec_if_positive\n"
>> +                 "addic.    %0,%0,-1\n"
>> +                 "blt-    2f\n"
>> +                 "stwcx.    %0,0,%1\n"
>> +                 "bne-    1b\n"
>> +                 PPC_ATOMIC_EXIT_BARRIER
>> +                 "2:" : "=&r"(t)
>> +                 : "r"(&v->counter) : "cc", "memory");
> 
> Missing blanks near the parentheses. Would also be nice if the padding
> blanks actually vertically aligned the operands.

I tried to make the spacing uniform across all asm blocks in this file,
but the convention I used was just a single space between the mnemonic
and the operands. I seemed to have missed this one though, so I'll bring
it in line with the others.

>> +    return t;
>> +}
>> +
>> +static inline atomic_t atomic_compareandswap(atomic_t old, atomic_t new,
>> +                                             atomic_t *v)
>> +{
>> +    atomic_t rc;
>> +    rc.counter = __cmpxchg(&v->counter, old.counter, new.counter, sizeof(int));
>> +    return rc;
>> +}
>> +
>> +#define arch_cmpxchg(ptr, o, n)                                                \
>> +    ({                                                                         \
>> +        __typeof__(*(ptr)) _o_ = (o);                                          \
>> +        __typeof__(*(ptr)) _n_ = (n);                                          \
> 
> Problematic leading underscores again.
> 

Will fix.

>> +        (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long) _o_,             \
>> +                                       (unsigned long) _n_, sizeof(*(ptr)));   \
>> +    })
>> +
>> +static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
>> +{
>> +    return arch_cmpxchg(&v->counter, old, new);
>> +}
>> +
>> +#define ATOMIC_OP(op, insn, suffix, sign) \
>> +    static inline void atomic_##op(int a, atomic_t *v)                           \
>> +    {                                                                            \
>> +        int t;                                                                   \
>> +        asm volatile ( "1: lwarx %0,0,%3\n"                                      \
>> +                       insn "%I2" suffix " %0,%0,%2\n"                         \
>> +                       "stwcx. %0,0,%3 \n"                                       \
>> +                       "bne- 1b\n"                                               \
>> +                       : "=&r"(t), "+m"(v->counter)                              \
>> +                       : "r" #sign(a), "r"(&v->counter)                          \
>> +                       : "cc" );                                                 \
>> +    }
>> +
>> +ATOMIC_OP(and, "and", ".", K)
>> +
>> +static inline int atomic_sub_and_test(int i, atomic_t *v)
>> +{
>> +    return atomic_sub_return(i, v) == 0;
>> +}
>> +
>> +static inline int atomic_inc_and_test(atomic_t *v)
>> +{
>> +    return atomic_add_return(1, v) == 0;
>> +}
>> +
>> +static inline int atomic_dec_and_test(atomic_t *v)
>> +{
>> +    return atomic_sub_return(1, v) == 0;
>> +}
>> +
>> +static inline int atomic_add_negative(int i, atomic_t *v)
>> +{
>> +    return atomic_add_return(i, v) < 0;
>> +}
>> +
>> +static inline int __atomic_add_unless(atomic_t *v, int a, int u)
>> +{
>> +	int c, old;
>> +
>> +	c = atomic_read(v);
>> +	while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
> 
> Btw, no real need to parenthesize v in cases like this one. Otoh a needs
> parenthesizing.

FWIW this was copied directly from arm64/atomic.h, but seeing as its a
normal function and not a macro I'm not sure I see why `a` would need
parenthesis. I'll drop the ones around `v` though.

> Jan

Thanks,
Shawn
Jan Beulich Aug. 9, 2023, 6:48 a.m. UTC | #3
On 08.08.2023 21:19, Shawn Anastasio wrote:
> On 8/7/23 11:13 AM, Jan Beulich wrote:
>> On 03.08.2023 01:02, Shawn Anastasio wrote:
>>> Implement atomic.h for PPC, based off of the original Xen 3.2
>>> implementation.
>>
>> Since likely that originally came from Linux, did you cross check that
>> Linux hasn't gained any bug fixes in the meantime?
> 
> I did -- the atomic barrier instructions used by linux have changed
> since this code was originally written, so I've updated them to be
> inline with modern linux.

Please mention this in the description then.

>>> +#include <xen/atomic.h>
>>> +
>>> +#include <asm/memory.h>
>>> +#include <asm/system.h>
>>> +
>>> +static inline int atomic_read(const atomic_t *v)
>>> +{
>>> +    return *(volatile int *)&v->counter;
>>> +}
>>> +
>>> +static inline int _atomic_read(atomic_t v)
>>> +{
>>> +    return v.counter;
>>> +}
>>> +
>>> +static inline void atomic_set(atomic_t *v, int i)
>>> +{
>>> +    v->counter = i;
>>> +}
>>> +
>>> +static inline void _atomic_set(atomic_t *v, int i)
>>> +{
>>> +    v->counter = i;
>>> +}
>>> +
>>> +void __bad_atomic_read(const volatile void *p, void *res);
>>> +void __bad_atomic_size(void);
>>> +
>>> +#define build_atomic_read(name, insn, type)                                    \
>>> +    static inline type name(const volatile type *addr)                         \
>>> +    {                                                                          \
>>> +        type ret;                                                              \
>>> +        asm volatile ( insn "%U1%X1 %0,%1" : "=r"(ret) : "m<>"(*addr) );       \
>>
>> As I think I had mentioned before, asm() contraints want a blank between
>> closing quote and opend paren. I.e. like this
>>
>>         asm volatile ( insn "%U1%X1 %0,%1" : "=r" (ret) : "m<>" (*addr) );
>>
> 
> My mistake, I went through and hand-formatted all of this code to try to
> be inline with Xen's style but forgot about the constraints.
> 
> As an aside, I don't suppose there is an automatic formatter somewhere
> that I've missed? I found an old clang-format fork that claims to add
> support for Xen's formatting[1] but it seems to only handle a subset of
> Xen's rules so I haven't found it very useful.
> 
> [1] https://github.com/NastyaVicodin/llvm-project/commits/main

Work there was recently revived, but we're not quite there yet, sorry.

>>> +#define read_atomic(p)                                                         \
>>> +    ({                                                                         \
>>> +        union {                                                                \
>>> +            typeof(*(p)) val;                                                  \
>>> +            char c[0];                                                         \
>>> +        } x_;                                                                  \
>>> +        read_atomic_size(p, x_.c, sizeof(*(p)));                               \
>>> +        x_.val;                                                                \
>>> +    })
>>> +
>>> +#define write_atomic(p, x)                                                     \
>>> +    do                                                                         \
>>> +    {                                                                          \
>>> +        typeof(*(p)) x_ = (x);                                                 \
>>> +        write_atomic_size(p, &x_, sizeof(*(p)));                               \
>>> +    } while ( 0 )
>>
>> Up to here you use underscore-suffixed locals, but then ...
>>
>>> +#define add_sized(p, x)                                                        \
>>> +    ({                                                                         \
>>> +        typeof(*(p)) __x = (x);                                                \
>>
>> ... you have even two prefixing underscores here.
>>
> 
> The definitions of these macros were directly copied from elsewhere in
> Xen (x86 and arm). I can change them all to use underscore-suffixed
> local naming here, though.

We're still far away from eliminating all pre-existing issues. So copying
existing code is always at risk of then getting such comments. Again -
sorry for that, but otherwise we'll grow the number of issues.

>>> +        switch ( sizeof(*(p)) )                                                \
>>> +        {                                                                      \
>>> +        case 1:                                                                \
>>> +            add_u8_sized((uint8_t *) (p), __x);                                \
>>> +            break;                                                             \
>>> +        case 2:                                                                \
>>> +            add_u16_sized((uint16_t *) (p), __x);                              \
>>> +            break;                                                             \
>>> +        case 4:                                                                \
>>> +            add_u32_sized((uint32_t *) (p), __x);                              \
>>> +            break;                                                             \
>>> +        default:                                                               \
>>> +            __bad_atomic_size();                                               \
>>> +            break;                                                             \
>>> +        }                                                                      \
>>> +    })
>>> +
>>> +static inline void atomic_add(int a, atomic_t *v)
>>> +{
>>> +    int t;
>>> +
>>> +    asm volatile ( "1: lwarx %0,0,%3\n"
>>> +                   "add %0,%2,%0\n"
>>> +                   "stwcx. %0,0,%3\n"
>>> +                   "bne- 1b"
>>> +                   : "=&r"(t), "=m"(v->counter)
>>> +                   : "r"(a), "r"(&v->counter), "m"(v->counter) : "cc" );
>>
>> "+m" and then drop the last input?
>>
> 
> Yes, that makes sense. Not sure why it was originally written that way
> but I'll change it.

I think this was attributed to not sufficiently well written documentation
for older gcc.

>>> +static inline int __atomic_add_unless(atomic_t *v, int a, int u)
>>> +{
>>> +	int c, old;
>>> +
>>> +	c = atomic_read(v);
>>> +	while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
>>
>> Btw, no real need to parenthesize v in cases like this one. Otoh a needs
>> parenthesizing.
> 
> FWIW this was copied directly from arm64/atomic.h, but seeing as its a
> normal function and not a macro I'm not sure I see why `a` would need
> parenthesis.

Oh, right you are. The parenthesized v misled me.

Jan
diff mbox series

Patch

diff --git a/xen/arch/ppc/include/asm/atomic.h b/xen/arch/ppc/include/asm/atomic.h
new file mode 100644
index 0000000000..336dedc476
--- /dev/null
+++ b/xen/arch/ppc/include/asm/atomic.h
@@ -0,0 +1,387 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * PowerPC64 atomic operations
+ *
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright Raptor Engineering LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_PPC64_ATOMIC_H_
+#define _ASM_PPC64_ATOMIC_H_
+
+#include <xen/atomic.h>
+
+#include <asm/memory.h>
+#include <asm/system.h>
+
+static inline int atomic_read(const atomic_t *v)
+{
+    return *(volatile int *)&v->counter;
+}
+
+static inline int _atomic_read(atomic_t v)
+{
+    return v.counter;
+}
+
+static inline void atomic_set(atomic_t *v, int i)
+{
+    v->counter = i;
+}
+
+static inline void _atomic_set(atomic_t *v, int i)
+{
+    v->counter = i;
+}
+
+void __bad_atomic_read(const volatile void *p, void *res);
+void __bad_atomic_size(void);
+
+#define build_atomic_read(name, insn, type)                                    \
+    static inline type name(const volatile type *addr)                         \
+    {                                                                          \
+        type ret;                                                              \
+        asm volatile ( insn "%U1%X1 %0,%1" : "=r"(ret) : "m<>"(*addr) );       \
+        return ret;                                                            \
+    }
+
+#define build_atomic_write(name, insn, type)                                   \
+    static inline void name(volatile type *addr, type val)                     \
+    {                                                                          \
+        asm volatile ( insn "%U0%X0 %1,%0" : "=m<>"(*addr) : "r"(val) );       \
+    }
+
+#define build_add_sized(name, ldinsn, stinsn, type)                            \
+    static inline void name(volatile type *addr, type val)                     \
+    {                                                                          \
+        type t;                                                                \
+        asm volatile ( "1: " ldinsn " %0,0,%3\n"                               \
+                       "add%I2 %0,%0,%2\n"                                     \
+                       stinsn " %0,0,%3 \n"                                    \
+                       "bne- 1b\n"                                             \
+                       : "=&r"(t), "+m"(*addr)                                 \
+                       : "r"(val), "r"(addr)                                   \
+                       : "cc" );                                               \
+    }
+
+build_atomic_read(read_u8_atomic, "lbz", uint8_t)
+build_atomic_read(read_u16_atomic, "lhz", uint16_t)
+build_atomic_read(read_u32_atomic, "lwz", uint32_t)
+build_atomic_read(read_u64_atomic, "ldz", uint64_t)
+
+build_atomic_write(write_u8_atomic, "stb", uint8_t)
+build_atomic_write(write_u16_atomic, "sth", uint16_t)
+build_atomic_write(write_u32_atomic, "stw", uint32_t)
+build_atomic_write(write_u64_atomic, "std", uint64_t)
+
+build_add_sized(add_u8_sized, "lbarx", "stbcx.",uint8_t)
+build_add_sized(add_u16_sized, "lharx", "sthcx.", uint16_t)
+build_add_sized(add_u32_sized, "lwarx", "stwcx.", uint32_t)
+
+#undef build_atomic_read
+#undef build_atomic_write
+#undef build_add_sized
+
+static always_inline void read_atomic_size(const volatile void *p, void *res,
+                                           unsigned int size)
+{
+    ASSERT(IS_ALIGNED((vaddr_t) p, size));
+    switch ( size )
+    {
+    case 1:
+        *(uint8_t *)res = read_u8_atomic(p);
+        break;
+    case 2:
+        *(uint16_t *)res = read_u16_atomic(p);
+        break;
+    case 4:
+        *(uint32_t *)res = read_u32_atomic(p);
+        break;
+    case 8:
+        *(uint64_t *)res = read_u64_atomic(p);
+        break;
+    default:
+        __bad_atomic_read(p, res);
+        break;
+    }
+}
+
+static always_inline void write_atomic_size(volatile void *p, void *val,
+                                            unsigned int size)
+{
+    ASSERT(IS_ALIGNED((vaddr_t) p, size));
+    switch ( size )
+    {
+    case 1:
+        write_u8_atomic(p, *(uint8_t *)val);
+        break;
+    case 2:
+        write_u16_atomic(p, *(uint16_t *)val);
+        break;
+    case 4:
+        write_u32_atomic(p, *(uint32_t *)val);
+        break;
+    case 8:
+        write_u64_atomic(p, *(uint64_t *)val);
+        break;
+    default:
+        __bad_atomic_size();
+        break;
+    }
+}
+
+#define read_atomic(p)                                                         \
+    ({                                                                         \
+        union {                                                                \
+            typeof(*(p)) val;                                                  \
+            char c[0];                                                         \
+        } x_;                                                                  \
+        read_atomic_size(p, x_.c, sizeof(*(p)));                               \
+        x_.val;                                                                \
+    })
+
+#define write_atomic(p, x)                                                     \
+    do                                                                         \
+    {                                                                          \
+        typeof(*(p)) x_ = (x);                                                 \
+        write_atomic_size(p, &x_, sizeof(*(p)));                               \
+    } while ( 0 )
+
+#define add_sized(p, x)                                                        \
+    ({                                                                         \
+        typeof(*(p)) __x = (x);                                                \
+        switch ( sizeof(*(p)) )                                                \
+        {                                                                      \
+        case 1:                                                                \
+            add_u8_sized((uint8_t *) (p), __x);                                \
+            break;                                                             \
+        case 2:                                                                \
+            add_u16_sized((uint16_t *) (p), __x);                              \
+            break;                                                             \
+        case 4:                                                                \
+            add_u32_sized((uint32_t *) (p), __x);                              \
+            break;                                                             \
+        default:                                                               \
+            __bad_atomic_size();                                               \
+            break;                                                             \
+        }                                                                      \
+    })
+
+static inline void atomic_add(int a, atomic_t *v)
+{
+    int t;
+
+    asm volatile ( "1: lwarx %0,0,%3\n"
+                   "add %0,%2,%0\n"
+                   "stwcx. %0,0,%3\n"
+                   "bne- 1b"
+                   : "=&r"(t), "=m"(v->counter)
+                   : "r"(a), "r"(&v->counter), "m"(v->counter) : "cc" );
+}
+
+static inline int atomic_add_return(int a, atomic_t *v)
+{
+    int t;
+
+    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
+                   "1: lwarx %0,0,%2\n"
+                   "add %0,%1,%0\n"
+                   "stwcx. %0,0,%2\n"
+                   "bne- 1b"
+                   PPC_ATOMIC_EXIT_BARRIER
+                   : "=&r"(t)
+                   : "r"(a), "r"(&v->counter)
+                   : "cc", "memory" );
+
+    return t;
+}
+
+static inline void atomic_sub(int a, atomic_t *v)
+{
+    int t;
+
+    asm volatile ( "1: lwarx %0,0,%3\n"
+                   "subf %0,%2,%0\n"
+                   "stwcx. %0,0,%3\n"
+                   "bne- 1b"
+                   : "=&r"(t), "=m"(v->counter)
+                   : "r"(a), "r"(&v->counter), "m"(v->counter)
+                   : "cc" );
+}
+
+static inline int atomic_sub_return(int a, atomic_t *v)
+{
+    int t;
+
+    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
+                   "1: lwarx %0,0,%2\n"
+                   "subf %0,%1,%0\n"
+                   "stwcx. %0,0,%2\n"
+                   "bne- 1b"
+                   PPC_ATOMIC_EXIT_BARRIER
+                   : "=&r"(t)
+                   : "r"(a), "r"(&v->counter)
+                   : "cc", "memory" );
+
+    return t;
+}
+
+static inline void atomic_inc(atomic_t *v)
+{
+    int t;
+
+    asm volatile ( "1: lwarx %0,0,%2\n"
+                   "addic %0,%0,1\n"
+                   "stwcx. %0,0,%2\n"
+                   "bne- 1b"
+                   : "=&r"(t), "=m"(v->counter)
+                   : "r"(&v->counter), "m"(v->counter)
+                   : "cc" );
+}
+
+static inline int atomic_inc_return(atomic_t *v)
+{
+    int t;
+
+    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
+                   "1: lwarx %0,0,%1\n"
+                   "addic %0,%0,1\n"
+                   "stwcx. %0,0,%1\n"
+                   "bne- 1b"
+                   PPC_ATOMIC_EXIT_BARRIER
+                   : "=&r"(t)
+                   : "r"(&v->counter)
+                   : "cc", "memory" );
+
+    return t;
+}
+
+static inline void atomic_dec(atomic_t *v)
+{
+    int t;
+
+    asm volatile ( "1: lwarx %0,0,%2\n"
+                   "addic %0,%0,-1\n"
+                   "stwcx. %0,0,%2\n"
+                   "bne- 1b"
+                   : "=&r"(t), "=m"(v->counter)
+                   : "r"(&v->counter), "m"(v->counter)
+                   : "cc" );
+}
+
+static inline int atomic_dec_return(atomic_t *v)
+{
+    int t;
+
+    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
+                   "1: lwarx %0,0,%1\n"
+                   "addic %0,%0,-1\n"
+                   "stwcx. %0,0,%1\n"
+                   "bne- 1b"
+                   PPC_ATOMIC_EXIT_BARRIER
+                   : "=&r"(t)
+                   : "r"(&v->counter)
+                   : "cc", "memory" );
+
+    return t;
+}
+
+/*
+ * Atomically test *v and decrement if it is greater than 0.
+ * The function returns the old value of *v minus 1.
+ */
+static inline int atomic_dec_if_positive(atomic_t *v)
+{
+    int t;
+
+    asm volatile(PPC_ATOMIC_ENTRY_BARRIER
+                 "1:    lwarx    %0,0,%1        # atomic_dec_if_positive\n"
+                 "addic.    %0,%0,-1\n"
+                 "blt-    2f\n"
+                 "stwcx.    %0,0,%1\n"
+                 "bne-    1b\n"
+                 PPC_ATOMIC_EXIT_BARRIER
+                 "2:" : "=&r"(t)
+                 : "r"(&v->counter) : "cc", "memory");
+
+    return t;
+}
+
+static inline atomic_t atomic_compareandswap(atomic_t old, atomic_t new,
+                                             atomic_t *v)
+{
+    atomic_t rc;
+    rc.counter = __cmpxchg(&v->counter, old.counter, new.counter, sizeof(int));
+    return rc;
+}
+
+#define arch_cmpxchg(ptr, o, n)                                                \
+    ({                                                                         \
+        __typeof__(*(ptr)) _o_ = (o);                                          \
+        __typeof__(*(ptr)) _n_ = (n);                                          \
+        (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long) _o_,             \
+                                       (unsigned long) _n_, sizeof(*(ptr)));   \
+    })
+
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+    return arch_cmpxchg(&v->counter, old, new);
+}
+
+#define ATOMIC_OP(op, insn, suffix, sign) \
+    static inline void atomic_##op(int a, atomic_t *v)                           \
+    {                                                                            \
+        int t;                                                                   \
+        asm volatile ( "1: lwarx %0,0,%3\n"                                      \
+                       insn "%I2" suffix " %0,%0,%2\n"                         \
+                       "stwcx. %0,0,%3 \n"                                       \
+                       "bne- 1b\n"                                               \
+                       : "=&r"(t), "+m"(v->counter)                              \
+                       : "r" #sign(a), "r"(&v->counter)                          \
+                       : "cc" );                                                 \
+    }
+
+ATOMIC_OP(and, "and", ".", K)
+
+static inline int atomic_sub_and_test(int i, atomic_t *v)
+{
+    return atomic_sub_return(i, v) == 0;
+}
+
+static inline int atomic_inc_and_test(atomic_t *v)
+{
+    return atomic_add_return(1, v) == 0;
+}
+
+static inline int atomic_dec_and_test(atomic_t *v)
+{
+    return atomic_sub_return(1, v) == 0;
+}
+
+static inline int atomic_add_negative(int i, atomic_t *v)
+{
+    return atomic_add_return(i, v) < 0;
+}
+
+static inline int __atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+
+	c = atomic_read(v);
+	while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
+		c = old;
+	return c;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+    return __atomic_add_unless(v, a, u);
+}
+
+#endif /* _ASM_PPC64_ATOMIC_H_ */
diff --git a/xen/arch/ppc/include/asm/memory.h b/xen/arch/ppc/include/asm/memory.h
new file mode 100644
index 0000000000..7b12e01b1a
--- /dev/null
+++ b/xen/arch/ppc/include/asm/memory.h
@@ -0,0 +1,34 @@ 
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright (C) IBM Corp. 2005
+ *
+ * Authors: Jimi Xenidis <jimix@watson.ibm.com>
+ */
+
+#ifndef _ASM_MEMORY_H_
+#define _ASM_MEMORY_H_
+
+#include <xen/config.h>
+
+#ifdef CONFIG_SMP
+#define PPC_ATOMIC_ENTRY_BARRIER "sync\n"
+#define PPC_ATOMIC_EXIT_BARRIER  "sync\n"
+#else
+#define PPC_ATOMIC_ENTRY_BARRIER
+#define PPC_ATOMIC_EXIT_BARRIER
+#endif
+
+#endif