]> err.no Git - linux-2.6/blobdiff - drivers/net/ibm_emac/ibm_emac_core.c
[PATCH] ibm_emac: fix graceful stop timeout handling
[linux-2.6] / drivers / net / ibm_emac / ibm_emac_core.c
index eb7d6947871555812408a40aa7e0c6fba697275e..1da8a66f91e115cf913f6c0492c3c2187cd6be75 100644 (file)
@@ -65,7 +65,7 @@
  */
 
 #define DRV_NAME        "emac"
-#define DRV_VERSION     "3.53"
+#define DRV_VERSION     "3.54"
 #define DRV_DESC        "PPC 4xx OCP EMAC driver"
 
 MODULE_DESCRIPTION(DRV_DESC);
@@ -158,6 +158,14 @@ static inline void emac_report_timeout_error(struct ocp_enet_private *dev,
 #define PHY_POLL_LINK_ON       HZ
 #define PHY_POLL_LINK_OFF      (HZ / 5)
 
+/* Graceful stop timeouts in us. 
+ * We should allow up to 1 frame time (full-duplex, ignoring collisions) 
+ */
+#define STOP_TIMEOUT_10                1230    
+#define STOP_TIMEOUT_100       124
+#define STOP_TIMEOUT_1000      13
+#define STOP_TIMEOUT_1000_JUMBO        73
+
 /* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */
 static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = {
        "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum",
@@ -222,10 +230,12 @@ static void emac_tx_disable(struct ocp_enet_private *dev)
 
        r = in_be32(&p->mr0);
        if (r & EMAC_MR0_TXE) {
-               int n = 300;
+               int n = dev->stop_timeout;
                out_be32(&p->mr0, r & ~EMAC_MR0_TXE);
-               while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n)
+               while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) {
+                       udelay(1);
                        --n;
+               }       
                if (unlikely(!n))
                        emac_report_timeout_error(dev, "TX disable timeout");
        }
@@ -248,9 +258,11 @@ static void emac_rx_enable(struct ocp_enet_private *dev)
        if (!(r & EMAC_MR0_RXE)) {
                if (unlikely(!(r & EMAC_MR0_RXI))) {
                        /* Wait if previous async disable is still in progress */
-                       int n = 100;
-                       while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n)
+                       int n = dev->stop_timeout;
+                       while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
+                               udelay(1);
                                --n;
+                       }       
                        if (unlikely(!n))
                                emac_report_timeout_error(dev,
                                                          "RX disable timeout");
@@ -273,10 +285,12 @@ static void emac_rx_disable(struct ocp_enet_private *dev)
 
        r = in_be32(&p->mr0);
        if (r & EMAC_MR0_RXE) {
-               int n = 300;
+               int n = dev->stop_timeout;
                out_be32(&p->mr0, r & ~EMAC_MR0_RXE);
-               while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n)
+               while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
+                       udelay(1);
                        --n;
+               }       
                if (unlikely(!n))
                        emac_report_timeout_error(dev, "RX disable timeout");
        }
@@ -395,6 +409,7 @@ static int emac_configure(struct ocp_enet_private *dev)
        r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST;
        if (dev->phy.duplex == DUPLEX_FULL)
                r |= EMAC_MR1_FDE;
+       dev->stop_timeout = STOP_TIMEOUT_10;
        switch (dev->phy.speed) {
        case SPEED_1000:
                if (emac_phy_gpcs(dev->phy.mode)) {
@@ -409,12 +424,16 @@ static int emac_configure(struct ocp_enet_private *dev)
                        r |= EMAC_MR1_MF_1000;
                r |= EMAC_MR1_RFS_16K;
                gige = 1;
-               
-               if (dev->ndev->mtu > ETH_DATA_LEN)
+
+               if (dev->ndev->mtu > ETH_DATA_LEN) {
                        r |= EMAC_MR1_JPSM;
+                       dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO;
+               } else
+                       dev->stop_timeout = STOP_TIMEOUT_1000;
                break;
        case SPEED_100:
                r |= EMAC_MR1_MF_100;
+               dev->stop_timeout = STOP_TIMEOUT_100;
                /* Fall through */
        default:
                r |= EMAC_MR1_RFS_4K;
@@ -2048,6 +2067,7 @@ static int __init emac_probe(struct ocp_device *ocpdev)
        dev->phy.duplex = DUPLEX_FULL;
        dev->phy.autoneg = AUTONEG_DISABLE;
        dev->phy.pause = dev->phy.asym_pause = 0;
+       dev->stop_timeout = STOP_TIMEOUT_100;
        init_timer(&dev->link_timer);
        dev->link_timer.function = emac_link_timer;
        dev->link_timer.data = (unsigned long)dev;