staging: unisys: Fix improper use of NETDEV_TX_BUSY
authorNeil Horman <nhorman@redhat.com>
Tue, 21 Jul 2015 13:55:45 +0000 (09:55 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Jul 2015 04:20:25 +0000 (21:20 -0700)
Using NETDEV_TX_BUSY is tricky.  Its meant for situations where the error
in question is transient and quickly resolved.  But the driver rarely is
able to know that to a certainty.  And in the case of visornic, it just
uses it without any care for that, in the hopes that it won't loose frames,
even if the problem is that the skb is somehow malformed for the hardware.
If we get one of those kinds of skbs, NETDEV_TX_BUSY will just cause us to
spin, processing the same error over and over.

Fix it by dropping the frame, stopping the queue where appropriate, and
returning NETDEV_TX_OK

Signed-off-by: Neil Horman <nhorman@redhat.com>
Signed-off-by: Benjamin Romer <benjamin.romer@unisys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/unisys/visornic/visornic_main.c

index 338ca8c299159160c3e1933c385db3e28099f509..8cc9017a67a1ba8b6edb365f944879167a5569f9 100644 (file)
@@ -787,7 +787,7 @@ visornic_close(struct net_device *netdev)
  *     function is protected from concurrent calls by a spinlock xmit_lock
  *     in the net_device struct, but as soon as the function returns it
  *     can be called again.
- *     Returns NETDEV_TX_OK for success, NETDEV_TX_BUSY for error.
+ *     Returns NETDEV_TX_OK.
  */
 static int
 visornic_xmit(struct sk_buff *skb, struct net_device *netdev)
@@ -806,7 +806,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev)
                devdata->busy_cnt++;
                dev_dbg(&netdev->dev,
                        "%s busy - queue stopped\n", __func__);
-               return NETDEV_TX_BUSY;
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
        }
 
        /* sk_buff struct is used to host network data throughout all the
@@ -827,7 +828,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev)
                dev_err(&netdev->dev,
                        "%s busy - first frag too small (%d)\n",
                        __func__, firstfraglen);
-               return NETDEV_TX_BUSY;
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
        }
 
        if ((len < ETH_MIN_PACKET_SIZE) &&
@@ -869,7 +871,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev)
                dev_dbg(&netdev->dev,
                        "%s busy - waiting for iovm to catch up\n",
                        __func__);
-               return NETDEV_TX_BUSY;
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
        }
        if (devdata->queuefullmsg_logged)
                devdata->queuefullmsg_logged = 0;
@@ -911,7 +914,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev)
                devdata->busy_cnt++;
                dev_err(&netdev->dev,
                        "%s busy - copy frags failed\n", __func__);
-               return NETDEV_TX_BUSY;
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
        }
 
        if (!visorchannel_signalinsert(devdata->dev->visorchannel,
@@ -921,7 +925,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev)
                devdata->busy_cnt++;
                dev_dbg(&netdev->dev,
                        "%s busy - signalinsert failed\n", __func__);
-               return NETDEV_TX_BUSY;
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
        }
 
        /* Track the skbs that have been sent to the IOVM for XMIT */