summaryrefslogtreecommitdiff
path: root/nuttx
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2015-01-17 10:59:45 -0600
committerGregory Nutt <gnutt@nuttx.org>2015-01-17 10:59:45 -0600
commiteebc384e9ba10466185c9d4e7955ce819838463d (patch)
treeab3b846b1ce0660316c37b90f08d25a0375a10d7 /nuttx
parent0847f74ab27f3cb3c9affefd3cf823b0f4a95a52 (diff)
downloadpx4-nuttx-eebc384e9ba10466185c9d4e7955ce819838463d.tar.gz
px4-nuttx-eebc384e9ba10466185c9d4e7955ce819838463d.tar.bz2
px4-nuttx-eebc384e9ba10466185c9d4e7955ce819838463d.zip
Tive Ethernet: Fix some race conditions in the driver that become apparent when debug is enabled
Diffstat (limited to 'nuttx')
-rw-r--r--nuttx/arch/arm/src/tiva/tm4c_ethernet.c98
-rw-r--r--nuttx/drivers/net/skeleton.c104
2 files changed, 176 insertions, 26 deletions
diff --git a/nuttx/arch/arm/src/tiva/tm4c_ethernet.c b/nuttx/arch/arm/src/tiva/tm4c_ethernet.c
index 8ef82c0e1..98efdb2ea 100644
--- a/nuttx/arch/arm/src/tiva/tm4c_ethernet.c
+++ b/nuttx/arch/arm/src/tiva/tm4c_ethernet.c
@@ -726,6 +726,10 @@ static void tiva_poll_expiry(int argc, uint32_t arg, ...);
static int tiva_ifup(struct net_driver_s *dev);
static int tiva_ifdown(struct net_driver_s *dev);
+static inline void tiva_txavail_process(FAR struct tiva_ethmac_s *priv);
+#ifdef CONFIG_NET_NOINTS
+static void tiva_txavail_work(FAR void *arg);
+#endif
static int tiva_txavail(struct net_driver_s *dev);
#ifdef CONFIG_NET_IGMP
static int tiva_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
@@ -1820,7 +1824,7 @@ static void tiva_receive(FAR struct tiva_ethmac_s *priv)
static void tiva_freeframe(FAR struct tiva_ethmac_s *priv)
{
- struct emac_txdesc_s *txdesc;
+ FAR struct emac_txdesc_s *txdesc;
int i;
nvdbg("txhead: %p txtail: %p inflight: %d\n",
@@ -1916,11 +1920,15 @@ static void tiva_freeframe(FAR struct tiva_ethmac_s *priv)
static void tiva_txdone(FAR struct tiva_ethmac_s *priv)
{
+ FAR struct net_driver_s *dev = &priv->dev;
+
DEBUGASSERT(priv->txtail != NULL);
/* Scan the TX descriptor change, returning buffers to free list */
tiva_freeframe(priv);
+ dev->d_buf = NULL;
+ dev->d_len = 0;
/* If no further xmits are pending, then cancel the TX timeout */
@@ -2502,6 +2510,65 @@ static int tiva_ifdown(struct net_driver_s *dev)
}
/****************************************************************************
+ * Function: tiva_txavail_process
+ *
+ * Description:
+ * Perform an out-of-cycle poll.
+ *
+ * Parameters:
+ * priv - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called in normal user mode
+ *
+ ****************************************************************************/
+
+static inline void tiva_txavail_process(FAR struct tiva_ethmac_s *priv)
+{
+ nvdbg("ifup: %d\n", priv->ifup);
+
+ /* Ignore the notification if the interface is not yet up */
+
+ if (priv->ifup)
+ {
+ /* Poll uIP for new XMIT data */
+
+ tiva_dopoll(priv);
+ }
+}
+
+/****************************************************************************
+ * Function: tiva_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ * arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_NOINTS
+static void tiva_txavail_work(FAR void *arg)
+{
+ FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)arg;
+
+ /* Perform the poll */
+
+ tiva_txavail_process(priv);
+}
+#endif
+
+/****************************************************************************
* Function: tiva_txavail
*
* Description:
@@ -2523,9 +2590,22 @@ static int tiva_ifdown(struct net_driver_s *dev)
static int tiva_txavail(struct net_driver_s *dev)
{
FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)dev->d_private;
- irqstate_t flags;
- nvdbg("ifup: %d\n", priv->ifup);
+#ifdef CONFIG_NET_NOINTS
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
+ */
+
+ if (work_available(&priv->work))
+ {
+ /* Schedule to serialize the poll on the worker thread. */
+
+ work_queue(HPWORK, &priv->work, tiva_txavail_work, priv, 0);
+ }
+
+#else
+ irqstate_t flags;
/* Disable interrupts because this function may be called from interrupt
* level processing.
@@ -2533,16 +2613,12 @@ static int tiva_txavail(struct net_driver_s *dev)
flags = irqsave();
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
- {
- /* Poll uIP for new XMIT data */
-
- tiva_dopoll(priv);
- }
+ /* Perform the out-of-cycle poll now */
+ tiva_txavail_process(priv);
irqrestore(flags);
+#endif
+
return OK;
}
diff --git a/nuttx/drivers/net/skeleton.c b/nuttx/drivers/net/skeleton.c
index 1a932c056..86f1f83a1 100644
--- a/nuttx/drivers/net/skeleton.c
+++ b/nuttx/drivers/net/skeleton.c
@@ -155,12 +155,16 @@ static void skel_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
-static int skel_ifup(struct net_driver_s *dev);
-static int skel_ifdown(struct net_driver_s *dev);
-static int skel_txavail(struct net_driver_s *dev);
+static int skel_ifup(FAR struct net_driver_s *dev);
+static int skel_ifdown(FAR struct net_driver_s *dev);
+static inline int skel_txavail_process(FAR struct skel_driver_s *skel);
+#ifdef CONFIG_NET_NOINTS
+static void skel_txavail_work(FAR void *arg);
+#endif
+static int skel_txavail(FAR struct net_driver_s *dev);
#ifdef CONFIG_NET_IGMP
-static int skel_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
-static int skel_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+static int skel_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
+static int skel_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
#endif
/****************************************************************************
@@ -827,6 +831,67 @@ static int skel_ifdown(struct net_driver_s *dev)
}
/****************************************************************************
+ * Function: skel_txavail_process
+ *
+ * Description:
+ * Perform an out-of-cycle poll.
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int inline skel_txavail_process(FAR struct skel_driver_s *skel)
+{
+ /* Ignore the notification if the interface is not yet up */
+
+ if (skel->sk_bifup)
+ {
+ /* Check if there is room in the hardware to hold another outgoing packet. */
+
+ /* If so, then poll uIP for new XMIT data */
+
+ (void)devif_poll(&skel->sk_dev, skel_txpoll);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Function: skel_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ * arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_NOINTS
+static void skel_txavail_work(FAR void *arg)
+{
+ FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg;
+
+ /* Perform the poll */
+
+ skel_txavail_process(skel);
+}
+#endif
+
+/****************************************************************************
* Function: skel_txavail
*
* Description:
@@ -848,6 +913,21 @@ static int skel_ifdown(struct net_driver_s *dev)
static int skel_txavail(struct net_driver_s *dev)
{
FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)dev->d_private;
+
+#ifdef CONFIG_NET_NOINTS
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
+ */
+
+ if (work_available(&skel->sk_work))
+ {
+ /* Schedule to serialize the poll on the worker thread. */
+
+ work_queue(HPWORK, &skel->sk_work, skel_txavail_work, skel, 0);
+ }
+
+#else
irqstate_t flags;
/* Disable interrupts because this function may be called from interrupt
@@ -856,18 +936,12 @@ static int skel_txavail(struct net_driver_s *dev)
flags = irqsave();
- /* Ignore the notification if the interface is not yet up */
-
- if (skel->sk_bifup)
- {
- /* Check if there is room in the hardware to hold another outgoing packet. */
-
- /* If so, then poll uIP for new XMIT data */
-
- (void)devif_poll(&skel->sk_dev, skel_txpoll);
- }
+ /* Perform the out-of-cycle poll now */
+ skel_poll_process(skel);
irqrestore(flags);
+#endif
+
return OK;
}