risc-v/es32c3: improve passthrough performance by iob offload

Use iob offload model to improve passthrough performance

1. Use iob buffer instead of reserved packet buffer
2. Enable TCP/UDP buffer mode

-------------------------------------------------
|  Protocol      | Server | Client |            |
|-----------------------------------------------|
|  TCP           |    7   |    12  |  Mbits/sec |
|  TCP(Offload)  |   17   |    11  |  Mbits/sec |
|  UDP           |   10   |    16  |  Mbits/sec |
|  UDP(Offload)  |   43   |    28  |  Mbits/sec |
-------------------------------------------------

Signed-off-by: chao an <anchao@xiaomi.com>
This commit is contained in:
chao an 2022-12-08 04:03:01 +08:00 committed by Xiang Xiao
parent 563f5f4fa4
commit 61563d6004
3 changed files with 84 additions and 363 deletions

View File

@ -755,10 +755,6 @@ config ESP32C3_WIFI_RXBA_AMPDU_WZ
int "Wi-Fi RX BA AMPDU windown size"
default 6
config ESP32C3_WLAN_PKTBUF_NUM
int "WLAN netcard packet buffer number per netcard"
default 16
config ESP32C3_WIFI_CONNECT_TIMEOUT
int "Connect timeout by second"
default 10

View File

@ -72,41 +72,14 @@
* Total size : 1514
*/
#define WLAN_BUF_SIZE (CONFIG_NET_ETH_PKTSIZE)
/* WLAN packet buffer number */
#define WLAN_PKTBUF_NUM (CONFIG_ESP32C3_WLAN_PKTBUF_NUM)
/* Receive threshold which allows the receive function to trigger a scheduler
* to activate the application if possible.
*/
#ifdef CONFIG_MM_IOB
# define IOBBUF_SIZE (CONFIG_IOB_NBUFFERS * CONFIG_IOB_BUFSIZE)
# if (WLAN_PKTBUF_NUM) > (CONFIG_IOB_BUFSIZE + 1)
# define WLAN_RX_THRESHOLD (IOBBUF_SIZE - WLAN_BUF_SIZE + 1)
# else
# define WLAN_RX_THRESHOLD (WLAN_PKTBUF_NUM - 1) * WLAN_BUF_SIZE
# endif
#endif
#define WLAN_BUF_SIZE (CONFIG_NET_ETH_PKTSIZE + \
CONFIG_NET_LL_GUARDSIZE + \
CONFIG_NET_GUARDSIZE)
/****************************************************************************
* Private Types
****************************************************************************/
/* WLAN packet buffer */
struct wlan_pktbuf_s
{
sq_entry_t entry; /* Queue entry */
/* Packet data buffer */
uint8_t buffer[WLAN_BUF_SIZE];
uint16_t len; /* Packet data length */
};
/* WLAN operations */
struct wlan_ops_s
@ -153,21 +126,17 @@ struct wlan_priv_s
struct net_driver_s dev;
/* Packet buffer cache */
struct wlan_pktbuf_s pktbuf[WLAN_PKTBUF_NUM];
/* RX packet queue */
sq_queue_t rxb;
struct iob_queue_s rxb;
/* TX ready packet queue */
sq_queue_t txb;
struct iob_queue_s txb;
/* Free packet buffer queue */
/* Flat buffer swap */
sq_queue_t freeb;
uint8_t flatbuf[WLAN_BUF_SIZE];
};
/****************************************************************************
@ -281,105 +250,6 @@ static void wlan_ipv6multicast(struct wlan_priv_s *priv);
* mutex/semaphore instead of disable interrupt, if necessary.
*/
/****************************************************************************
* Function: wlan_init_buffer
*
* Description:
* Initialize the free buffer list
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* None
*
****************************************************************************/
static inline void wlan_init_buffer(struct wlan_priv_s *priv)
{
int i;
irqstate_t flags;
flags = enter_critical_section();
priv->dev.d_buf = NULL;
priv->dev.d_len = 0;
sq_init(&priv->freeb);
sq_init(&priv->rxb);
sq_init(&priv->txb);
for (i = 0; i < WLAN_PKTBUF_NUM; i++)
{
sq_addlast(&priv->pktbuf[i].entry, &priv->freeb);
}
leave_critical_section(flags);
}
/****************************************************************************
* Function: wlan_alloc_buffer
*
* Description:
* Allocate one buffer from the free buffer queue
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* Pointer to the allocated buffer on success; NULL on failure
*
****************************************************************************/
static struct wlan_pktbuf_s *wlan_alloc_buffer(
struct wlan_priv_s *priv)
{
sq_entry_t *entry;
irqstate_t flags;
struct wlan_pktbuf_s *pktbuf = NULL;
flags = enter_critical_section();
entry = sq_remfirst(&priv->freeb);
if (entry != NULL)
{
pktbuf = container_of(entry, struct wlan_pktbuf_s, entry);
}
leave_critical_section(flags);
return pktbuf;
}
/****************************************************************************
* Function: wlan_free_buffer
*
* Description:
* Insert a free Rx buffer into the free queue
*
* Input Parameters:
* priv - Reference to the driver state structure
* buffer - A pointer to the packet buffer to be freed
*
* Returned Value:
* None
*
****************************************************************************/
static inline void wlan_free_buffer(struct wlan_priv_s *priv,
uint8_t *buffer)
{
struct wlan_pktbuf_s *pktbuf;
irqstate_t flags;
flags = enter_critical_section();
pktbuf = container_of(buffer, struct wlan_pktbuf_s, buffer);
sq_addlast(&pktbuf->entry, &priv->freeb);
leave_critical_section(flags);
}
/****************************************************************************
* Function: wlan_cache_txpkt_tail
*
@ -396,109 +266,8 @@ static inline void wlan_free_buffer(struct wlan_priv_s *priv,
static inline void wlan_cache_txpkt_tail(struct wlan_priv_s *priv)
{
struct wlan_pktbuf_s *pktbuf;
irqstate_t flags;
struct net_driver_s *dev = &priv->dev;
pktbuf = container_of(dev->d_buf, struct wlan_pktbuf_s, buffer);
pktbuf->len = dev->d_len;
flags = enter_critical_section();
sq_addlast(&pktbuf->entry, &priv->txb);
leave_critical_section(flags);
dev->d_buf = NULL;
dev->d_len = 0;
}
/****************************************************************************
* Function: wlan_add_txpkt_head
*
* Description:
* Add packet into head of TX ready queue.
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* None
*
****************************************************************************/
static inline void wlan_add_txpkt_head(struct wlan_priv_s *priv,
struct wlan_pktbuf_s *pktbuf)
{
irqstate_t flags;
flags = enter_critical_section();
sq_addfirst(&pktbuf->entry, &priv->txb);
leave_critical_section(flags);
}
/****************************************************************************
* Function: wlan_recvframe
*
* Description:
* Try to receive RX packet from RX done packet queue.
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* RX packet if success or NULl if no packet in queue.
*
****************************************************************************/
static struct wlan_pktbuf_s *wlan_recvframe(struct wlan_priv_s *priv)
{
irqstate_t flags;
sq_entry_t *entry;
struct wlan_pktbuf_s *pktbuf = NULL;
flags = enter_critical_section();
entry = sq_remfirst(&priv->rxb);
if (entry != NULL)
{
pktbuf = container_of(entry, struct wlan_pktbuf_s, entry);
}
leave_critical_section(flags);
return pktbuf;
}
/****************************************************************************
* Function: wlan_txframe
*
* Description:
* Try to receive TX buffer from TX ready buffer queue.
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* TX packets buffer if success or NULL if no packet in queue.
*
****************************************************************************/
static struct wlan_pktbuf_s *wlan_txframe(struct wlan_priv_s *priv)
{
irqstate_t flags;
sq_entry_t *entry;
struct wlan_pktbuf_s *pktbuf = NULL;
flags = enter_critical_section();
entry = sq_remfirst(&priv->txb);
if (entry != NULL)
{
pktbuf = container_of(entry, struct wlan_pktbuf_s, entry);
}
leave_critical_section(flags);
return pktbuf;
iob_tryadd_queue(priv->dev.d_iob, &priv->txb);
netdev_iob_clear(&priv->dev);
}
/****************************************************************************
@ -518,15 +287,19 @@ static struct wlan_pktbuf_s *wlan_txframe(struct wlan_priv_s *priv)
static void wlan_transmit(struct wlan_priv_s *priv)
{
struct wlan_pktbuf_s *pktbuf;
uint16_t llhdrlen = NET_LL_HDRLEN(&priv->dev);
unsigned int offset = CONFIG_NET_LL_GUARDSIZE - llhdrlen;
struct iob_s *iob;
int ret;
while ((pktbuf = wlan_txframe(priv)) != NULL)
while ((iob = iob_peek_queue(&priv->txb)) != NULL)
{
ret = priv->ops->send(pktbuf->buffer, pktbuf->len);
iob_copyout(priv->flatbuf + llhdrlen, iob, iob->io_pktlen, 0);
memcpy(priv->flatbuf, iob->io_data + offset, llhdrlen);
ret = priv->ops->send(priv->flatbuf, iob->io_pktlen + llhdrlen);
if (ret == -ENOMEM)
{
wlan_add_txpkt_head(priv, pktbuf);
wd_start(&priv->txtimeout, WLAN_TXTOUT,
wlan_txtimeout_expiry, (uint32_t)priv);
break;
@ -538,7 +311,11 @@ static void wlan_transmit(struct wlan_priv_s *priv)
nwarn("WARN: Failed to send pkt, ret: %d\n", ret);
}
wlan_free_buffer(priv, pktbuf->buffer);
iob_remove_queue(&priv->txb);
/* And free the I/O buffer chain */
iob_free_chain(iob);
}
}
}
@ -586,7 +363,7 @@ static void wlan_tx_done(struct wlan_priv_s *priv)
static int wlan_rx_done(struct wlan_priv_s *priv, void *buffer,
uint16_t len, void *eb)
{
struct wlan_pktbuf_s *pktbuf;
struct iob_s *iob = NULL;
irqstate_t flags;
int ret = 0;
@ -603,25 +380,43 @@ static int wlan_rx_done(struct wlan_priv_s *priv, void *buffer,
goto out;
}
pktbuf = wlan_alloc_buffer(priv);
if (pktbuf == NULL)
if (len > iob_navail(false) * CONFIG_IOB_BUFSIZE)
{
ret = -ENOBUFS;
goto out;
}
memcpy(pktbuf->buffer, buffer, len);
pktbuf->len = len;
iob = iob_tryalloc(false);
if (iob == NULL)
{
ret = -ENOBUFS;
goto out;
}
ret = iob_trycopyin(iob, buffer, len, 0, false);
if (ret != len)
{
ret = -ENOBUFS;
goto out;
}
iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE);
flags = enter_critical_section();
ret = iob_tryadd_queue(iob, &priv->rxb);
leave_critical_section(flags);
if (ret < 0)
{
ret = -ENOBUFS;
goto out;
}
if (eb != NULL)
{
esp_wifi_free_eb(eb);
}
flags = enter_critical_section();
sq_addlast(&pktbuf->entry, &priv->rxb);
leave_critical_section(flags);
if (work_available(&priv->rxwork))
{
work_queue(WLAN_WORK, &priv->rxwork, wlan_rxpoll, priv, 0);
@ -630,11 +425,18 @@ static int wlan_rx_done(struct wlan_priv_s *priv, void *buffer,
return 0;
out:
if (iob != NULL)
{
iob_free_chain(iob);
}
if (eb != NULL)
{
esp_wifi_free_eb(eb);
}
wlan_txavail(&priv->dev);
return ret;
}
@ -655,32 +457,25 @@ out:
static void wlan_rxpoll(void *arg)
{
struct wlan_pktbuf_s *pktbuf;
struct eth_hdr_s *eth_hdr;
struct wlan_priv_s *priv = (struct wlan_priv_s *)arg;
struct net_driver_s *dev = &priv->dev;
#ifdef WLAN_RX_THRESHOLD
uint32_t rbytes = 0;
#endif
struct eth_hdr_s *eth_hdr;
struct iob_s *iob;
/* Try to send all cached TX packets for TX ack and so on */
wlan_transmit(priv);
/* Loop while while wlan_recvframe() successfully retrieves valid
/* Loop while while iob_remove_queue() successfully retrieves valid
* Ethernet frames.
*/
net_lock();
while ((pktbuf = wlan_recvframe(priv)) != NULL)
while ((iob = iob_remove_queue(&priv->rxb)) != NULL)
{
dev->d_buf = pktbuf->buffer;
dev->d_len = pktbuf->len;
#ifdef WLAN_RX_THRESHOLD
rbytes += pktbuf->len;
#endif
dev->d_iob = iob;
dev->d_len = iob->io_pktlen;
#ifdef CONFIG_NET_PKT
@ -691,27 +486,9 @@ static void wlan_rxpoll(void *arg)
pkt_input(&priv->dev);
#endif
/* Check if the packet is a valid size for the network
* buffer configuration (this should not happen)
*/
if (dev->d_len > WLAN_BUF_SIZE)
{
nwarn("WARNING: DROPPED Too big: %d\n", dev->d_len);
/* Free dropped packet buffer */
if (dev->d_buf)
{
wlan_free_buffer(priv, dev->d_buf);
dev->d_buf = NULL;
dev->d_len = 0;
}
continue;
}
eth_hdr = (struct eth_hdr_s *)dev->d_buf;
eth_hdr = (struct eth_hdr_s *)
&dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE -
NET_LL_HDRLEN(dev)];
/* We only accept IP packets of the configured type and ARP packets */
@ -786,34 +563,7 @@ static void wlan_rxpoll(void *arg)
ninfo("INFO: Dropped, Unknown type: %04x\n", eth_hdr->type);
}
/* We are finished with the RX buffer. NOTE: If the buffer is
* re-used for transmission, the dev->d_buf field will have been
* nullified.
*/
if (dev->d_buf)
{
/* Free the receive packet buffer */
wlan_free_buffer(priv, dev->d_buf);
dev->d_buf = NULL;
dev->d_len = 0;
}
#ifdef WLAN_RX_THRESHOLD
/**
* If received total bytes is larger than receive threshold,
* then do "unlock" to try to active applicantion to receive
* data from low-level buffer of IP stack.
*/
if (rbytes >= WLAN_RX_THRESHOLD)
{
net_unlock();
rbytes = 0;
net_lock();
}
#endif
netdev_iob_release(&priv->dev);
}
/* Try to send all cached TX packets */
@ -845,27 +595,16 @@ static void wlan_rxpoll(void *arg)
static int wlan_txpoll(struct net_driver_s *dev)
{
struct wlan_pktbuf_s *pktbuf;
struct wlan_priv_s *priv = (struct wlan_priv_s *)dev->d_private;
DEBUGASSERT(dev->d_buf != NULL);
struct wlan_priv_s *priv = dev->d_private;
wlan_cache_txpkt_tail(priv);
pktbuf = wlan_alloc_buffer(priv);
if (pktbuf == NULL)
{
return -ENOMEM;
}
dev->d_buf = pktbuf->buffer;
dev->d_len = WLAN_BUF_SIZE;
wlan_transmit(priv);
/* If zero is returned, the polling will continue until
* all connections have been examined.
*/
return OK;
return 1;
}
/****************************************************************************
@ -890,36 +629,10 @@ static int wlan_txpoll(struct net_driver_s *dev)
static void wlan_dopoll(struct wlan_priv_s *priv)
{
struct net_driver_s *dev = &priv->dev;
struct wlan_pktbuf_s *pktbuf;
uint8_t *txbuf;
int ret;
pktbuf = wlan_alloc_buffer(priv);
if (pktbuf == NULL)
{
return ;
}
dev->d_buf = pktbuf->buffer;
dev->d_len = WLAN_BUF_SIZE;
/* Try to let TCP/IP to send all packets to netcard driver */
do
{
txbuf = dev->d_buf;
ret = devif_poll(dev, wlan_txpoll);
}
while ((ret == 0) &&
(dev->d_buf != txbuf));
if (dev->d_buf != NULL)
{
wlan_free_buffer(priv, dev->d_buf);
dev->d_buf = NULL;
dev->d_len = 0;
}
while (devif_poll(dev, wlan_txpoll));
/* Try to send all cached TX packets */
@ -1088,7 +801,11 @@ static int wlan_ifup(struct net_driver_s *dev)
wlan_ipv6multicast(priv);
#endif
wlan_init_buffer(priv);
IOB_QINIT(&priv->rxb);
IOB_QINIT(&priv->txb);
priv->dev.d_buf = NULL;
priv->dev.d_len = 0;
priv->ifup = true;
if (g_callback_register_ref == 0)
@ -1141,6 +858,9 @@ static int wlan_ifdown(struct net_driver_s *dev)
priv->ifup = false;
iob_free_queue(&priv->rxb);
iob_free_queue(&priv->txb);
ret = priv->ops->stop();
if (ret < 0)
{

View File

@ -29,19 +29,24 @@ CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IDLETHREAD_STACKSIZE=3072
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_FLOATINGPOINT=y
CONFIG_IOB_NBUFFERS=124
CONFIG_IOB_THROTTLE=24
CONFIG_LIBC_MAX_EXITFUNS=1
CONFIG_NAME_MAX=48
CONFIG_NETDB_DNSCLIENT=y
CONFIG_NETDEV_LATEINIT=y
CONFIG_NETDEV_PHY_IOCTL=y
CONFIG_NETDEV_WIRELESS_IOCTL=y
CONFIG_NETUTILS_IPERF=y
CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_PKTSIZE=1514
CONFIG_NET_ICMP=y
CONFIG_NET_ICMP_SOCKET=y
CONFIG_NET_TCP=y
CONFIG_NET_TCP_DELAYED_ACK=y
CONFIG_NET_TCP_WRITE_BUFFERS=y
CONFIG_NET_UDP=y
CONFIG_NET_UDP_WRITE_BUFFERS=y
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512