arch/arm/src/lpc54xx: Correct handling of the Ethernet RBU error. With this fix, Ethernet now appears to be fully functional although still undertested.

This commit is contained in:
Gregory Nutt
2018-01-01 15:08:19 -06:00
parent 24b594cbc4
commit c3d3e91a3f
4 changed files with 111 additions and 35 deletions
+1 -1
View File
@@ -300,7 +300,7 @@
# define ETH_MAC_FRAME_FILTER_PCF_FILTERED (3 << ETH_MAC_FRAME_FILTER_PCF_SHIFT) /* Control frames accepted if pass the address filter */
#define ETH_MAC_FRAME_FILTER_SAIF (1 << 8) /* Bit 8: SA inverse filtering */
#define ETH_MAC_FRAME_FILTER_SAF (1 << 9) /* Bit 9: Source address filter enable */
#define ETH_MAC_FRAME_FILTER_RA (1 << 31) /* Bit 31: Receive all */
#define ETH_MAC_FRAME_FILTER_RA (1 << 31) /* Bit 31: Receive all */
/* MAC watchdog timeout */
#define ETH_MAC_WD_TIMEROUT_
+76 -17
View File
@@ -368,7 +368,7 @@ static uint32_t lpc54_getreg(uintptr_t addr);
static void lpc54_putreg(uint32_t val, uintptr_t addr);
#else
# define lpc54_getreg(addr) getreg32(addr)
# define lpc54_putreg(val,addr) lpc54_putreg(val,addr)
# define lpc54_putreg(val,addr) putreg32(val,addr)
#endif
/* Common TX logic */
@@ -381,7 +381,7 @@ static int lpc54_eth_txpoll(struct net_driver_s *dev);
/* Interrupt handling */
static void lpc54_eth_rxdisptch(struct lpc54_ethdriver_s *priv);
static void lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
static int lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
unsigned int chan);
static void lpc54_eth_txdone(struct lpc54_ethdriver_s *priv,
unsigned int chan);
@@ -1020,14 +1020,14 @@ static void lpc54_eth_rxdisptch(struct lpc54_ethdriver_s *priv)
* chan - The channel with the completed Rx transfer
*
* Returned Value:
* None
* The number of Rx descriptors processed
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static void lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
static int lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
unsigned int chan)
{
struct lpc54_rxring_s *rxring;
@@ -1036,8 +1036,8 @@ static void lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
unsigned int pktlen;
unsigned int supply;
uint32_t regval;
bool lastframe = false;
bool suspend;
int ndesc;
/* Get the Rx ring associated with this channel */
@@ -1048,16 +1048,31 @@ static void lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
regval = lpc54_getreg(LPC54_ETH_DMACH_STAT(chan));
suspend = ((regval & ETH_DMACH_INT_RBU) != 0);
/* Loop until the last received frame is encountered */
/* Loop until the next full frame is encountered or until we encounter a
* descriptor still owned by the DMA.
*/
pktlen = 0;
while (!lastframe)
ndesc = 0;
for (; ; )
{
/* Get the last Rx descriptor in the ring */
supply = rxring->rr_supply;
rxdesc = rxring->rr_desc + supply;
/* Is this frame still owned by the DMA? */
if ((rxdesc->ctrl & ETH_RXDES3_OWN) != 0)
{
/* Yes.. then bail */
return ndesc;
}
ndesc++;
/* Set the supplier index to the next descriptor */
if (++(rxring->rr_supply) > rxring->rr_ndesc)
@@ -1067,7 +1082,7 @@ static void lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
/* Is this the last descriptor of the frame? */
if (rxdesc->ctrl & ETH_RXDES3_LD)
if ((rxdesc->ctrl & ETH_RXDES3_LD) != 0)
{
/* Have we been discarding Rx data? If so, that was the last
* packet to be discarded.
@@ -1081,10 +1096,9 @@ static void lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
{
/* Last frame encountered. This is a valid packet */
lastframe = true;
framelen = (rxdesc->ctrl & ETH_RXDES3_PL_MASK);
pktlen += framelen;
pktlen += framelen;
if (pktlen > 0)
{
/* Recover the buffer.
@@ -1138,6 +1152,8 @@ static void lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
#endif
rxdesc->ctrl = regval;
}
return ndesc;
}
}
else if (!priv->eth_rxdiscard)
@@ -1162,15 +1178,23 @@ static void lpc54_eth_receive(struct lpc54_ethdriver_s *priv,
}
}
/* Restart the receiver if it was suspended. */
/* Restart the receiver and clear the RBU status if it was suspended. */
if (suspend)
{
uintptr_t regaddr = LPC54_ETH_DMACH_RXDESC_TAIL_PTR(chan);
/* Clear the RBU status */
lpc54_putreg(ETH_DMACH_INT_RBU, LPC54_ETH_DMACH_STAT(chan));
/* Writing to the tail pointer register will restart the Rx processing */
regval = lpc54_getreg(regaddr);
lpc54_putreg(regval, regaddr);
}
return ndesc;
}
/****************************************************************************
@@ -1295,9 +1319,12 @@ static void lpc54_eth_channel_work(struct lpc54_ethdriver_s *priv,
if ((pending & LPC54_ABNORM_INTMASK) != 0)
{
/* Acknowledge the normal receive interrupt */
/* Acknowledge the abnormal interrupt interrupts except for RBU...
* that is a special case where the status will be cleared in
* lpc54_eth_receive(). See comments below.
*/
lpc54_putreg(LPC54_ABNORM_INTMASK, regaddr);
lpc54_putreg((LPC54_ABNORM_INTMASK & ~ETH_DMACH_INT_RBU), regaddr);
/* Handle the incoming packet */
@@ -1316,6 +1343,25 @@ static void lpc54_eth_channel_work(struct lpc54_ethdriver_s *priv,
NETDEV_TXERRORS(priv->eth_dev);
}
/* The Receive Buffer Unavailable (RBU) error is a special case. It
* means that we have an Rx overrun condition: All of the Rx buffers
* have been filled with packet data and there are no Rx descriptors
* available to receive the next packet.
*
* Often RBU is accompanied by RI but we need to force that condition
* in all cases. In the case of RBU, we need to perform receive
* processing in order to recover from the situation and to resume.
*
* This is really a configuration problem: It really means that we
* have not assigned enough Rx buffers for the environment and
* addressing filtering options that we have selected.
*/
if ((pending & ETH_DMACH_INT_RBU) != 0)
{
pending |= ETH_DMACH_INT_RI;
}
pending &= ~LPC54_ABNORM_INTMASK;
}
@@ -1323,18 +1369,31 @@ static void lpc54_eth_channel_work(struct lpc54_ethdriver_s *priv,
if ((pending & ETH_DMACH_INT_RI) != 0)
{
int ndesc;
/* Acknowledge the normal receive interrupt */
lpc54_putreg(ETH_DMACH_INT_RI | ETH_DMACH_INT_NI, regaddr);
pending &= ~(ETH_DMACH_INT_RI | ETH_DMACH_INT_NI);
/* Update statistics */
/* Loop until all available Rx packets in the ring have been processed */
NETDEV_RXPACKETS(priv->eth_dev);
for (; ; )
{
/* Dispatch the next packet from the Rx ring */
/* Handle the incoming packet */
ndesc = lpc54_eth_receive(priv, chan);
if (ndesc > 0)
{
/* Update statistics if a packet was dispatched */
lpc54_eth_receive(priv, chan);
NETDEV_RXPACKETS(priv->eth_dev);
}
else
{
break;
}
}
}
/* Check for a transmit interrupt */
+25 -9
View File
@@ -47,8 +47,8 @@ STATUS
in receiving the button events, especially when the button is
released. But if you do not press the buttons too quickly all events
are processed. This, I suspect, is a consequence of the strong glitch
filtering that is enbled in the pin configuration. Snappier
response my be obtainble with filtering off.
filtering that is enabled in the pin configuration. Snappier
response my be obtainable with filtering off.
2017-12-17: Added a driver for the FT5x06 capacitive, multi-touch
controller. Add support logic for the LPCXpresso-LPC54528 to
initialize and the register the FT5x06 driver. Unfortunately, the
@@ -84,11 +84,13 @@ STATUS
access timing in some way???
2017-12-30: Completed implementation of an Ethernet driver. Untested as
of this writing. Also added the netnsh configuration will, eventually,
be used to test the Ethernet diver.
be used to test the Ethernet driver.
2018-01-01: There Ethernet driver appears to be fully functional although
more testing is certainly needed.
There is still no support for the Accelerometer, SPIFI, or USB. There are
complete but not-yet-functional SD card and Ethernet drivers. There is a
partial SPI driver, but no on-board SPI devices to test it.
There is still no support for the Accelerometer, SPIFI, or USB. There is a
complete but not-yet-functional SD card. There is a partial SPI driver,
but no on-board SPI devices to test it.
Configurations
==============
@@ -223,7 +225,8 @@ Configurations
------
This is a special version of the NuttShell (nsh) configuration that is
tailored for network testing. This version derives from nsh
configuration so manhy of the notes apply there except as noted below.
configuration so many of the notes there apply here except as noted
below.
NOTES:
@@ -231,6 +234,9 @@ Configurations
and RJ45 network connector. Support is enabled for IPv4, IPv6, TCP/IP,
UDP, ICMP, ICMPv6, and ARP.
The default IP addresses are 10.0.0.2 (IPv4) and fc00::2 (IPv6). You
should reconfigure these as appropriate for your test network.
2. SD card and I2C support are not enabled. The I2C tool application is
not enabled
@@ -248,6 +254,16 @@ Configurations
nsh> ifup eth0
6. Telnet is supported, but the Telnet daemon must be started manually
like:
nsh> telnetd ipv4
Use the argument 'ipv6' to run telnet in the IPv6 address space. With
the above command, you can create a remote Telnet session via:
$ telnet 10.0.0.2
nsh:
Configures the NuttShell (nsh) application located at examples/nsh.
@@ -354,8 +370,8 @@ Configurations
There are noticeable delays in receiving the button events,
especially when the button is released. But if you do not press the
buttons too quickly all events are processed. This, I suspect, is a
consequence of the strong glitch filtering that is enbled in the pin
configuration. Snappier response my be obtainble with filtering off
consequence of the strong glitch filtering that is enabled in the pin
configuration. Snappier response my be obtainable with filtering off
if desired.
5. This configuration has been used for testing the SDMMC driver with
+9 -8
View File
@@ -70,8 +70,8 @@
* Name: arp_arpin
*
* Description:
* This function should be called by the Ethernet device driver when an ARP
* packet has been received. The function will act differently
* This function should be called by the Ethernet device driver when an
* ARP packet has been received. The function will act differently
* depending on the ARP packet type: if it is a reply for a request
* that we previously sent out, the ARP cache will be filled in with
* the values from the ARP reply. If the incoming ARP packet is an ARP
@@ -82,10 +82,11 @@
* Ethernet header is present in the d_buf buffer and that the length of
* the packet is set in the d_len field.
*
* When the function returns, the value of the field d_len indicates whether
* the device driver should send out the ARP reply packet or not. If d_len
* is zero, no packet should be sent; If d_len is non-zero, it contains the
* length of the outbound packet that is present in the d_buf buffer.
* When the function returns, the value of the field d_len indicates
* whether the device driver should send out the ARP reply packet or not.
* If d_len is zero, no packet should be sent; If d_len is non-zero, it
* contains the length of the outbound packet that is present in the
* d_buf buffer.
*
****************************************************************************/
@@ -107,7 +108,7 @@ void arp_arpin(FAR struct net_driver_s *dev)
switch (arp->ah_opcode)
{
case HTONS(ARP_REQUEST):
ninfo("ARP request for IP %04lx\n", (long)ipaddr);
ninfo("ARP request for IP %04lx\n", (unsigned long)ipaddr);
/* ARP request. If it asked for our address, we send out a reply. */
@@ -139,7 +140,7 @@ void arp_arpin(FAR struct net_driver_s *dev)
break;
case HTONS(ARP_REPLY):
ninfo("ARP reply for IP %04lx\n", (long)ipaddr);
ninfo("ARP reply for IP %04lx\n", (unsigned long)ipaddr);
/* ARP reply. We insert or update the ARP table if it was meant
* for us.