From d3238e6f9553ce6991409162e7ca6661e391ac84 Mon Sep 17 00:00:00 2001 From: Andrew Webster Date: Thu, 21 Jan 2016 19:00:21 -0600 Subject: [PATCH] Kinetis enet: buffer management update This patch manages the packet buffer used by the upper layers by making sure it is always set to a valid transmit buffer that can be used by the MAC-NET core. The only exception to this is when the upper layer re-uses a receive buffer to send a response. In this case, the updated receive buffer is swapped with an empty transmit buffer. If there is no empty transmit buffer available, the packet will be dropped. Signed-off-by: Andrew Webster Kinetis enet: add support for DBSWP Signed-off-by: Andrew Webster --- arch/arm/src/kinetis/kinetis_enet.c | 67 +++++++++++++++++++++-------- arch/arm/src/kinetis/kinetis_enet.h | 55 ++++++++++++++++++++--- 2 files changed, 98 insertions(+), 24 deletions(-) diff --git a/arch/arm/src/kinetis/kinetis_enet.c b/arch/arm/src/kinetis/kinetis_enet.c index 0b4a859f079..6c37704a8a1 100644 --- a/arch/arm/src/kinetis/kinetis_enet.c +++ b/arch/arm/src/kinetis/kinetis_enet.c @@ -196,7 +196,7 @@ static struct kinetis_driver_s g_enet[CONFIG_ENET_NETHIFS]; ****************************************************************************/ /* Utility functions */ -#ifdef CONFIG_ENDIAN_BIG +#ifndef KINETIS_BUFFERS_SWAP # define kinesis_swap32(value) (value) # define kinesis_swap16(value) (value) #else @@ -346,6 +346,7 @@ static int kinetis_transmit(FAR struct kinetis_driver_s *priv) { struct enet_desc_s *txdesc; uint32_t regval; + uint8_t *buf; /* Since this can be called from kinetis_receive, it is possible that * the transmit queue is full, so check for that now. If this is the @@ -388,6 +389,22 @@ static int kinetis_transmit(FAR struct kinetis_driver_s *priv) #endif txdesc->status1 |= (TXDESC_R | TXDESC_L | TXDESC_TC); + buf = (uint8_t*)kinesis_swap32((uint32_t)priv->dev.d_buf); + if (priv->rxdesc[priv->rxtail].data == buf) + { + struct enet_desc_s *rxdesc = &priv->rxdesc[priv->rxtail]; + + /* Data was written into the RX buffer, so swap the TX and RX buffers */ + + DEBUGASSERT((rxdesc->status1 & RXDESC_E) == 0); + rxdesc->data = txdesc->data; + txdesc->data = buf; + } + else + { + ASSERT(txdesc->data == buf); + } + /* Start the TX transfer (if it was not already waiting for buffers) */ putreg32(ENET_TDAR, KINETIS_ENET_TDAR); @@ -463,6 +480,7 @@ static int kinetis_txpoll(struct net_driver_s *dev) /* Send the packet */ kinetis_transmit(priv); + priv->dev.d_buf = (uint8_t*)kinesis_swap32((uint32_t)priv->txdesc[priv->txhead].data); /* Check if there is room in the device to hold another packet. If not, * return a non-zero value to terminate the poll. @@ -515,22 +533,6 @@ static void kinetis_receive(FAR struct kinetis_driver_s *priv) priv->dev.d_len = kinesis_swap16(priv->rxdesc[priv->rxtail].length); priv->dev.d_buf = (uint8_t *)kinesis_swap32((uint32_t)priv->rxdesc[priv->rxtail].data); - /* Doing this here could cause corruption! */ - - priv->rxdesc[priv->rxtail].status1 |= RXDESC_E; - - /* Update the index to the next descriptor */ - - priv->rxtail++; - if (priv->rxtail >= CONFIG_ENET_NTXBUFFERS) - { - priv->rxtail = 0; - } - - /* Indicate that there have been empty receive buffers produced */ - - putreg32(ENET_RDAR, KINETIS_ENET_RDAR); - #ifdef CONFIG_NET_PKT /* When packet sockets are enabled, feed the frame into the packet tap */ @@ -639,6 +641,27 @@ static void kinetis_receive(FAR struct kinetis_driver_s *priv) { NETDEV_RXDROPPED(&priv->dev); } + + /* Point the packet buffer back to the next TX buffer, which will be used during + * the next write. If the write queue is full, then this will point at an active + * buffer, which must not be written to. This is OK because devif_poll won't be + * called unless the queue is not full. + */ + + priv->dev.d_buf = (uint8_t*)kinesis_swap32((uint32_t)priv->txdesc[priv->txhead].data); + priv->rxdesc[priv->rxtail].status1 |= RXDESC_E; + + /* Update the index to the next descriptor */ + + priv->rxtail++; + if (priv->rxtail >= CONFIG_ENET_NRXBUFFERS) + { + priv->rxtail = 0; + } + + /* Indicate that there have been empty receive buffers produced */ + + putreg32(ENET_RDAR, KINETIS_ENET_RDAR); } } @@ -942,7 +965,11 @@ static int kinetis_ifup(struct net_driver_s *dev) /* And enable the MAC itself */ regval = getreg32(KINETIS_ENET_ECR); - regval |= ENET_ECR_ETHEREN; + regval |= ENET_ECR_ETHEREN +#ifdef KINETIS_USE_DBSWAP + | ENET_ECR_DBSWP +#endif + ; putreg32(regval, KINETIS_ENET_ECR); /* Indicate that there have been empty receive buffers produced */ @@ -1453,6 +1480,10 @@ static void kinetis_initbuffers(struct kinetis_driver_s *priv) priv->txtail = 0; priv->txhead = 0; priv->rxtail = 0; + + /* Initialize the packet buffer, which is used when sending */ + + priv->dev.d_buf = (uint8_t*)kinesis_swap32((uint32_t)priv->txdesc[priv->txhead].data); } /**************************************************************************** diff --git a/arch/arm/src/kinetis/kinetis_enet.h b/arch/arm/src/kinetis/kinetis_enet.h index 1843afcd054..cadd006d8ce 100644 --- a/arch/arm/src/kinetis/kinetis_enet.h +++ b/arch/arm/src/kinetis/kinetis_enet.h @@ -195,7 +195,10 @@ /* Bit 5: Reserved */ #define ENET_ECR_DBGEN (1 << 6) /* Bit 6: Debug enable */ #define ENET_ECR_STOPEN (1 << 7) /* Bit 7: STOPEN Signal Control */ - /* Bits 8-31: Reserved */ +#ifdef KINETIS_ENET_HAS_DBSWAP +#define ENET_ECR_DBSWP (1 << 8) /* Bit 8: Swap bytes */ +#endif + /* Bits 9-31: Reserved */ /* MII Management Frame Register */ #define ENET_MMFR_DATA_SHIFT (0) /* Bits 0-15: Management frame data */ @@ -454,7 +457,17 @@ * the underlying hardware writes the data in big-endian byte order. */ -#ifdef CONFIG_ENDIAN_BIG +#ifdef KINETIS_ENET_HAS_DBSWAP +# ifndef CONFIG_ENDIAN_BIG +# define KINETIS_USE_DBSWAP +# endif +#else +# ifndef CONFIG_ENDIAN_BIG +# define KINETIS_BUFFERS_SWAP +# endif +#endif + +#ifndef KINETIS_BUFFERS_SWAP # define TXDESC_ABC (1 << 9) /* Legacy */ # define TXDESC_TC (1 << 10) /* Common */ # define TXDESC_L (1 << 11) /* Common */ @@ -474,7 +487,7 @@ /* Enhanced (only) TX Buffer Descriptor Bit Definitions */ -#ifdef CONFIG_ENDIAN_BIG +#ifndef KINETIS_BUFFERS_SWAP # define TXDESC_TSE (1 << 8) # define TXDESC_OE (1 << 9) # define TXDESC_LCE (1 << 10) @@ -508,7 +521,7 @@ /* Legacy (and Common) RX Buffer Descriptor Bit Definitions */ -#ifdef CONFIG_ENDIAN_BIG +#ifndef KINETIS_BUFFERS_SWAP # define RXDESC_TR (1 << 0) # define RXDESC_OV (1 << 1) # define RXDESC_CR (1 << 2) @@ -540,7 +553,7 @@ /* Enhanced (only) TX Buffer Descriptor Bit Definitions */ -#ifdef CONFIG_ENDIAN_BIG +#ifndef KINETIS_BUFFERS_SWAP # define RXDESC_FRAG (1 << 0) # define RXDESC_IPV6 (1 << 1) # define RXDESC_VLAN (1 << 2) @@ -575,6 +588,26 @@ /* Legacy Buffer Descriptor */ #ifdef CONFIG_ENET_ENHANCEDBD +#ifdef KINETIS_USE_DBSWAP +/* When DBSWP is used to swap the bytes in hardware, it is done 32-bits + * at a time. Therefore, all 16 bit elements need to be swapped to + * compensate. + */ + +struct enet_desc_s +{ + uint16_t length; /* Data length */ + uint16_t status1; /* Control and status */ + uint8_t *data; /* Buffer address */ + uint32_t status2; /* Extended status */ + uint16_t checksum; /* Payload checksum */ + uint16_t lenproto; /* Header length + Protocol type */ + uint32_t bdu; /* BDU */ + uint32_t timestamp; /* Time stamp */ + uint32_t reserved1; /* unused */ + uint32_t reserved2; /* unused */ +}; +#else struct enet_desc_s { uint16_t status1; /* Control and status */ @@ -587,7 +620,16 @@ struct enet_desc_s uint32_t timestamp; /* Time stamp */ uint32_t reserved1; /* unused */ uint32_t reserved2; /* unused */ -} +}; +#endif +#else +#ifdef KINETIS_USE_DBSWAP +struct enet_desc_s +{ + uint16_t length; /* Data length */ + uint16_t status1; /* Control and status */ + uint8_t *data; /* Buffer address */ +}; #else struct enet_desc_s { @@ -596,6 +638,7 @@ struct enet_desc_s uint8_t *data; /* Buffer address */ }; #endif +#endif /******************************************************************************************** * Public Data