aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@mvista.com>2010-06-30 02:39:15 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-30 14:35:43 -0400
commit511d934f4496076898e45aaa09e0c85376eb16ee (patch)
treea50a7b366c340a66b7a1f10f59b737f23c370ebc /drivers
parentdeb90eacd084d9edfeda2f714d99c29a86360077 (diff)
gianfar: Implement workaround for eTSEC-A002 erratum
MPC8313ECE says: "If the controller receives a 1- or 2-byte frame (such as an illegal runt packet or a packet with RX_ER asserted) before GRS is asserted and does not receive any other frames, the controller may fail to set GRSC even when the receive logic is completely idle. Any subsequent receive frame that is larger than two bytes will reset the state so the graceful stop can complete. A MAC receiver (Rx) reset will also reset the state." This patch implements the proposed workaround: "If IEVENT[GRSC] is still not set after the timeout, read the eTSEC register at offset 0xD1C. If bits 7-14 are the same as bits 23-30, the eTSEC Rx is assumed to be idle and the Rx can be safely reset. If the register fields are not equal, wait for another timeout period and check again." Signed-off-by: Anton Vorontsov <avorontsov@mvista.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/gianfar.c40
-rw-r--r--drivers/net/gianfar.h1
2 files changed, 38 insertions, 3 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index c2fabc1853ad..fccb7a371cc8 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -947,6 +947,11 @@ static void gfar_detect_errata(struct gfar_private *priv)
947 (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0)) 947 (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
948 priv->errata |= GFAR_ERRATA_76; 948 priv->errata |= GFAR_ERRATA_76;
949 949
950 /* MPC8313 and MPC837x all rev */
951 if ((pvr == 0x80850010 && mod == 0x80b0) ||
952 (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
953 priv->errata |= GFAR_ERRATA_A002;
954
950 if (priv->errata) 955 if (priv->errata)
951 dev_info(dev, "enabled errata workarounds, flags: 0x%x\n", 956 dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
952 priv->errata); 957 priv->errata);
@@ -1570,6 +1575,29 @@ static void init_registers(struct net_device *dev)
1570 gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS); 1575 gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
1571} 1576}
1572 1577
1578static int __gfar_is_rx_idle(struct gfar_private *priv)
1579{
1580 u32 res;
1581
1582 /*
1583 * Normaly TSEC should not hang on GRS commands, so we should
1584 * actually wait for IEVENT_GRSC flag.
1585 */
1586 if (likely(!gfar_has_errata(priv, GFAR_ERRATA_A002)))
1587 return 0;
1588
1589 /*
1590 * Read the eTSEC register at offset 0xD1C. If bits 7-14 are
1591 * the same as bits 23-30, the eTSEC Rx is assumed to be idle
1592 * and the Rx can be safely reset.
1593 */
1594 res = gfar_read((void __iomem *)priv->gfargrp[0].regs + 0xd1c);
1595 res &= 0x7f807f80;
1596 if ((res & 0xffff) == (res >> 16))
1597 return 1;
1598
1599 return 0;
1600}
1573 1601
1574/* Halt the receive and transmit queues */ 1602/* Halt the receive and transmit queues */
1575static void gfar_halt_nodisable(struct net_device *dev) 1603static void gfar_halt_nodisable(struct net_device *dev)
@@ -1593,12 +1621,18 @@ static void gfar_halt_nodisable(struct net_device *dev)
1593 tempval = gfar_read(&regs->dmactrl); 1621 tempval = gfar_read(&regs->dmactrl);
1594 if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) 1622 if ((tempval & (DMACTRL_GRS | DMACTRL_GTS))
1595 != (DMACTRL_GRS | DMACTRL_GTS)) { 1623 != (DMACTRL_GRS | DMACTRL_GTS)) {
1624 int ret;
1625
1596 tempval |= (DMACTRL_GRS | DMACTRL_GTS); 1626 tempval |= (DMACTRL_GRS | DMACTRL_GTS);
1597 gfar_write(&regs->dmactrl, tempval); 1627 gfar_write(&regs->dmactrl, tempval);
1598 1628
1599 spin_event_timeout(((gfar_read(&regs->ievent) & 1629 do {
1600 (IEVENT_GRSC | IEVENT_GTSC)) == 1630 ret = spin_event_timeout(((gfar_read(&regs->ievent) &
1601 (IEVENT_GRSC | IEVENT_GTSC)), -1, 0); 1631 (IEVENT_GRSC | IEVENT_GTSC)) ==
1632 (IEVENT_GRSC | IEVENT_GTSC)), 1000000, 0);
1633 if (!ret && !(gfar_read(&regs->ievent) & IEVENT_GRSC))
1634 ret = __gfar_is_rx_idle(priv);
1635 } while (!ret);
1602 } 1636 }
1603} 1637}
1604 1638
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index c414374f407f..710810e2adb4 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1028,6 +1028,7 @@ struct gfar_priv_grp {
1028enum gfar_errata { 1028enum gfar_errata {
1029 GFAR_ERRATA_74 = 0x01, 1029 GFAR_ERRATA_74 = 0x01,
1030 GFAR_ERRATA_76 = 0x02, 1030 GFAR_ERRATA_76 = 0x02,
1031 GFAR_ERRATA_A002 = 0x04,
1031}; 1032};
1032 1033
1033/* Struct stolen almost completely (and shamelessly) from the FCC enet source 1034/* Struct stolen almost completely (and shamelessly) from the FCC enet source