diff options
-rw-r--r-- | drivers/net/gianfar.c | 40 | ||||
-rw-r--r-- | drivers/net/gianfar.h | 1 |
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(®s->minflr, MINFLR_INIT_SETTINGS); | 1575 | gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); |
1571 | } | 1576 | } |
1572 | 1577 | ||
1578 | static 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 */ |
1575 | static void gfar_halt_nodisable(struct net_device *dev) | 1603 | static 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(®s->dmactrl); | 1621 | tempval = gfar_read(®s->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(®s->dmactrl, tempval); | 1627 | gfar_write(®s->dmactrl, tempval); |
1598 | 1628 | ||
1599 | spin_event_timeout(((gfar_read(®s->ievent) & | 1629 | do { |
1600 | (IEVENT_GRSC | IEVENT_GTSC)) == | 1630 | ret = spin_event_timeout(((gfar_read(®s->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(®s->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 { | |||
1028 | enum gfar_errata { | 1028 | enum 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 |