This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit f594859d99b1a8d2f4aba366ecba8c1efd485f73 Author: Tiago Medicci Serrano <tiago.medi...@espressif.com> AuthorDate: Tue Jun 18 17:05:51 2024 -0300 esp32s3/wifi: Fix bug related to IOB off-loading with SMP For now, IOB off-loading in the wireless driver was removed because it is not compatible with SMP-enabled devices, which is valid for ESP32-S3. The performance gain by keeping the IOB off-loading in the wireless drivers is not exceeded by keeping the flat buffer approach and enabling `CONFIG_SMP=y`. --- arch/xtensa/src/esp32s3/Kconfig | 6 +- arch/xtensa/src/esp32s3/esp32s3_wlan.c | 429 ++++++++++++++++++++++++++------- 2 files changed, 348 insertions(+), 87 deletions(-) diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig index 67f5ac1815..48521315df 100644 --- a/arch/xtensa/src/esp32s3/Kconfig +++ b/arch/xtensa/src/esp32s3/Kconfig @@ -1544,6 +1544,10 @@ config ESP32S3_WIFI_RXBA_AMPDU_WZ int "Wi-Fi RX BA AMPDU windown size" default 6 +config ESP32S3_WLAN_PKTBUF_NUM + int "WLAN netcard packet buffer number per netcard" + default 16 + config ESP_WIFI_GCMP_SUPPORT bool "WiFi GCMP Support(GCMP128 and GCMP256)" default n @@ -2398,7 +2402,7 @@ config ESP32S3_KERNEL_IMAGE_SIZE config ESP32S3_KERNEL_RAM_SIZE hex "Kernel Allocated RAM" - default 0x29000 + default 0x30000 range 0x10000 0x54700 depends on ESP32S3_APP_FORMAT_LEGACY ---help--- diff --git a/arch/xtensa/src/esp32s3/esp32s3_wlan.c b/arch/xtensa/src/esp32s3/esp32s3_wlan.c index 92c37d74c3..1c9a30a1a0 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_wlan.c +++ b/arch/xtensa/src/esp32s3/esp32s3_wlan.c @@ -75,14 +75,39 @@ * Total size : 1514 */ -#define WLAN_BUF_SIZE (CONFIG_NET_ETH_PKTSIZE + \ - CONFIG_NET_LL_GUARDSIZE + \ - CONFIG_NET_GUARDSIZE) +#define WLAN_BUF_SIZE (CONFIG_NET_ETH_PKTSIZE) + +/* WLAN packet buffer number */ + +#define WLAN_PKTBUF_NUM (CONFIG_ESP32S3_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 (IOBBUF_SIZE) > (WLAN_BUF_SIZE + 1) +# define WLAN_RX_THRESHOLD (IOBBUF_SIZE - WLAN_BUF_SIZE + 1) +# endif +#endif /**************************************************************************** * Private Types ****************************************************************************/ +/* WLAN packet buffer */ + +struct wlan_pktbuf +{ + 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 @@ -129,17 +154,23 @@ struct wlan_priv_s struct net_driver_s dev; + /* Packet buffer cache */ + + struct wlan_pktbuf pktbuf[WLAN_PKTBUF_NUM]; + /* RX packet queue */ - struct iob_queue_s rxb; + sq_queue_t rxb; /* TX ready packet queue */ - struct iob_queue_s txb; + sq_queue_t txb; - /* Flat buffer swap */ + /* Free packet buffer queue */ - uint8_t flatbuf[WLAN_BUF_SIZE]; + sq_queue_t freeb; + + /* Device specific lock */ spinlock_t lock; }; @@ -204,8 +235,10 @@ static const struct wlan_ops g_softap_ops = * Private Function Prototypes ****************************************************************************/ -/* Common TX logic */ +/* Common TX/RX logic */ +static struct wlan_pktbuf *wlan_recvframe(struct wlan_priv_s *priv); +static struct wlan_pktbuf *wlan_txframe(struct wlan_priv_s *priv); static void wlan_transmit(struct wlan_priv_s *priv); static void wlan_rxpoll(void *arg); static int wlan_txpoll(struct net_driver_s *dev); @@ -251,6 +284,102 @@ static int wlan_ioctl(struct net_driver_s *dev, int cmd, * 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) +{ + irqstate_t flags; + + int i; + flags = spin_lock_irqsave(&priv->lock); + + 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); + } + + spin_unlock_irqrestore(&priv->lock, 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 inline struct wlan_pktbuf *wlan_alloc_buffer(struct wlan_priv_s *priv) +{ + struct wlan_pktbuf *pktbuf = NULL; + + sq_entry_t *entry; + irqstate_t flags = spin_lock_irqsave(&priv->lock); + + entry = sq_remfirst(&priv->freeb); + if (entry) + { + pktbuf = container_of(entry, struct wlan_pktbuf, entry); + } + + spin_unlock_irqrestore(&priv->lock, 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 *pktbuf; + + irqstate_t flags = spin_lock_irqsave(&priv->lock); + + pktbuf = container_of(buffer, struct wlan_pktbuf, buffer); + sq_addlast(&pktbuf->entry, &priv->freeb); + + spin_unlock_irqrestore(&priv->lock, flags); +} + /**************************************************************************** * Function: wlan_cache_txpkt_tail * @@ -267,12 +396,43 @@ static int wlan_ioctl(struct net_driver_s *dev, int cmd, static inline void wlan_cache_txpkt_tail(struct wlan_priv_s *priv) { - if (priv->dev.d_iob) - { - iob_tryadd_queue(priv->dev.d_iob, &priv->txb); - } + struct wlan_pktbuf *pktbuf; + irqstate_t flags; + struct net_driver_s *dev = &priv->dev; + + pktbuf = container_of(dev->d_buf, struct wlan_pktbuf, buffer); + pktbuf->len = dev->d_len; + + flags = spin_lock_irqsave(&priv->lock); + sq_addlast(&pktbuf->entry, &priv->txb); + spin_unlock_irqrestore(&priv->lock, flags); + + dev->d_buf = NULL; + dev->d_len = 0; +} - netdev_iob_clear(&priv->dev); +/**************************************************************************** + * 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 *pktbuf) +{ + irqstate_t flags; + + flags = spin_lock_irqsave(&priv->lock); + sq_addfirst(&pktbuf->entry, &priv->txb); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -289,13 +449,56 @@ static inline void wlan_cache_txpkt_tail(struct wlan_priv_s *priv) * ****************************************************************************/ -static struct iob_s *wlan_recvframe(struct wlan_priv_s *priv) +static struct wlan_pktbuf *wlan_recvframe(struct wlan_priv_s *priv) { - struct iob_s *iob; + irqstate_t flags; + sq_entry_t *entry; + struct wlan_pktbuf *pktbuf = NULL; + + flags = spin_lock_irqsave(&priv->lock); - iob = iob_remove_queue(&priv->rxb); + entry = sq_remfirst(&priv->rxb); + if (entry) + { + pktbuf = container_of(entry, struct wlan_pktbuf, entry); + } + + spin_unlock_irqrestore(&priv->lock, flags); - return iob; + 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 *wlan_txframe(struct wlan_priv_s *priv) +{ + irqstate_t flags; + sq_entry_t *entry; + struct wlan_pktbuf *pktbuf = NULL; + + flags = spin_lock_irqsave(&priv->lock); + + entry = sq_remfirst(&priv->txb); + if (entry) + { + pktbuf = container_of(entry, struct wlan_pktbuf, entry); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return pktbuf; } /**************************************************************************** @@ -315,19 +518,15 @@ static struct iob_s *wlan_recvframe(struct wlan_priv_s *priv) static void wlan_transmit(struct wlan_priv_s *priv) { - uint16_t llhdrlen = NET_LL_HDRLEN(&priv->dev); - unsigned int offset = CONFIG_NET_LL_GUARDSIZE - llhdrlen; - struct iob_s *iob; + struct wlan_pktbuf *pktbuf; int ret; - while ((iob = iob_peek_queue(&priv->txb)) != NULL) + while ((pktbuf = wlan_txframe(priv))) { - 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); + ret = priv->ops->send(pktbuf->buffer, pktbuf->len); if (ret == -ENOMEM) { + wlan_add_txpkt_head(priv, pktbuf); wd_start(&priv->txtimeout, WLAN_TXTOUT, wlan_txtimeout_expiry, (uint32_t)priv); break; @@ -339,11 +538,7 @@ static void wlan_transmit(struct wlan_priv_s *priv) nwarn("WARN: Failed to send pkt, ret: %d\n", ret); } - iob_remove_queue(&priv->txb); - - /* And free the I/O buffer chain */ - - iob_free_chain(iob); + wlan_free_buffer(priv, pktbuf->buffer); } } } @@ -391,8 +586,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 net_driver_s *dev = &priv->dev; - struct iob_s *iob = NULL; + struct wlan_pktbuf *pktbuf; irqstate_t flags; int ret = 0; @@ -409,57 +603,38 @@ static int wlan_rx_done(struct wlan_priv_s *priv, void *buffer, goto out; } - if (len > iob_navail(false) * CONFIG_IOB_BUFSIZE) - { - ret = -ENOBUFS; - goto out; - } - - iob = iob_tryalloc(false); - if (iob == NULL) + pktbuf = wlan_alloc_buffer(priv); + if (!pktbuf) { ret = -ENOBUFS; goto out; } - iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE - NET_LL_HDRLEN(dev)); + memcpy(pktbuf->buffer, buffer, len); + pktbuf->len = len; - ret = iob_trycopyin(iob, buffer, len, 0, false); - if (ret != len) + if (eb) { - ret = -ENOBUFS; - goto out; + esp_wifi_free_eb(eb); } flags = spin_lock_irqsave(&priv->lock); - ret = iob_tryadd_queue(iob, &priv->rxb); + sq_addlast(&pktbuf->entry, &priv->rxb); spin_unlock_irqrestore(&priv->lock, flags); - if (ret < 0) + if (work_available(&priv->rxwork)) { - ret = -ENOBUFS; - goto out; + work_queue(WLAN_WORK, &priv->rxwork, wlan_rxpoll, priv, 0); } -out: + return 0; - if (eb != NULL) +out: + if (eb) { esp_wifi_free_eb(eb); } - if (ret != OK && iob != NULL) - { - iob_free_chain(iob); - } - - if (work_available(&priv->rxwork)) - { - work_queue(WLAN_WORK, &priv->rxwork, wlan_rxpoll, priv, 0); - } - - wlan_txavail(&priv->dev); - return ret; } @@ -480,27 +655,32 @@ out: static void wlan_rxpoll(void *arg) { + struct wlan_pktbuf *pktbuf; + struct eth_hdr_s *eth_hdr; struct wlan_priv_s *priv = (struct wlan_priv_s *)arg; struct net_driver_s *dev = &priv->dev; - struct eth_hdr_s *eth_hdr; - struct iob_s *iob; +#ifdef WLAN_RX_THRESHOLD + uint32_t rbytes = 0; +#endif /* Try to send all cached TX packets for TX ack and so on */ wlan_transmit(priv); - /* Loop while while iob_remove_queue() successfully retrieves valid + /* Loop while while wlan_recvframe() successfully retrieves valid * Ethernet frames. */ net_lock(); - while ((iob = wlan_recvframe(priv)) != NULL) + while ((pktbuf = wlan_recvframe(priv)) != NULL) { - dev->d_iob = iob; - dev->d_len = iob->io_pktlen; + dev->d_buf = pktbuf->buffer; + dev->d_len = pktbuf->len; - iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE); +#ifdef WLAN_RX_THRESHOLD + rbytes += pktbuf->len; +#endif #ifdef CONFIG_NET_PKT @@ -511,9 +691,27 @@ static void wlan_rxpoll(void *arg) pkt_input(&priv->dev); #endif - eth_hdr = (struct eth_hdr_s *) - &dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE - - NET_LL_HDRLEN(dev)]; + /* 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; /* We only accept IP packets of the configured type and ARP packets */ @@ -588,7 +786,33 @@ static void wlan_rxpoll(void *arg) ninfo("INFO: Dropped, Unknown type: %04x\n", eth_hdr->type); } - netdev_iob_release(&priv->dev); + /* 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 } /* Try to send all cached TX packets */ @@ -620,10 +844,25 @@ static void wlan_rxpoll(void *arg) static int wlan_txpoll(struct net_driver_s *dev) { - struct wlan_priv_s *priv = dev->d_private; + struct wlan_pktbuf *pktbuf; + struct wlan_priv_s *priv = (struct wlan_priv_s *)dev->d_private; + + DEBUGASSERT(dev->d_buf != NULL); wlan_cache_txpkt_tail(priv); - wlan_transmit(priv); + + pktbuf = wlan_alloc_buffer(priv); + if (!pktbuf) + { + return -ENOMEM; + } + + dev->d_buf = pktbuf->buffer; + dev->d_len = WLAN_BUF_SIZE; + + /* If zero is returned, the polling will continue until + * all connections have been examined. + */ return OK; } @@ -650,10 +889,36 @@ 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 *pktbuf; + uint8_t *txbuf; + int ret; + + pktbuf = wlan_alloc_buffer(priv); + if (!pktbuf) + { + return ; + } + + dev->d_buf = pktbuf->buffer; + dev->d_len = WLAN_BUF_SIZE; /* Try to let TCP/IP to send all packets to netcard driver */ - while (devif_poll(dev, wlan_txpoll)); + do + { + txbuf = dev->d_buf; + ret = devif_poll(dev, wlan_txpoll); + } + while ((ret == 0) && + (dev->d_buf != txbuf)); + + if (dev->d_buf) + { + wlan_free_buffer(priv, dev->d_buf); + + dev->d_buf = NULL; + dev->d_len = 0; + } /* Try to send all cached TX packets */ @@ -807,6 +1072,7 @@ static int wlan_ifup(struct net_driver_s *dev) return OK; } + wlan_init_buffer(priv); ret = priv->ops->start(); if (ret < 0) { @@ -815,12 +1081,6 @@ static int wlan_ifup(struct net_driver_s *dev) return ret; } - 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) { @@ -872,9 +1132,6 @@ 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) {