Re: [PATCH] alpha: add udelay to io port paths

From: Mikulas Patocka (mpatocka@xxxxxxxxxx)
Date: Fri Apr 05 2019 - 07:12:45 EST

On Thu, 4 Apr 2019, Linus Torvalds wrote:

> On Wed, Apr 3, 2019 at 9:28 AM Mikulas Patocka <mpatocka@xxxxxxxxxx> wrote:
> >
> > So, I submit this patch that adds 1us delay between any I/O accesses
> > directed at the ISA bus. This patch makes my machine boot. 1us seems to be
> > minimal acceptable value, with 800ns I still get hangs.
> I don't think this is right.
> The *read* in 'in[bwl]' likely should not need an extra delay. An ISA
> port access will simply take that long on proper ISA hardware.
> The problem is almost c ertainly on the write side. An 'out[bwl]' on
> x86 will actualluy wait for the write to complete, while I suspect the
> problem on alpha is that writes are posted, so they happen
> "immediately" as far as the CPU is concerned. The 1us delay will then
> effectively wait for the write to complete on the device.
> I wonder if there is some way on alpha to wait for ISA writes to
> complete (perhaps doing a dummy read from the IO complex)?
> Linus

You're right that the delay is only needed for writes, there's no need for
it when reading.

Here I'm resending the patch, so that it only delays after writes and it
uses dummy reads of port 0x80 instead of udelay.


From: Mikulas Patocka <mpatocka@xxxxxxxxxx>
Subject: [PATCH] alpha: add delay to io port paths

The patches cd0e00c106722eca40b38ebf11cf134c01901086 and
92d7223a74235054f2aa7227d207d9c57f84dca0 fix a theoretical issue where the
code didn't follow the specification. Unfortunatelly, they also reduce
timing between IO port write and IO port read.

This causes problem on Alpha Avanti. Old chipsets based in the ISA bus
have problems with back-to-back I/O accesses and require delays. The
"mb()" call used to serve as a delay, hiding the bug.

However, using mb() for delay is unreliable, so we'd better add
explicit delays.

This patch adds the required delays after writes to the ISA bus, using
dummy read of the port 0x80.

Signed-off-by: Mikulas Patocka <mpatocka@xxxxxxxxxx>
Fixes: cd0e00c10672 ("alpha: io: reorder barriers to guarantee writeX() and iowriteX() ordering")
Cc: stable@xxxxxxxxxxxxxxx # v4.17+

arch/alpha/kernel/io.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

Index: linux-stable/arch/alpha/kernel/io.c
--- linux-stable.orig/arch/alpha/kernel/io.c 2019-04-05 12:47:35.000000000 +0200
+++ linux-stable/arch/alpha/kernel/io.c 2019-04-05 12:47:43.000000000 +0200
@@ -60,6 +60,12 @@ EXPORT_SYMBOL(iowrite8);

+static void delay_if_isa(unsigned long port)
+ if (port < 0x400)
+ inb(0x80);
u8 inb(unsigned long port)
return ioread8(ioport_map(port, 1));
@@ -78,16 +84,19 @@ u32 inl(unsigned long port)
void outb(u8 b, unsigned long port)
iowrite8(b, ioport_map(port, 1));
+ delay_if_isa(port);

void outw(u16 b, unsigned long port)
iowrite16(b, ioport_map(port, 2));
+ delay_if_isa(port);

void outl(u32 b, unsigned long port)
iowrite32(b, ioport_map(port, 4));
+ delay_if_isa(port);

@@ -336,6 +345,7 @@ void iowrite8_rep(void __iomem *port, co
void outsb(unsigned long port, const void *src, unsigned long count)
iowrite8_rep(ioport_map(port, 1), src, count);
+ delay_if_isa(port);

@@ -376,6 +386,7 @@ void iowrite16_rep(void __iomem *port, c
void outsw(unsigned long port, const void *src, unsigned long count)
iowrite16_rep(ioport_map(port, 2), src, count);
+ delay_if_isa(port);

@@ -408,6 +419,7 @@ void iowrite32_rep(void __iomem *port, c
void outsl(unsigned long port, const void *src, unsigned long count)
iowrite32_rep(ioport_map(port, 4), src, count);
+ delay_if_isa(port);