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)
     {

Reply via email to