Skip to content

Commit 54505a1

Browse files
Mikulas Patockamattst88
Mikulas Patocka
authored andcommitted
alpha: fix memory barriers so that they conform to the specification
The commits cd0e00c and 92d7223 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: Mikulas Patocka <[email protected]> Fixes: cd0e00c ("alpha: io: reorder barriers to guarantee writeX() and iowriteX() ordering") Fixes: 92d7223 ("alpha: io: reorder barriers to guarantee writeX() and iowriteX() ordering gregkh#2") Cc: [email protected] # v4.17+ Acked-by: Ivan Kokshaysky <[email protected]> Reviewed-by: Maciej W. Rozycki <[email protected]> Signed-off-by: Matt Turner <[email protected]>
1 parent c0ebf71 commit 54505a1

File tree

2 files changed

+112
-22
lines changed

2 files changed

+112
-22
lines changed

arch/alpha/include/asm/io.h

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -309,14 +309,18 @@ static inline int __is_mmio(const volatile void __iomem *addr)
309309
#if IO_CONCAT(__IO_PREFIX,trivial_io_bw)
310310
extern inline unsigned int ioread8(void __iomem *addr)
311311
{
312-
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
312+
unsigned int ret;
313+
mb();
314+
ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
313315
mb();
314316
return ret;
315317
}
316318

317319
extern inline unsigned int ioread16(void __iomem *addr)
318320
{
319-
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
321+
unsigned int ret;
322+
mb();
323+
ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
320324
mb();
321325
return ret;
322326
}
@@ -357,7 +361,9 @@ extern inline void outw(u16 b, unsigned long port)
357361
#if IO_CONCAT(__IO_PREFIX,trivial_io_lq)
358362
extern inline unsigned int ioread32(void __iomem *addr)
359363
{
360-
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
364+
unsigned int ret;
365+
mb();
366+
ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
361367
mb();
362368
return ret;
363369
}
@@ -402,14 +408,18 @@ extern inline void __raw_writew(u16 b, volatile void __iomem *addr)
402408

403409
extern inline u8 readb(const volatile void __iomem *addr)
404410
{
405-
u8 ret = __raw_readb(addr);
411+
u8 ret;
412+
mb();
413+
ret = __raw_readb(addr);
406414
mb();
407415
return ret;
408416
}
409417

410418
extern inline u16 readw(const volatile void __iomem *addr)
411419
{
412-
u16 ret = __raw_readw(addr);
420+
u16 ret;
421+
mb();
422+
ret = __raw_readw(addr);
413423
mb();
414424
return ret;
415425
}
@@ -450,14 +460,18 @@ extern inline void __raw_writeq(u64 b, volatile void __iomem *addr)
450460

451461
extern inline u32 readl(const volatile void __iomem *addr)
452462
{
453-
u32 ret = __raw_readl(addr);
463+
u32 ret;
464+
mb();
465+
ret = __raw_readl(addr);
454466
mb();
455467
return ret;
456468
}
457469

458470
extern inline u64 readq(const volatile void __iomem *addr)
459471
{
460-
u64 ret = __raw_readq(addr);
472+
u64 ret;
473+
mb();
474+
ret = __raw_readq(addr);
461475
mb();
462476
return ret;
463477
}
@@ -486,14 +500,44 @@ extern inline void writeq(u64 b, volatile void __iomem *addr)
486500
#define outb_p outb
487501
#define outw_p outw
488502
#define outl_p outl
489-
#define readb_relaxed(addr) __raw_readb(addr)
490-
#define readw_relaxed(addr) __raw_readw(addr)
491-
#define readl_relaxed(addr) __raw_readl(addr)
492-
#define readq_relaxed(addr) __raw_readq(addr)
493-
#define writeb_relaxed(b, addr) __raw_writeb(b, addr)
494-
#define writew_relaxed(b, addr) __raw_writew(b, addr)
495-
#define writel_relaxed(b, addr) __raw_writel(b, addr)
496-
#define writeq_relaxed(b, addr) __raw_writeq(b, addr)
503+
504+
extern u8 readb_relaxed(const volatile void __iomem *addr);
505+
extern u16 readw_relaxed(const volatile void __iomem *addr);
506+
extern u32 readl_relaxed(const volatile void __iomem *addr);
507+
extern u64 readq_relaxed(const volatile void __iomem *addr);
508+
509+
#if IO_CONCAT(__IO_PREFIX,trivial_io_bw)
510+
extern inline u8 readb_relaxed(const volatile void __iomem *addr)
511+
{
512+
mb();
513+
return __raw_readb(addr);
514+
}
515+
516+
extern inline u16 readw_relaxed(const volatile void __iomem *addr)
517+
{
518+
mb();
519+
return __raw_readw(addr);
520+
}
521+
#endif
522+
523+
#if IO_CONCAT(__IO_PREFIX,trivial_io_lq)
524+
extern inline u32 readl_relaxed(const volatile void __iomem *addr)
525+
{
526+
mb();
527+
return __raw_readl(addr);
528+
}
529+
530+
extern inline u64 readq_relaxed(const volatile void __iomem *addr)
531+
{
532+
mb();
533+
return __raw_readq(addr);
534+
}
535+
#endif
536+
537+
#define writeb_relaxed writeb
538+
#define writew_relaxed writew
539+
#define writel_relaxed writel
540+
#define writeq_relaxed writeq
497541

498542
/*
499543
* String version of IO memory access ops:

arch/alpha/kernel/io.c

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,27 @@
1616
unsigned int
1717
ioread8(void __iomem *addr)
1818
{
19-
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
19+
unsigned int ret;
20+
mb();
21+
ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
2022
mb();
2123
return ret;
2224
}
2325

2426
unsigned int ioread16(void __iomem *addr)
2527
{
26-
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
28+
unsigned int ret;
29+
mb();
30+
ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
2731
mb();
2832
return ret;
2933
}
3034

3135
unsigned int ioread32(void __iomem *addr)
3236
{
33-
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
37+
unsigned int ret;
38+
mb();
39+
ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
3440
mb();
3541
return ret;
3642
}
@@ -148,28 +154,36 @@ EXPORT_SYMBOL(__raw_writeq);
148154

149155
u8 readb(const volatile void __iomem *addr)
150156
{
151-
u8 ret = __raw_readb(addr);
157+
u8 ret;
158+
mb();
159+
ret = __raw_readb(addr);
152160
mb();
153161
return ret;
154162
}
155163

156164
u16 readw(const volatile void __iomem *addr)
157165
{
158-
u16 ret = __raw_readw(addr);
166+
u16 ret;
167+
mb();
168+
ret = __raw_readw(addr);
159169
mb();
160170
return ret;
161171
}
162172

163173
u32 readl(const volatile void __iomem *addr)
164174
{
165-
u32 ret = __raw_readl(addr);
175+
u32 ret;
176+
mb();
177+
ret = __raw_readl(addr);
166178
mb();
167179
return ret;
168180
}
169181

170182
u64 readq(const volatile void __iomem *addr)
171183
{
172-
u64 ret = __raw_readq(addr);
184+
u64 ret;
185+
mb();
186+
ret = __raw_readq(addr);
173187
mb();
174188
return ret;
175189
}
@@ -207,6 +221,38 @@ EXPORT_SYMBOL(writew);
207221
EXPORT_SYMBOL(writel);
208222
EXPORT_SYMBOL(writeq);
209223

224+
/*
225+
* The _relaxed functions must be ordered w.r.t. each other, but they don't
226+
* have to be ordered w.r.t. other memory accesses.
227+
*/
228+
u8 readb_relaxed(const volatile void __iomem *addr)
229+
{
230+
mb();
231+
return __raw_readb(addr);
232+
}
233+
234+
u16 readw_relaxed(const volatile void __iomem *addr)
235+
{
236+
mb();
237+
return __raw_readw(addr);
238+
}
239+
240+
u32 readl_relaxed(const volatile void __iomem *addr)
241+
{
242+
mb();
243+
return __raw_readl(addr);
244+
}
245+
246+
u64 readq_relaxed(const volatile void __iomem *addr)
247+
{
248+
mb();
249+
return __raw_readq(addr);
250+
}
251+
252+
EXPORT_SYMBOL(readb_relaxed);
253+
EXPORT_SYMBOL(readw_relaxed);
254+
EXPORT_SYMBOL(readl_relaxed);
255+
EXPORT_SYMBOL(readq_relaxed);
210256

211257
/*
212258
* Read COUNT 8-bit bytes from port PORT into memory starting at SRC.

0 commit comments

Comments
 (0)