Commit 7c95ecec authored by Jose Abreu's avatar Jose Abreu Committed by Juerg Haefliger

ARC: io.h: Implement reads{x}()/writes{x}()

BugLink: https://bugs.launchpad.net/bugs/1811252

[ Upstream commit 10d44343 ]

Some ARC CPU's do not support unaligned loads/stores. Currently, generic
implementation of reads{b/w/l}()/writes{b/w/l}() is being used with ARC.
This can lead to misfunction of some drivers as generic functions do a
plain dereference of a pointer that can be unaligned.

Let's use {get/put}_unaligned() helpers instead of plain dereference of
pointer in order to fix. The helpers allow to get and store data from an
unaligned address whilst preserving the CPU internal alignment.
According to [1], the use of these helpers are costly in terms of
performance so we added an initial check for a buffer already aligned so
that the usage of the helpers can be avoided, when possible.

[1] Documentation/unaligned-memory-access.txt

Cc: Alexey Brodkin <abrodkin@synopsys.com>
Cc: Joao Pinto <jpinto@synopsys.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Tested-by: default avatarVitor Soares <soares@synopsys.com>
Signed-off-by: default avatarJose Abreu <joabreu@synopsys.com>
Signed-off-by: default avatarVineet Gupta <vgupta@synopsys.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarJuerg Haefliger <juergh@canonical.com>
Signed-off-by: default avatarStefan Bader <stefan.bader@canonical.com>
parent 0cb33ab1
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/unaligned.h>
#ifdef CONFIG_ISA_ARCV2 #ifdef CONFIG_ISA_ARCV2
#include <asm/barrier.h> #include <asm/barrier.h>
...@@ -85,6 +86,42 @@ static inline u32 __raw_readl(const volatile void __iomem *addr) ...@@ -85,6 +86,42 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
return w; 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 #define __raw_writeb __raw_writeb
static inline void __raw_writeb(u8 b, volatile void __iomem *addr) static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
{ {
...@@ -117,6 +154,35 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr) ...@@ -117,6 +154,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 * MMIO can also get buffered/optimized in micro-arch, so barriers needed
* Based on ARM model for the typical use case * Based on ARM model for the typical use case
...@@ -132,10 +198,16 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr) ...@@ -132,10 +198,16 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c) ({ u16 __v = readw_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 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 writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); }) #define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); })
#define writel(v,c) ({ __iowmb(); writel_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 * Relaxed API for drivers which can handle barrier ordering themselves
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment