staging: android: persistent_ram: remove atomic operations
Varun Wadekar [Mon, 3 Sep 2012 06:57:28 +0000 (11:57 +0530)]
The atomic operations (LDREX/STREX) to handle a buffer's start
pointer and size do not seem to work well on ARMv7.

Bug 1035205

Suggested by: Colin Cross <ccross@android.com>

Change-Id: I71d61c8eb6a9669137dfc5fc6793e57e939f4a12
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Signed-off-by: Johnny Qiu <joqiu@nvidia.com>
Reviewed-on: http://git-master/r/130065
Reviewed-by: Automatic_Commit_Validation_User

drivers/staging/android/persistent_ram.c

index b3aa083..baa32bc 100644 (file)
 #include <linux/rslib.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/spinlock.h>
 
 struct persistent_ram_buffer {
-       uint32_t    sig;
-       atomic_t    start;
-       atomic_t    size;
-       uint8_t     data[0];
+       uint32_t sig;
+       size_t start;
+       size_t size;
+       uint8_t data[0];
 };
 
+static DEFINE_SPINLOCK(buffer_lock);
+
 #define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
 
 static __devinitdata LIST_HEAD(persistent_ram_list);
 
 static inline size_t buffer_size(struct persistent_ram_zone *prz)
 {
-       return atomic_read(&prz->buffer->size);
+       return prz->buffer->size;
 }
 
 static inline size_t buffer_start(struct persistent_ram_zone *prz)
 {
-       return atomic_read(&prz->buffer->start);
+       return prz->buffer->start;
+}
+
+static inline int compare_and_exchange(size_t *v, int old, int new)
+{
+       size_t ret;
+
+       spin_lock(&buffer_lock);
+
+       ret = *v;
+       if (likely(ret == old))
+               *v = new;
+
+       spin_unlock(&buffer_lock);
+
+       return ret;
 }
 
 /* increase and wrap the start pointer, returning the old value */
@@ -53,11 +71,11 @@ static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
        int new;
 
        do {
-               old = atomic_read(&prz->buffer->start);
+               old = prz->buffer->start;
                new = old + a;
                while (unlikely(new > prz->buffer_size))
                        new -= prz->buffer_size;
-       } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
+       } while (compare_and_exchange(&prz->buffer->start, old, new) != old);
 
        return old;
 }
@@ -68,15 +86,15 @@ static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
        size_t old;
        size_t new;
 
-       if (atomic_read(&prz->buffer->size) == prz->buffer_size)
+       if (prz->buffer->size == prz->buffer_size)
                return;
 
        do {
-               old = atomic_read(&prz->buffer->size);
+               old = prz->buffer->size;
                new = old + a;
                if (new > prz->buffer_size)
                        new = prz->buffer_size;
-       } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
+       } while (compare_and_exchange(&prz->buffer->size, old, new) != old);
 }
 
 static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
@@ -426,8 +444,8 @@ struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
        }
 
        prz->buffer->sig = PERSISTENT_RAM_SIG;
-       atomic_set(&prz->buffer->start, 0);
-       atomic_set(&prz->buffer->size, 0);
+       prz->buffer->start = 0;
+       prz->buffer->size = 0;
 
        return prz;
 err: