Most Ethernet drviers: Check if the poll timer is running before restarting it at the end of each TX.

This commit is contained in:
Gregory Nutt
2017-02-24 15:58:17 -06:00
parent 12a4a58aa6
commit 8ee2e8d8b0
21 changed files with 329 additions and 103 deletions
+2 -1
View File
@@ -1453,7 +1453,8 @@ static void dm9x_poll_expiry(int argc, wdparm_t arg, ...)
* cycle.
*/
(void)wd_start(priv->dm_txpoll, DM9X_WDDELAY, dm9x_poll_expiry, 1, arg);
(void)wd_start(priv->dm_txpoll, DM9X_WDDELAY, dm9x_poll_expiry,
1, arg);
}
}
+20 -7
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* drivers/net/enc28j60.c
*
* Copyright (C) 2010-2012, 2014-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2010-2012, 2014-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References:
@@ -1275,6 +1275,8 @@ static void enc_linkstatus(FAR struct enc_driver_s *priv)
static void enc_txif(FAR struct enc_driver_s *priv)
{
int delay;
/* Update statistics */
NETDEV_TXDONE(&priv->dev);
@@ -1287,14 +1289,25 @@ static void enc_txif(FAR struct enc_driver_s *priv)
wd_cancel(priv->txtimeout);
/* Then make sure that the TX poll timer is running (if it is already
* running, the following would restart it). This is necessary to
* avoid certain race conditions where the polling sequence can be
* interrupted.
/* Check if the poll timer is running. If it is not, then start it now.
* There is a race condition here: We may test the time remaining on the
* poll timer and determine that it is still running, but then the timer
* expires immiately. That should not be problem, however, the poll timer
* processing should be in the work queue and should execute immediately
* after we complete the TX poll. Inefficient, but not fatal.
*/
(void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1,
(wdparm_t)priv);
delay = wd_gettime(priv->txpoll);
if (delay <= 0)
{
/* The poll timer is not running .. restart it. This is necessary to
* avoid certain race conditions where the polling sequence can be
* interrupted.
*/
(void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1,
(wdparm_t)priv);
}
/* Then poll the network for new XMIT data */
+20 -6
View File
@@ -1291,18 +1291,32 @@ static void enc_txif(FAR struct enc_driver_s *priv)
if (sq_empty(&priv->txqueue))
{
int delay;
/* If no further xmits are pending, then cancel the TX timeout */
wd_cancel(priv->txtimeout);
/* Then make sure that the TX poll timer is running (if it is already
* running, the following would restart it). This is necessary to
* avoid certain race conditions where the polling sequence can be
* interrupted.
/* Check if the poll timer is running. If it is not, then start it
* now. There is a race condition here: We may test the time
* remaining on the poll timer and determine that it is still running,
* but then the timer expires immiately. That should not be problem,
* however, the poll timer processing should be in the work queue and
* should execute immediately after we complete the TX poll.
* Inefficient, but not fatal.
*/
(void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1,
(wdparm_t)priv);
delay = wd_gettime(priv->txpoll);
if (delay <= 0)
{
/* The poll timer is not running .. restart it. This is necessary
* to avoid certain race conditions where the polling sequence can
* be interrupted.
*/
(void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1,
(wdparm_t)priv);
}
/* Poll for TX packets from the networking layer */
+18 -5
View File
@@ -805,6 +805,7 @@ static void ftmac100_receive(FAR struct ftmac100_driver_s *priv)
static void ftmac100_txdone(FAR struct ftmac100_driver_s *priv)
{
FAR struct ftmac100_txdes_s *txdes;
int delay;
/* Check if a Tx was pending */
@@ -843,13 +844,25 @@ static void ftmac100_txdone(FAR struct ftmac100_driver_s *priv)
wd_cancel(priv->ft_txtimeout);
/* Then make sure that the TX poll timer is running (if it is already
* running, the following would restart it). This is necessary to avoid
* certain race conditions where the polling sequence can be interrupted.
/* Check if the poll timer is running. If it is not, then start it now.
* There is a race condition here: We may test the time remaining on the
* poll timer and determine that it is still running, but then the timer
* expires immiately. That should not be problem, however, the poll timer
* processing should be in the work queue and should execute immediately
* after we complete the TX poll. Inefficient, but not fatal.
*/
(void)wd_start(priv->ft_txpoll, FTMAC100_WDDELAY, ftmac100_poll_expiry, 1,
(wdparm_t)priv);
delay = wd_gettime(priv->ft_txpoll);
if (delay <= 0)
{
/* The poll timer is not running .. restart it. This is necessary to
* avoid certain race conditions where the polling sequence can be
* interrupted.
*/
(void)wd_start(priv->ft_txpoll, FTMAC100_WDDELAY, ftmac100_poll_expiry,
1, (wdparm_t)priv);
}
/* Then poll the network for new XMIT data */
+2 -1
View File
@@ -338,7 +338,8 @@ static int lo_ifup(FAR struct net_driver_s *dev)
/* Set and activate a timer process */
(void)wd_start(priv->lo_polldog, LO_WDDELAY, lo_poll_expiry, 1, (wdparm_t)priv);
(void)wd_start(priv->lo_polldog, LO_WDDELAY, lo_poll_expiry,
1, (wdparm_t)priv);
priv->lo_bifup = true;
return OK;
+20 -7
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* drivers/net/skeleton.c
*
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -463,6 +463,8 @@ static void skel_receive(FAR struct skel_driver_s *priv)
static void skel_txdone(FAR struct skel_driver_s *priv)
{
int delay;
/* Check for errors and update statistics */
NETDEV_TXDONE(priv->sk_dev);
@@ -475,14 +477,25 @@ static void skel_txdone(FAR struct skel_driver_s *priv)
wd_cancel(priv->sk_txtimeout);
/* Then make sure that the TX poll timer is running (if it is already
* running, the following would restart it). This is necessary to
* avoid certain race conditions where the polling sequence can be
* interrupted.
/* Check if the poll timer is running. If it is not, then start it now.
* There is a race condition here: We may test the time remaining on the
* poll timer and determine that it is still running, but then the timer
* expires immiately. That should not be problem, however, the poll timer
* processing should be in the work queue and should execute immediately
* after we complete the TX poll. Inefficient, but not fatal.
*/
(void)wd_start(priv->sk_txpoll, skeleton_WDDELAY, skel_poll_expiry, 1,
(wdparm_t)priv);
delay = wd_gettime(priv->sk_txpoll);
if (delay <= 0)
{
/* The poll timer is not running .. restart it. This is necessary to
* avoid certain race conditions where the polling sequence can be
* interrupted.
*/
(void)wd_start(priv->sk_txpoll, skeleton_WDDELAY, skel_poll_expiry,
1, (wdparm_t)priv);
}
/* And disable further TX interrupts. */
+2 -1
View File
@@ -656,7 +656,8 @@ static int tun_ifup(struct net_driver_s *dev)
/* Set and activate a timer process */
(void)wd_start(priv->txpoll, TUN_WDDELAY, tun_poll_expiry, 1, (wdparm_t)priv);
(void)wd_start(priv->txpoll, TUN_WDDELAY, tun_poll_expiry,
1, (wdparm_t)priv);
priv->bifup = true;
return OK;