Commit 54505a1e authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Matt Turner

alpha: fix memory barriers so that they conform to the specification

The commits cd0e00c1 and 92d7223a broke boot on the Alpha Avanti
platform. The patches move memory barriers after a write before the write.
The result is that if there's iowrite followed by ioread, there is no
barrier between them.

The Alpha architecture allows reordering of the accesses to the I/O space,
and the missing barrier between write and read causes hang with serial
port and real time clock.

This patch makes barriers confiorm to the specification.

1. We add mb() before readX_relaxed and writeX_relaxed -
   memory-barriers.txt claims that these functions must be ordered w.r.t.
   each other. Alpha doesn't order them, so we need an explicit barrier.
2. We add mb() before reads from the I/O space - so that if there's a
   write followed by a read, there should be a barrier between them.
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Fixes: cd0e00c1 ("alpha: io: reorder barriers to guarantee writeX() and iowriteX() ordering")
Fixes: 92d7223a ("alpha: io: reorder barriers to guarantee writeX() and iowriteX() ordering #2")
Cc: stable@vger.kernel.org      # v4.17+
Acked-by: default avatarIvan Kokshaysky <ink@jurassic.park.msu.ru>
Reviewed-by: default avatarMaciej W. Rozycki <macro@linux-mips.org>
Signed-off-by: default avatarMatt Turner <mattst88@gmail.com>
parent c0ebf715
...@@ -309,14 +309,18 @@ static inline int __is_mmio(const volatile void __iomem *addr) ...@@ -309,14 +309,18 @@ static inline int __is_mmio(const volatile void __iomem *addr)
#if IO_CONCAT(__IO_PREFIX,trivial_io_bw) #if IO_CONCAT(__IO_PREFIX,trivial_io_bw)
extern inline unsigned int ioread8(void __iomem *addr) extern inline unsigned int ioread8(void __iomem *addr)
{ {
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr); unsigned int ret;
mb();
ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
mb(); mb();
return ret; return ret;
} }
extern inline unsigned int ioread16(void __iomem *addr) extern inline unsigned int ioread16(void __iomem *addr)
{ {
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr); unsigned int ret;
mb();
ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
mb(); mb();
return ret; return ret;
} }
...@@ -357,7 +361,9 @@ extern inline void outw(u16 b, unsigned long port) ...@@ -357,7 +361,9 @@ extern inline void outw(u16 b, unsigned long port)
#if IO_CONCAT(__IO_PREFIX,trivial_io_lq) #if IO_CONCAT(__IO_PREFIX,trivial_io_lq)
extern inline unsigned int ioread32(void __iomem *addr) extern inline unsigned int ioread32(void __iomem *addr)
{ {
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr); unsigned int ret;
mb();
ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
mb(); mb();
return ret; return ret;
} }
...@@ -402,14 +408,18 @@ extern inline void __raw_writew(u16 b, volatile void __iomem *addr) ...@@ -402,14 +408,18 @@ extern inline void __raw_writew(u16 b, volatile void __iomem *addr)
extern inline u8 readb(const volatile void __iomem *addr) extern inline u8 readb(const volatile void __iomem *addr)
{ {
u8 ret = __raw_readb(addr); u8 ret;
mb();
ret = __raw_readb(addr);
mb(); mb();
return ret; return ret;
} }
extern inline u16 readw(const volatile void __iomem *addr) extern inline u16 readw(const volatile void __iomem *addr)
{ {
u16 ret = __raw_readw(addr); u16 ret;
mb();
ret = __raw_readw(addr);
mb(); mb();
return ret; return ret;
} }
...@@ -450,14 +460,18 @@ extern inline void __raw_writeq(u64 b, volatile void __iomem *addr) ...@@ -450,14 +460,18 @@ extern inline void __raw_writeq(u64 b, volatile void __iomem *addr)
extern inline u32 readl(const volatile void __iomem *addr) extern inline u32 readl(const volatile void __iomem *addr)
{ {
u32 ret = __raw_readl(addr); u32 ret;
mb();
ret = __raw_readl(addr);
mb(); mb();
return ret; return ret;
} }
extern inline u64 readq(const volatile void __iomem *addr) extern inline u64 readq(const volatile void __iomem *addr)
{ {
u64 ret = __raw_readq(addr); u64 ret;
mb();
ret = __raw_readq(addr);
mb(); mb();
return ret; return ret;
} }
...@@ -486,14 +500,44 @@ extern inline void writeq(u64 b, volatile void __iomem *addr) ...@@ -486,14 +500,44 @@ extern inline void writeq(u64 b, volatile void __iomem *addr)
#define outb_p outb #define outb_p outb
#define outw_p outw #define outw_p outw
#define outl_p outl #define outl_p outl
#define readb_relaxed(addr) __raw_readb(addr)
#define readw_relaxed(addr) __raw_readw(addr) extern u8 readb_relaxed(const volatile void __iomem *addr);
#define readl_relaxed(addr) __raw_readl(addr) extern u16 readw_relaxed(const volatile void __iomem *addr);
#define readq_relaxed(addr) __raw_readq(addr) extern u32 readl_relaxed(const volatile void __iomem *addr);
#define writeb_relaxed(b, addr) __raw_writeb(b, addr) extern u64 readq_relaxed(const volatile void __iomem *addr);
#define writew_relaxed(b, addr) __raw_writew(b, addr)
#define writel_relaxed(b, addr) __raw_writel(b, addr) #if IO_CONCAT(__IO_PREFIX,trivial_io_bw)
#define writeq_relaxed(b, addr) __raw_writeq(b, addr) extern inline u8 readb_relaxed(const volatile void __iomem *addr)
{
mb();
return __raw_readb(addr);
}
extern inline u16 readw_relaxed(const volatile void __iomem *addr)
{
mb();
return __raw_readw(addr);
}
#endif
#if IO_CONCAT(__IO_PREFIX,trivial_io_lq)
extern inline u32 readl_relaxed(const volatile void __iomem *addr)
{
mb();
return __raw_readl(addr);
}
extern inline u64 readq_relaxed(const volatile void __iomem *addr)
{
mb();
return __raw_readq(addr);
}
#endif
#define writeb_relaxed writeb
#define writew_relaxed writew
#define writel_relaxed writel
#define writeq_relaxed writeq
/* /*
* String version of IO memory access ops: * String version of IO memory access ops:
......
...@@ -16,21 +16,27 @@ ...@@ -16,21 +16,27 @@
unsigned int unsigned int
ioread8(void __iomem *addr) ioread8(void __iomem *addr)
{ {
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr); unsigned int ret;
mb();
ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
mb(); mb();
return ret; return ret;
} }
unsigned int ioread16(void __iomem *addr) unsigned int ioread16(void __iomem *addr)
{ {
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr); unsigned int ret;
mb();
ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
mb(); mb();
return ret; return ret;
} }
unsigned int ioread32(void __iomem *addr) unsigned int ioread32(void __iomem *addr)
{ {
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr); unsigned int ret;
mb();
ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
mb(); mb();
return ret; return ret;
} }
...@@ -148,28 +154,36 @@ EXPORT_SYMBOL(__raw_writeq); ...@@ -148,28 +154,36 @@ EXPORT_SYMBOL(__raw_writeq);
u8 readb(const volatile void __iomem *addr) u8 readb(const volatile void __iomem *addr)
{ {
u8 ret = __raw_readb(addr); u8 ret;
mb();
ret = __raw_readb(addr);
mb(); mb();
return ret; return ret;
} }
u16 readw(const volatile void __iomem *addr) u16 readw(const volatile void __iomem *addr)
{ {
u16 ret = __raw_readw(addr); u16 ret;
mb();
ret = __raw_readw(addr);
mb(); mb();
return ret; return ret;
} }
u32 readl(const volatile void __iomem *addr) u32 readl(const volatile void __iomem *addr)
{ {
u32 ret = __raw_readl(addr); u32 ret;
mb();
ret = __raw_readl(addr);
mb(); mb();
return ret; return ret;
} }
u64 readq(const volatile void __iomem *addr) u64 readq(const volatile void __iomem *addr)
{ {
u64 ret = __raw_readq(addr); u64 ret;
mb();
ret = __raw_readq(addr);
mb(); mb();
return ret; return ret;
} }
...@@ -207,6 +221,38 @@ EXPORT_SYMBOL(writew); ...@@ -207,6 +221,38 @@ EXPORT_SYMBOL(writew);
EXPORT_SYMBOL(writel); EXPORT_SYMBOL(writel);
EXPORT_SYMBOL(writeq); EXPORT_SYMBOL(writeq);
/*
* The _relaxed functions must be ordered w.r.t. each other, but they don't
* have to be ordered w.r.t. other memory accesses.
*/
u8 readb_relaxed(const volatile void __iomem *addr)
{
mb();
return __raw_readb(addr);
}
u16 readw_relaxed(const volatile void __iomem *addr)
{
mb();
return __raw_readw(addr);
}
u32 readl_relaxed(const volatile void __iomem *addr)
{
mb();
return __raw_readl(addr);
}
u64 readq_relaxed(const volatile void __iomem *addr)
{
mb();
return __raw_readq(addr);
}
EXPORT_SYMBOL(readb_relaxed);
EXPORT_SYMBOL(readw_relaxed);
EXPORT_SYMBOL(readl_relaxed);
EXPORT_SYMBOL(readq_relaxed);
/* /*
* Read COUNT 8-bit bytes from port PORT into memory starting at SRC. * Read COUNT 8-bit bytes from port PORT into memory starting at SRC.
......
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