PATCH [1/1] GIANFAR infiinate loop on reception of PAUSE FRAME

Staale.Aakermann at kongsberg.com Staale.Aakermann at kongsberg.com
Thu Feb 21 19:04:06 EST 2013


There is a undesired behavior in the GIANFAR driver that causes a infinite loop stalling the CPU when reception of PAUSE FRAMES.
I found this error during testing with a DSL modem (Westermo http://www.westermo.com). This equipment spawns PAUSE FRAMES continuously on its LAN side as long as the link is not up on the WAN side. The GIANFAR driver does not handle that it get an timeout on transmission on the first packet sent. It will try to gracefully stop all ongoing transactions, but this will fail as there aren't any, and it will loop forever.

--- drivers/net/ethernet/freescale/gianfar.c    2012-12-11 04:30:57.000000000 +0100
+++ drivers/net/ethernet/freescale/gianfar.c    2013-02-20 20:28:13.201931602 +0100
@@ -1600,8 +1600,10 @@
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = NULL;
        u32 tempval;
-       int i;
-
+       u32 reset_value = DMACTRL_GRS;
+       u32 event_value = IEVENT_GRSC;
+       int i = 0;
+
        for (i = 0; i < priv->num_grps; i++) {
                regs = priv->gfargrp[i].regs;
                /* Mask all interrupts */
@@ -1612,22 +1614,32 @@
        }

        regs = priv->gfargrp[0].regs;
+
+       if (!((gfar_read(&regs->tctrl) & TCTRL_RFCPAUSE) == TCTRL_RFCPAUSE))
+       {
+               reset_value |= DMACTRL_GTS;
+               event_value |= IEVENT_GTSC;
+
+       }
+
        /* Stop the DMA, and wait for it to stop */
        tempval = gfar_read(&regs->dmactrl);
-       if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) !=
-           (DMACTRL_GRS | DMACTRL_GTS)) {
+       if ((tempval & reset_value) != reset_value) {
                int ret;

-               tempval |= (DMACTRL_GRS | DMACTRL_GTS);
+               tempval |= reset_value;
                gfar_write(&regs->dmactrl, tempval);

                do {
-                       ret = spin_event_timeout(((gfar_read(&regs->ievent) &
-                                (IEVENT_GRSC | IEVENT_GTSC)) ==
-                                (IEVENT_GRSC | IEVENT_GTSC)), 1000000, 0);
+
+                       ret = spin_event_timeout(((gfar_read(&regs->ievent) & event_value) == event_value), 1000000, 0);
+
                        if (!ret && !(gfar_read(&regs->ievent) & IEVENT_GRSC))
+                       {
                                ret = __gfar_is_rx_idle(priv);
+                       }
                } while (!ret);
+
        }
 }

@@ -1668,9 +1682,10 @@
        lock_rx_qs(priv);

        gfar_halt(dev);
-
+
        unlock_rx_qs(priv);
        unlock_tx_qs(priv);
+
        local_irq_restore(flags);

        /* Free the IRQs */
@@ -2424,22 +2439,32 @@
        struct gfar_private *priv = container_of(work, struct gfar_private,
                                                 reset_task);
        struct net_device *dev = priv->ndev;
-
        if (dev->flags & IFF_UP) {
                netif_tx_stop_all_queues(dev);
                stop_gfar(dev);
                startup_gfar(dev);
                netif_tx_start_all_queues(dev);
        }
-
        netif_tx_schedule_all(dev);
 }

 static void gfar_timeout(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
+       struct gfar __iomem *regs = NULL;

-       dev->stats.tx_errors++;
+       regs = priv->gfargrp[0].regs;
+
+       if ((gfar_read(&regs->tctrl) & TCTRL_RFCPAUSE) == TCTRL_RFCPAUSE)
+       {
+               printk(KERN_DEBUG "PAUSE FRAME RECEIVED\n");
+               dev->stats.tx_dropped++;
+       }
+       else
+       {
+               dev->stats.tx_errors++;
+       }
+
        schedule_work(&priv->reset_task);
 }


________________________________

CONFIDENTIALITY
This e-mail and any attachment contain KONGSBERG information which may be proprietary, confidential or subject to export regulations, and is only meant for the intended recipient(s). Any disclosure, copying, distribution or use is prohibited, if not otherwise explicitly agreed with KONGSBERG. If received in error, please delete it immediately from your system and notify the sender properly.


More information about the Linuxppc-dev mailing list