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 <awebster@arcx.com>

Kinetis enet: add support for DBSWP

Signed-off-by: Andrew Webster <awebster@arcx.com>
This commit is contained in:
Andrew Webster 2016-01-21 19:00:21 -06:00 committed by Gregory Nutt
parent 64a0f54767
commit d3238e6f95
2 changed files with 98 additions and 24 deletions

View File

@ -196,7 +196,7 @@ static struct kinetis_driver_s g_enet[CONFIG_ENET_NETHIFS];
****************************************************************************/ ****************************************************************************/
/* Utility functions */ /* Utility functions */
#ifdef CONFIG_ENDIAN_BIG #ifndef KINETIS_BUFFERS_SWAP
# define kinesis_swap32(value) (value) # define kinesis_swap32(value) (value)
# define kinesis_swap16(value) (value) # define kinesis_swap16(value) (value)
#else #else
@ -346,6 +346,7 @@ static int kinetis_transmit(FAR struct kinetis_driver_s *priv)
{ {
struct enet_desc_s *txdesc; struct enet_desc_s *txdesc;
uint32_t regval; uint32_t regval;
uint8_t *buf;
/* Since this can be called from kinetis_receive, it is possible that /* 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 * 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 #endif
txdesc->status1 |= (TXDESC_R | TXDESC_L | TXDESC_TC); 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) */ /* Start the TX transfer (if it was not already waiting for buffers) */
putreg32(ENET_TDAR, KINETIS_ENET_TDAR); putreg32(ENET_TDAR, KINETIS_ENET_TDAR);
@ -463,6 +480,7 @@ static int kinetis_txpoll(struct net_driver_s *dev)
/* Send the packet */ /* Send the packet */
kinetis_transmit(priv); 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, /* Check if there is room in the device to hold another packet. If not,
* return a non-zero value to terminate the poll. * 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_len = kinesis_swap16(priv->rxdesc[priv->rxtail].length);
priv->dev.d_buf = (uint8_t *)kinesis_swap32((uint32_t)priv->rxdesc[priv->rxtail].data); 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 #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 */
@ -639,6 +641,27 @@ static void kinetis_receive(FAR struct kinetis_driver_s *priv)
{ {
NETDEV_RXDROPPED(&priv->dev); 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 */ /* And enable the MAC itself */
regval = getreg32(KINETIS_ENET_ECR); 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); putreg32(regval, KINETIS_ENET_ECR);
/* Indicate that there have been empty receive buffers produced */ /* 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->txtail = 0;
priv->txhead = 0; priv->txhead = 0;
priv->rxtail = 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);
} }
/**************************************************************************** /****************************************************************************

View File

@ -195,7 +195,10 @@
/* Bit 5: Reserved */ /* Bit 5: Reserved */
#define ENET_ECR_DBGEN (1 << 6) /* Bit 6: Debug enable */ #define ENET_ECR_DBGEN (1 << 6) /* Bit 6: Debug enable */
#define ENET_ECR_STOPEN (1 << 7) /* Bit 7: STOPEN Signal Control */ #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 */ /* MII Management Frame Register */
#define ENET_MMFR_DATA_SHIFT (0) /* Bits 0-15: Management frame data */ #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. * 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_ABC (1 << 9) /* Legacy */
# define TXDESC_TC (1 << 10) /* Common */ # define TXDESC_TC (1 << 10) /* Common */
# define TXDESC_L (1 << 11) /* Common */ # define TXDESC_L (1 << 11) /* Common */
@ -474,7 +487,7 @@
/* Enhanced (only) TX Buffer Descriptor Bit Definitions */ /* Enhanced (only) TX Buffer Descriptor Bit Definitions */
#ifdef CONFIG_ENDIAN_BIG #ifndef KINETIS_BUFFERS_SWAP
# define TXDESC_TSE (1 << 8) # define TXDESC_TSE (1 << 8)
# define TXDESC_OE (1 << 9) # define TXDESC_OE (1 << 9)
# define TXDESC_LCE (1 << 10) # define TXDESC_LCE (1 << 10)
@ -508,7 +521,7 @@
/* Legacy (and Common) RX Buffer Descriptor Bit Definitions */ /* Legacy (and Common) RX Buffer Descriptor Bit Definitions */
#ifdef CONFIG_ENDIAN_BIG #ifndef KINETIS_BUFFERS_SWAP
# define RXDESC_TR (1 << 0) # define RXDESC_TR (1 << 0)
# define RXDESC_OV (1 << 1) # define RXDESC_OV (1 << 1)
# define RXDESC_CR (1 << 2) # define RXDESC_CR (1 << 2)
@ -540,7 +553,7 @@
/* Enhanced (only) TX Buffer Descriptor Bit Definitions */ /* Enhanced (only) TX Buffer Descriptor Bit Definitions */
#ifdef CONFIG_ENDIAN_BIG #ifndef KINETIS_BUFFERS_SWAP
# define RXDESC_FRAG (1 << 0) # define RXDESC_FRAG (1 << 0)
# define RXDESC_IPV6 (1 << 1) # define RXDESC_IPV6 (1 << 1)
# define RXDESC_VLAN (1 << 2) # define RXDESC_VLAN (1 << 2)
@ -575,6 +588,26 @@
/* Legacy Buffer Descriptor */ /* Legacy Buffer Descriptor */
#ifdef CONFIG_ENET_ENHANCEDBD #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 struct enet_desc_s
{ {
uint16_t status1; /* Control and status */ uint16_t status1; /* Control and status */
@ -587,7 +620,16 @@ struct enet_desc_s
uint32_t timestamp; /* Time stamp */ uint32_t timestamp; /* Time stamp */
uint32_t reserved1; /* unused */ uint32_t reserved1; /* unused */
uint32_t reserved2; /* 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 #else
struct enet_desc_s struct enet_desc_s
{ {
@ -596,6 +638,7 @@ struct enet_desc_s
uint8_t *data; /* Buffer address */ uint8_t *data; /* Buffer address */
}; };
#endif #endif
#endif
/******************************************************************************************** /********************************************************************************************
* Public Data * Public Data