From 443549cbbe6fdd0f169f02f3593eec4d35bc9ae6 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 30 Dec 2014 14:56:37 -0600 Subject: drivers/net/skeleton.c: Add outline for support with CONFIG_NET_NOINTS --- nuttx/TODO | 2 + nuttx/drivers/net/skeleton.c | 264 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 245 insertions(+), 21 deletions(-) diff --git a/nuttx/TODO b/nuttx/TODO index c78bc8a4f..ce0d3112d 100644 --- a/nuttx/TODO +++ b/nuttx/TODO @@ -910,6 +910,8 @@ o Network (net/, drivers/net) SAMA5D NO 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 Priority: Pretty high if you want a well behaved system. diff --git a/nuttx/drivers/net/skeleton.c b/nuttx/drivers/net/skeleton.c index 061e8df3d..060ab185f 100644 --- a/nuttx/drivers/net/skeleton.c +++ b/nuttx/drivers/net/skeleton.c @@ -55,9 +55,20 @@ #include #include +#ifndef CONFIG_NET_NOINTS +# include +#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 * that will be supported. @@ -93,6 +104,9 @@ struct skel_driver_s bool sk_bifup; /* true:ifup false:ifdown */ WDOG_ID sk_txpoll; /* TX poll 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 */ @@ -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_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); /* 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 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, ...); /* NuttX callback functions */ @@ -327,26 +354,25 @@ static void skel_txdone(FAR struct skel_driver_s *skel) } /**************************************************************************** - * Function: skel_interrupt + * Function: skel_interrupt_process * * Description: - * Hardware interrupt handler + * Interrupt processing. This may be performed either within the interrupt + * handler or on the worker thread, depending upon the configuration * * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) + * skel - Reference to the driver state structure * * Returned Value: - * OK on success + * None * * Assumptions: + * Ethernet interrupts are disabled * ****************************************************************************/ -static int skel_interrupt(int irq, FAR void *context) +static inline void skel_interrupt_process(FAR struct skel_driver_s *skel) { - register FAR struct skel_driver_s *skel = &g_skel[0]; - /* Get and clear interrupt status bits */ /* Handle interrupts according to status bit settings */ @@ -357,24 +383,92 @@ static int skel_interrupt(int irq, FAR void *context) /* Check if a packet transmission just completed. If so, call skel_txdone. * This may disable further Tx interrupts if there are no pending - * tansmissions. + * 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 + * + * Description: + * Hardware interrupt handler + * + * Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + * Assumptions: + * + ****************************************************************************/ + +static int skel_interrupt(int irq, FAR void *context) +{ + FAR struct skel_driver_s *skel = &g_skel[0]; + +#ifdef CONFIG_NET_NOINTS + /* TODO: Disable further Ethernet interrupts */ + + /* Schedule to perform the interrupt processing on the worker thread. + * TODO: Assure that no timeouts can occur. + */ + + 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; } /**************************************************************************** - * Function: skel_txtimeout + * Function: skel_txtimeout_process * * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the hardware and start again. + * 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: - * argc - The number of available arguments - * arg - The first argument + * skel - Reference to the driver state structure * * Returned Value: * None @@ -384,10 +478,8 @@ static int skel_interrupt(int irq, FAR void *context) * ****************************************************************************/ -static void skel_txtimeout(int argc, uint32_t arg, ...) +static inline void skel_txtimeout_process(FAR struct skel_driver_s *skel) { - FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg; - /* Increment statistics and dump debug info */ /* Then reset the hardware */ @@ -398,10 +490,39 @@ static void skel_txtimeout(int argc, uint32_t arg, ...) } /**************************************************************************** - * Function: skel_polltimer + * Function: skel_txtimeout_work * * Description: - * Periodic timer handler. Called from the timer interrupt handler. + * 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 + * + * Description: + * Our TX watchdog timed out. Called from the timer interrupt handler. + * The last TX never completed. Reset the hardware and start again. * * Parameters: * argc - The number of available arguments @@ -415,10 +536,45 @@ static void skel_txtimeout(int argc, uint32_t arg, ...) * ****************************************************************************/ -static void skel_polltimer(int argc, uint32_t arg, ...) +static void skel_txtimeout(int argc, uint32_t arg, ...) { FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg; +#ifdef CONFIG_NET_NOINTS + /* TODO: Disable further Ethernet interrupts */ + + /* Schedule to perform the TX timeout processing on the worker thread. + * TODO: Assure that no there is not pending interrupt or poll work. + */ + + DEBUGASSERT(work_available(&skel->work); + work_queue(HPWORK, &skel->work, skel_txtimeout_work, skel, 0); +#else + /* Process the interrupt now */ + + 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. */ @@ -435,6 +591,72 @@ static void skel_polltimer(int argc, uint32_t arg, ...) (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 + * + * Description: + * Periodic timer handler. Called from the timer interrupt handler. + * + * Parameters: + * argc - The number of available arguments + * arg - The first argument + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * + ****************************************************************************/ + +static void skel_polltimer(int argc, uint32_t arg, ...) +{ + FAR struct skel_driver_s *skel = (FAR struct skel_driver_s *)arg; + +#ifdef CONFIG_NET_NOINTS + /* Schedule to perform the interrupt processing on the worker thread. + * TODO: Make sure that there can be no pending interrupt work. + */ + + DEBUGASSERT(work_available(&skel->work); + work_queue(HPWORK, &skel->work, skel_poll_work, skel, 0); +#else + /* Process the interrupt now */ + + skel_poll_process(skel); +#endif + + return OK; +} + /**************************************************************************** * Function: skel_ifup * -- cgit v1.2.3