STM32 F7 Ethernet: Add cache operations to make sure we have data coherency when accessing all DMA-related data
This commit is contained in:
parent
2ce3c75264
commit
bab4a5308a
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user