diff --git a/arch/arm/src/lpc17xx/Kconfig b/arch/arm/src/lpc17xx/Kconfig index e17100b4c7..0352eb0876 100644 --- a/arch/arm/src/lpc17xx/Kconfig +++ b/arch/arm/src/lpc17xx/Kconfig @@ -517,6 +517,12 @@ config ADC_CHANLIST (2) provide an array g_adc_chanlist[] with the channel numbers matching the ADC0_MASK within the board-specific library. +config ADC_BURSTMODE + bool "One interrupt at the end of all ADC cconversions" + default n + ---help--- + Select this if you want to generate only one interrupt once all selected channels has been converted by the ADC + config ADC_NCHANNELS int "ADC0 number of channels" depends on ADC_CHANLIST @@ -727,6 +733,13 @@ config NET_MULTICAST Enable receipt of multicast (and unicast) frames. Automatically set if NET_IGMP is selected. +config NET_WORKER_THREAD + bool "Net worker thread enable" + default y + depends on SCHED_WORKQUEUE + ---help--- + Enable use of ethernet worker thread (depends on CONFIG_SCHED_WORKQUEUE). + endmenu menu "LCD device driver options" diff --git a/arch/arm/src/lpc17xx/lpc17_ethernet.c b/arch/arm/src/lpc17xx/lpc17_ethernet.c index 0f5495ed04..97a154722f 100644 --- a/arch/arm/src/lpc17xx/lpc17_ethernet.c +++ b/arch/arm/src/lpc17xx/lpc17_ethernet.c @@ -52,6 +52,7 @@ #include #include +#include #include #include #include @@ -275,6 +276,12 @@ struct lpc17_driver_s WDOG_ID lp_txpoll; /* TX poll timer */ WDOG_ID lp_txtimeout; /* TX timeout timer */ +#ifdef CONFIG_NET_WORKER_THREAD + struct work_s irqwork_txdone; /* Interrupt continuation work queue support */ + struct work_s irqwork_rxdone; /* Interrupt continuation work queue support */ + uint32_t status; +#endif /*CONFIG_NET_WORKER_THREAD*/ + #if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET) struct lpc17_statistics_s lp_stat; #endif @@ -332,6 +339,10 @@ static int lpc17_txpoll(struct net_driver_s *dev); static void lpc17_response(struct lpc17_driver_s *priv); static void lpc17_rxdone(struct lpc17_driver_s *priv); static void lpc17_txdone(struct lpc17_driver_s *priv); +#ifdef CONFIG_NET_WORKER_THREAD +static void lpc17_eth_irqworker_txdone(FAR void *arg); +static void lpc17_eth_irqworker_rxdone(FAR void *arg); +#endif /*CONFIG_NET_WORKER_THREAD*/ static int lpc17_interrupt(int irq, void *context); /* Watchdog timer expirations */ @@ -731,20 +742,20 @@ static void lpc17_response(struct lpc17_driver_s *priv) ret = lpc17_txdesc(priv); if (ret == OK) { - /* Yes.. queue the packet now. */ + /* Yes.. queue the packet now. */ - lpc17_transmit(priv); + lpc17_transmit(priv); } else { - /* No.. mark the Tx as pending and halt further Tx interrupts */ + /* No.. mark the Tx as pending and halt further Tx interrupts */ - DEBUGASSERT((priv->lp_inten & ETH_INT_TXDONE) != 0); + DEBUGASSERT((priv->lp_inten & ETH_INT_TXDONE) != 0); - priv->lp_txpending = true; - priv->lp_inten &= ~ETH_RXINTS; - lpc17_putreg(priv->lp_inten, LPC17_ETH_INTEN); - EMAC_STAT(priv, tx_pending); + priv->lp_txpending = true; + priv->lp_inten &= ~ETH_TXINTS; + lpc17_putreg(priv->lp_inten, LPC17_ETH_INTEN); + EMAC_STAT(priv, tx_pending); } } @@ -981,6 +992,46 @@ static void lpc17_txdone(struct lpc17_driver_s *priv) } } +/**************************************************************************** + * Function: lpc17_eth_irqworker_txdone and lpc17_eth_irqworker_rxdone + * + * Description: + * Perform interrupt handling logic outside of the interrupt handler (on + * the work queue thread). + * + * Parameters: + * arg - The reference to the driver structure (case to void*) + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_WORKER_THREAD +static void lpc17_eth_irqworker_txdone(FAR void *arg) +{ + FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg; + + DEBUGASSERT(priv); + + lpc17_txdone(priv); + + work_cancel(HPWORK, &priv->irqwork_txdone); +} + +static void lpc17_eth_irqworker_rxdone(FAR void *arg) +{ + FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg; + + DEBUGASSERT(priv); + + lpc17_rxdone(priv); + work_cancel(HPWORK, &priv->irqwork_rxdone); +} +#endif /*CONFIG_NET_WORKER_THREAD */ + /**************************************************************************** * Function: lpc17_interrupt * @@ -1078,28 +1129,30 @@ static int lpc17_interrupt(int irq, void *context) /* RX FINISHED -- Triggered when all receive descriptors have * been processed i.e. on the transition to the situation * where ProduceIndex == ConsumeIndex. - */ - - if ((status & ETH_INT_RXFIN) != 0) - { - EMAC_STAT(priv, rx_finished); -#if 0 /* REVISIT: Reported to cause false alarm assertions */ - DEBUGASSERT(lpc17_getreg(LPC17_ETH_RXPRODIDX) == lpc17_getreg(LPC17_ETH_RXCONSIDX)); -#endif - } - - /* RX DONE -- Triggered when a receive descriptor has been + * + * Treated as INT_RX_DONE if ProduceIndex != ConsumeIndex so the + * packets are processed anyway. + * + * RX DONE -- Triggered when a receive descriptor has been * processed while the Interrupt bit in the Control field of * the descriptor was set. */ - if ((status & ETH_INT_RXDONE) != 0) + if ((status & ETH_INT_RXFIN) != 0 || (status & ETH_INT_RXDONE) != 0) { EMAC_STAT(priv, rx_done); /* We have received at least one new incoming packet. */ +#ifdef CONFIG_NET_WORKER_THREAD + work_queue(HPWORK, &priv->irqwork_rxdone, + (worker_t)lpc17_eth_irqworker_rxdone, + (FAR void *)priv, 0); + +#else /*CONFIG_NET_WORKER_THREAD*/ lpc17_rxdone(priv); + +#endif /*CONFIG_NET_WORKER_THREAD*/ } /* Check for Tx events ********************************************/ @@ -1136,7 +1189,19 @@ static int lpc17_interrupt(int irq, void *context) /* A packet transmission just completed */ +#ifdef CONFIG_NET_WORKER_THREAD + /* Disable the Ethernet interrupt for now, will be re-enabled + * later + */ + + work_queue(HPWORK, &priv->irqwork_txdone, + (worker_t)lpc17_eth_irqworker_txdone, + (FAR void *)priv, 0); + +#else /*CONFIG_NET_WORKER_THREAD*/ lpc17_txdone(priv); + +#endif /*CONFIG_NET_WORKER_THREAD*/ } } } @@ -1215,6 +1280,8 @@ static void lpc17_txtimeout(int argc, uint32_t arg, ...) static void lpc17_polltimer(int argc, uint32_t arg, ...) { struct lpc17_driver_s *priv = (struct lpc17_driver_s *)arg; + unsigned int prodidx; + unsigned int considx; /* 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. @@ -1230,6 +1297,27 @@ static void lpc17_polltimer(int argc, uint32_t arg, ...) (void)devif_timer(&priv->lp_dev, lpc17_txpoll, LPC17_POLLHSEC); } + /* Simulate a fake receive to relaunch the data exchanges when a receive + * interrupt has been lost and all the receive buffers are used. + */ + + /* Get the current producer and consumer indices */ + + considx = lpc17_getreg(LPC17_ETH_RXCONSIDX) & ETH_RXCONSIDX_MASK; + prodidx = lpc17_getreg(LPC17_ETH_RXPRODIDX) & ETH_RXPRODIDX_MASK; + + if (considx != prodidx) + { +#if CONFIG_NET_WORKER_THREAD + work_queue(HPWORK, &priv->irqwork_rxdone, + (worker_t)lpc17_eth_irqworker_rxdone, + (FAR void *)priv, 0); + +#else /*CONFIG_NET_WORKER_THREAD*/ + lpc17_rxdone(priv); + +#endif /*CONFIG_NET_WORKER_THREAD*/ + /* Setup the watchdog poll timer again */ (void)wd_start(priv->lp_txpoll, LPC17_WDDELAY, lpc17_polltimer, 1, arg); @@ -1466,13 +1554,17 @@ static int lpc17_ifdown(struct net_driver_s *dev) static int lpc17_txavail(struct net_driver_s *dev) { struct lpc17_driver_s *priv = (struct lpc17_driver_s *)dev->d_private; +#ifndef CONFIG_NET_WORKER_THREAD irqstate_t flags; +#endif /*CONFIG_NET_WORKER_THREAD*/ /* Disable interrupts because this function may be called from interrupt * level processing. */ +#ifndef CONFIG_NET_WORKER_THREAD flags = irqsave(); +#endif /*CONFIG_NET_WORKER_THREAD*/ /* Ignore the notification if the interface is not yet up */ @@ -1488,7 +1580,9 @@ static int lpc17_txavail(struct net_driver_s *dev) } } +#ifndef CONFIG_NET_WORKER_THREAD irqrestore(flags); +#endif /*CONFIG_NET_WORKER_THREAD*/ return OK; } @@ -1845,7 +1939,12 @@ static int lpc17_phymode(uint8_t phyaddr, uint8_t mode) for (timeout = MII_BIG_TIMEOUT; timeout > 0; timeout--) { -#ifdef CONFIG_ETH0_PHY_DP83848C + /* REVISIT: This should not depend explicity on the board configuration. + * Rather, there should be some additional configuration option to + * suppress this DP83848C-specific behavior. + */ + +#if defined(CONFIG_ETH0_PHY_DP83848C) && !defined(CONFIG_ARCH_BOARD_MBED) phyreg = lpc17_phyread(phyaddr, MII_DP83848C_STS); if ((phyreg & 0x0001) != 0) {