imxrt:Enet ensure proper dcache for Writeback mode
Use aligned_data added proper handeling for Writeback
This commit is contained in:
parent
522a949ed5
commit
0628019c2c
@ -154,28 +154,6 @@
|
|||||||
# error "Need at least one RX buffer"
|
# error "Need at least one RX buffer"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NENET_NBUFFERS \
|
|
||||||
(CONFIG_IMXRT_ENET_NTXBUFFERS + CONFIG_IMXRT_ENET_NRXBUFFERS)
|
|
||||||
|
|
||||||
/* Normally you would clean the cache after writing new values to the DMA
|
|
||||||
* memory so assure that the dirty cache lines are flushed to memory
|
|
||||||
* before the DMA occurs. And you would invalid the cache after a data is
|
|
||||||
* received via DMA so that you fetch the actual content of the data from
|
|
||||||
* the cache.
|
|
||||||
*
|
|
||||||
* These conditions are not fully supported here. If the write-throuch
|
|
||||||
* D-Cache is enabled, however, then many of these issues go away: The
|
|
||||||
* cache clean operation does nothing (because there are not dirty cache
|
|
||||||
* lines) and the cache invalid operation is innocuous (because there are
|
|
||||||
* never dirty cache lines to be lost; valid data will always be reloaded).
|
|
||||||
*
|
|
||||||
* At present, we simply insist that write through cache be enabled.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(CONFIG_ARMV7M_DCACHE) && !defined(CONFIG_ARMV7M_DCACHE_WRITETHROUGH)
|
|
||||||
# error Write back D-Cache not yet supported
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Align assuming that the D-Cache is enabled (probably 32-bytes).
|
/* Align assuming that the D-Cache is enabled (probably 32-bytes).
|
||||||
*
|
*
|
||||||
* REVISIT: The size of descriptors and buffers must also be in even units
|
* REVISIT: The size of descriptors and buffers must also be in even units
|
||||||
@ -190,6 +168,14 @@
|
|||||||
#define ENET_ALIGN_MASK (ENET_ALIGN - 1)
|
#define ENET_ALIGN_MASK (ENET_ALIGN - 1)
|
||||||
#define ENET_ALIGN_UP(n) (((n) + ENET_ALIGN_MASK) & ~ENET_ALIGN_MASK)
|
#define ENET_ALIGN_UP(n) (((n) + ENET_ALIGN_MASK) & ~ENET_ALIGN_MASK)
|
||||||
|
|
||||||
|
#define DESC_SIZE sizeof(struct enet_desc_s)
|
||||||
|
#define DESC_PADSIZE ENET_ALIGN_UP(DESC_SIZE)
|
||||||
|
|
||||||
|
#define ALIGNED_BUFSIZE ENET_ALIGN_UP(CONFIG_NET_ETH_PKTSIZE + \
|
||||||
|
CONFIG_NET_GUARDSIZE)
|
||||||
|
#define NENET_NBUFFERS \
|
||||||
|
(CONFIG_IMXRT_ENET_NTXBUFFERS + CONFIG_IMXRT_ENET_NRXBUFFERS)
|
||||||
|
|
||||||
/* TX timeout = 1 minute */
|
/* TX timeout = 1 minute */
|
||||||
|
|
||||||
#define IMXRT_TXTIMEOUT (60 * CLK_TCK)
|
#define IMXRT_TXTIMEOUT (60 * CLK_TCK)
|
||||||
@ -300,9 +286,6 @@
|
|||||||
|
|
||||||
#define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
|
#define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
|
||||||
|
|
||||||
#define IMXRT_BUF_SIZE ENET_ALIGN_UP(CONFIG_NET_ETH_PKTSIZE + \
|
|
||||||
CONFIG_NET_GUARDSIZE)
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -331,27 +314,31 @@ struct imxrt_driver_s
|
|||||||
struct net_driver_s dev; /* Interface understood by the network */
|
struct net_driver_s dev; /* Interface understood by the network */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* This union type forces the allocated size of TX&RX descriptors to be
|
||||||
|
* padded to a exact multiple of the Cortex-M7 D-Cache line size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
union enet_desc_u
|
||||||
|
{
|
||||||
|
uint8_t pad[DESC_PADSIZE];
|
||||||
|
struct enet_desc_s desc;
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static struct imxrt_driver_s g_enet[CONFIG_IMXRT_ENET_NETHIFS];
|
static struct imxrt_driver_s g_enet[CONFIG_IMXRT_ENET_NETHIFS];
|
||||||
|
|
||||||
/* The DMA descriptors. A unaligned uint8_t is used to allocate the
|
/* The DMA descriptors */
|
||||||
* memory; 16 is added to assure that we can meet the descriptor alignment
|
|
||||||
* requirements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static uint8_t g_desc_pool[NENET_NBUFFERS * sizeof(struct enet_desc_s)]
|
static union enet_desc_u g_desc_pool[NENET_NBUFFERS]
|
||||||
aligned_data(ENET_ALIGN);
|
aligned_data(ENET_ALIGN);
|
||||||
|
|
||||||
/* The DMA buffers. Again, A unaligned uint8_t is used to allocate the
|
/* The DMA buffers */
|
||||||
* memory; 16 is added to assure that we can meet the descriptor alignment
|
|
||||||
* requirements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static uint8_t g_buffer_pool[NENET_NBUFFERS * IMXRT_BUF_SIZE]
|
static uint8_t g_buffer_pool[NENET_NBUFFERS][ALIGNED_BUFSIZE]
|
||||||
aligned_data(ENET_ALIGN);
|
aligned_data(ENET_ALIGN);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Function Prototypes
|
* Private Function Prototypes
|
||||||
@ -359,12 +346,12 @@ static uint8_t g_buffer_pool[NENET_NBUFFERS * IMXRT_BUF_SIZE]
|
|||||||
|
|
||||||
/* Utility functions */
|
/* Utility functions */
|
||||||
|
|
||||||
static inline uint32_t imxrt_enet_getreg32(FAR struct imxrt_driver_s *priv,
|
static inline uint32_t imxrt_enet_getreg32(struct imxrt_driver_s *priv,
|
||||||
uint32_t offset);
|
uint32_t offset);
|
||||||
static inline void imxrt_enet_putreg32(FAR struct imxrt_driver_s *priv,
|
static inline void imxrt_enet_putreg32(struct imxrt_driver_s *priv,
|
||||||
uint32_t value, uint32_t offset);
|
uint32_t value, uint32_t offset);
|
||||||
|
|
||||||
static inline void imxrt_enet_modifyreg32(FAR struct imxrt_driver_s *priv,
|
static inline void imxrt_enet_modifyreg32(struct imxrt_driver_s *priv,
|
||||||
unsigned int offset,
|
unsigned int offset,
|
||||||
uint32_t clearbits,
|
uint32_t clearbits,
|
||||||
uint32_t setbits);
|
uint32_t setbits);
|
||||||
@ -461,8 +448,8 @@ static void imxrt_reset(struct imxrt_driver_s *priv);
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static inline uint32_t
|
static inline uint32_t imxrt_enet_getreg32(struct imxrt_driver_s *priv,
|
||||||
imxrt_enet_getreg32(FAR struct imxrt_driver_s *priv, uint32_t offset)
|
uint32_t offset)
|
||||||
{
|
{
|
||||||
return getreg32(priv->base + offset);
|
return getreg32(priv->base + offset);
|
||||||
}
|
}
|
||||||
@ -484,7 +471,7 @@ imxrt_enet_getreg32(FAR struct imxrt_driver_s *priv, uint32_t offset)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static inline void imxrt_enet_modifyreg32(FAR struct imxrt_driver_s *priv,
|
static inline void imxrt_enet_modifyreg32(struct imxrt_driver_s *priv,
|
||||||
unsigned int offset,
|
unsigned int offset,
|
||||||
uint32_t clearbits,
|
uint32_t clearbits,
|
||||||
uint32_t setbits)
|
uint32_t setbits)
|
||||||
@ -508,7 +495,7 @@ static inline void imxrt_enet_modifyreg32(FAR struct imxrt_driver_s *priv,
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static inline void imxrt_enet_putreg32(FAR struct imxrt_driver_s *priv,
|
static inline void imxrt_enet_putreg32(struct imxrt_driver_s *priv,
|
||||||
uint32_t value, uint32_t offset)
|
uint32_t value, uint32_t offset)
|
||||||
{
|
{
|
||||||
putreg32(value, priv->base + offset);
|
putreg32(value, priv->base + offset);
|
||||||
@ -666,18 +653,31 @@ static int imxrt_transmit(struct imxrt_driver_s *priv)
|
|||||||
|
|
||||||
buf = (uint8_t *)imxrt_swap32((uint32_t)priv->dev.d_buf);
|
buf = (uint8_t *)imxrt_swap32((uint32_t)priv->dev.d_buf);
|
||||||
|
|
||||||
|
struct enet_desc_s *rxdesc = &priv->rxdesc[priv->rxtail];
|
||||||
|
|
||||||
|
up_invalidate_dcache((uintptr_t)rxdesc,
|
||||||
|
(uintptr_t)rxdesc + sizeof(struct enet_desc_s));
|
||||||
|
|
||||||
|
if (rxdesc->data == buf)
|
||||||
|
{
|
||||||
/* Data was written into the RX buffer, so swap the TX and RX buffers */
|
/* Data was written into the RX buffer, so swap the TX and RX buffers */
|
||||||
|
|
||||||
DEBUGASSERT((rxdesc->status1 & RXDESC_E) == 0);
|
DEBUGASSERT((rxdesc->status1 & RXDESC_E) == 0);
|
||||||
rxdesc->data = txdesc->data;
|
rxdesc->data = txdesc->data;
|
||||||
txdesc->data = buf;
|
txdesc->data = buf;
|
||||||
|
up_clean_dcache((uintptr_t)rxdesc,
|
||||||
|
(uintptr_t)rxdesc + sizeof(struct enet_desc_s));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUGASSERT(txdesc->data == buf);
|
DEBUGASSERT(txdesc->data == buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make the following operations atomic */
|
up_clean_dcache((uintptr_t)txdesc,
|
||||||
|
(uintptr_t)txdesc + sizeof(struct enet_desc_s));
|
||||||
|
|
||||||
|
up_clean_dcache((uintptr_t)priv->dev.d_buf,
|
||||||
|
(uintptr_t)priv->dev.d_buf + priv->dev.d_len);
|
||||||
|
|
||||||
/* Start the TX transfer (if it was not already waiting for buffers) */
|
/* Start the TX transfer (if it was not already waiting for buffers) */
|
||||||
|
|
||||||
@ -989,6 +989,9 @@ static void imxrt_receive(struct imxrt_driver_s *priv)
|
|||||||
imxrt_swap32((uint32_t)priv->txdesc[priv->txhead].data);
|
imxrt_swap32((uint32_t)priv->txdesc[priv->txhead].data);
|
||||||
rxdesc->status1 |= RXDESC_E;
|
rxdesc->status1 |= RXDESC_E;
|
||||||
|
|
||||||
|
up_clean_dcache((uintptr_t)rxdesc,
|
||||||
|
(uintptr_t)rxdesc + sizeof(struct enet_desc_s));
|
||||||
|
|
||||||
/* Update the index to the next descriptor */
|
/* Update the index to the next descriptor */
|
||||||
|
|
||||||
priv->rxtail++;
|
priv->rxtail++;
|
||||||
@ -1223,8 +1226,8 @@ static void imxrt_enet_interrupt_work(void *arg)
|
|||||||
|
|
||||||
static int imxrt_enet_interrupt(int irq, void *context, void *arg)
|
static int imxrt_enet_interrupt(int irq, void *context, void *arg)
|
||||||
{
|
{
|
||||||
register FAR struct imxrt_driver_s *priv =
|
register struct imxrt_driver_s *priv =
|
||||||
(FAR struct imxrt_driver_s *) arg;
|
(struct imxrt_driver_s *)arg;
|
||||||
|
|
||||||
/* Disable further Ethernet interrupts. Because Ethernet interrupts are
|
/* Disable further Ethernet interrupts. Because Ethernet interrupts are
|
||||||
* also disabled if the TX timeout event occurs, there can be no race
|
* also disabled if the TX timeout event occurs, there can be no race
|
||||||
@ -1393,7 +1396,7 @@ static int imxrt_ifup_action(struct net_driver_s *dev, bool resetphy)
|
|||||||
|
|
||||||
/* Set the RX buffer size */
|
/* Set the RX buffer size */
|
||||||
|
|
||||||
imxrt_enet_putreg32(priv, IMXRT_BUF_SIZE, IMXRT_ENET_MRBR_OFFSET);
|
imxrt_enet_putreg32(priv, ALIGNED_BUFSIZE, IMXRT_ENET_MRBR_OFFSET);
|
||||||
|
|
||||||
/* Point to the start of the circular RX buffer descriptor queue */
|
/* Point to the start of the circular RX buffer descriptor queue */
|
||||||
|
|
||||||
@ -2419,13 +2422,11 @@ static void imxrt_initbuffers(struct imxrt_driver_s *priv)
|
|||||||
|
|
||||||
/* Get an aligned TX descriptor (array) address */
|
/* Get an aligned TX descriptor (array) address */
|
||||||
|
|
||||||
addr = (uintptr_t)g_desc_pool;
|
priv->txdesc = &g_desc_pool[0].desc;
|
||||||
priv->txdesc = (struct enet_desc_s *)addr;
|
|
||||||
|
|
||||||
/* Get an aligned RX descriptor (array) address */
|
/* Get an aligned RX descriptor (array) address */
|
||||||
|
|
||||||
addr += CONFIG_IMXRT_ENET_NTXBUFFERS * sizeof(struct enet_desc_s);
|
priv->rxdesc = &g_desc_pool[CONFIG_IMXRT_ENET_NTXBUFFERS].desc;
|
||||||
priv->rxdesc = (struct enet_desc_s *)addr;
|
|
||||||
|
|
||||||
/* Get the beginning of the first aligned buffer */
|
/* Get the beginning of the first aligned buffer */
|
||||||
|
|
||||||
@ -2441,7 +2442,7 @@ static void imxrt_initbuffers(struct imxrt_driver_s *priv)
|
|||||||
#ifdef CONFIG_IMXRT_ENETENHANCEDBD
|
#ifdef CONFIG_IMXRT_ENETENHANCEDBD
|
||||||
priv->txdesc[i].status2 = TXDESC_IINS | TXDESC_PINS;
|
priv->txdesc[i].status2 = TXDESC_IINS | TXDESC_PINS;
|
||||||
#endif
|
#endif
|
||||||
addr += IMXRT_BUF_SIZE;
|
addr += ALIGNED_BUFSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then fill in the RX descriptors */
|
/* Then fill in the RX descriptors */
|
||||||
@ -2455,7 +2456,7 @@ static void imxrt_initbuffers(struct imxrt_driver_s *priv)
|
|||||||
priv->rxdesc[i].bdu = 0;
|
priv->rxdesc[i].bdu = 0;
|
||||||
priv->rxdesc[i].status2 = RXDESC_INT;
|
priv->rxdesc[i].status2 = RXDESC_INT;
|
||||||
#endif
|
#endif
|
||||||
addr += IMXRT_BUF_SIZE;
|
addr += ALIGNED_BUFSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the wrap bit in the last descriptors to form a ring */
|
/* Set the wrap bit in the last descriptors to form a ring */
|
||||||
@ -2463,6 +2464,9 @@ static void imxrt_initbuffers(struct imxrt_driver_s *priv)
|
|||||||
priv->txdesc[CONFIG_IMXRT_ENET_NTXBUFFERS - 1].status1 |= TXDESC_W;
|
priv->txdesc[CONFIG_IMXRT_ENET_NTXBUFFERS - 1].status1 |= TXDESC_W;
|
||||||
priv->rxdesc[CONFIG_IMXRT_ENET_NRXBUFFERS - 1].status1 |= RXDESC_W;
|
priv->rxdesc[CONFIG_IMXRT_ENET_NRXBUFFERS - 1].status1 |= RXDESC_W;
|
||||||
|
|
||||||
|
up_clean_dcache((uintptr_t)g_desc_pool,
|
||||||
|
(uintptr_t)g_desc_pool + sizeof(g_desc_pool));
|
||||||
|
|
||||||
/* We start with RX descriptor 0 and with no TX descriptors in use */
|
/* We start with RX descriptor 0 and with no TX descriptors in use */
|
||||||
|
|
||||||
priv->txtail = 0;
|
priv->txtail = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user