mirror of
https://github.com/apache/nuttx.git
synced 2026-06-06 08:22:32 +08:00
drivers/net: Add framework for serialization in the case where multiple low-priority work queues are used.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
NuttX TODO List (Last updated February 12, 2017)
|
NuttX TODO List (Last updated March 4, 2017)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
||||||
@@ -1055,6 +1055,12 @@ o Network (net/, drivers/net)
|
|||||||
additional mechanism would have to be added to enforce that
|
additional mechanism would have to be added to enforce that
|
||||||
serialization.
|
serialization.
|
||||||
|
|
||||||
|
See nuttx/drivers/net/skeleton.c for an example of how
|
||||||
|
serialization may be added to an Ethernet driver.
|
||||||
|
|
||||||
|
Status: Open
|
||||||
|
Priority: High if you happen to be using Ethernet in this configuration.
|
||||||
|
|
||||||
o USB (drivers/usbdev, drivers/usbhost)
|
o USB (drivers/usbdev, drivers/usbhost)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|||||||
+77
-1
@@ -43,6 +43,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <semaphore.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@@ -68,19 +69,30 @@
|
|||||||
* is required.
|
* is required.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#undef ETH_SERIALIZATION
|
||||||
|
|
||||||
#if !defined(CONFIG_SCHED_WORKQUEUE)
|
#if !defined(CONFIG_SCHED_WORKQUEUE)
|
||||||
# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
|
# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Use the low priority work queue if possible */
|
/* Use the low priority work queue if possible */
|
||||||
|
|
||||||
# if defined(CONFIG_skeleton_HPWORK)
|
# if defined(CONFIG_skeleton_HPWORK)
|
||||||
# define ETHWORK HPWORK
|
# define ETHWORK HPWORK
|
||||||
# elif defined(CONFIG_skeleton_LPWORK)
|
# elif defined(CONFIG_skeleton_LPWORK)
|
||||||
# define ETHWORK LPWORK
|
# define ETHWORK LPWORK
|
||||||
|
|
||||||
|
/* Serialization may be required in the special case where there are
|
||||||
|
* multiple low priority work queues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# if CONFIG_SCHED_LPNTHREADS > 1
|
||||||
|
# define ETH_SERIALIZATION 1
|
||||||
|
# endif
|
||||||
# else
|
# else
|
||||||
# error Neither CONFIG_skeleton_HPWORK nor CONFIG_skeleton_LPWORK defined
|
# error Neither CONFIG_skeleton_HPWORK nor CONFIG_skeleton_LPWORK defined
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* CONFIG_skeleton_NINTERFACES determines the number of physical interfaces
|
/* CONFIG_skeleton_NINTERFACES determines the number of physical interfaces
|
||||||
@@ -118,6 +130,9 @@ struct skel_driver_s
|
|||||||
WDOG_ID sk_txtimeout; /* TX timeout timer */
|
WDOG_ID sk_txtimeout; /* TX timeout timer */
|
||||||
struct work_s sk_irqwork; /* For deferring interupt work to the work queue */
|
struct work_s sk_irqwork; /* For deferring interupt work to the work queue */
|
||||||
struct work_s sk_pollwork; /* For deferring poll work to the work queue */
|
struct work_s sk_pollwork; /* For deferring poll work to the work queue */
|
||||||
|
#ifdef ETH_SERIALIZATION
|
||||||
|
sem_t sk_lock; /* Serialization semaphore */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This holds the information visible to the NuttX network */
|
/* This holds the information visible to the NuttX network */
|
||||||
|
|
||||||
@@ -147,6 +162,17 @@ static struct skel_driver_s g_skel[CONFIG_skeleton_NINTERFACES];
|
|||||||
* Private Function Prototypes
|
* Private Function Prototypes
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef ETH_SERIALIZATION
|
||||||
|
/* Serialization support */
|
||||||
|
|
||||||
|
static void skel_lock(FAR struct skel_driver_s *priv);
|
||||||
|
# define skel_unlock(p) (void)sem_post(&(p)->sk_lock)
|
||||||
|
|
||||||
|
#else
|
||||||
|
# define skel_lock(p)
|
||||||
|
# define skel_unlock(p)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Common TX logic */
|
/* Common TX logic */
|
||||||
|
|
||||||
static int skel_transmit(FAR struct skel_driver_s *priv);
|
static int skel_transmit(FAR struct skel_driver_s *priv);
|
||||||
@@ -190,6 +216,36 @@ static void skel_ipv6multicast(FAR struct skel_driver_s *priv);
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Function: skel_lock
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* When there are multiple LP work queues, we must force serialization of
|
||||||
|
* work.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* priv - Reference to the driver state structure
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called in the context of thread of the LP work queue.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef ETH_SERIALIZATION
|
||||||
|
static void skel_lock(FAR struct skel_driver_s *priv)
|
||||||
|
{
|
||||||
|
while (sem_wait(&priv->sk_lock) < 0)
|
||||||
|
{
|
||||||
|
/* EINTR is the only expected error value */
|
||||||
|
|
||||||
|
DEBUGASSERT(errno == EINTR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Function: skel_transmit
|
* Function: skel_transmit
|
||||||
*
|
*
|
||||||
@@ -506,6 +562,8 @@ static void skel_interrupt_work(FAR void *arg)
|
|||||||
{
|
{
|
||||||
FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
|
FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
|
||||||
|
|
||||||
|
skel_lock(priv);
|
||||||
|
|
||||||
/* Process pending Ethernet interrupts */
|
/* Process pending Ethernet interrupts */
|
||||||
|
|
||||||
/* Get and clear interrupt status bits */
|
/* Get and clear interrupt status bits */
|
||||||
@@ -528,6 +586,7 @@ static void skel_interrupt_work(FAR void *arg)
|
|||||||
/* Re-enable Ethernet interrupts */
|
/* Re-enable Ethernet interrupts */
|
||||||
|
|
||||||
up_enable_irq(CONFIG_skeleton_IRQ);
|
up_enable_irq(CONFIG_skeleton_IRQ);
|
||||||
|
skel_unlock(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -596,6 +655,8 @@ static void skel_txtimeout_work(FAR void *arg)
|
|||||||
{
|
{
|
||||||
FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
|
FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
|
||||||
|
|
||||||
|
skel_lock(priv);
|
||||||
|
|
||||||
/* Increment statistics and dump debug info */
|
/* Increment statistics and dump debug info */
|
||||||
|
|
||||||
NETDEV_TXTIMEOUTS(priv->sk_dev);
|
NETDEV_TXTIMEOUTS(priv->sk_dev);
|
||||||
@@ -607,6 +668,8 @@ static void skel_txtimeout_work(FAR void *arg)
|
|||||||
net_lock();
|
net_lock();
|
||||||
(void)devif_poll(&priv->sk_dev, skel_txpoll);
|
(void)devif_poll(&priv->sk_dev, skel_txpoll);
|
||||||
net_unlock();
|
net_unlock();
|
||||||
|
|
||||||
|
skel_unlock(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -686,6 +749,8 @@ static void skel_poll_work(FAR void *arg)
|
|||||||
{
|
{
|
||||||
FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
|
FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
|
||||||
|
|
||||||
|
skel_lock(priv);
|
||||||
|
|
||||||
/* Perform the poll */
|
/* Perform the poll */
|
||||||
|
|
||||||
/* Check if there is room in the send another TX packet. We cannot perform
|
/* Check if there is room in the send another TX packet. We cannot perform
|
||||||
@@ -705,6 +770,8 @@ static void skel_poll_work(FAR void *arg)
|
|||||||
(void)wd_start(priv->sk_txpoll, skeleton_WDDELAY, skel_poll_expiry, 1,
|
(void)wd_start(priv->sk_txpoll, skeleton_WDDELAY, skel_poll_expiry, 1,
|
||||||
(wdparm_t)priv);
|
(wdparm_t)priv);
|
||||||
net_unlock();
|
net_unlock();
|
||||||
|
|
||||||
|
skel_unlock(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -853,6 +920,8 @@ static void skel_txavail_work(FAR void *arg)
|
|||||||
{
|
{
|
||||||
FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
|
FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
|
||||||
|
|
||||||
|
skel_lock(priv);
|
||||||
|
|
||||||
/* Ignore the notification if the interface is not yet up */
|
/* Ignore the notification if the interface is not yet up */
|
||||||
|
|
||||||
net_lock();
|
net_lock();
|
||||||
@@ -866,6 +935,7 @@ static void skel_txavail_work(FAR void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
net_unlock();
|
net_unlock();
|
||||||
|
skel_unlock(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -1096,6 +1166,12 @@ int skel_initialize(int intf)
|
|||||||
priv->sk_txpoll = wd_create(); /* Create periodic poll timer */
|
priv->sk_txpoll = wd_create(); /* Create periodic poll timer */
|
||||||
priv->sk_txtimeout = wd_create(); /* Create TX timeout timer */
|
priv->sk_txtimeout = wd_create(); /* Create TX timeout timer */
|
||||||
|
|
||||||
|
#ifdef ETH_SERIALIZATION
|
||||||
|
/* Initialize the serialization semaphore */
|
||||||
|
|
||||||
|
sem_init(&priv->sk_lock, 0, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Put the interface in the down state. This usually amounts to resetting
|
/* Put the interface in the down state. This usually amounts to resetting
|
||||||
* the device and/or calling skel_ifdown().
|
* the device and/or calling skel_ifdown().
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user