PIC32MX/Z Ethernet: Now supports CONFIG_NET_NOINT
This commit is contained in:
parent
bfa1da14e2
commit
eba1e076ec
@ -1094,13 +1094,6 @@ config NET_WOL
|
||||
---help---
|
||||
Enable Wake-up on LAN (not fully implemented).
|
||||
|
||||
config NET_REGDEBUG
|
||||
bool "Register level debug"
|
||||
default n
|
||||
depends on PIC32MX_ETHERNET && DEBUG_NET_INFO
|
||||
---help---
|
||||
Enabled low level register debug. Also needs CONFIG_DEBUG_FEATURES.
|
||||
|
||||
config NET_HASH
|
||||
bool "Hash"
|
||||
default n
|
||||
@ -1116,6 +1109,33 @@ config PIC32MX_MULTICAST
|
||||
Enable receipt of multicast (and unicast) frames. Automatically set if
|
||||
NET_IGMP is selected.
|
||||
|
||||
choice
|
||||
prompt "Work queue"
|
||||
default PIC32MX_ETHERNET_LPWORK if SCHED_LPWORK
|
||||
default PIC32MX_ETHERNET_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
|
||||
depends on SCHED_WORKQUEUE
|
||||
---help---
|
||||
Work queue support is required to use the Ethernet driver. If the
|
||||
low priority work queue is available, then it should be used by the
|
||||
driver.
|
||||
|
||||
config PIC32MX_ETHERNET_HPWORK
|
||||
bool "High priority"
|
||||
depends on SCHED_HPWORK
|
||||
|
||||
config PIC32MX_ETHERNET_LPWORK
|
||||
bool "Low priority"
|
||||
depends on SCHED_LPWORK
|
||||
|
||||
endchoice # Work queue
|
||||
|
||||
config NET_REGDEBUG
|
||||
bool "Register level debug"
|
||||
default n
|
||||
depends on PIC32MX_ETHERNET && DEBUG_NET_INFO
|
||||
---help---
|
||||
Enabled low level register debug. Also needs CONFIG_DEBUG_FEATURES.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Device Configuration 0 (DEVCFG0)"
|
||||
|
@ -55,6 +55,11 @@
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/wdog.h>
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
# include <nuttx/wqueue.h>
|
||||
#endif
|
||||
|
||||
#include <nuttx/net/mii.h>
|
||||
#include <nuttx/net/netconfig.h>
|
||||
#include <nuttx/net/arp.h>
|
||||
@ -81,6 +86,26 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Configuration ************************************************************/
|
||||
/* If processing is not done at the interrupt level, then work queue support
|
||||
* is required.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
|
||||
# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
|
||||
#endif
|
||||
|
||||
/* Use the low priority work queue if possible */
|
||||
|
||||
#if defined(CONFIG_SCHED_WORKQUEUE)
|
||||
# if defined(CONFIG_PIC32MX_ETHERNET_HPWORK)
|
||||
# define ETHWORK HPWORK
|
||||
# elif defined(CONFIG_PIC32MX_ETHERNET_LPWORK)
|
||||
# define ETHWORK LPWORK
|
||||
# else
|
||||
# error Neither CONFIG_PIC32MX_ETHERNET_HPWORK nor CONFIG_PIC32MX_ETHERNET_LPWORK defined
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* CONFIG_PIC32MX_NINTERFACES determines the number of physical interfaces
|
||||
* that will be supported -- unless it is more than actually supported by the
|
||||
* hardware!
|
||||
@ -301,6 +326,9 @@ struct pic32mx_driver_s
|
||||
uint32_t pd_inten; /* Shadow copy of INTEN register */
|
||||
WDOG_ID pd_txpoll; /* TX poll timer */
|
||||
WDOG_ID pd_txtimeout; /* TX timeout timer */
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
struct work_s pd_work; /* For deferring work to the work queue */
|
||||
#endif
|
||||
|
||||
sq_queue_t pd_freebuffers; /* The free buffer list */
|
||||
|
||||
@ -372,18 +400,38 @@ static void pic32mx_timerpoll(struct pic32mx_driver_s *priv);
|
||||
static void pic32mx_response(struct pic32mx_driver_s *priv);
|
||||
static void pic32mx_rxdone(struct pic32mx_driver_s *priv);
|
||||
static void pic32mx_txdone(struct pic32mx_driver_s *priv);
|
||||
|
||||
static inline void pic32mx_interrupt_process(struct pic32mx_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mx_interrupt_work(void *arg);
|
||||
#endif
|
||||
static int pic32mx_interrupt(int irq, void *context);
|
||||
|
||||
/* Watchdog timer expirations */
|
||||
|
||||
static void pic32mx_polltimer(int argc, uint32_t arg, ...);
|
||||
static void pic32mx_txtimeout(int argc, uint32_t arg, ...);
|
||||
static inline void pic32mx_txtimeout_process(struct pic32mx_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mx_txtimeout_work(void *arg);
|
||||
#endif
|
||||
static void pic32mx_txtimeout_expiry(int argc, uint32_t arg, ...);
|
||||
|
||||
static inline void pic32mx_poll_process(struct pic32mx_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mx_poll_work(void *arg);
|
||||
#endif
|
||||
static void pic32mx_poll_expiry(int argc, uint32_t arg, ...);
|
||||
|
||||
/* NuttX callback functions */
|
||||
|
||||
static int pic32mx_ifup(struct net_driver_s *dev);
|
||||
static int pic32mx_ifdown(struct net_driver_s *dev);
|
||||
|
||||
static inline void pic32mx_txavail_process(struct pic32mx_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mx_txavail_work(void *arg);
|
||||
#endif
|
||||
static int pic32mx_txavail(struct net_driver_s *dev);
|
||||
|
||||
#ifdef CONFIG_NET_IGMP
|
||||
static int pic32mx_addmac(struct net_driver_s *dev, const uint8_t *mac);
|
||||
static int pic32mx_rmmac(struct net_driver_s *dev, const uint8_t *mac);
|
||||
@ -1055,8 +1103,8 @@ static int pic32mx_transmit(struct pic32mx_driver_s *priv)
|
||||
|
||||
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
|
||||
|
||||
(void)wd_start(priv->pd_txtimeout, PIC32MX_TXTIMEOUT, pic32mx_txtimeout,
|
||||
1, (uint32_t)priv);
|
||||
(void)wd_start(priv->pd_txtimeout, PIC32MX_TXTIMEOUT,
|
||||
pic32mx_txtimeout_expiry, 1, (uint32_t)priv);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@ -1634,33 +1682,27 @@ static void pic32mx_txdone(struct pic32mx_driver_s *priv)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_interrupt
|
||||
* Function: pic32mx_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)
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pic32mx_interrupt(int irq, void *context)
|
||||
static inline void pic32mx_interrupt_process(struct pic32mx_driver_s *priv)
|
||||
{
|
||||
register struct pic32mx_driver_s *priv;
|
||||
uint32_t status;
|
||||
|
||||
#if CONFIG_PIC32MX_NINTERFACES > 1
|
||||
# error "A mechanism to associate and interface with an IRQ is needed"
|
||||
#else
|
||||
priv = &g_ethdrvr[0];
|
||||
#endif
|
||||
|
||||
/* Get the interrupt status (zero means no interrupts pending). */
|
||||
|
||||
status = pic32mx_getreg(PIC32MX_ETH_IRQ);
|
||||
@ -1789,22 +1831,200 @@ static int pic32mx_interrupt(int irq, void *context)
|
||||
* (ETHCON1:0) bit to decrement the BUFCNT counter. Writing a ‘0’ or a
|
||||
* ‘1’ has no effect.
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/* Clear the pending interrupt */
|
||||
|
||||
# if CONFIG_PIC32MX_NINTERFACES > 1
|
||||
#if CONFIG_PIC32MX_NINTERFACES > 1
|
||||
up_clrpend_irq(priv->pd_irqsrc);
|
||||
# else
|
||||
#else
|
||||
up_clrpend_irq(PIC32MX_IRQSRC_ETH);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_interrupt_work
|
||||
*
|
||||
* Description:
|
||||
* Perform interrupt related work from the worker thread
|
||||
*
|
||||
* Parameters:
|
||||
* arg - The argument passed when work_queue() was called.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mx_interrupt_work(void *arg)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
|
||||
net_lock_t state;
|
||||
|
||||
/* Process pending Ethernet interrupts */
|
||||
|
||||
state = net_lock();
|
||||
pic32mx_interrupt_process(priv);
|
||||
net_unlock(state);
|
||||
|
||||
/* Re-enable Ethernet interrupts */
|
||||
|
||||
#if CONFIG_PIC32MX_NINTERFACES > 1
|
||||
up_enable_irq(priv->pd_irqsrc);
|
||||
#else
|
||||
up_enable_irq(PIC32MX_IRQSRC_ETH);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_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 pic32mx_interrupt(int irq, void *context)
|
||||
{
|
||||
struct pic32mx_driver_s *priv;
|
||||
uint32_t status;
|
||||
|
||||
#if CONFIG_PIC32MX_NINTERFACES > 1
|
||||
# error "A mechanism to associate an interface with an IRQ is needed"
|
||||
#else
|
||||
priv = &g_ethdrvr[0];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
/* Disable further Ethernet interrupts. Because Ethernet interrupts are
|
||||
* also disabled if the TX timeout event occurs, there can be no race
|
||||
* condition here.
|
||||
*/
|
||||
|
||||
#if CONFIG_PIC32MX_NINTERFACES > 1
|
||||
up_disable_irq(priv->pd_irqsrc);
|
||||
#else
|
||||
up_disable_irq(PIC32MX_IRQSRC_ETH);
|
||||
#endif
|
||||
|
||||
/* Get the interrupt status (zero means no interrupts pending). */
|
||||
|
||||
status = pic32mx_getreg(PIC32MX_ETH_IRQ);
|
||||
|
||||
/* Determine if a TX transfer just completed */
|
||||
|
||||
if ((status & ETH_INT_TXDONE) != 0)
|
||||
{
|
||||
/* If a TX transfer just completed, then cancel the TX timeout so
|
||||
* there will be no race condition between any subsequent timeout
|
||||
* expiration and the deferred interrupt processing.
|
||||
*/
|
||||
|
||||
wd_cancel(priv->pd_txtimeout);
|
||||
}
|
||||
|
||||
/* Cancel any pending poll work */
|
||||
|
||||
work_cancel(HPWORK, &priv->pd_work);
|
||||
|
||||
/* Schedule to perform the interrupt processing on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->pd_work, pic32mx_interrupt_work, priv, 0);
|
||||
|
||||
#else
|
||||
/* Process the interrupt now */
|
||||
|
||||
pic32mx_interrupt_process(priv);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_txtimeout
|
||||
* Function: pic32mx_txtimeout_process
|
||||
*
|
||||
* Description:
|
||||
* Process a TX timeout. Called from the either the watchdog timer
|
||||
* expiration logic or from the worker thread, depending upon the
|
||||
* configuration. The timeout means that the last TX never completed.
|
||||
* Reset the hardware and start again.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void pic32mx_txtimeout_process(struct pic32mx_driver_s *priv)
|
||||
{
|
||||
/* Increment statistics and dump debug info */
|
||||
|
||||
NETDEV_TXTIMEOUTS(&priv->pd_dev);
|
||||
if (priv->pd_ifup)
|
||||
{
|
||||
/* Then reset the hardware. ifup() will reset the interface, then bring
|
||||
* it back up.
|
||||
*/
|
||||
|
||||
(void)pic32mx_ifup(&priv->pd_dev);
|
||||
|
||||
/* Then poll the network for new XMIT data (We are guaranteed to have
|
||||
* a free buffer here).
|
||||
*/
|
||||
|
||||
pic32mx_poll(priv);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_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:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mx_txtimeout_work(void *arg)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
|
||||
net_lock_t state;
|
||||
|
||||
/* Process pending Ethernet interrupts */
|
||||
|
||||
state = net_lock();
|
||||
pic32mx_txtimeout_process(priv);
|
||||
net_unlock(state);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_txtimeout_expiry
|
||||
*
|
||||
* Description:
|
||||
* Our TX watchdog timed out. Called from the timer interrupt handler.
|
||||
@ -1822,51 +2042,57 @@ static int pic32mx_interrupt(int irq, void *context)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pic32mx_txtimeout(int argc, uint32_t arg, ...)
|
||||
static void pic32mx_txtimeout_expiry(int argc, wdparm_t arg, ...)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
|
||||
|
||||
/* Increment statistics and dump debug info */
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
/* Disable further Ethernet interrupts. This will prevent some race
|
||||
* conditions with interrupt work. There is still a potential race
|
||||
* condition with interrupt work that is already queued and in progress.
|
||||
*/
|
||||
|
||||
NETDEV_TXTIMEOUTS(&priv->pd_dev);
|
||||
if (priv->pd_ifup)
|
||||
{
|
||||
/* Then reset the hardware. ifup() will reset the interface, then bring
|
||||
* it back up.
|
||||
*/
|
||||
#if CONFIG_PIC32MX_NINTERFACES > 1
|
||||
up_disable_irq(priv->pd_irqsrc);
|
||||
#else
|
||||
up_disable_irq(PIC32MX_IRQSRC_ETH);
|
||||
#endif
|
||||
|
||||
(void)pic32mx_ifup(&priv->pd_dev);
|
||||
/* Cancel any pending poll or interrupt work. This will have no effect
|
||||
* on work that has already been started.
|
||||
*/
|
||||
|
||||
/* Then poll the network for new XMIT data (We are guaranteed to have a free
|
||||
* buffer here).
|
||||
*/
|
||||
work_cancel(ETHWORK, &priv->pd_work);
|
||||
|
||||
pic32mx_poll(priv);
|
||||
}
|
||||
/* Schedule to perform the TX timeout processing on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->pd_work, pic32mx_txtimeout_work, priv, 0);
|
||||
#else
|
||||
/* Process the timeout now */
|
||||
|
||||
pic32mx_txtimeout_process(priv);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_polltimer
|
||||
* Function: pic32mx_poll_process
|
||||
*
|
||||
* Description:
|
||||
* Periodic timer handler. Called from the timer interrupt handler.
|
||||
* Perform the periodic poll. This may be called either from watchdog
|
||||
* timer logic or from the worker thread, depending upon the configuration.
|
||||
*
|
||||
* Parameters:
|
||||
* argc - The number of available arguments
|
||||
* arg - The first argument
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Global interrupts are disabled by the watchdog logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pic32mx_polltimer(int argc, uint32_t arg, ...)
|
||||
static inline void pic32mx_poll_process(struct pic32mx_driver_s *priv)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
|
||||
|
||||
/* Check if the next Tx descriptor is available. We cannot perform the Tx
|
||||
* poll if we are unable to accept another packet for transmission.
|
||||
*/
|
||||
@ -1883,7 +2109,89 @@ static void pic32mx_polltimer(int argc, uint32_t arg, ...)
|
||||
|
||||
/* Setup the watchdog poll timer again */
|
||||
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_polltimer, 1, arg);
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_poll_expiry,
|
||||
1, priv);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_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:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mx_poll_work(void *arg)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
|
||||
net_lock_t state;
|
||||
|
||||
/* Perform the poll */
|
||||
|
||||
state = net_lock();
|
||||
pic32mx_poll_process(priv);
|
||||
net_unlock(state);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_poll_expiry
|
||||
*
|
||||
* 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 pic32mx_poll_expiry(int argc, wdparm_t arg, ...)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
/* Is our single work structure available? It may not be if there are
|
||||
* pending interrupt actions.
|
||||
*/
|
||||
|
||||
if (work_available(&priv->pd_work))
|
||||
{
|
||||
/* Schedule to perform the interrupt processing on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->pd_work, pic32mx_poll_work, priv, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just re-start the watchdog poll timer, missing one polling
|
||||
* cycle.
|
||||
*/
|
||||
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_poll_expiry,
|
||||
1, arg);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Process the interrupt now */
|
||||
|
||||
pic32mx_poll_process(priv);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -2175,12 +2483,13 @@ static int pic32mx_ifup(struct net_driver_s *dev)
|
||||
|
||||
/* Set and activate a timer process */
|
||||
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_polltimer, 1,
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_poll_expiry, 1,
|
||||
(uint32_t)priv);
|
||||
|
||||
/* Finally, enable the Ethernet interrupt at the interrupt controller */
|
||||
|
||||
priv->pd_ifup = true;
|
||||
|
||||
#if CONFIG_PIC32MX_NINTERFACES > 1
|
||||
up_enable_irq(priv->pd_irqsrc);
|
||||
#else
|
||||
@ -2233,15 +2542,13 @@ static int pic32mx_ifdown(struct net_driver_s *dev)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_txavail
|
||||
* Function: pic32mx_txavail_process
|
||||
*
|
||||
* Description:
|
||||
* Driver callback invoked when new TX data is available. This is a
|
||||
* stimulus perform an out-of-cycle poll and, thereby, reduce the TX
|
||||
* latency.
|
||||
* Perform an out-of-cycle poll.
|
||||
*
|
||||
* Parameters:
|
||||
* dev - Reference to the NuttX driver state structure
|
||||
* dev - Reference to the NuttX driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
@ -2251,17 +2558,8 @@ static int pic32mx_ifdown(struct net_driver_s *dev)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pic32mx_txavail(struct net_driver_s *dev)
|
||||
static inline void pic32mx_txavail_process(struct pic32mx_driver_s *priv)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)dev->d_private;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Disable interrupts because this function may be called from interrupt
|
||||
* level processing.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Ignore the notification if the interface is not yet up */
|
||||
|
||||
if (priv->pd_ifup)
|
||||
@ -2277,8 +2575,90 @@ static int pic32mx_txavail(struct net_driver_s *dev)
|
||||
pic32mx_poll(priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_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 pic32mx_txavail_work(void *arg)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
|
||||
net_lock_t state;
|
||||
|
||||
/* Perform the poll */
|
||||
|
||||
state = net_lock();
|
||||
pic32mx_txavail_process(priv);
|
||||
net_unlock(state);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mx_txavail
|
||||
*
|
||||
* Description:
|
||||
* Driver callback invoked when new TX data is available. This is a
|
||||
* stimulus perform an out-of-cycle poll and, thereby, reduce the TX
|
||||
* latency.
|
||||
*
|
||||
* Parameters:
|
||||
* dev - Reference to the NuttX driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Called in normal user mode
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pic32mx_txavail(struct net_driver_s *dev)
|
||||
{
|
||||
struct pic32mx_driver_s *priv = (struct pic32mx_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(&priv->pd_work))
|
||||
{
|
||||
/* Schedule to serialize the poll on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->pd_work, pic32mx_txavail_work, priv, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
irqstate_t flags;
|
||||
|
||||
/* Disable interrupts because this function may be called from interrupt
|
||||
* level processing.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Perform the out-of-cycle poll now */
|
||||
|
||||
pic32mx_txavail_process(priv);
|
||||
leave_critical_section(flags);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ config PIC32MZ_CTMU
|
||||
bool "Charge Time Measurement Unit (CMTU)"
|
||||
default n
|
||||
|
||||
endmenu # PIC32MX Peripheral Support
|
||||
endmenu # PIC32MZ Peripheral Support
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ
|
||||
bool "GPIO Interrupt Support"
|
||||
@ -397,13 +397,6 @@ config NET_WOL
|
||||
---help---
|
||||
Enable Wake-up on LAN (not fully implemented).
|
||||
|
||||
config NET_REGDEBUG
|
||||
bool "Register level debug"
|
||||
default n
|
||||
depends on PIC32MZ_ETHERNET && DEBUG_NET_INFO
|
||||
---help---
|
||||
Enabled low level register debug. Also needs CONFIG_DEBUG_FEATURES.
|
||||
|
||||
config NET_HASH
|
||||
bool "Hash"
|
||||
default n
|
||||
@ -419,6 +412,33 @@ config PIC32MZ_MULTICAST
|
||||
Enable receipt of multicast (and unicast) frames. Automatically set if
|
||||
NET_IGMP is selected.
|
||||
|
||||
choice
|
||||
prompt "Work queue"
|
||||
default PIC32MZ_ETHERNET_LPWORK if SCHED_LPWORK
|
||||
default PIC32MZ_ETHERNET_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
|
||||
depends on SCHED_WORKQUEUE
|
||||
---help---
|
||||
Work queue support is required to use the Ethernet driver. If the
|
||||
low priority work queue is available, then it should be used by the
|
||||
driver.
|
||||
|
||||
config PIC32MZ_ETHERNET_HPWORK
|
||||
bool "High priority"
|
||||
depends on SCHED_HPWORK
|
||||
|
||||
config PIC32MZ_ETHERNET_LPWORK
|
||||
bool "Low priority"
|
||||
depends on SCHED_LPWORK
|
||||
|
||||
endchoice # Work queue
|
||||
|
||||
config NET_REGDEBUG
|
||||
bool "Register level debug"
|
||||
default n
|
||||
depends on PIC32MZ_ETHERNET && DEBUG_NET_INFO
|
||||
---help---
|
||||
Enabled low level register debug. Also needs CONFIG_DEBUG_FEATURES.
|
||||
|
||||
endmenu # PIC32MZ PHY/Ethernet device driver settings
|
||||
|
||||
menu "Device Configuration 0 (DEVCFG0)"
|
||||
|
@ -55,6 +55,11 @@
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/wdog.h>
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
# include <nuttx/wqueue.h>
|
||||
#endif
|
||||
|
||||
#include <nuttx/net/mii.h>
|
||||
#include <nuttx/net/netconfig.h>
|
||||
#include <nuttx/net/arp.h>
|
||||
@ -81,6 +86,26 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Configuration ************************************************************/
|
||||
/* If processing is not done at the interrupt level, then work queue support
|
||||
* is required.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
|
||||
# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
|
||||
#endif
|
||||
|
||||
/* Use the low priority work queue if possible */
|
||||
|
||||
#if defined(CONFIG_SCHED_WORKQUEUE)
|
||||
# if defined(CONFIG_PIC32MZ_ETHERNET_HPWORK)
|
||||
# define ETHWORK HPWORK
|
||||
# elif defined(CONFIG_PIC32MZ_ETHERNET_LPWORK)
|
||||
# define ETHWORK LPWORK
|
||||
# else
|
||||
# error Neither CONFIG_PIC32MZ_ETHERNET_HPWORK nor CONFIG_PIC32MZ_ETHERNET_LPWORK defined
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* CONFIG_PIC32MZ_NINTERFACES determines the number of physical interfaces
|
||||
* that will be supported -- unless it is more than actually supported by the
|
||||
* hardware!
|
||||
@ -328,6 +353,9 @@ struct pic32mz_driver_s
|
||||
uint32_t pd_inten; /* Shadow copy of INTEN register */
|
||||
WDOG_ID pd_txpoll; /* TX poll timer */
|
||||
WDOG_ID pd_txtimeout; /* TX timeout timer */
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
struct work_s pd_work; /* For deferring work to the work queue */
|
||||
#endif
|
||||
|
||||
sq_queue_t pd_freebuffers; /* The free buffer list */
|
||||
|
||||
@ -399,18 +427,38 @@ static void pic32mz_timerpoll(struct pic32mz_driver_s *priv);
|
||||
static void pic32mz_response(struct pic32mz_driver_s *priv);
|
||||
static void pic32mz_rxdone(struct pic32mz_driver_s *priv);
|
||||
static void pic32mz_txdone(struct pic32mz_driver_s *priv);
|
||||
|
||||
static inline void pic32mz_interrupt_process(struct pic32mz_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mz_interrupt_work(void *arg);
|
||||
#endif
|
||||
static int pic32mz_interrupt(int irq, void *context);
|
||||
|
||||
/* Watchdog timer expirations */
|
||||
|
||||
static void pic32mz_polltimer(int argc, uint32_t arg, ...);
|
||||
static void pic32mz_txtimeout(int argc, uint32_t arg, ...);
|
||||
static inline void pic32mz_txtimeout_process(struct pic32mz_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mz_txtimeout_work(void *arg);
|
||||
#endif
|
||||
static void pic32mz_txtimeout_expiry(int argc, uint32_t arg, ...);
|
||||
|
||||
static inline void pic32mz_poll_process(struct pic32mz_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mz_poll_work(void *arg);
|
||||
#endif
|
||||
static void pic32mz_poll_expiry(int argc, uint32_t arg, ...);
|
||||
|
||||
/* NuttX callback functions */
|
||||
|
||||
static int pic32mz_ifup(struct net_driver_s *dev);
|
||||
static int pic32mz_ifdown(struct net_driver_s *dev);
|
||||
|
||||
static inline void pic32mz_txavail_process(struct pic32mz_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mz_txavail_work(void *arg);
|
||||
#endif
|
||||
static int pic32mz_txavail(struct net_driver_s *dev);
|
||||
|
||||
#ifdef CONFIG_NET_IGMP
|
||||
static int pic32mz_addmac(struct net_driver_s *dev, const uint8_t *mac);
|
||||
static int pic32mz_rmmac(struct net_driver_s *dev, const uint8_t *mac);
|
||||
@ -1082,7 +1130,7 @@ static int pic32mz_transmit(struct pic32mz_driver_s *priv)
|
||||
|
||||
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
|
||||
|
||||
(void)wd_start(priv->pd_txtimeout, PIC32MZ_TXTIMEOUT, pic32mz_txtimeout,
|
||||
(void)wd_start(priv->pd_txtimeout, PIC32MZ_TXTIMEOUT, pic32mz_txtimeout_expiry,
|
||||
1, (uint32_t)priv);
|
||||
|
||||
return OK;
|
||||
@ -1661,33 +1709,27 @@ static void pic32mz_txdone(struct pic32mz_driver_s *priv)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_interrupt
|
||||
* Function: pic32mz_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)
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pic32mz_interrupt(int irq, void *context)
|
||||
static inline void pic32mz_interrupt_process(struct pic32mz_driver_s *priv)
|
||||
{
|
||||
register struct pic32mz_driver_s *priv;
|
||||
uint32_t status;
|
||||
|
||||
#if CONFIG_PIC32MZ_NINTERFACES > 1
|
||||
# error "A mechanism to associate and interface with an IRQ is needed"
|
||||
#else
|
||||
priv = &g_ethdrvr[0];
|
||||
#endif
|
||||
|
||||
/* Get the interrupt status (zero means no interrupts pending). */
|
||||
|
||||
status = pic32mz_getreg(PIC32MZ_ETH_IRQ);
|
||||
@ -1816,43 +1858,148 @@ static int pic32mz_interrupt(int irq, void *context)
|
||||
* (ETHCON1:0) bit to decrement the BUFCNT counter. Writing a ‘0’ or a
|
||||
* ‘1’ has no effect.
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/* Clear the pending interrupt */
|
||||
|
||||
# if CONFIG_PIC32MZ_NINTERFACES > 1
|
||||
#if CONFIG_PIC32MZ_NINTERFACES > 1
|
||||
up_clrpend_irq(priv->pd_irqsrc);
|
||||
# else
|
||||
#else
|
||||
up_clrpend_irq(PIC32MZ_IRQ_ETH);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_interrupt_work
|
||||
*
|
||||
* Description:
|
||||
* Perform interrupt related work from the worker thread
|
||||
*
|
||||
* Parameters:
|
||||
* arg - The argument passed when work_queue() was called.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mz_interrupt_work(void *arg)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
|
||||
net_lock_t state;
|
||||
|
||||
/* Process pending Ethernet interrupts */
|
||||
|
||||
state = net_lock();
|
||||
pic32mz_interrupt_process(priv);
|
||||
net_unlock(state);
|
||||
|
||||
/* Re-enable Ethernet interrupts */
|
||||
|
||||
#if CONFIG_PIC32MZ_NINTERFACES > 1
|
||||
up_enable_irq(priv->pd_irqsrc);
|
||||
#else
|
||||
up_enable_irq(PIC32MZ_IRQ_ETH);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_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 pic32mz_interrupt(int irq, void *context)
|
||||
{
|
||||
struct pic32mz_driver_s *priv;
|
||||
uint32_t status;
|
||||
|
||||
#if CONFIG_PIC32MZ_NINTERFACES > 1
|
||||
# error "A mechanism to associate an interface with an IRQ is needed"
|
||||
#else
|
||||
priv = &g_ethdrvr[0];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
/* Disable further Ethernet interrupts. Because Ethernet interrupts are
|
||||
* also disabled if the TX timeout event occurs, there can be no race
|
||||
* condition here.
|
||||
*/
|
||||
|
||||
#if CONFIG_PIC32MZ_NINTERFACES > 1
|
||||
up_disable_irq(priv->pd_irqsrc);
|
||||
#else
|
||||
up_disable_irq(PIC32MZ_IRQ_ETH);
|
||||
#endif
|
||||
|
||||
/* Get the interrupt status (zero means no interrupts pending). */
|
||||
|
||||
status = pic32mz_getreg(PIC32MZ_ETH_IRQ);
|
||||
|
||||
/* Determine if a TX transfer just completed */
|
||||
|
||||
if ((status & ETH_INT_TXDONE) != 0)
|
||||
{
|
||||
/* If a TX transfer just completed, then cancel the TX timeout so
|
||||
* there will be no race condition between any subsequent timeout
|
||||
* expiration and the deferred interrupt processing.
|
||||
*/
|
||||
|
||||
wd_cancel(priv->pd_txtimeout);
|
||||
}
|
||||
|
||||
/* Cancel any pending poll work */
|
||||
|
||||
work_cancel(HPWORK, &priv->pd_work);
|
||||
|
||||
/* Schedule to perform the interrupt processing on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->pd_work, pic32mz_interrupt_work, priv, 0);
|
||||
|
||||
#else
|
||||
/* Process the interrupt now */
|
||||
|
||||
pic32mz_interrupt_process(priv);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_txtimeout
|
||||
* Function: pic32mz_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, depending 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
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Global interrupts are disabled by the watchdog logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pic32mz_txtimeout(int argc, uint32_t arg, ...)
|
||||
static inline void pic32mz_txtimeout_process(struct pic32mz_driver_s *priv)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
|
||||
|
||||
/* Increment statistics and dump debug info */
|
||||
|
||||
NETDEV_TXTIMEOUTS(&priv->pd_dev);
|
||||
@ -1873,7 +2020,159 @@ static void pic32mz_txtimeout(int argc, uint32_t arg, ...)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_polltimer
|
||||
* Function: pic32mz_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:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mz_txtimeout_work(void *arg)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
|
||||
net_lock_t state;
|
||||
|
||||
/* Process pending Ethernet interrupts */
|
||||
|
||||
state = net_lock();
|
||||
pic32mz_txtimeout_process(priv);
|
||||
net_unlock(state);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_txtimeout_expiry
|
||||
*
|
||||
* 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
|
||||
* arg - The first argument
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Global interrupts are disabled by the watchdog logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pic32mz_txtimeout_expiry(int argc, wdparm_t arg, ...)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
/* Disable further Ethernet interrupts. This will prevent some race
|
||||
* conditions with interrupt work. There is still a potential race
|
||||
* condition with interrupt work that is already queued and in progress.
|
||||
*/
|
||||
|
||||
#if CONFIG_PIC32MZ_NINTERFACES > 1
|
||||
up_disable_irq(priv->pd_irqsrc);
|
||||
#else
|
||||
up_disable_irq(PIC32MZ_IRQ_ETH);
|
||||
#endif
|
||||
|
||||
/* Cancel any pending poll or interrupt work. This will have no effect
|
||||
* on work that has already been started.
|
||||
*/
|
||||
|
||||
work_cancel(ETHWORK, &priv->pd_work);
|
||||
|
||||
/* Schedule to perform the TX timeout processing on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->pd_work, pic32mz_txtimeout_work, priv, 0);
|
||||
#else
|
||||
/* Process the timeout now */
|
||||
|
||||
pic32mz_txtimeout_process(priv);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_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:
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void pic32mz_poll_process(struct pic32mz_driver_s *priv)
|
||||
{
|
||||
/* Check if the next Tx descriptor is available. We cannot perform the Tx
|
||||
* poll if we are unable to accept another packet for transmission.
|
||||
*/
|
||||
|
||||
if (pic32mz_txdesc(priv) != NULL)
|
||||
{
|
||||
/* If so, update TCP timing states and poll the network 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?
|
||||
*/
|
||||
|
||||
pic32mz_timerpoll(priv);
|
||||
}
|
||||
|
||||
/* Setup the watchdog poll timer again */
|
||||
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_poll_expiry,
|
||||
1, priv);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_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:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void pic32mz_poll_work(void *arg)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
|
||||
net_lock_t state;
|
||||
|
||||
/* Perform the poll */
|
||||
|
||||
state = net_lock();
|
||||
pic32mz_poll_process(priv);
|
||||
net_unlock(state);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_poll_expiry
|
||||
*
|
||||
* Description:
|
||||
* Periodic timer handler. Called from the timer interrupt handler.
|
||||
@ -1890,27 +2189,35 @@ static void pic32mz_txtimeout(int argc, uint32_t arg, ...)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pic32mz_polltimer(int argc, uint32_t arg, ...)
|
||||
static void pic32mz_poll_expiry(int argc, wdparm_t arg, ...)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
|
||||
|
||||
/* Check if the next Tx descriptor is available. We cannot perform the Tx
|
||||
* poll if we are unable to accept another packet for transmission.
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
/* Is our single work structure available? It may not be if there are
|
||||
* pending interrupt actions.
|
||||
*/
|
||||
|
||||
if (pic32mz_txdesc(priv) != NULL)
|
||||
if (work_available(&priv->pd_work))
|
||||
{
|
||||
/* If so, update TCP timing states and poll the network 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?
|
||||
/* Schedule to perform the interrupt processing on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->pd_work, pic32mz_poll_work, priv, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just re-start the watchdog poll timer, missing one polling
|
||||
* cycle.
|
||||
*/
|
||||
|
||||
pic32mz_timerpoll(priv);
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_poll_expiry, 1, arg);
|
||||
}
|
||||
|
||||
/* Setup the watchdog poll timer again */
|
||||
#else
|
||||
/* Process the interrupt now */
|
||||
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_polltimer, 1, arg);
|
||||
pic32mz_poll_process(priv);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -2207,17 +2514,19 @@ static int pic32mz_ifup(struct net_driver_s *dev)
|
||||
|
||||
/* Set and activate a timer process */
|
||||
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_polltimer, 1,
|
||||
(void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_poll_expiry, 1,
|
||||
(uint32_t)priv);
|
||||
|
||||
/* Finally, enable the Ethernet interrupt at the interrupt controller */
|
||||
|
||||
priv->pd_ifup = true;
|
||||
|
||||
#if CONFIG_PIC32MZ_NINTERFACES > 1
|
||||
up_enable_irq(priv->pd_irqsrc);
|
||||
#else
|
||||
up_enable_irq(PIC32MZ_IRQ_ETH);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -2265,15 +2574,13 @@ static int pic32mz_ifdown(struct net_driver_s *dev)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_txavail
|
||||
* Function: pic32mz_txavail_process
|
||||
*
|
||||
* Description:
|
||||
* Driver callback invoked when new TX data is available. This is a
|
||||
* stimulus perform an out-of-cycle poll and, thereby, reduce the TX
|
||||
* latency.
|
||||
* Perform an out-of-cycle poll.
|
||||
*
|
||||
* Parameters:
|
||||
* dev - Reference to the NuttX driver state structure
|
||||
* dev - Reference to the NuttX driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
@ -2283,17 +2590,8 @@ static int pic32mz_ifdown(struct net_driver_s *dev)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pic32mz_txavail(struct net_driver_s *dev)
|
||||
static inline void pic32mz_txavail_process(struct pic32mz_driver_s *priv)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)dev->d_private;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Disable interrupts because this function may be called from interrupt
|
||||
* level processing.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Ignore the notification if the interface is not yet up */
|
||||
|
||||
if (priv->pd_ifup)
|
||||
@ -2309,8 +2607,90 @@ static int pic32mz_txavail(struct net_driver_s *dev)
|
||||
pic32mz_poll(priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_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 pic32mz_txavail_work(void *arg)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
|
||||
net_lock_t state;
|
||||
|
||||
/* Perform the poll */
|
||||
|
||||
state = net_lock();
|
||||
pic32mz_txavail_process(priv);
|
||||
net_unlock(state);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Function: pic32mz_txavail
|
||||
*
|
||||
* Description:
|
||||
* Driver callback invoked when new TX data is available. This is a
|
||||
* stimulus perform an out-of-cycle poll and, thereby, reduce the TX
|
||||
* latency.
|
||||
*
|
||||
* Parameters:
|
||||
* dev - Reference to the NuttX driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Called in normal user mode
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pic32mz_txavail(struct net_driver_s *dev)
|
||||
{
|
||||
struct pic32mz_driver_s *priv = (struct pic32mz_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(&priv->pd_work))
|
||||
{
|
||||
/* Schedule to serialize the poll on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->pd_work, pic32mz_txavail_work, priv, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
irqstate_t flags;
|
||||
|
||||
/* Disable interrupts because this function may be called from interrupt
|
||||
* level processing.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Perform the out-of-cycle poll now */
|
||||
|
||||
pic32mz_txavail_process(priv);
|
||||
leave_critical_section(flags);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -246,6 +246,7 @@ CONFIG_PIC32MX_T1PRIO=16
|
||||
# PIC32MX PHY/Ethernet device driver settings
|
||||
#
|
||||
# CONFIG_PIC32MX_MULTICAST is not set
|
||||
CONFIG_PIC32MX_ETHERNET_HPWORK=y
|
||||
|
||||
#
|
||||
# Device Configuration 0 (DEVCFG0)
|
||||
@ -422,6 +423,7 @@ CONFIG_NAME_MAX=32
|
||||
# CONFIG_SCHED_STARTHOOK is not set
|
||||
# CONFIG_SCHED_ATEXIT is not set
|
||||
# CONFIG_SCHED_ONEXIT is not set
|
||||
# CONFIG_SIG_EVTHREAD is not set
|
||||
|
||||
#
|
||||
# Signal Numbers
|
||||
@ -430,6 +432,7 @@ CONFIG_SIG_SIGUSR1=1
|
||||
CONFIG_SIG_SIGUSR2=2
|
||||
CONFIG_SIG_SIGALARM=3
|
||||
CONFIG_SIG_SIGCONDTIMEDOUT=16
|
||||
CONFIG_SIG_SIGWORK=17
|
||||
|
||||
#
|
||||
# POSIX Message Queue Options
|
||||
@ -441,8 +444,11 @@ CONFIG_MQ_MAXMSGSIZE=32
|
||||
#
|
||||
# Work queue support
|
||||
#
|
||||
# CONFIG_SCHED_WORKQUEUE is not set
|
||||
# CONFIG_SCHED_HPWORK is not set
|
||||
CONFIG_SCHED_WORKQUEUE=y
|
||||
CONFIG_SCHED_HPWORK=y
|
||||
CONFIG_SCHED_HPWORKPRIORITY=224
|
||||
CONFIG_SCHED_HPWORKPERIOD=50000
|
||||
CONFIG_SCHED_HPWORKSTACKSIZE=2048
|
||||
# CONFIG_SCHED_LPWORK is not set
|
||||
|
||||
#
|
||||
@ -574,7 +580,6 @@ CONFIG_ARCH_HAVE_NETDEV_STATISTICS=y
|
||||
# CONFIG_NET_DM90x0 is not set
|
||||
# CONFIG_ENC28J60 is not set
|
||||
# CONFIG_ENCX24J600 is not set
|
||||
|
||||
# CONFIG_NET_SLIP is not set
|
||||
# CONFIG_NET_FTMAC100 is not set
|
||||
|
||||
@ -668,7 +673,7 @@ CONFIG_RAMLOG_SYSLOG=y
|
||||
CONFIG_ARCH_HAVE_NET=y
|
||||
CONFIG_ARCH_HAVE_PHY=y
|
||||
CONFIG_NET=y
|
||||
# CONFIG_NET_NOINTS is not set
|
||||
CONFIG_NET_NOINTS=y
|
||||
# CONFIG_NET_PROMISCUOUS is not set
|
||||
|
||||
#
|
||||
|
@ -254,6 +254,7 @@ CONFIG_PIC32MX_USBPRIO=16
|
||||
# PIC32MX PHY/Ethernet device driver settings
|
||||
#
|
||||
# CONFIG_PIC32MX_MULTICAST is not set
|
||||
CONFIG_PIC32MX_ETHERNET_HPWORK=y
|
||||
|
||||
#
|
||||
# Device Configuration 0 (DEVCFG0)
|
||||
@ -431,6 +432,7 @@ CONFIG_NAME_MAX=32
|
||||
# CONFIG_SCHED_STARTHOOK is not set
|
||||
# CONFIG_SCHED_ATEXIT is not set
|
||||
# CONFIG_SCHED_ONEXIT is not set
|
||||
# CONFIG_SIG_EVTHREAD is not set
|
||||
|
||||
#
|
||||
# Signal Numbers
|
||||
@ -439,6 +441,7 @@ CONFIG_SIG_SIGUSR1=1
|
||||
CONFIG_SIG_SIGUSR2=2
|
||||
CONFIG_SIG_SIGALARM=3
|
||||
CONFIG_SIG_SIGCONDTIMEDOUT=16
|
||||
CONFIG_SIG_SIGWORK=17
|
||||
|
||||
#
|
||||
# POSIX Message Queue Options
|
||||
@ -450,8 +453,11 @@ CONFIG_MQ_MAXMSGSIZE=32
|
||||
#
|
||||
# Work queue support
|
||||
#
|
||||
# CONFIG_SCHED_WORKQUEUE is not set
|
||||
# CONFIG_SCHED_HPWORK is not set
|
||||
CONFIG_SCHED_WORKQUEUE=y
|
||||
CONFIG_SCHED_HPWORK=y
|
||||
CONFIG_SCHED_HPWORKPRIORITY=224
|
||||
CONFIG_SCHED_HPWORKPERIOD=50000
|
||||
CONFIG_SCHED_HPWORKSTACKSIZE=2048
|
||||
# CONFIG_SCHED_LPWORK is not set
|
||||
|
||||
#
|
||||
@ -593,7 +599,6 @@ CONFIG_ARCH_HAVE_NETDEV_STATISTICS=y
|
||||
# CONFIG_NET_DM90x0 is not set
|
||||
# CONFIG_ENC28J60 is not set
|
||||
# CONFIG_ENCX24J600 is not set
|
||||
|
||||
# CONFIG_NET_SLIP is not set
|
||||
# CONFIG_NET_FTMAC100 is not set
|
||||
|
||||
@ -731,7 +736,7 @@ CONFIG_SYSLOG_CONSOLE=y
|
||||
CONFIG_ARCH_HAVE_NET=y
|
||||
CONFIG_ARCH_HAVE_PHY=y
|
||||
CONFIG_NET=y
|
||||
# CONFIG_NET_NOINTS is not set
|
||||
CONFIG_NET_NOINTS=y
|
||||
# CONFIG_NET_PROMISCUOUS is not set
|
||||
|
||||
#
|
||||
|
@ -53,13 +53,14 @@
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/wdog.h>
|
||||
#include <nuttx/net/arp.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
# include <nuttx/wqueue.h>
|
||||
#endif
|
||||
|
||||
#include <nuttx/net/arp.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
# include <nuttx/net/pkt.h>
|
||||
#endif
|
||||
@ -185,11 +186,13 @@ static void skel_poll_expiry(int argc, wdparm_t arg, ...);
|
||||
|
||||
static int skel_ifup(FAR struct net_driver_s *dev);
|
||||
static int skel_ifdown(FAR struct net_driver_s *dev);
|
||||
|
||||
static inline void skel_txavail_process(FAR struct skel_driver_s *priv);
|
||||
#ifdef CONFIG_NET_NOINTS
|
||||
static void skel_txavail_work(FAR void *arg);
|
||||
#endif
|
||||
static int skel_txavail(FAR struct net_driver_s *dev);
|
||||
|
||||
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
|
||||
static int skel_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
|
||||
#ifdef CONFIG_NET_IGMP
|
||||
@ -610,7 +613,7 @@ static int skel_interrupt(int irq, FAR void *context)
|
||||
|
||||
{
|
||||
/* If a TX transfer just completed, then cancel the TX timeout so
|
||||
* there will be do race condition between any subsequent timeout
|
||||
* there will be no race condition between any subsequent timeout
|
||||
* expiration and the deferred interrupt processing.
|
||||
*/
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user