STM32 F7 Ethernet: Add cache operations to make sure we have data coherency when accessing all DMA-related data

This commit is contained in:
Gregory Nutt 2015-07-19 17:04:43 -06:00
parent 2ce3c75264
commit bab4a5308a

View File

@ -64,9 +64,9 @@
# include <nuttx/net/pkt.h> # include <nuttx/net/pkt.h>
#endif #endif
#include "cache.h"
#include "up_internal.h" #include "up_internal.h"
#include "chip.h"
#include "chip/stm32_syscfg.h" #include "chip/stm32_syscfg.h"
#include "chip/stm32_pinmap.h" #include "chip/stm32_pinmap.h"
#include "stm32_gpio.h" #include "stm32_gpio.h"
@ -1065,6 +1065,11 @@ static int stm32_transmit(struct stm32_ethmac_s *priv)
DEBUGASSERT(txdesc && (txdesc->tdes0 & ETH_TDES0_OWN) == 0); DEBUGASSERT(txdesc && (txdesc->tdes0 & ETH_TDES0_OWN) == 0);
/* Flush the contents of the TX buffer into physical memory */
arch_clean_dcache((uintptr_t)priv->dev.d_buf,
(uintptr_t)priv->dev.d_buf + priv->dev.d_len);
/* Is the size to be sent greater than the size of the Ethernet buffer? */ /* Is the size to be sent greater than the size of the Ethernet buffer? */
DEBUGASSERT(priv->dev.d_len > 0 && priv->dev.d_buf != NULL); DEBUGASSERT(priv->dev.d_len > 0 && priv->dev.d_buf != NULL);
@ -1130,7 +1135,17 @@ static int stm32_transmit(struct stm32_ethmac_s *priv)
/* Give the descriptor to DMA */ /* Give the descriptor to DMA */
txdesc->tdes0 |= ETH_TDES0_OWN; txdesc->tdes0 |= ETH_TDES0_OWN;
txdesc = (struct eth_txdesc_s *)txdesc->tdes3;
/* Flush the contents of the modified TX descriptor into physical
* memory.
*/
arch_clean_dcache((uintptr_t)txdesc,
(uintptr_t)txdesc + sizeof(struct eth_txdesc_s));
/* Get the next descriptor in the link list */
txdesc = (struct eth_txdesc_s *)txdesc->tdes3;
} }
} }
else else
@ -1157,6 +1172,13 @@ static int stm32_transmit(struct stm32_ethmac_s *priv)
txdesc->tdes0 |= ETH_TDES0_OWN; txdesc->tdes0 |= ETH_TDES0_OWN;
/* Flush the contents of the modified TX descriptor into physical
* memory.
*/
arch_clean_dcache((uintptr_t)txdesc,
(uintptr_t)txdesc + sizeof(struct eth_txdesc_s));
/* Point to the next available TX descriptor */ /* Point to the next available TX descriptor */
txdesc = (struct eth_txdesc_s *)txdesc->tdes3; txdesc = (struct eth_txdesc_s *)txdesc->tdes3;
@ -1483,12 +1505,26 @@ static void stm32_freesegment(struct stm32_ethmac_s *priv,
nllvdbg("rxfirst: %p segments: %d\n", rxfirst, segments); nllvdbg("rxfirst: %p segments: %d\n", rxfirst, segments);
/* Set OWN bit in RX descriptors. This gives the buffers back to DMA */ /* Give the freed RX buffers back to the Ethernet MAC to be refilled */
rxdesc = rxfirst; rxdesc = rxfirst;
for (i = 0; i < segments; i++) for (i = 0; i < segments; i++)
{ {
/* Set OWN bit in RX descriptors. This gives the buffers back to DMA */
rxdesc->rdes0 = ETH_RDES0_OWN; rxdesc->rdes0 = ETH_RDES0_OWN;
/* Make sure that the modified RX descriptor is written to physical
* memory.
*/
arch_clean_dcache((uintptr_t)rxdesc,
(uintptr_t)rxdesc + sizeof(struct eth_rxdesc_s));
/* Get the next RX descriptor in the chain (cache coherency should not
* be an issue because the link address is constant.
*/
rxdesc = (struct eth_rxdesc_s *)rxdesc->rdes3; rxdesc = (struct eth_rxdesc_s *)rxdesc->rdes3;
} }
@ -1571,6 +1607,11 @@ static int stm32_recvframe(struct stm32_ethmac_s *priv)
priv->inflight < CONFIG_STM32F7_ETH_NTXDESC; priv->inflight < CONFIG_STM32F7_ETH_NTXDESC;
i++) i++)
{ {
/* Forces the descriptor to be re-read from physical memory */
arch_invalidate_dcache((uintptr_t)rxdesc,
(uintptr_t)rxdesc + sizeof(struct eth_rxdesc_s));
/* Check if this is the first segment in the frame */ /* Check if this is the first segment in the frame */
if ((rxdesc->rdes0 & ETH_RDES0_FS) != 0 && if ((rxdesc->rdes0 & ETH_RDES0_FS) != 0 &&
@ -1614,7 +1655,7 @@ static int stm32_recvframe(struct stm32_ethmac_s *priv)
{ {
struct net_driver_s *dev = &priv->dev; struct net_driver_s *dev = &priv->dev;
/* Get the Frame Length of the received packet: substruct 4 /* Get the Frame Length of the received packet: subtract 4
* bytes of the CRC * bytes of the CRC
*/ */
@ -1637,16 +1678,32 @@ static int stm32_recvframe(struct stm32_ethmac_s *priv)
dev->d_buf = (uint8_t*)rxcurr->rdes2; dev->d_buf = (uint8_t*)rxcurr->rdes2;
rxcurr->rdes2 = (uint32_t)buffer; rxcurr->rdes2 = (uint32_t)buffer;
/* Return success, remebering where we should re-start scanning /* Make sure that the modified RX descriptor is written to
* and resetting the segment scanning logic * physical memory.
*/
arch_clean_dcache((uintptr_t)rxcurr,
(uintptr_t)rxdesc + sizeof(struct eth_rxdesc_s));
/* Remember where we should re-start scanning and reset the segment
* scanning logic
*/ */
priv->rxhead = (struct eth_rxdesc_s *)rxdesc->rdes3; priv->rxhead = (struct eth_rxdesc_s *)rxdesc->rdes3;
stm32_freesegment(priv, rxcurr, priv->segments); stm32_freesegment(priv, rxcurr, priv->segments);
/* Force the completed RX DMA buffer to be re-read from
* physical memory.
*/
arch_invalidate_dcache((uintptr_t)dev->d_buf,
(uintptr_t)dev->d_buf + dev->d_len);
nllvdbg("rxhead: %p d_buf: %p d_len: %d\n", nllvdbg("rxhead: %p d_buf: %p d_len: %d\n",
priv->rxhead, dev->d_buf, dev->d_len); priv->rxhead, dev->d_buf, dev->d_len);
/* Return success*/
return OK; return OK;
} }
else else
@ -1721,9 +1778,9 @@ static void stm32_receive(struct stm32_ethmac_s *priv)
} }
#ifdef CONFIG_NET_PKT #ifdef CONFIG_NET_PKT
/* When packet sockets are enabled, feed the frame into the packet tap */ /* When packet sockets are enabled, feed the frame into the packet tap */
pkt_input(&priv->dev); pkt_input(&priv->dev);
#endif #endif
/* We only accept IP packets of the configured type and ARP packets */ /* We only accept IP packets of the configured type and ARP packets */
@ -1877,6 +1934,11 @@ static void stm32_freeframe(struct stm32_ethmac_s *priv)
{ {
DEBUGASSERT(priv->inflight > 0); DEBUGASSERT(priv->inflight > 0);
/* Force re-reading of the TX descriptor for physical memory */
arch_invalidate_dcache((uintptr_t)txdesc,
(uintptr_t)txdesc + sizeof(struct eth_txdesc_s));
for (i = 0; (txdesc->tdes0 & ETH_TDES0_OWN) == 0; i++) for (i = 0; (txdesc->tdes0 & ETH_TDES0_OWN) == 0; i++)
{ {
/* There should be a buffer assigned to all in-flight /* There should be a buffer assigned to all in-flight
@ -1901,7 +1963,14 @@ static void stm32_freeframe(struct stm32_ethmac_s *priv)
txdesc->tdes2 = 0; txdesc->tdes2 = 0;
/* Check if this is the last segement of a TX frame */ /* Flush the contents of the modified TX descriptor into
* physical memory.
*/
arch_clean_dcache((uintptr_t)txdesc,
(uintptr_t)txdesc + sizeof(struct eth_txdesc_s));
/* Check if this is the last segment of a TX frame */
if ((txdesc->tdes0 & ETH_TDES0_LS) != 0) if ((txdesc->tdes0 & ETH_TDES0_LS) != 0)
{ {
@ -1928,6 +1997,11 @@ static void stm32_freeframe(struct stm32_ethmac_s *priv)
/* Try the next descriptor in the TX chain */ /* Try the next descriptor in the TX chain */
txdesc = (struct eth_txdesc_s *)txdesc->tdes3; txdesc = (struct eth_txdesc_s *)txdesc->tdes3;
/* Force re-reading of the TX descriptor for physical memory */
arch_invalidate_dcache((uintptr_t)txdesc,
(uintptr_t)txdesc + sizeof(struct eth_txdesc_s));
} }
/* We get here if (1) there are still frames "in-flight". Remember /* We get here if (1) there are still frames "in-flight". Remember