From e1d55397788939bc4029621acc7090472e03d8b0 Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 13 Mar 2012 16:15:24 +0000 Subject: [PATCH] Correct PIC32 Ethernet Tx ring handling git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4484 42af7a65-404d-4744-a932-0658087f49c3 --- arch/mips/src/pic32mx/pic32mx-ethernet.c | 110 ++++++++++++++++------- 1 file changed, 80 insertions(+), 30 deletions(-) diff --git a/arch/mips/src/pic32mx/pic32mx-ethernet.c b/arch/mips/src/pic32mx/pic32mx-ethernet.c index 8bbd629067..1638df4682 100644 --- a/arch/mips/src/pic32mx/pic32mx-ethernet.c +++ b/arch/mips/src/pic32mx/pic32mx-ethernet.c @@ -116,6 +116,10 @@ # define CONFIG_NET_NTXDESC 2 #endif +#if CONFIG_NET_NTXDESC > 255 +# error "The number of TX descriptors exceeds the range of a uint8_t index" +#endif + #ifndef CONFIG_NET_NRXDESC # define CONFIG_NET_NRXDESC 4 #endif @@ -335,6 +339,7 @@ struct pic32mx_driver_s #ifdef PIC32MX_HAVE_PHY uint8_t pd_phyaddr; /* PHY device address */ #endif + uint8_t pd_txnext; /* Index to the next Tx descriptor */ uint32_t pd_inten; /* Shadow copy of INTEN register */ WDOG_ID pd_txpoll; /* TX poll timer */ WDOG_ID pd_txtimeout; /* TX timeout timer */ @@ -396,7 +401,8 @@ static void pic32mx_freebuffer(struct pic32mx_driver_s *priv, uint8_t *buffer); static inline void pic32mx_txdescinit(struct pic32mx_driver_s *priv); static inline void pic32mx_rxdescinit(struct pic32mx_driver_s *priv); -static struct pic32mx_txdesc_s *pic32mx_txdesc(struct pic32mx_driver_s *priv); +static inline struct pic32mx_txdesc_s *pic32mx_txdesc(struct pic32mx_driver_s *priv); +static inline void pic32mx_txnext(struct pic32mx_driver_s *priv); static inline void pic32mx_rxreturn(struct pic32mx_rxdesc_s *rxdesc); static struct pic32mx_rxdesc_s *pic32mx_rxdesc(struct pic32mx_driver_s *priv); @@ -765,6 +771,10 @@ static inline void pic32mx_txdescinit(struct pic32mx_driver_s *priv) pic32mx_dumptxdesc(txdesc, "Initial"); } + /* Position the Tx index to the first descriptor in the ring */ + + priv->pd_txnext = 0; + /* Update the ETHTXST register with the physical address of the head of * the TX descriptors list. */ @@ -843,49 +853,85 @@ static inline void pic32mx_rxdescinit(struct pic32mx_driver_s *priv) * Function: pic32mx_txdesc * * Description: - * Check if a free TX descriptor is available. + * Check if the next Tx descriptor is available. * * Parameters: * priv - Reference to the driver state structure * * Returned Value: - * A pointer to an available TX descriptor on success; NULL on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. + * A pointer to the next available Tx descriptor on success; NULL if the + * next Tx dscriptor is not available. * ****************************************************************************/ -static struct pic32mx_txdesc_s *pic32mx_txdesc(struct pic32mx_driver_s *priv) +static inline struct pic32mx_txdesc_s *pic32mx_txdesc(struct pic32mx_driver_s *priv) { struct pic32mx_txdesc_s *txdesc; - int i; - /* Inspect the list of TX descriptors to see if the EOWN bit is cleared. If it - * is, this descriptor is now under software control and the message was - * transmitted. + /* Get a reference to the next Tx descriptor in the ring */ + + txdesc = &priv->pd_txdesc[priv->pd_txnext]; + + /* Check if the EOWN bit is cleared. If it is, this descriptor is now under + * software control and the message has been transmitted. + * + * Also check that the buffer address is NULL. There is a race condition + * in that the hardware may have completed the transfer, but there may + * still be a valid buffer attached to the Tx descriptor because we have + * not yet processed the Tx done condition. We will know that the Tx + * done condition has been processed when the buffer has been freed and + * reset to zero. */ - for (i = 0; i < CONFIG_NET_NTXDESC; i++) + if ((txdesc->status & TXDESC_STATUS_EOWN) == 0 && txdesc->address == 0) { - /* Check if software owns this descriptor */ + /* Yes.. return a pointer to the descriptor */ - txdesc = &priv->pd_txdesc[i]; - if ((txdesc->status & TXDESC_STATUS_EOWN) == 0) - { - /* Yes.. return a pointer to the desciptor */ - - return txdesc; - } + return txdesc; } - /* All descriptors are owned by the Ethernet controller.. return NULL */ + /* The next Tx descriptor is still owned by the Ethernet controller.. the + * Tx ring if full and cannot be used now. Return NULL. + */ return NULL; } +/**************************************************************************** + * Function: pic32mx_txnext + * + * Description: + * After the next Tx descriptor has been given to the hardware, update the + * index to the next Tx descriptor in the ring. + * + * Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static inline void pic32mx_txnext(struct pic32mx_driver_s *priv) +{ + /* Increment the index to the next Tx descriptor in the ring */ + + int txnext = priv->pd_txnext + 1; + + /* If the new index would go beyond the end of the allocated descriptors + * for the Tx ring, then reset to first descriptor. + */ + + if (txnext >= CONFIG_NET_NTXDESC) + { + txnext = 0; + } + + /* Save the index to the next Tx descriptor */ + + priv->pd_txnext = txnext; +} + /**************************************************************************** * Function: pic32mx_rxreturn * @@ -1005,7 +1051,7 @@ static int pic32mx_transmit(struct pic32mx_driver_s *priv) * the message. */ - /* Find the first available TX descriptor. We are guaranteed that is will + /* Find the next available TX descriptor. We are guaranteed that is will * not fail by upstream logic that assures that a TX packet is available * before polling uIP. */ @@ -1038,6 +1084,10 @@ static int pic32mx_transmit(struct pic32mx_driver_s *priv) txdesc->status = status; pic32mx_dumptxdesc(txdesc, "After transmit setup"); + /* Update the index to the next descriptor to use in the Tx ring */ + + pic32mx_txnext(priv); + /* Enable the transmission of the message by setting the TXRTS bit (ETHCON1:9). */ pic32mx_putreg(ETH_CON1_TXRTS | ETH_CON1_ON, PIC32MX_ETH_CON1SET); @@ -1097,8 +1147,8 @@ static int pic32mx_uiptxpoll(struct uip_driver_s *dev) uip_arp_out(&priv->pd_dev); pic32mx_transmit(priv); - /* Check if there is room in the device to hold another packet. If not, - * return any non-zero value to terminate the poll. + /* Check if the next TX descriptor is avaialable. If not, return any + * non-zero value to terminate the poll. */ if (pic32mx_txdesc(priv) == NULL || sq_empty(&priv->pd_freebuffers)) @@ -1144,7 +1194,7 @@ static void pic32mx_response(struct pic32mx_driver_s *priv) { struct pic32mx_txdesc_s *txdesc; - /* Check if there is room in the device to hold another packet. */ + /* Check if the next TX descriptor is available. */ txdesc = pic32mx_txdesc(priv); if (txdesc != NULL) @@ -1696,8 +1746,8 @@ static void pic32mx_polltimer(int argc, uint32_t arg, ...) { struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg; - /* 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. + /* 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 (pic32mx_txdesc(priv) != NULL) @@ -2107,7 +2157,7 @@ static int pic32mx_txavail(struct uip_driver_s *dev) if (priv->pd_ifup) { - /* Check if there is room in the hardware to hold another outgoing packet. */ + /* Check if the next Tx descriptor is available. */ if (pic32mx_txdesc(priv) != NULL) {