Tive Ethernet: Fix some race conditions in the driver that become apparent when debug is enabled

This commit is contained in:
Gregory Nutt 2015-01-17 10:59:45 -06:00
parent 26499b440b
commit b7c0bfebd5
2 changed files with 176 additions and 26 deletions

View File

@ -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 */
@ -2501,6 +2509,65 @@ static int tiva_ifdown(struct net_driver_s *dev)
return OK;
}
/****************************************************************************
* 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
*
@ -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;
}

View File

@ -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
/****************************************************************************
@ -826,6 +830,67 @@ static int skel_ifdown(struct net_driver_s *dev)
return OK;
}
/****************************************************************************
* 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
*
@ -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;
}