|
@@ -12,6 +12,7 @@
|
|
|
#include <linux/types.h>
|
|
|
#include <asm/byteorder.h>
|
|
|
#include <asm/page.h>
|
|
|
+#include <asm/unaligned.h>
|
|
|
|
|
|
#ifdef CONFIG_ISA_ARCV2
|
|
|
#include <asm/barrier.h>
|
|
@@ -94,6 +95,42 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
|
|
|
return w;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * {read,write}s{b,w,l}() repeatedly access the same IO address in
|
|
|
+ * native endianness in 8-, 16-, 32-bit chunks {into,from} memory,
|
|
|
+ * @count times
|
|
|
+ */
|
|
|
+#define __raw_readsx(t,f) \
|
|
|
+static inline void __raw_reads##f(const volatile void __iomem *addr, \
|
|
|
+ void *ptr, unsigned int count) \
|
|
|
+{ \
|
|
|
+ bool is_aligned = ((unsigned long)ptr % ((t) / 8)) == 0; \
|
|
|
+ u##t *buf = ptr; \
|
|
|
+ \
|
|
|
+ if (!count) \
|
|
|
+ return; \
|
|
|
+ \
|
|
|
+ /* Some ARC CPU's don't support unaligned accesses */ \
|
|
|
+ if (is_aligned) { \
|
|
|
+ do { \
|
|
|
+ u##t x = __raw_read##f(addr); \
|
|
|
+ *buf++ = x; \
|
|
|
+ } while (--count); \
|
|
|
+ } else { \
|
|
|
+ do { \
|
|
|
+ u##t x = __raw_read##f(addr); \
|
|
|
+ put_unaligned(x, buf++); \
|
|
|
+ } while (--count); \
|
|
|
+ } \
|
|
|
+}
|
|
|
+
|
|
|
+#define __raw_readsb __raw_readsb
|
|
|
+__raw_readsx(8, b)
|
|
|
+#define __raw_readsw __raw_readsw
|
|
|
+__raw_readsx(16, w)
|
|
|
+#define __raw_readsl __raw_readsl
|
|
|
+__raw_readsx(32, l)
|
|
|
+
|
|
|
#define __raw_writeb __raw_writeb
|
|
|
static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
|
|
|
{
|
|
@@ -126,6 +163,35 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
|
|
|
|
|
|
}
|
|
|
|
|
|
+#define __raw_writesx(t,f) \
|
|
|
+static inline void __raw_writes##f(volatile void __iomem *addr, \
|
|
|
+ const void *ptr, unsigned int count) \
|
|
|
+{ \
|
|
|
+ bool is_aligned = ((unsigned long)ptr % ((t) / 8)) == 0; \
|
|
|
+ const u##t *buf = ptr; \
|
|
|
+ \
|
|
|
+ if (!count) \
|
|
|
+ return; \
|
|
|
+ \
|
|
|
+ /* Some ARC CPU's don't support unaligned accesses */ \
|
|
|
+ if (is_aligned) { \
|
|
|
+ do { \
|
|
|
+ __raw_write##f(*buf++, addr); \
|
|
|
+ } while (--count); \
|
|
|
+ } else { \
|
|
|
+ do { \
|
|
|
+ __raw_write##f(get_unaligned(buf++), addr); \
|
|
|
+ } while (--count); \
|
|
|
+ } \
|
|
|
+}
|
|
|
+
|
|
|
+#define __raw_writesb __raw_writesb
|
|
|
+__raw_writesx(8, b)
|
|
|
+#define __raw_writesw __raw_writesw
|
|
|
+__raw_writesx(16, w)
|
|
|
+#define __raw_writesl __raw_writesl
|
|
|
+__raw_writesx(32, l)
|
|
|
+
|
|
|
/*
|
|
|
* MMIO can also get buffered/optimized in micro-arch, so barriers needed
|
|
|
* Based on ARM model for the typical use case
|
|
@@ -141,10 +207,16 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
|
|
|
#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
|
|
|
#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
|
|
|
#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
|
|
|
+#define readsb(p,d,l) ({ __raw_readsb(p,d,l); __iormb(); })
|
|
|
+#define readsw(p,d,l) ({ __raw_readsw(p,d,l); __iormb(); })
|
|
|
+#define readsl(p,d,l) ({ __raw_readsl(p,d,l); __iormb(); })
|
|
|
|
|
|
#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
|
|
|
#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); })
|
|
|
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
|
|
|
+#define writesb(p,d,l) ({ __iowmb(); __raw_writesb(p,d,l); })
|
|
|
+#define writesw(p,d,l) ({ __iowmb(); __raw_writesw(p,d,l); })
|
|
|
+#define writesl(p,d,l) ({ __iowmb(); __raw_writesl(p,d,l); })
|
|
|
|
|
|
/*
|
|
|
* Relaxed API for drivers which can handle barrier ordering themselves
|