summaryrefslogtreecommitdiffstats
path: root/drivers/net/niu.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-11-12 23:32:54 +0100
committerDavid S. Miller <davem@davemloft.net>2008-11-12 23:32:54 +0100
commite23a59e1ca6d177a57a7791b3629db93ff1d9813 (patch)
treefa96090d8b055468cc249c133e0980a3ba462187 /drivers/net/niu.c
parentnet: put_cmsg_compat + SO_TIMESTAMP[NS]: use same name for value as caller (diff)
downloadlinux-e23a59e1ca6d177a57a7791b3629db93ff1d9813.tar.xz
linux-e23a59e1ca6d177a57a7791b3629db93ff1d9813.zip
niu: Fix readq implementation when architecture does not provide one.
This fixes a TX hang reported by Jesper Dangaard Brouer. When an architecutre cannot provide a fully functional 64-bit atomic readq/writeq, the driver must implement it's own. This is because only the driver can say whether doing something like using two 32-bit reads to implement the full 64-bit read will actually work properly. In particular one of the issues is whether the top 32-bits or the bottom 32-bits of the 64-bit register should be read first. There could be side effects, and in fact that is exactly the problem here. The TX_CS register has counters in the upper 32-bits and state bits in the lower 32-bits. A read clears the state bits. We would read the counter half before the state bit half. That first read would clear the state bits, and then the driver thinks that no interrupts are pending because the interrupt indication state bits are seen clear every time. Fix this by reading the bottom half before the upper half. Tested-by: Jesper Dangaard Brouer <jdb@comx.dk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to '')
-rw-r--r--drivers/net/niu.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 9acb5d70a3ae..d8463b1c3df3 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -51,8 +51,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);
#ifndef readq
static u64 readq(void __iomem *reg)
{
- return (((u64)readl(reg + 0x4UL) << 32) |
- (u64)readl(reg));
+ return ((u64) readl(reg)) | (((u64) readl(reg + 4UL)) << 32);
}
static void writeq(u64 val, void __iomem *reg)