| From fcb9d538380180c62507bb3d18c5c7101e98f48b Mon Sep 17 00:00:00 2001 |
| From: David S. Miller <davem@davemloft.net> |
| Date: Wed, 12 Nov 2008 14:32:54 -0800 |
| Subject: niu: Fix readq implementation when architecture does not provide one. |
| |
| From: David S. Miller <davem@davemloft.net> |
| |
| [ Upstream commit e23a59e1ca6d177a57a7791b3629db93ff1d9813 ] |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/net/niu.c | 3 +-- |
| 1 file changed, 1 insertion(+), 2 deletions(-) |
| |
| --- 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) |