From 8ee2e8d8b04d4ebdb5093985c7aaf8b24429cc1d Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 24 Feb 2017 15:58:17 -0600 Subject: [PATCH] Most Ethernet drviers: Check if the poll timer is running before restarting it at the end of each TX. --- arch/arm/src/lpc17xx/lpc17_ethernet.c | 30 +++++++++++++++----- arch/arm/src/lpc43xx/lpc43_ethernet.c | 27 ++++++++++++++---- arch/arm/src/sam34/sam_emac.c | 27 ++++++++++++++---- arch/arm/src/sama5/sam_emaca.c | 27 ++++++++++++++---- arch/arm/src/sama5/sam_emacb.c | 27 ++++++++++++++---- arch/arm/src/sama5/sam_gmac.c | 26 +++++++++++++---- arch/arm/src/samv7/sam_emac.c | 27 ++++++++++++++---- arch/arm/src/stm32/stm32_eth.c | 27 ++++++++++++++---- arch/arm/src/stm32f7/stm32_ethernet.c | 27 ++++++++++++++---- arch/arm/src/tiva/lm3s_ethernet.c | 6 ++-- arch/arm/src/tiva/tm4c_ethernet.c | 36 ++++++++++++++++++------ arch/mips/src/pic32mz/pic32mz-ethernet.c | 3 +- arch/misoc/src/common/misoc_net.c | 27 +++++++++++++----- arch/z80/src/ez80/ez80_emac.c | 3 +- drivers/net/dm90x0.c | 3 +- drivers/net/enc28j60.c | 27 +++++++++++++----- drivers/net/encx24j600.c | 26 +++++++++++++---- drivers/net/ftmac100.c | 23 +++++++++++---- drivers/net/loopback.c | 3 +- drivers/net/skeleton.c | 27 +++++++++++++----- drivers/net/tun.c | 3 +- 21 files changed, 329 insertions(+), 103 deletions(-) diff --git a/arch/arm/src/lpc17xx/lpc17_ethernet.c b/arch/arm/src/lpc17xx/lpc17_ethernet.c index fa9b65a95f..9a91d0af1f 100644 --- a/arch/arm/src/lpc17xx/lpc17_ethernet.c +++ b/arch/arm/src/lpc17xx/lpc17_ethernet.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/lpc17xx/lpc17_ethernet.c * - * Copyright (C) 2010-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2010-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -1262,6 +1262,8 @@ static int lpc17_interrupt(int irq, void *context) if ((status & ETH_INT_TXDONE) != 0) { + int delay; + NETDEV_TXDONE(&priv->lp_dev); /* A packet transmission just completed */ @@ -1283,14 +1285,28 @@ static int lpc17_interrupt(int irq, void *context) work_cancel(ETHWORK, &priv->lp_txwork); - /* 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 is + * queued for 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->lp_txpoll, LPC17_WDDELAY, lpc17_poll_expiry, - 1, priv); + delay = wd_gettime(priv->lp_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->lp_txpoll, LPC17_WDDELAY, + lpc17_poll_expiry, 1, priv); + } /* Schedule TX-related work to be performed on the work thread */ diff --git a/arch/arm/src/lpc43xx/lpc43_ethernet.c b/arch/arm/src/lpc43xx/lpc43_ethernet.c index f6f666c7ca..e54e4e666c 100644 --- a/arch/arm/src/lpc43xx/lpc43_ethernet.c +++ b/arch/arm/src/lpc43xx/lpc43_ethernet.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/lpc43/lpc43_eth.c * - * Copyright (C) 2011-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -1862,17 +1862,32 @@ static void lpc43_txdone(FAR struct lpc43_ethmac_s *priv) if (priv->inflight <= 0) { + int delay; + /* 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, LPC43_WDDELAY, lpc43_poll_expiry, 1, 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, LPC43_WDDELAY, lpc43_poll_expiry, + 1, priv); + } /* And disable further TX interrupts. */ diff --git a/arch/arm/src/sam34/sam_emac.c b/arch/arm/src/sam34/sam_emac.c index 7ce3b0c316..9afcc865ee 100644 --- a/arch/arm/src/sam34/sam_emac.c +++ b/arch/arm/src/sam34/sam_emac.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/sam34/sam_emac.c * - * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This logic derives from the SAM34D3 Ethernet driver. @@ -1638,6 +1638,8 @@ static int sam_emac_interrupt(int irq, void *context) tsr = sam_getreg(priv, SAM_EMAC_TSR); if ((tsr & EMAC_TSR_TXCOMP) != 0) { + int delay; + /* If a TX transfer just completed, then cancel the TX timeout so * there will be do race condition between any subsequent timeout * expiration and the deferred interrupt processing. @@ -1645,13 +1647,26 @@ static int sam_emac_interrupt(int irq, void *context) wd_cancel(priv->txtimeout); - /* 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, SAM_WDDELAY, sam_poll_expiry, 1, 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, SAM_WDDELAY, sam_poll_expiry, + 1, priv); + } } /* Cancel any pending poll work */ diff --git a/arch/arm/src/sama5/sam_emaca.c b/arch/arm/src/sama5/sam_emaca.c index 29bd28c5a7..605bb965a0 100644 --- a/arch/arm/src/sama5/sam_emaca.c +++ b/arch/arm/src/sama5/sam_emaca.c @@ -4,7 +4,7 @@ * 10/100 Base-T Ethernet driver for the SAMA5D3. Denoted as 'A' to * distinguish it from the SAMA5D4 EMAC driver. * - * Copyright (C) 2013-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: @@ -1676,6 +1676,8 @@ static int sam_emac_interrupt(int irq, void *context) tsr = sam_getreg(priv, SAM_EMAC_TSR_OFFSET); if ((tsr & EMAC_TSR_COMP) != 0) { + int delay; + /* If a TX transfer just completed, then cancel the TX timeout so * there will be do race condition between any subsequent timeout * expiration and the deferred interrupt processing. @@ -1683,13 +1685,26 @@ static int sam_emac_interrupt(int irq, void *context) wd_cancel(priv->txtimeout); - /* 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, SAM_WDDELAY, sam_poll_expiry, 1, 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, SAM_WDDELAY, sam_poll_expiry, + 1, priv); + } } /* Cancel any pending poll work */ diff --git a/arch/arm/src/sama5/sam_emacb.c b/arch/arm/src/sama5/sam_emacb.c index 44b477cb7b..4aa61f4b9e 100644 --- a/arch/arm/src/sama5/sam_emacb.c +++ b/arch/arm/src/sama5/sam_emacb.c @@ -8,7 +8,7 @@ * separate (mostly because the 'B' driver needs to support two EMAC blocks. * But the 'B' driver should replace the 'A' driver someday. * - * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This logic derives from the SAM4E Ethernet driver which, in turn, derived @@ -2043,6 +2043,8 @@ static int sam_emac_interrupt(struct sam_emac_s *priv) tsr = sam_getreg(priv, SAM_EMAC_TSR_OFFSET); if ((tsr & EMAC_TSR_TXCOMP) != 0) { + int delay; + /* If a TX transfer just completed, then cancel the TX timeout so * there will be do race condition between any subsequent timeout * expiration and the deferred interrupt processing. @@ -2050,13 +2052,26 @@ static int sam_emac_interrupt(struct sam_emac_s *priv) wd_cancel(priv->txtimeout); - /* 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, SAM_WDDELAY, sam_poll_expiry, 1, 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, SAM_WDDELAY, sam_poll_expiry, + 1, priv); + } } /* Cancel any pending poll work */ diff --git a/arch/arm/src/sama5/sam_gmac.c b/arch/arm/src/sama5/sam_gmac.c index da6b320d52..ab97e40569 100644 --- a/arch/arm/src/sama5/sam_gmac.c +++ b/arch/arm/src/sama5/sam_gmac.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/sama5/sam_gmac.c * - * Copyright (C) 2013-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: @@ -1628,6 +1628,8 @@ static int sam_gmac_interrupt(int irq, void *context) tsr = sam_getreg(priv, SAM_GMAC_TSR_OFFSET); if ((tsr & GMAC_TSR_TXCOMP) != 0) { + int delay; + /* If a TX transfer just completed, then cancel the TX timeout so * there will be do race condition between any subsequent timeout * expiration and the deferred interrupt processing. @@ -1635,13 +1637,25 @@ static int sam_gmac_interrupt(int irq, void *context) wd_cancel(priv->txtimeout); - /* 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, SAM_WDDELAY, sam_poll_expiry, 1, 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, SAM_WDDELAY, sam_poll_expiry, 1, priv); + } } /* Cancel any pending poll work */ diff --git a/arch/arm/src/samv7/sam_emac.c b/arch/arm/src/samv7/sam_emac.c index a7ea10c109..617df6226b 100644 --- a/arch/arm/src/samv7/sam_emac.c +++ b/arch/arm/src/samv7/sam_emac.c @@ -2,7 +2,7 @@ * arch/arm/src/samv7/sam_emac.c * 10/100 Base-T Ethernet driver for the SAMV71. * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This logic derives from the SAMA5 Ethernet driver which, in turn, derived @@ -2489,6 +2489,8 @@ static int sam_emac_interrupt(struct sam_emac_s *priv) tsr = sam_getreg(priv, SAM_EMAC_TSR_OFFSET); if ((tsr & EMAC_TSR_TXCOMP) != 0) { + int delay; + /* If a TX transfer just completed, then cancel the TX timeout so * there will be do race condition between any subsequent timeout * expiration and the deferred interrupt processing. @@ -2496,13 +2498,26 @@ static int sam_emac_interrupt(struct sam_emac_s *priv) wd_cancel(priv->txtimeout); - /* 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, SAM_WDDELAY, sam_poll_expiry, 1, 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, SAM_WDDELAY, sam_poll_expiry, + 1, priv); + } } /* Cancel any pending poll work */ diff --git a/arch/arm/src/stm32/stm32_eth.c b/arch/arm/src/stm32/stm32_eth.c index 52dcaacd72..adfc4412c3 100644 --- a/arch/arm/src/stm32/stm32_eth.c +++ b/arch/arm/src/stm32/stm32_eth.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32/stm32_eth.c * - * Copyright (C) 2011-2012, 2014, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 2014, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -1927,17 +1927,32 @@ static void stm32_txdone(FAR struct stm32_ethmac_s *priv) if (priv->inflight <= 0) { + int delay; + /* 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 is queued 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, STM32_WDDELAY, stm32_poll_expiry, 1, 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, STM32_WDDELAY, stm32_poll_expiry, + 1, priv); + } /* And disable further TX interrupts. */ diff --git a/arch/arm/src/stm32f7/stm32_ethernet.c b/arch/arm/src/stm32f7/stm32_ethernet.c index b84e8511ac..1ef4e09503 100644 --- a/arch/arm/src/stm32f7/stm32_ethernet.c +++ b/arch/arm/src/stm32f7/stm32_ethernet.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32f7/stm32_ethernet.c * - * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2015-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -2040,17 +2040,32 @@ static void stm32_txdone(struct stm32_ethmac_s *priv) if (priv->inflight <= 0) { + int delay; + /* 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, STM32_WDDELAY, stm32_poll_expiry, 1, 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, STM32_WDDELAY, stm32_poll_expiry, + 1, priv); + } /* And disable further TX interrupts. */ diff --git a/arch/arm/src/tiva/lm3s_ethernet.c b/arch/arm/src/tiva/lm3s_ethernet.c index 020569f293..0671306553 100644 --- a/arch/arm/src/tiva/lm3s_ethernet.c +++ b/arch/arm/src/tiva/lm3s_ethernet.c @@ -1272,7 +1272,8 @@ static void tiva_poll_expiry(int argc, wdparm_t arg, ...) * cycle. */ - (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, arg); + (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_poll_expiry, + 1, arg); } } @@ -1425,7 +1426,8 @@ static int tiva_ifup(struct net_driver_s *dev) /* Set and activate a timer process */ - (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, (uint32_t)priv); + (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_poll_expiry, + 1, (uint32_t)priv); priv->ld_bifup = true; leave_critical_section(flags); diff --git a/arch/arm/src/tiva/tm4c_ethernet.c b/arch/arm/src/tiva/tm4c_ethernet.c index a04854879d..ea04d5200d 100644 --- a/arch/arm/src/tiva/tm4c_ethernet.c +++ b/arch/arm/src/tiva/tm4c_ethernet.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/tiva/tm4c_ethernet.c * - * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -1955,17 +1955,32 @@ static void tiva_txdone(FAR struct tiva_ethmac_s *priv) if (priv->inflight <= 0) { + int delay; + /* 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, TIVA_WDDELAY, tiva_poll_expiry, 1, (uint32_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, TIVA_WDDELAY, tiva_poll_expiry, + 1, (uint32_t)priv); + } /* And disable further TX interrupts. */ @@ -2306,7 +2321,8 @@ static void tiva_poll_work(FAR void *arg) /* Setup the watchdog poll timer again */ - (void)wd_start(priv->txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, (uint32_t)priv); + (void)wd_start(priv->txpoll, TIVA_WDDELAY, tiva_poll_expiry, + 1, (uint32_t)priv); net_unlock(); } @@ -2348,7 +2364,8 @@ static void tiva_poll_expiry(int argc, uint32_t arg, ...) * cycle. */ - (void)wd_start(priv->txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, (uint32_t)priv); + (void)wd_start(priv->txpoll, TIVA_WDDELAY, tiva_poll_expiry, + 1, (uint32_t)priv); } } @@ -2396,7 +2413,8 @@ static int tiva_ifup(struct net_driver_s *dev) /* Set and activate a timer process */ - (void)wd_start(priv->txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, (uint32_t)priv); + (void)wd_start(priv->txpoll, TIVA_WDDELAY, tiva_poll_expiry, + 1, (uint32_t)priv); /* Enable the Ethernet interrupt */ diff --git a/arch/mips/src/pic32mz/pic32mz-ethernet.c b/arch/mips/src/pic32mz/pic32mz-ethernet.c index 7eb5c4d54c..bdf8121857 100644 --- a/arch/mips/src/pic32mz/pic32mz-ethernet.c +++ b/arch/mips/src/pic32mz/pic32mz-ethernet.c @@ -2097,7 +2097,8 @@ static void pic32mz_poll_expiry(int argc, wdparm_t arg, ...) * cycle. */ - (void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_poll_expiry, 1, arg); + (void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_poll_expiry, + 1, arg); } } diff --git a/arch/misoc/src/common/misoc_net.c b/arch/misoc/src/common/misoc_net.c index 85d6e60bbf..63902b6eb7 100644 --- a/arch/misoc/src/common/misoc_net.c +++ b/arch/misoc/src/common/misoc_net.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/misoc/src/commong/misoc_net_net.c * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * Ramtin Amin * @@ -542,6 +542,8 @@ static void misoc_net_receive(FAR struct misoc_net_driver_s *priv) static void misoc_net_txdone(FAR struct misoc_net_driver_s *priv) { + int delay; + /* Check for errors and update statistics */ NETDEV_TXDONE(priv->misoc_net_dev); @@ -554,14 +556,25 @@ static void misoc_net_txdone(FAR struct misoc_net_driver_s *priv) wd_cancel(priv->misoc_net_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->misoc_net_txpoll, MISOC_NET_WDDELAY, - misoc_net_poll_expiry, 1, (wdparm_t)priv); + delay = wd_gettime(priv->misoc_net_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->misoc_net_txpoll, MISOC_NET_WDDELAY, + misoc_net_poll_expiry, 1, (wdparm_t)priv); + } /* And disable further TX interrupts. */ diff --git a/arch/z80/src/ez80/ez80_emac.c b/arch/z80/src/ez80/ez80_emac.c index 71f1c4ee9c..6d34a38a89 100644 --- a/arch/z80/src/ez80/ez80_emac.c +++ b/arch/z80/src/ez80/ez80_emac.c @@ -1980,7 +1980,8 @@ static void ez80emac_poll_expiry(int argc, wdparm_t arg, ...) * cycle. */ - (void)wd_start(priv->txpoll, EMAC_WDDELAY, ez80emac_poll_expiry, 1, arg); + (void)wd_start(priv->txpoll, EMAC_WDDELAY, ez80emac_poll_expiry, + 1, arg); } } diff --git a/drivers/net/dm90x0.c b/drivers/net/dm90x0.c index 61c22a929b..c90fc283e6 100644 --- a/drivers/net/dm90x0.c +++ b/drivers/net/dm90x0.c @@ -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); } } diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index e91a5652ce..9289a1bb33 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -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 * * 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 */ diff --git a/drivers/net/encx24j600.c b/drivers/net/encx24j600.c index e169068047..2249d4e58f 100644 --- a/drivers/net/encx24j600.c +++ b/drivers/net/encx24j600.c @@ -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 */ diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index 1550d9ad7c..4ac01decae 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -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 */ diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 06459d5449..ced03b5910 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -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; diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c index 59c5a8fac5..b312d3460f 100644 --- a/drivers/net/skeleton.c +++ b/drivers/net/skeleton.c @@ -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 * * 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. */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ebb59587b6..cf44ca651b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -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;