|
@@ -105,6 +105,7 @@ const char gfar_driver_version[] = "1.3";
|
|
|
|
|
|
static int gfar_enet_open(struct net_device *dev);
|
|
|
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
|
|
+static void gfar_reset_task(struct work_struct *work);
|
|
|
static void gfar_timeout(struct net_device *dev);
|
|
|
static int gfar_close(struct net_device *dev);
|
|
|
struct sk_buff *gfar_new_skb(struct net_device *dev);
|
|
@@ -209,6 +210,7 @@ static int gfar_probe(struct platform_device *pdev)
|
|
|
spin_lock_init(&priv->txlock);
|
|
|
spin_lock_init(&priv->rxlock);
|
|
|
spin_lock_init(&priv->bflock);
|
|
|
+ INIT_WORK(&priv->reset_task, gfar_reset_task);
|
|
|
|
|
|
platform_set_drvdata(pdev, dev);
|
|
|
|
|
@@ -1212,6 +1214,7 @@ static int gfar_close(struct net_device *dev)
|
|
|
|
|
|
napi_disable(&priv->napi);
|
|
|
|
|
|
+ cancel_work_sync(&priv->reset_task);
|
|
|
stop_gfar(dev);
|
|
|
|
|
|
/* Disconnect from the PHY */
|
|
@@ -1326,13 +1329,16 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* gfar_timeout gets called when a packet has not been
|
|
|
+/* gfar_reset_task gets scheduled when a packet has not been
|
|
|
* transmitted after a set amount of time.
|
|
|
* For now, assume that clearing out all the structures, and
|
|
|
- * starting over will fix the problem. */
|
|
|
-static void gfar_timeout(struct net_device *dev)
|
|
|
+ * starting over will fix the problem.
|
|
|
+ */
|
|
|
+static void gfar_reset_task(struct work_struct *work)
|
|
|
{
|
|
|
- dev->stats.tx_errors++;
|
|
|
+ struct gfar_private *priv = container_of(work, struct gfar_private,
|
|
|
+ reset_task);
|
|
|
+ struct net_device *dev = priv->dev;
|
|
|
|
|
|
if (dev->flags & IFF_UP) {
|
|
|
stop_gfar(dev);
|
|
@@ -1342,6 +1348,14 @@ static void gfar_timeout(struct net_device *dev)
|
|
|
netif_tx_schedule_all(dev);
|
|
|
}
|
|
|
|
|
|
+static void gfar_timeout(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct gfar_private *priv = netdev_priv(dev);
|
|
|
+
|
|
|
+ dev->stats.tx_errors++;
|
|
|
+ schedule_work(&priv->reset_task);
|
|
|
+}
|
|
|
+
|
|
|
/* Interrupt Handler for Transmit complete */
|
|
|
static int gfar_clean_tx_ring(struct net_device *dev)
|
|
|
{
|