summaryrefslogtreecommitdiff
path: root/nuttx/drivers/net
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-09-17 18:35:37 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-09-17 18:35:37 +0000
commit24acf10752079d502696d57e20c2078b4e2ea801 (patch)
tree1701d3d2c3f6c456a04442336d5fa406bf553b55 /nuttx/drivers/net
parentb468f0fc17590b77076802afd66e23cb78373943 (diff)
downloadnuttx-24acf10752079d502696d57e20c2078b4e2ea801.tar.gz
nuttx-24acf10752079d502696d57e20c2078b4e2ea801.tar.bz2
nuttx-24acf10752079d502696d57e20c2078b4e2ea801.zip
Resync new repository with old repo r5166
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5154 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/drivers/net')
-rw-r--r--nuttx/drivers/net/Kconfig9
-rw-r--r--nuttx/drivers/net/enc28j60.c244
-rw-r--r--nuttx/drivers/net/enc28j60.h8
3 files changed, 201 insertions, 60 deletions
diff --git a/nuttx/drivers/net/Kconfig b/nuttx/drivers/net/Kconfig
index b5c09bf01..a42d35fea 100644
--- a/nuttx/drivers/net/Kconfig
+++ b/nuttx/drivers/net/Kconfig
@@ -25,6 +25,7 @@ config ENC28J60
References:
ENC28J60 Data Sheet, Stand-Alone Ethernet Controller with SPI Interface,
DS39662C, 2008 Microchip Technology Inc.
+
if ENC28J60
config ENC28J60_NINTERFACES
int "Number of physical ENC28J60"
@@ -61,6 +62,14 @@ config ENC28J60_HALFDUPPLEX
default n
---help---
Default is full duplex
+
+config ENC28J60_DUMPPACKET
+ bool "Dump Packets"
+ default n
+ ---help---
+ If selected, the ENC28J60 driver will dump the contents of each
+ packet to the console.
+
endif
config NET_E1000
diff --git a/nuttx/drivers/net/enc28j60.c b/nuttx/drivers/net/enc28j60.c
index d3c735b11..bb79910b3 100644
--- a/nuttx/drivers/net/enc28j60.c
+++ b/nuttx/drivers/net/enc28j60.c
@@ -110,7 +110,7 @@
/* We need to have the work queue to handle SPI interrupts */
-#if !defined(CONFIG_SCHED_WORKQUEUE) && !defined(CONFIG_SPI_OWNBUS)
+#ifndef CONFIG_SCHED_WORKQUEUE
# error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
#endif
@@ -122,6 +122,12 @@
# define enc_dumppacket(m,a,n)
#endif
+/* The ENC28J60 will not do interrupt level processing */
+
+#ifndef CONFIG_NET_NOINTS
+# warrning "CONFIG_NET_NOINTS should be set"
+#endif
+
/* Timing *******************************************************************/
/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */
@@ -144,7 +150,7 @@
#define ALIGNED_BUFSIZE ((CONFIG_NET_BUFSIZE + 255) & ~255)
#define PKTMEM_TX_START 0x0000 /* Start TX buffer at 0 */
-#define PKTMEM_TX_ENDP1 ALIGNED_BUFSIZE /* Allow TX buffer for one frame + */
+#define PKTMEM_TX_ENDP1 ALIGNED_BUFSIZE /* Allow TX buffer for one frame */
#define PKTMEM_RX_START PKTMEM_TX_ENDP1 /* Followed by RX buffer */
#define PKTMEM_RX_END PKTMEM_END /* RX buffer goes to the end of SRAM */
@@ -171,7 +177,7 @@
enum enc_state_e
{
- ENCSTATE_UNIT = 0, /* The interface is in an unknown state */
+ ENCSTATE_UNINIT = 0, /* The interface is in an uninitialized state */
ENCSTATE_DOWN, /* The interface is down */
ENCSTATE_UP /* The interface is up */
};
@@ -200,10 +206,10 @@ struct enc_driver_s
/* If we don't own the SPI bus, then we cannot do SPI accesses from the
* interrupt handler.
*/
-
-#ifndef CONFIG_SPI_OWNBUS
- struct work_s work; /* Work queue support */
-#endif
+
+ struct work_s irqwork; /* Interrupt continuation work queue support */
+ struct work_s towork; /* Tx timeout work queue support */
+ struct work_s pollwork; /* Poll timeout work queue support */
/* This is the contained SPI driver intstance */
@@ -279,15 +285,17 @@ static void enc_txif(FAR struct enc_driver_s *priv);
static void enc_txerif(FAR struct enc_driver_s *priv);
static void enc_txerif(FAR struct enc_driver_s *priv);
static void enc_rxerif(FAR struct enc_driver_s *priv);
-static void enc_rxdispath(FAR struct enc_driver_s *priv);
+static void enc_rxdispatch(FAR struct enc_driver_s *priv);
static void enc_pktif(FAR struct enc_driver_s *priv);
-static void enc_worker(FAR void *arg);
+static void enc_irqworker(FAR void *arg);
static int enc_interrupt(int irq, FAR void *context);
/* Watchdog timer expirations */
-static void enc_polltimer(int argc, uint32_t arg, ...);
+static void enc_toworker(FAR void *arg);
static void enc_txtimeout(int argc, uint32_t arg, ...);
+static void enc_pollworker(FAR void *arg);
+static void enc_polltimer(int argc, uint32_t arg, ...);
/* NuttX callback functions */
@@ -652,14 +660,14 @@ static uint8_t enc_rdbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg)
DEBUGASSERT(priv && priv->spi);
- /* Select ENC28J60 chip */
-
- enc_select(priv);
-
/* Set the bank */
enc_setbank(priv, GETBANK(ctrlreg));
+ /* Select ENC28J60 chip */
+
+ enc_select(priv);
+
/* Send the RCR command and collect the data. How we collect the data
* depends on if this is a PHY/CAN or not. The normal sequence requires
* 16-clocks: 8 to clock out the cmd and 8 to clock in the data.
@@ -672,10 +680,10 @@ static uint8_t enc_rdbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg)
* 8 dummy bits, and 8 to clock in the PHY/MAC data.
*/
- (void)SPI_SEND(priv->spi, 0); /* Clock in the dummy byte */
+ (void)SPI_SEND(priv->spi, 0); /* Clock in the dummy byte */
}
- rddata = SPI_SEND(priv->spi, 0); /* Clock in the data */
+ rddata = SPI_SEND(priv->spi, 0); /* Clock in the data */
/* De-select ENC28J60 chip */
@@ -1026,6 +1034,7 @@ static int enc_transmit(FAR struct enc_driver_s *priv)
* OK on success; a negated errno on failure
*
* Assumptions:
+ * Interrupts are enabled but the caller holds the uIP lock.
*
****************************************************************************/
@@ -1095,6 +1104,7 @@ static void enc_linkstatus(FAR struct enc_driver_s *priv)
* None
*
* Assumptions:
+ * Interrupts are enabled but the caller holds the uIP lock.
*
****************************************************************************/
@@ -1195,7 +1205,7 @@ static void enc_rxerif(FAR struct enc_driver_s *priv)
}
/****************************************************************************
- * Function: enc_rxdispath
+ * Function: enc_rxdispatch
*
* Description:
* Give the newly received packet to uIP.
@@ -1207,10 +1217,11 @@ static void enc_rxerif(FAR struct enc_driver_s *priv)
* None
*
* Assumptions:
+ * Interrupts are enabled but the caller holds the uIP lock.
*
****************************************************************************/
-static void enc_rxdispath(FAR struct enc_driver_s *priv)
+static void enc_rxdispatch(FAR struct enc_driver_s *priv)
{
/* We only accept IP packets of the configured type and ARP packets */
@@ -1267,6 +1278,7 @@ static void enc_rxdispath(FAR struct enc_driver_s *priv)
* None
*
* Assumptions:
+ * Interrupts are enabled but the caller holds the uIP lock.
*
****************************************************************************/
@@ -1326,7 +1338,7 @@ static void enc_pktif(FAR struct enc_driver_s *priv)
nlldbg("Bad packet size dropped (%d)\n", pktlen);
#ifdef CONFIG_ENC28J60_STATS
priv->stats.rxpktlen++;
-#endif
+#endif
}
/* Otherwise, read and process the packet */
@@ -1340,11 +1352,11 @@ static void enc_pktif(FAR struct enc_driver_s *priv)
/* Copy the data data from the receive buffer to priv->dev.d_buf */
enc_rdbuffer(priv, priv->dev.d_buf, priv->dev.d_len);
- enc_dumppacket("Received Packet", priv->ld_dev.d_buf, priv->ld_dev.d_len);
+ enc_dumppacket("Received Packet", priv->dev.d_buf, priv->dev.d_len);
/* Dispatch the packet to uIP */
- enc_rxdispath(priv);
+ enc_rxdispatch(priv);
}
/* Move the RX read pointer to the start of the next received packet.
@@ -1360,7 +1372,7 @@ static void enc_pktif(FAR struct enc_driver_s *priv)
}
/****************************************************************************
- * Function: enc_worker
+ * Function: enc_irqworker
*
* Description:
* Perform interrupt handling logic outside of the interrupt handler (on
@@ -1376,14 +1388,26 @@ static void enc_pktif(FAR struct enc_driver_s *priv)
*
****************************************************************************/
-static void enc_worker(FAR void *arg)
+static void enc_irqworker(FAR void *arg)
{
FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+ uip_lock_t lock;
uint8_t eir;
DEBUGASSERT(priv);
- /* Disable further interrupts by clearing the global interrup enable bit */
+ /* Get exclusive access to uIP. */
+
+ lock = uip_lock();
+
+ /* Disable further interrupts by clearing the global interrupt enable bit.
+ * "After an interrupt occurs, the host controller should clear the global
+ * enable bit for the interrupt pin before servicing the interrupt. Clearing
+ * the enable bit will cause the interrupt pin to return to the non-asserted
+ * state (high). Doing so will prevent the host controller from missing a
+ * falling edge should another interrupt occur while the immediate interrupt
+ * is being serviced."
+ */
enc_bfcgreg(priv, ENC_EIE, EIE_INTIE);
@@ -1395,9 +1419,12 @@ static void enc_worker(FAR void *arg)
while ((eir = enc_rdgreg(priv, ENC_EIR) & EIR_ALLINTS) != 0)
{
/* Handle interrupts according to interrupt register register bit
- * settings
- *
- * DMAIF: The DMA interrupt indicates that the DMA module has completed
+ * settings.
+ */
+
+ nllvdbg("EIR: %02x\n", eir);
+
+ /* DMAIF: The DMA interrupt indicates that the DMA module has completed
* its memory copy or checksum calculation. Additionally, this interrupt
* will be caused if the host controller cancels a DMA operation by
* manually clearing the DMAST bit. Once set, DMAIF can only be cleared
@@ -1514,6 +1541,8 @@ static void enc_worker(FAR void *arg)
uint8_t pktcnt = enc_rdbreg(priv, ENC_EPKTCNT);
if (pktcnt > 0)
{
+ nllvdbg("EPKTCNT: %02x\n", pktcnt);
+
#ifdef CONFIG_ENC28J60_STATS
if (pktcnt > priv->stats.maxpktcnt)
{
@@ -1551,12 +1580,19 @@ static void enc_worker(FAR void *arg)
enc_rxerif(priv); /* Handle the RX error */
enc_bfcgreg(priv, ENC_EIR, EIR_RXERIF); /* Clear the RXERIF interrupt */
}
-
}
+ /* Release lock on uIP */
+
+ uip_unlock(lock);
+
/* Enable Ethernet interrupts */
enc_bfsgreg(priv, ENC_EIE, EIE_INTIE);
+
+ /* Enable GPIO interrupts */
+
+ priv->lower->enable(priv->lower);
}
/****************************************************************************
@@ -1580,15 +1616,6 @@ static int enc_interrupt(int irq, FAR void *context)
{
register FAR struct enc_driver_s *priv = &g_enc28j60[0];
-#ifdef CONFIG_SPI_OWNBUS
- /* In very simple environments, we own the SPI and can do data transfers
- * from the interrupt handler. That is actually a very bad idea in any
- * case because it keeps interrupts disabled for a long time.
- */
-
- enc_worker((FAR void*)priv);
- return OK;
-#else
/* In complex environments, we cannot do SPI transfers from the interrupt
* handler because semaphores are probably used to lock the SPI bus. In
* this case, we will defer processing to the worker thread. This is also
@@ -1596,20 +1623,26 @@ static int enc_interrupt(int irq, FAR void *context)
* a good thing to do in any event.
*/
- return work_queue(HPWORK, &priv->work, enc_worker, (FAR void *)priv, 0);
-#endif
+ DEBUGASSERT(work_available(&priv->irqwork));
+
+ /* Notice that further GPIO interrupts are disabled until the work is
+ * actually performed. This is to prevent overrun of the worker thread.
+ * Interrupts are re-enabled in enc_irqworker() when the work is completed.
+ */
+
+ priv->lower->disable(priv->lower);
+ return work_queue(HPWORK, &priv->irqwork, enc_irqworker, (FAR void *)priv, 0);
}
/****************************************************************************
- * Function: enc_txtimeout
+ * Function: enc_toworker
*
* Description:
- * Our TX watchdog timed out. Called from the timer interrupt handler.
- * The last TX never completed. Reset the hardware and start again.
+ * Our TX watchdog timed out. This is the worker thread continuation of
+ * the watchdog timer interrupt. Reset the hardware and start again.
*
* Parameters:
- * argc - The number of available arguments
- * arg - The first argument
+ * arg - The reference to the driver structure (case to void*)
*
* Returned Value:
* None
@@ -1618,14 +1651,21 @@ static int enc_interrupt(int irq, FAR void *context)
*
****************************************************************************/
-static void enc_txtimeout(int argc, uint32_t arg, ...)
+static void enc_toworker(FAR void *arg)
{
FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+ uip_lock_t lock;
int ret;
+ nlldbg("Tx timeout\n");
+ DEBUGASSERT(priv);
+
+ /* Get exclusive access to uIP. */
+
+ lock = uip_lock();
+
/* Increment statistics and dump debug info */
- nlldbg("Tx timeout\n");
#ifdef CONFIG_ENC28J60_STATS
priv->stats.txtimeouts++;
#endif
@@ -1642,13 +1682,18 @@ static void enc_txtimeout(int argc, uint32_t arg, ...)
/* Then poll uIP for new XMIT data */
(void)uip_poll(&priv->dev, enc_uiptxpoll);
+
+ /* Release lock on uIP */
+
+ uip_unlock(lock);
}
/****************************************************************************
- * Function: enc_polltimer
+ * Function: enc_txtimeout
*
* Description:
- * Periodic timer handler. Called from the timer interrupt handler.
+ * Our TX watchdog timed out. Called from the timer interrupt handler.
+ * The last TX never completed. Perform work on the worker thread.
*
* Parameters:
* argc - The number of available arguments
@@ -1661,9 +1706,55 @@ static void enc_txtimeout(int argc, uint32_t arg, ...)
*
****************************************************************************/
-static void enc_polltimer(int argc, uint32_t arg, ...)
+static void enc_txtimeout(int argc, uint32_t arg, ...)
{
FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+ int ret;
+
+ /* In complex environments, we cannot do SPI transfers from the timout
+ * handler because semaphores are probably used to lock the SPI bus. In
+ * this case, we will defer processing to the worker thread. This is also
+ * much kinder in the use of system resources and is, therefore, probably
+ * a good thing to do in any event.
+ */
+
+ DEBUGASSERT(priv && work_available(&priv->towork));
+
+ /* Notice that Tx timeout watchdog is not active so further Tx timeouts
+ * can occur until we restart the Tx timeout watchdog.
+ */
+
+ ret = work_queue(HPWORK, &priv->towork, enc_toworker, (FAR void *)priv, 0);
+ DEBUGASSERT(ret == OK);
+}
+
+/****************************************************************************
+ * Function: enc_pollworker
+ *
+ * Description:
+ * Periodic timer handler continuation.
+ *
+ * Parameters:
+ * argc - The number of available arguments
+ * arg - The first argument
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_pollworker(FAR void *arg)
+{
+ FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+ uip_lock_t lock;
+
+ DEBUGASSERT(priv);
+
+ /* Get exclusive access to uIP. */
+
+ lock = uip_lock();
/* Verify that the hardware is ready to send another packet. The driver
* start a transmission process by setting ECON1.TXRTS. When the packet is
@@ -1681,12 +1772,55 @@ static void enc_polltimer(int argc, uint32_t arg, ...)
(void)uip_timer(&priv->dev, enc_uiptxpoll, ENC_POLLHSEC);
}
+ /* Release lock on uIP */
+
+ uip_unlock(lock);
+
/* Setup the watchdog poll timer again */
(void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1, arg);
}
/****************************************************************************
+ * Function: enc_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:
+ *
+ ****************************************************************************/
+
+static void enc_polltimer(int argc, uint32_t arg, ...)
+{
+ FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+ int ret;
+
+ /* In complex environments, we cannot do SPI transfers from the timout
+ * handler because semaphores are probably used to lock the SPI bus. In
+ * this case, we will defer processing to the worker thread. This is also
+ * much kinder in the use of system resources and is, therefore, probably
+ * a good thing to do in any event.
+ */
+
+ DEBUGASSERT(priv && work_available(&priv->pollwork));
+
+ /* Notice that poll watchdog is not active so further poll timeouts can
+ * occur until we restart the poll timeout watchdog.
+ */
+
+ ret = work_queue(HPWORK, &priv->pollwork, enc_pollworker, (FAR void *)priv, 0);
+ DEBUGASSERT(ret == OK);
+}
+
+/****************************************************************************
* Function: enc_ifup
*
* Description:
@@ -1727,11 +1861,9 @@ static int enc_ifup(struct uip_driver_s *dev)
*/
enc_wrphy(priv, ENC_PHIE, PHIE_PGEIE | PHIE_PLNKIE);
- enc_bfsgreg(priv, ENC_EIE, EIE_INTIE | EIE_PKTIE);
- enc_bfsgreg(priv, ENC_EIR, EIR_DMAIF | EIR_LINKIF | EIR_TXIF |
- EIR_TXERIF | EIR_RXERIF | EIR_PKTIF);
- enc_wrgreg(priv, ENC_EIE, EIE_INTIE | EIE_PKTIE | EIE_LINKIE |
- EIE_TXIE | EIE_TXERIE | EIE_RXERIE);
+ enc_bfcgreg(priv, ENC_EIR, EIR_ALLINTS);
+ enc_wrgreg(priv, ENC_EIE, EIE_INTIE | EIE_PKTIE | EIE_LINKIE |
+ EIE_TXIE | EIE_TXERIE | EIE_RXERIE);
/* Enable the receiver */
@@ -2160,7 +2292,7 @@ static int enc_reset(FAR struct enc_driver_s *priv)
enc_wrbreg(priv, ENC_MAIPGL, 0x12);
- /* Set ack-to-Back Inter-Packet Gap */
+ /* Set Back-to-Back Inter-Packet Gap */
enc_wrbreg(priv, ENC_MABBIPG, 0x15);
#endif
@@ -2245,7 +2377,7 @@ int enc_initialize(FAR struct spi_dev_s *spi,
* bringing the interface up.
*/
- priv->ifstate = ENCSTATE_UNIT;
+ priv->ifstate = ENCSTATE_UNINIT;
/* Attach the interrupt to the driver (but don't enable it yet) */
diff --git a/nuttx/drivers/net/enc28j60.h b/nuttx/drivers/net/enc28j60.h
index 3c787c533..dab9cc5cf 100644
--- a/nuttx/drivers/net/enc28j60.h
+++ b/nuttx/drivers/net/enc28j60.h
@@ -131,10 +131,10 @@
#define ECON1_BSEL_SHIFT (0) /* Bits 0-1: Bank select */
#define ECON1_BSEL_MASK (3 << ECON1_BSEL_SHIFT)
-# define ECON1_BSEL_BANK0 (0 << 0) /* Bank 0 */
-# define ECON1_BSEL_BANK1 (1 << 1) /* Bank 1 */
-# define ECON1_BSEL_BANK2 (2 << 0) /* Bank 2 */
-# define ECON1_BSEL_BANK3 (3 << 0) /* Bank 3 */
+# define ECON1_BSEL_BANK0 (0 << ECON1_BSEL_SHIFT) /* Bank 0 */
+# define ECON1_BSEL_BANK1 (1 << ECON1_BSEL_SHIFT) /* Bank 1 */
+# define ECON1_BSEL_BANK2 (2 << ECON1_BSEL_SHIFT) /* Bank 2 */
+# define ECON1_BSEL_BANK3 (3 << ECON1_BSEL_SHIFT) /* Bank 3 */
#define ECON1_RXEN (1 << 2) /* Bit 2: Receive Enable */
#define ECON1_TXRTS (1 << 3) /* Bit 3: Transmit Request to Send */
#define ECON1_CSUMEN (1 << 4) /* Bit 4: DMA Checksum Enable */