aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2012-11-21 05:27:19 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-25 15:53:31 -0500
commita9dbe40fc10cea2efe6e1ff9e03c62dd7579c5ba (patch)
treee9eac61be2534827fb758fd8b91efec8909dffeb /drivers/net
parent071e3ef4a94a021b16a2912f3885c86f4ff36b49 (diff)
8139cp: set ring address after enabling C+ mode
This fixes (for me) a regression introduced by commit b01af457 ("8139cp: set ring address before enabling receiver"). That commit configured the descriptor ring addresses earlier in the initialisation sequence, in order to avoid the possibility of triggering stray DMA before the correct address had been set up. Unfortunately, it seems that the hardware will scribble garbage into the TxRingAddr registers when we enable "plus mode" Tx in the CpCmd register. Observed on a Traverse Geos router board. To deal with this, while not reintroducing the problem which led to the original commit, we augment cp_start_hw() to write to the CpCmd register *first*, then set the descriptor ring addresses, and then finally to enable Rx and Tx in the original 8139 Cmd register. The datasheet actually indicates that we should enable Tx/Rx in the Cmd register *before* configuring the descriptor addresses, but that would appear to re-introduce the problem that the offending commit b01af457 was trying to solve. And this variant appears to work fine on real hardware. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Cc: stable@kernel.org [3.5+] Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c40
1 files changed, 28 insertions, 12 deletions
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 1c818254b7b..5166d94a224 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -957,7 +957,35 @@ static void cp_reset_hw (struct cp_private *cp)
957 957
958static inline void cp_start_hw (struct cp_private *cp) 958static inline void cp_start_hw (struct cp_private *cp)
959{ 959{
960 dma_addr_t ring_dma;
961
960 cpw16(CpCmd, cp->cpcmd); 962 cpw16(CpCmd, cp->cpcmd);
963
964 /*
965 * These (at least TxRingAddr) need to be configured after the
966 * corresponding bits in CpCmd are enabled. Datasheet v1.6 ยง6.33
967 * (C+ Command Register) recommends that these and more be configured
968 * *after* the [RT]xEnable bits in CpCmd are set. And on some hardware
969 * it's been observed that the TxRingAddr is actually reset to garbage
970 * when C+ mode Tx is enabled in CpCmd.
971 */
972 cpw32_f(HiTxRingAddr, 0);
973 cpw32_f(HiTxRingAddr + 4, 0);
974
975 ring_dma = cp->ring_dma;
976 cpw32_f(RxRingAddr, ring_dma & 0xffffffff);
977 cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16);
978
979 ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE;
980 cpw32_f(TxRingAddr, ring_dma & 0xffffffff);
981 cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16);
982
983 /*
984 * Strictly speaking, the datasheet says this should be enabled
985 * *before* setting the descriptor addresses. But what, then, would
986 * prevent it from doing DMA to random unconfigured addresses?
987 * This variant appears to work fine.
988 */
961 cpw8(Cmd, RxOn | TxOn); 989 cpw8(Cmd, RxOn | TxOn);
962} 990}
963 991
@@ -969,7 +997,6 @@ static void cp_enable_irq(struct cp_private *cp)
969static void cp_init_hw (struct cp_private *cp) 997static void cp_init_hw (struct cp_private *cp)
970{ 998{
971 struct net_device *dev = cp->dev; 999 struct net_device *dev = cp->dev;
972 dma_addr_t ring_dma;
973 1000
974 cp_reset_hw(cp); 1001 cp_reset_hw(cp);
975 1002
@@ -979,17 +1006,6 @@ static void cp_init_hw (struct cp_private *cp)
979 cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0))); 1006 cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0)));
980 cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4))); 1007 cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
981 1008
982 cpw32_f(HiTxRingAddr, 0);
983 cpw32_f(HiTxRingAddr + 4, 0);
984
985 ring_dma = cp->ring_dma;
986 cpw32_f(RxRingAddr, ring_dma & 0xffffffff);
987 cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16);
988
989 ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE;
990 cpw32_f(TxRingAddr, ring_dma & 0xffffffff);
991 cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16);
992
993 cp_start_hw(cp); 1009 cp_start_hw(cp);
994 cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ 1010 cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
995 1011