Handle RX descriptor wrapping

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1602 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2009-03-14 14:24:22 +00:00
parent 3390476f74
commit 78c50dbfb6

View File

@ -347,10 +347,11 @@ static int ez80emac_miiconfigure(FAR struct ez80emac_driver_s *priv);
static void ez80emac_machash(FAR ubyte *mac, int *ndx, int *bitno)
#endif
/* Common TX logic */
/* Common TX/RX logic */
static int ez80emac_transmit(struct ez80emac_driver_s *priv);
static int ez80emac_uiptxpoll(struct uip_driver_s *dev);
static int ez80emac_receive(struct ez80emac_driver_s *priv);
/* Interrupt handling */
@ -1070,6 +1071,172 @@ static int ez80emac_uiptxpoll(struct uip_driver_s *dev)
return ret;
}
/****************************************************************************
* Function: ez80emac_receive
*
* Description:
* Process received packets pending in the RX buffer
*
* Parameters:
* priv - Driver data instance
*
* Returned Value:
* 0: Success, but nothing received
* >0: Success, number of packets received
* <0: ERROR, negated error number
*
* Returned Value:
* Interrupts are disabled
*
****************************************************************************/
static int ez80emac_receive(struct ez80emac_driver_s *priv)
{
FAR struct ez80emac_desc_s *rxdesc = priv->rxnext;
ubyte *psrc;
ubyte *pdest;
int pktlen;
int npackets;
/* The RRP register points to where the next Receive packet is read from.
* The read-only EMAC Receive Write Pointer (RWP) egisters reports the
* current RxDMA Receive Write pointer. The RxDMA block uses the RRP[12:5]
* to compare to RWP[12:5] for determining how many buffers remain. The
* result is the BLKSLFT register.
*/
nvdbg("rxnext=%p {%06x, %u, %04x} rrp=%02x%02x rwp=%02x%02x blkslft=%02x\n",
rxdesc, rxdesc->np, rxdesc->pktsize, rxdesc->stat,
inp(EZ80_EMAC_RRP_H), inp(EZ80_EMAC_RRP_L),
inp(EZ80_EMAC_RWP_H), inp(EZ80_EMAC_RWP_L),
inp(EZ80_EMAC_BLKSLFT_H), inp(EZ80_EMAC_BLKSLFT_L));
/* The RxDMA reads the data from the RxFIFO and stores it in the EMAC
* memory Receive buffer. When the end of the packet is detected, the
* RxDMA reads the next two bytes from the RxFIFO and writes them into
* the Rx descriptor status LSB and MSB. The packet length counter is
* stored into the descriptor table packet length field, the descriptor
* table next pointer is written into the Rx descriptor table and finally
* the Rx_DONE_STAT bit in the EMAC Interrupt Status Register register is
* set to 1.
*/
/* Process all packets that ownership has been given to the ez80 */
npackets = 0;
while ((rxdesc->stat & EMAC_TXDESC_OWNER) != 0)
{
if ((rxdesc->stat & EMAC_RXDESC_OK) == 0)
{
nvdbg("Skipping bad RX pkt: %04x\n", rxdesc->stat);
continue;
}
/* We have a good packet. Check if the packet is a valid size
* for the uIP buffer configuration (I routinely see
*/
if (rxdesc->pktsize > CONFIG_NET_BUFSIZE)
{
nvdbg("Truncated oversize RX pkt: %d->%d\n", rxdesc->pktsize, CONFIG_NET_BUFSIZE);
pktlen = CONFIG_NET_BUFSIZE;
}
else
{
pktlen = rxdesc->pktsize;
}
/* Copy the data data from the hardware to priv->dev.d_buf */
psrc = (FAR ubyte*)priv->rxnext + SIZEOF_EMACSDESC;
pdest = priv->dev.d_buf;
/* Check for wraparound */
if ((FAR ubyte*)(psrc + pktlen) > (FAR ubyte*)priv->rxendp1)
{
int nbytes = (int)((FAR ubyte*)priv->rxendp1 - (FAR ubyte*)psrc);
nvdbg("RX wraps after %d bytes\n", nbytes + SIZEOF_EMACSDESC);
memcpy(pdest, psrc, nbytes);
memcpy(&pdest[nbytes], priv->rxstart, pktlen - nbytes);
}
else
{
memcpy(pdest, psrc, pktlen);
}
/* Set the amount of data in priv->dev.d_len */
priv->dev.d_len = pktlen;
/* Reclaim the Rx descriptor */
priv->rxnext = (FAR struct ez80emac_desc_s *)rxdesc->np;
rxdesc->np = 0;
rxdesc->pktsize = 0;
rxdesc->stat = 0;
rxdesc = priv->rxnext;
nvdbg("rxnext=%p {%06x, %u, %04x} rrp=%02x%02x rwp=%02x%02x blkslft=%02x\n",
rxdesc, rxdesc->np, rxdesc->pktsize, rxdesc->stat,
inp(EZ80_EMAC_RRP_H), inp(EZ80_EMAC_RRP_L),
inp(EZ80_EMAC_RWP_H), inp(EZ80_EMAC_RWP_L),
inp(EZ80_EMAC_BLKSLFT_H), inp(EZ80_EMAC_BLKSLFT_L));
/* We only accept IP packets of the configured type and ARP packets */
#ifdef CONFIG_NET_IPv6
if (ETHBUF->type == HTONS(UIP_ETHTYPE_IP6))
#else
if (ETHBUF->type == HTONS(UIP_ETHTYPE_IP))
#endif
{
nvdbg("IP packet received (%02x)\n", ETHBUF->type);
EMAC_STAT(priv, rx_ip);
uip_arp_ipin();
uip_input(&priv->dev);
/* If the above function invocation resulted in data that should be
* sent out on the network, the field d_len will set to a value > 0.
*/
if (priv->dev.d_len > 0)
{
uip_arp_out(&priv->dev);
ez80emac_transmit(priv);
}
}
else if (ETHBUF->type == htons(UIP_ETHTYPE_ARP))
{
nvdbg("ARP packet received (%02x)\n", ETHBUF->type);
EMAC_STAT(priv, rx_arp);
uip_arp_arpin(&priv->dev);
/* If the above function invocation resulted in data that should be
* sent out on the network, the field d_len will set to a value > 0.
*/
if (priv->dev.d_len > 0)
{
ez80emac_transmit(priv);
}
}
#ifdef CONFIG_DEBUG
else
{
ndbg("Unsupported packet type dropped (%02x)\n", ETHBUF->type);
EMAC_STAT(priv, rx_dropped);
}
#endif
npackets++;
}
return npackets;
}
/****************************************************************************
* Function: ez80emac_txinterrupt
*
@ -1195,9 +1362,7 @@ static int ez80emac_txinterrupt(int irq, FAR void *context)
static int ez80emac_rxinterrupt(int irq, FAR void *context)
{
FAR struct ez80emac_driver_s *priv = &g_emac;
FAR struct ez80emac_desc_s *rxdesc = priv->rxnext;
ubyte istat;
int pktlen;
/* EMAC Rx interrupts:
*
@ -1216,122 +1381,9 @@ static int ez80emac_rxinterrupt(int irq, FAR void *context)
EMAC_STAT(priv, rx_int);
/* The RRP register points to where the next Receive packet is read from.
* The read-only EMAC Receive Write Pointer (RWP) egisters reports the
* current RxDMA Receive Write pointer. The RxDMA block uses the RRP[12:5]
* to compare to RWP[12:5] for determining how many buffers remain. The
* result is the BLKSLFT register.
*/
/* Process any RX packets pending the RX buffer */
nvdbg("rxnext=%p {%06x, %u, %04x} rrp=%02x%02x rwp=%02x%02x blkslft=%02x istat=%02x\n",
rxdesc, rxdesc->np, rxdesc->pktsize, rxdesc->stat,
inp(EZ80_EMAC_RRP_H), inp(EZ80_EMAC_RRP_L),
inp(EZ80_EMAC_RWP_H), inp(EZ80_EMAC_RWP_L),
inp(EZ80_EMAC_BLKSLFT_H), inp(EZ80_EMAC_BLKSLFT_L),
istat);
/* The RxDMA reads the data from the RxFIFO and stores it in the EMAC
* memory Receive buffer. When the end of the packet is detected, the
* RxDMA reads the next two bytes from the RxFIFO and writes them into
* the Rx descriptor status LSB and MSB. The packet length counter is
* stored into the descriptor table packet length field, the descriptor
* table next pointer is written into the Rx descriptor table and finally
* the Rx_DONE_STAT bit in the EMAC Interrupt Status Register register is
* set to 1.
*/
/* Check if this packet was received intact */
if ((rxdesc->stat & EMAC_RXDESC_OK) == 0)
{
/* No frame received in this descriptor yet */
return OK;
}
/* We have a good packet. Check if the packet is a valid size
* for the uIP buffer configuration
*/
if (rxdesc->pktsize > CONFIG_NET_BUFSIZE)
{
nvdbg("receive oversize pkt\n");
pktlen = CONFIG_NET_BUFSIZE;
}
else
{
pktlen = rxdesc->pktsize;
}
/* Copy the data data from the hardware to priv->dev.d_buf. Set
* amount of data in priv->dev.d_len
*/
memcpy(priv->dev.d_buf, (FAR ubyte*)priv->rxnext + SIZEOF_EMACSDESC, pktlen);
priv->dev.d_len = pktlen;
/* Reclaim the Rx descriptor */
priv->rxnext = (FAR struct ez80emac_desc_s *)rxdesc->np;
rxdesc->np = 0;
rxdesc->pktsize = 0;
rxdesc->stat = 0;
nvdbg("rxnext=%p {%06x, %u, %04x} rrp=%02x%02x rwp=%02x%02x blkslft=%02x istat=%02x\n",
rxdesc, rxdesc->np, rxdesc->pktsize, rxdesc->stat,
inp(EZ80_EMAC_RRP_H), inp(EZ80_EMAC_RRP_L),
inp(EZ80_EMAC_RWP_H), inp(EZ80_EMAC_RWP_L),
inp(EZ80_EMAC_BLKSLFT_H), inp(EZ80_EMAC_BLKSLFT_L),
istat);
/* We only accept IP packets of the configured type and ARP packets */
#ifdef CONFIG_NET_IPv6
if (ETHBUF->type == HTONS(UIP_ETHTYPE_IP6))
#else
if (ETHBUF->type == HTONS(UIP_ETHTYPE_IP))
#endif
{
nvdbg("IP packet received (%02x)\n", ETHBUF->type);
EMAC_STAT(priv, rx_ip);
uip_arp_ipin();
uip_input(&priv->dev);
/* If the above function invocation resulted in data that should be
* sent out on the network, the field d_len will set to a value > 0.
*/
if (priv->dev.d_len > 0)
{
uip_arp_out(&priv->dev);
ez80emac_transmit(priv);
}
}
else if (ETHBUF->type == htons(UIP_ETHTYPE_ARP))
{
nvdbg("ARP packet received (%02x)\n", ETHBUF->type);
EMAC_STAT(priv, rx_arp);
uip_arp_arpin(&priv->dev);
/* If the above function invocation resulted in data that should be
* sent out on the network, the field d_len will set to a value > 0.
*/
if (priv->dev.d_len > 0)
{
ez80emac_transmit(priv);
}
}
#ifdef CONFIG_DEBUG
else
{
ndbg("Unsupported packet type dropped (%02x)\n", ETHBUF->type);
EMAC_STAT(priv, rx_dropped);
}
#endif
(void)ez80emac_receive(priv);
return OK;
}