drivers/net/skeleton.c: Add outline for support with CONFIG_NET_NOINTS

This commit is contained in:
Gregory Nutt
2014-12-30 14:56:37 -06:00
parent 495a491560
commit 3666af88d4
2 changed files with 251 additions and 27 deletions
+2
View File
@@ -910,6 +910,8 @@ o Network (net/, drivers/net)
SAMA5D NO SAMA5D NO
SIM NO << Doesn't have interrupts anyway SIM NO << Doesn't have interrupts anyway
The general outline of how this might be done is included in
drivers/net/skeleton.c
Status: Open Status: Open
Priority: Pretty high if you want a well behaved system. Priority: Pretty high if you want a well behaved system.
+249 -27
View File
@@ -55,9 +55,20 @@
#include <nuttx/net/arp.h> #include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h> #include <nuttx/net/netdev.h>
#ifndef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
/**************************************************************************** /****************************************************************************
* Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* If processing is not done at the interrupt level, then high priority
* work queue support is required.
*/
#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_HPWORK)
# error High priority work queue support is required
#endif
/* CONFIG_skeleton_NINTERFACES determines the number of physical interfaces /* CONFIG_skeleton_NINTERFACES determines the number of physical interfaces
* that will be supported. * that will be supported.
@@ -93,6 +104,9 @@ struct skel_driver_s
bool sk_bifup; /* true:ifup false:ifdown */ bool sk_bifup; /* true:ifup false:ifdown */
WDOG_ID sk_txpoll; /* TX poll timer */ WDOG_ID sk_txpoll; /* TX poll timer */
WDOG_ID sk_txtimeout; /* TX timeout timer */ WDOG_ID sk_txtimeout; /* TX timeout timer */
#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
#endif
/* This holds the information visible to uIP/NuttX */ /* This holds the information visible to uIP/NuttX */
@@ -118,11 +132,24 @@ static int skel_txpoll(struct net_driver_s *dev);
static void skel_receive(FAR struct skel_driver_s *skel); static void skel_receive(FAR struct skel_driver_s *skel);
static void skel_txdone(FAR struct skel_driver_s *skel); static void skel_txdone(FAR struct skel_driver_s *skel);
static inline void skel_interrupt_process(FAR struct skel_driver_s *skel);
#ifdef CONFIG_NET_NOINTS
static void skel_interrupt_work(FAR void *arg);
#endif
static int skel_interrupt(int irq, FAR void *context); static int skel_interrupt(int irq, FAR void *context);
/* Watchdog timer expirations */ /* Watchdog timer expirations */
static inline void skel_poll_process(FAR struct skel_driver_s *skel);
#ifdef CONFIG_NET_NOINTS
static void skel_poll_work(FAR void *arg);
#endif
static void skel_polltimer(int argc, uint32_t arg, ...); static void skel_polltimer(int argc, uint32_t arg, ...);
static inline void skel_txtimeout_process(FAR struct skel_driver_s *skel);
#ifdef CONFIG_NET_NOINTS
static void skel_txtimeout_work(FAR void *arg);
#endif
static void skel_txtimeout(int argc, uint32_t arg, ...); static void skel_txtimeout(int argc, uint32_t arg, ...);
/* NuttX callback functions */ /* NuttX callback functions */
@@ -326,6 +353,72 @@ static void skel_txdone(FAR struct skel_driver_s *skel)
(void)devif_poll(&skel->sk_dev, skel_txpoll); (void)devif_poll(&skel->sk_dev, skel_txpoll);
} }
/****************************************************************************
* Function: skel_interrupt_process
*
* Description:
* Interrupt processing. This may be performed either within the interrupt
* handler or on the worker thread, depending upon the configuration
*
* Parameters:
* skel - Reference to the driver state structure
*
* Returned Value:
* None
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
static inline void skel_interrupt_process(FAR struct skel_driver_s *skel)
{
/* Get and clear interrupt status bits */
/* Handle interrupts according to status bit settings */
/* Check if we received an incoming packet, if so, call skel_receive() */
skel_receive(skel);
/* Check if a packet transmission just completed. If so, call skel_txdone.
* This may disable further Tx interrupts if there are no pending
* transmissions.
*/
skel_txdone(skel);
}
/****************************************************************************
* Function: skel_interrupt_work
*
* Description:
* Perform interrupt related work from the worker thread
*
* Parameters:
* arg - The argument passed when work_queue() as called.
*
* Returned Value:
* OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
#ifdef CONFIG_NET_NOINTS
static void skel_interrupt_work(FAR void *arg)
{
FAR struct skel_driver_s *skel = ( FAR struct skel_driver_s *)arg;
/* Process pending Ethernet interrupts */
skel_interrupt_process(skel);
/* TODO: Re-enable Ethernet interrupts */
}
#endif
/**************************************************************************** /****************************************************************************
* Function: skel_interrupt * Function: skel_interrupt
* *
@@ -345,26 +438,85 @@ static void skel_txdone(FAR struct skel_driver_s *skel)
static int skel_interrupt(int irq, FAR void *context) static int skel_interrupt(int irq, FAR void *context)
{ {
register FAR struct skel_driver_s *skel = &g_skel[0]; FAR struct skel_driver_s *skel = &g_skel[0];
/* Get and clear interrupt status bits */ #ifdef CONFIG_NET_NOINTS
/* TODO: Disable further Ethernet interrupts */
/* Handle interrupts according to status bit settings */ /* Schedule to perform the interrupt processing on the worker thread.
* TODO: Assure that no timeouts can occur.
/* Check if we received an incoming packet, if so, call skel_receive() */
skel_receive(skel);
/* Check if a packet transmission just completed. If so, call skel_txdone.
* This may disable further Tx interrupts if there are no pending
* tansmissions.
*/ */
skel_txdone(skel); DEBUGASSERT(work_available(&skel->work);
work_queue(HPWORK, &skel->work, skel_interrupt_work, skel, 0);
#else
/* Process the interrupt now */
skel_interrupt_process(skel);
#endif
return OK; return OK;
} }
/****************************************************************************
* Function: skel_txtimeout_process
*
* Description:
* Process a TX timeout. Called from the either the watchdog timer
* expiration logic or from the worker thread, depeding upon the
* configuration. The timeout means that the last TX never completed.
* Reset the hardware and start again.
*
* Parameters:
* skel - Reference to the driver state structure
*
* Returned Value:
* None
*
* Assumptions:
* Global interrupts are disabled by the watchdog logic.
*
****************************************************************************/
static inline void skel_txtimeout_process(FAR struct skel_driver_s *skel)
{
/* Increment statistics and dump debug info */
/* Then reset the hardware */
/* Then poll uIP for new XMIT data */
(void)devif_poll(&skel->sk_dev, skel_txpoll);
}
/****************************************************************************
* Function: skel_txtimeout_work
*
* Description:
* Perform TX timeout related work from the worker thread
*
* Parameters:
* arg - The argument passed when work_queue() as called.
*
* Returned Value:
* OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
#ifdef CONFIG_NET_NOINTS
static void skel_txtimeout_work(FAR void *arg)
{
FAR struct skel_driver_s *skel = ( FAR struct skel_driver_s *)arg;
/* Process pending Ethernet interrupts */
skel_txtimetout_process(skel);
}
#endif
/**************************************************************************** /****************************************************************************
* Function: skel_txtimeout * Function: skel_txtimeout
* *
@@ -388,15 +540,85 @@ static void skel_txtimeout(int argc, uint32_t arg, ...)
{ {
FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg; FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg;
/* Increment statistics and dump debug info */ #ifdef CONFIG_NET_NOINTS
/* TODO: Disable further Ethernet interrupts */
/* Then reset the hardware */ /* Schedule to perform the TX timeout processing on the worker thread.
* TODO: Assure that no there is not pending interrupt or poll work.
*/
/* Then poll uIP for new XMIT data */ DEBUGASSERT(work_available(&skel->work);
work_queue(HPWORK, &skel->work, skel_txtimeout_work, skel, 0);
#else
/* Process the interrupt now */
(void)devif_poll(&skel->sk_dev, skel_txpoll); skel_txtimeout_process(skel);
#endif
} }
/****************************************************************************
* Function: skel_poll_process
*
* Description:
* Perform the periodic poll. This may be called either from watchdog
* timer logic or from the worker thread, depending upon the configuration.
*
* Parameters:
* skel - Reference to the driver state structure
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
static inline void skel_poll_process(FAR struct skel_driver_s *skel)
{
/* Check if there is room in the send another TX packet. We cannot perform
* the TX poll if he are unable to accept another packet for transmission.
*/
/* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm..
* might be bug here. Does this mean if there is a transmit in progress,
* we will missing TCP time state updates?
*/
(void)devif_timer(&skel->sk_dev, skel_txpoll, skeleton_POLLHSEC);
/* Setup the watchdog poll timer again */
(void)wd_start(skel->sk_txpoll, skeleton_WDDELAY, skel_polltimer, 1, arg);
}
/****************************************************************************
* Function: skel_poll_work
*
* Description:
* Perform periodic polling from the worker thread
*
* Parameters:
* arg - The argument passed when work_queue() as called.
*
* Returned Value:
* OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
#ifdef CONFIG_NET_NOINTS
static void skel_poll_work(FAR void *arg)
{
FAR struct skel_driver_s *skel = ( FAR struct skel_driver_s *)arg;
/* Perform the poll */
skel_poll_process(skel);
}
#endif
/**************************************************************************** /****************************************************************************
* Function: skel_polltimer * Function: skel_polltimer
* *
@@ -419,20 +641,20 @@ static void skel_polltimer(int argc, uint32_t arg, ...)
{ {
FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg; FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg;
/* Check if there is room in the send another TX packet. We cannot perform #ifdef CONFIG_NET_NOINTS
* the TX poll if he are unable to accept another packet for transmission. /* Schedule to perform the interrupt processing on the worker thread.
* TODO: Make sure that there can be no pending interrupt work.
*/ */
/* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm.. DEBUGASSERT(work_available(&skel->work);
* might be bug here. Does this mean if there is a transmit in progress, work_queue(HPWORK, &skel->work, skel_poll_work, skel, 0);
* we will missing TCP time state updates? #else
*/ /* Process the interrupt now */
(void)devif_timer(&skel->sk_dev, skel_txpoll, skeleton_POLLHSEC); skel_poll_process(skel);
#endif
/* Setup the watchdog poll timer again */ return OK;
(void)wd_start(skel->sk_txpoll, skeleton_WDDELAY, skel_polltimer, 1, arg);
} }
/**************************************************************************** /****************************************************************************