This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit ac675ec65363e51fb16e4aef8b9b4dcdbf5f3004
Author: raul_chen <[email protected]>
AuthorDate: Mon Jul 6 16:44:33 2026 +0800

    arch/arm/ameba: move WiFi netdev to lower-half and enable TCP SACK
    
    Rework the Ameba WHC WiFi driver from the legacy flat net_driver_s model
    to the netdev lower-half framework (netdev_lowerhalf_s + netdev_ops_s with
    .transmit/.receive, IOB-based quota backpressure and a dedicated
    NETDEV_RX_THREAD).  This provides real TX backpressure and moves RX off
    the IPC callback onto a bounded rx queue.
    
    Raise the host TX skb pool (skb_num_ap) to a minimum of 16.  The SDK
    default of 4 is too small for sustained TCP TX: the host send runs out of
    buffers (-2), which exhausts retransmits and tears the connection down.
    
    Enable CONFIG_NET_TCP_SELECTIVE_ACK (which selects OUT_OF_ORDER) in both
    board defconfigs.  WiFi's occasional loss otherwise stalls TCP RX on RTO
    timeouts (~2 Mbit/s); with SACK + out-of-order queuing RX recovers to
    ~12-13 Mbit/s.
    
    Signed-off-by: raul_chen <[email protected]>
---
 arch/arm/src/common/ameba/ameba_wlan.c             | 413 +++++++--------------
 arch/arm/src/common/ameba/wifi/ameba_wifi.c        |  13 +
 .../rtl8720f/rtl8720f_evb/configs/nsh/defconfig    |   1 +
 .../arm/rtl8721dx/pke8721daf/configs/nsh/defconfig |   1 +
 4 files changed, 154 insertions(+), 274 deletions(-)

diff --git a/arch/arm/src/common/ameba/ameba_wlan.c 
b/arch/arm/src/common/ameba/ameba_wlan.c
index 7eeeb34e542..48f15d6ecef 100644
--- a/arch/arm/src/common/ameba/ameba_wlan.c
+++ b/arch/arm/src/common/ameba/ameba_wlan.c
@@ -26,15 +26,21 @@
  * The NP runs the WiFi MAC/PHY and delivers/accepts 802.3 (Ethernet)
  * frames over the WHC IPC, so this is a plain Ethernet-style netdev
  * (NET_LL_IEEE80211).
+ *
+ * This driver uses the NuttX network "lower-half" framework
+ * (include/nuttx/net/netdev_lowerhalf.h + drivers/net/netdev_upperhalf.c):
+ * we implement struct netdev_ops_s (ifup/ifdown/transmit/receive/ioctl) and
+ * the generic upper half owns the poll loop, the RX/TX worker, the IOB
+ * (netpkt) accounting and the quota-based flow control.  See the guide
+ * in Documentation/components/net/netdriver.rst.
+ *
  * The data path crosses to the SDK-header side through a thin byte-buffer
  * ABI (the SDK's lwIP/pbuf headers collide with NuttX's, so they cannot
- * share a
- * translation unit):
+ * share a translation unit):
  *
- *   TX:  ameba_wlan_txpoll -> ameba_wifi_txframe()  [ameba_wifi_depend.c]
- *   RX:  netif_adapter_wifi_recv_whc() -> ameba_wlan_rxframe()  (this file)
+ *   TX: ameba_wlan_transmit() -> ameba_wifi_txframe() [ameba_wifi_depend.c]
+ *   RX: netif_adapter_wifi_recv_whc() -> ameba_wlan_rxframe() (this file)
  *
- * Follows the standard NuttX Ethernet-style netdev (devif) RX/TX idiom.
  * IW (wireless-extension) ioctls drive scan / connect / SoftAP via wapi.
  ****************************************************************************/
 
@@ -57,10 +63,8 @@
 #include <nuttx/wqueue.h>
 #include <nuttx/kmalloc.h>
 #include <nuttx/net/netdev.h>
+#include <nuttx/net/netdev_lowerhalf.h>
 #include <nuttx/mm/iob.h>
-#ifdef CONFIG_NET_PKT
-#  include <nuttx/net/pkt.h>
-#endif
 #ifdef CONFIG_NETDEV_IOCTL
 #  include <nuttx/wireless/wireless.h>
 #endif
@@ -79,16 +83,24 @@
 
 #define AMEBA_WLAN_BUFSIZE  (CONFIG_NET_ETH_PKTSIZE + CONFIG_NET_GUARDSIZE)
 
+/* Quotas: the WHC send copies the frame synchronously, so a single in-flight
+ * TX buffer is enough.  The RX quota bounds how many staged frames
+ * (netpkts) the driver may hold before the upper half
+ * drains them; keep it well under the IOB pool.
+ */
+
+#define AMEBA_WLAN_TX_QUOTA 1
+#define AMEBA_WLAN_RX_QUOTA 16
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
 
 struct ameba_wlan_s
 {
-  struct net_driver_s dev;         /* Interface understood by the network   */
-  struct work_s       pollwork;    /* For deferring TX poll work to LPWORK   */
-  struct work_s       rxwork;      /* For deferring RX processing to LPWORK   
*/
-  struct iob_queue_s  rxq;         /* Frames queued by the WHC RX callback    
*/
+  struct netdev_lowerhalf_s dev;   /* Lower-half interface to the upper half */
+  struct iob_queue_s  rxq;         /* Frames staged by the WHC RX callback    
*/
+  spinlock_t          rx_lock;     /* Guards rxq (producer WHC task vs worker) 
*/
   bool                bifup;       /* true: ifup; false: ifdown               
*/
   uint8_t             devnum;      /* NP interface index                      
*/
 
@@ -113,14 +125,14 @@ struct ameba_wlan_s
 
 static struct ameba_wlan_s g_ameba_wlan;
 
-/* TX work buffer (network stack fills it during devif_poll) and RX work
- * buffer (incoming frame copied in, with room for an in-place reply).
+/* Flat, contiguous TX staging buffer.  The WHC send ABI takes a single
+ * (buf, len) scatter entry, so a possibly-fragmented netpkt is copied out
+ * here before it is handed to the NP.  Only touched from transmit(), which
+ * the upper half serialises under the network lock.
  */
 
 static uint8_t g_txbuf[AMEBA_WLAN_BUFSIZE]
                  aligned_data(4);
-static uint8_t g_rxbuf[AMEBA_WLAN_BUFSIZE]
-                 aligned_data(4);
 
 /****************************************************************************
  * External Function Prototypes (SDK side, libameba_wifi.a)
@@ -178,195 +190,75 @@ static unsigned char ameba_wlan_is_dhcp(const uint8_t 
*frame,
  * Name: ameba_wlan_transmit
  *
  * Description:
- *   Hand the frame currently in dev->d_buf/d_len to the NP over WHC.
- *   Called with the network locked.
+ *   netdev_ops_s::transmit -- hand one packet to the NP over WHC.
+ *   Non-blocking; called by the upper half under the network lock, gated by
+ *   the TX quota.  The netpkt (possibly IOB-fragmented) is copied out into
+ *   the flat g_txbuf because the WHC send ABI wants a contiguous buffer.
+ *
+ *   On success we own the packet and free it (which restores TX quota).  On
+ *   failure (e.g. whc_ipc_host_send returns -2 when the NP skb pool is
+ *   exhausted) we return a negated errno WITHOUT freeing: the upper half
+ *   recycles the packet and stops the poll, which is genuine backpressure.
  *
  ****************************************************************************/
 
-static int ameba_wlan_transmit(struct ameba_wlan_s *priv)
+static int ameba_wlan_transmit(struct netdev_lowerhalf_s *dev,
+                               netpkt_t *pkt)
 {
-  struct net_driver_s *dev = &priv->dev;
+  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev;
+  unsigned int len = netpkt_getdatalen(dev, pkt);
   int ret;
 
-  NETDEV_TXPACKETS(dev);
-
-  ret = ameba_wifi_txframe(priv->devnum, dev->d_buf, dev->d_len,
-                           ameba_wlan_is_dhcp(dev->d_buf, dev->d_len));
-  ninfo("tx len=%u type=0x%04x ret=%d\n",
-        (unsigned)dev->d_len,
-        (unsigned)((dev->d_buf[12] << 8) | dev->d_buf[13]), ret);
-  if (ret != 0)
+  if (len == 0 || len > AMEBA_WLAN_BUFSIZE)
     {
-      NETDEV_TXERRORS(dev);
-      return -EIO;
-    }
-
-  NETDEV_TXDONE(dev);
-  return OK;
-}
+      /* Malformed: drop it (free -> quota restored) and report consumed. */
 
-/****************************************************************************
- * Name: ameba_wlan_txpoll
- *
- * Description:
- *   devif_poll() callback: transmit one prepared packet.  whc_host_send()
- *   copies the frame, so the work buffer is immediately reusable -> return 0
- *   to keep draining the queued packets.
- *
- ****************************************************************************/
-
-static int ameba_wlan_txpoll(struct net_driver_s *dev)
-{
-  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev->d_private;
-
-  if (dev->d_len > 0)
-    {
-      ameba_wlan_transmit(priv);
+      netpkt_free(dev, pkt, NETPKT_TX);
+      return OK;
     }
 
-  return 0;
-}
+  netpkt_copyout(dev, g_txbuf, pkt, len, 0);
 
-/****************************************************************************
- * Name: ameba_wlan_reply
- *
- * Description:
- *   Send the response, if any, that the network stack produced while
- *   handling a received frame.
- *
- *   NuttX processes RX packets IN PLACE and SYNCHRONOUSLY: ipv4_input() /
- *   ipv6_input() / arp_input() consume the frame in dev->d_buf and, when
- *   the protocol requires an immediate answer, build that answer into the
- *   SAME buffer and set dev->d_len to its length.  So after *_input()
- *   returns:
- *     - d_len > 0  -> the stack left a reply to send (e.g. an ARP reply to
- *                     an ARP request, an ICMP echo reply to a ping, a TCP
- *                     ACK) -> transmit it.
- *     - d_len == 0 -> nothing to send (e.g. a UDP datagram delivered to a
- *                     socket) -> do nothing.
- *
- *   This is NOT an echo/loopback of the received frame; it is the stack's
- *   own response.  It is the standard NuttX devif RX-then-maybe-TX idiom
- *   used by every NuttX Ethernet driver.
- *
- ****************************************************************************/
+  ret = ameba_wifi_txframe(priv->devnum, g_txbuf, len,
+                           ameba_wlan_is_dhcp(g_txbuf, len));
+  ninfo("tx len=%u type=0x%04x ret=%d\n", len,
+        (unsigned)((g_txbuf[12] << 8) | g_txbuf[13]), ret);
 
-static void ameba_wlan_reply(struct ameba_wlan_s *priv)
-{
-  if (priv->dev.d_len > 0)
+  if (ret != 0)
     {
-      ameba_wlan_transmit(priv);
-    }
-}
-
-/****************************************************************************
- * Name: ameba_wlan_rxdispatch
- *
- * Description:
- *   Feed one staged frame (already in dev->d_buf/d_len) into the network
- *   stack by EtherType and transmit any in-place reply it produced (see
- *   ameba_wlan_reply): <proto>_input() may turn the RX buffer into a
- *   response (ARP/ICMP/TCP) with d_len set.  Called from ameba_wlan_rxwork
- *   with the network locked.
- *
- ****************************************************************************/
-
-static void ameba_wlan_rxdispatch(struct ameba_wlan_s *priv)
-{
-  struct net_driver_s *dev = &priv->dev;
-  struct eth_hdr_s *eth = (struct eth_hdr_s *)dev->d_buf;
-
-  NETDEV_RXPACKETS(dev);
-
-#ifdef CONFIG_NET_PKT
-  pkt_input(dev);
-#endif
+      /* NP skb pool full: let the upper half recycle the packet and pause
+       * the poll (backpressure).  Do NOT free here.
+       */
 
-  if (eth->type == HTONS(ETHTYPE_IP))
-    {
-#ifdef CONFIG_NET_IPv4
-      NETDEV_RXIPV4(dev);
-      ipv4_input(dev);
-      ameba_wlan_reply(priv);
-#else
-      NETDEV_RXDROPPED(dev);
-#endif
-    }
-  else if (eth->type == HTONS(ETHTYPE_IP6))
-    {
-#ifdef CONFIG_NET_IPv6
-      NETDEV_RXIPV6(dev);
-      ipv6_input(dev);
-      ameba_wlan_reply(priv);
-#else
-      NETDEV_RXDROPPED(dev);
-#endif
-    }
-  else if (eth->type == HTONS(ETHTYPE_ARP))
-    {
-#ifdef CONFIG_NET_ARP
-      NETDEV_RXARP(dev);
-      arp_input(dev);
-      ameba_wlan_reply(priv);
-#else
-      NETDEV_RXDROPPED(dev);
-#endif
-    }
-  else
-    {
-      NETDEV_RXDROPPED(dev);
+      return -EIO;
     }
+
+  netpkt_free(dev, pkt, NETPKT_TX);
+  return OK;
 }
 
 /****************************************************************************
- * Name: ameba_wlan_rxwork
+ * Name: ameba_wlan_receive
  *
  * Description:
- *   Deferred RX processing (HPWORK).  Drains the frames queued by
- *   ameba_wlan_rxframe and runs each through the network stack.
- *
- *   Decoupling stack processing from the WHC RX callback is the whole point:
- *   the callback now returns immediately, so the WHC layer recycles its NP
- *   RX buffer (sends RECV_DONE) at once instead of waiting for ipv4_input()
- *   and the in-place reply TX.  Otherwise the NP RX ring drains and the NP
- *   drops the bulk of an incoming stream (iperf collapsed to <1 Mbps).  This
- *   is the standard NuttX WiFi netdev idiom and matches what the vendor lwIP
- *   adapter does via its tcpip mailbox.
+ *   netdev_ops_s::receive -- return one staged RX frame, or NULL when the
+ *   queue is empty.  The upper half calls this repeatedly (after
+ *   netdev_lower_rxready) and feeds each packet into the network stack,
+ *   including generating and transmitting any reply.
  *
  ****************************************************************************/
 
-static void ameba_wlan_rxwork(void *arg)
+static netpkt_t *ameba_wlan_receive(struct netdev_lowerhalf_s *dev)
 {
-  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)arg;
-  struct net_driver_s *dev = &priv->dev;
-  struct iob_s *iob;
+  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev;
+  netpkt_t *pkt;
   irqstate_t flags;
 
-  net_lock();
-
-  for (; ; )
-    {
-      flags = enter_critical_section();
-      iob = iob_remove_queue(&priv->rxq);
-      leave_critical_section(flags);
+  flags = spin_lock_irqsave(&priv->rx_lock);
+  pkt = netpkt_remove_queue(&priv->rxq);
+  spin_unlock_irqrestore(&priv->rx_lock, flags);
 
-      if (iob == NULL)
-        {
-          break;
-        }
-
-      /* Copy the queued frame out into the flat work buffer (room for an
-       * in-place reply) and run it through the stack.
-       */
-
-      dev->d_len = iob_copyout(g_rxbuf, iob, iob->io_pktlen, 0);
-      dev->d_buf = g_rxbuf;
-      iob_free_chain(iob);
-
-      ameba_wlan_rxdispatch(priv);
-    }
-
-  net_unlock();
+  return pkt;
 }
 
 /****************************************************************************
@@ -374,16 +266,18 @@ static void ameba_wlan_rxwork(void *arg)
  *
  * Description:
  *   RX entry from the WHC host RX path (SDK side).  Runs in the WHC RX task
- *   context: copy the frame into a pooled IOB, queue it, and schedule the
- *   deferred worker -- then return at once so the WHC layer can recycle the
- *   NP buffer (RECV_DONE) without waiting for stack processing.
+ *   context: copy the frame into a fresh netpkt, queue it, and notify the
+ *   upper half (netdev_lower_rxready) -- then return at once so the WHC
+ *   layer can recycle the NP buffer (RECV_DONE) without waiting for stack
+ *   processing.  If no RX resource is available the frame is dropped (never
+ *   block the WHC RX task, which would stall the NP).
  *
  ****************************************************************************/
 
 void ameba_wlan_rxframe(int idx, const unsigned char *buf, unsigned int len)
 {
   struct ameba_wlan_s *priv = &g_ameba_wlan;
-  struct iob_s *iob;
+  netpkt_t *pkt;
   irqstate_t flags;
   int ret;
 
@@ -394,100 +288,53 @@ void ameba_wlan_rxframe(int idx, const unsigned char 
*buf, unsigned int len)
       return;
     }
 
-  /* Backpressure: drop if the IOB pool cannot hold the frame.  Dropping here
-   * is far better than blocking the WHC RX task, which would stall the NP.
-   */
-
-  if (len > iob_navail(false) * CONFIG_IOB_BUFSIZE)
-    {
-      NETDEV_RXDROPPED(&priv->dev);
-      return;
-    }
-
-  iob = iob_tryalloc(false);
-  if (iob == NULL)
+  pkt = netpkt_alloc(&priv->dev, NETPKT_RX);
+  if (pkt == NULL)
     {
-      NETDEV_RXDROPPED(&priv->dev);
       return;
     }
 
-  ret = iob_trycopyin(iob, buf, len, 0, false);
-  if (ret != (int)len)
+  ret = netpkt_copyin(&priv->dev, pkt, buf, len, 0);
+  if (ret < 0)
     {
-      iob_free_chain(iob);
-      NETDEV_RXDROPPED(&priv->dev);
+      netpkt_free(&priv->dev, pkt, NETPKT_RX);
       return;
     }
 
-  flags = enter_critical_section();
-  ret = iob_tryadd_queue(iob, &priv->rxq);
-  leave_critical_section(flags);
+  flags = spin_lock_irqsave(&priv->rx_lock);
+  ret = netpkt_tryadd_queue(pkt, &priv->rxq);
+  spin_unlock_irqrestore(&priv->rx_lock, flags);
 
   if (ret < 0)
     {
-      iob_free_chain(iob);
-      NETDEV_RXDROPPED(&priv->dev);
+      netpkt_free(&priv->dev, pkt, NETPKT_RX);
       return;
     }
 
-  if (work_available(&priv->rxwork))
-    {
-      work_queue(HPWORK, &priv->rxwork, ameba_wlan_rxwork, priv, 0);
-    }
-}
-
-/****************************************************************************
- * Name: ameba_wlan_txavail_work / ameba_wlan_txavail
- ****************************************************************************/
-
-static void ameba_wlan_txavail_work(void *arg)
-{
-  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)arg;
-
-  net_lock();
-  if (priv->bifup)
-    {
-      priv->dev.d_buf = g_txbuf;
-      priv->dev.d_len = 0;
-      devif_poll(&priv->dev, ameba_wlan_txpoll);
-    }
-
-  net_unlock();
-}
-
-static int ameba_wlan_txavail(struct net_driver_s *dev)
-{
-  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev->d_private;
-
-  if (work_available(&priv->pollwork))
-    {
-      work_queue(LPWORK, &priv->pollwork, ameba_wlan_txavail_work, priv, 0);
-    }
-
-  return OK;
+  netdev_lower_rxready(&priv->dev);
 }
 
 /****************************************************************************
  * Name: ameba_wlan_ifup / ameba_wlan_ifdown
  ****************************************************************************/
 
-static int ameba_wlan_ifup(struct net_driver_s *dev)
+static int ameba_wlan_ifup(struct netdev_lowerhalf_s *dev)
 {
-  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev->d_private;
+  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev;
   uint8_t mac[IFHWADDRLEN];
 
   if (ameba_wifi_get_mac(priv->devnum, mac) == 0)
     {
-      memcpy(dev->d_mac.ether.ether_addr_octet, mac, IFHWADDRLEN);
+      memcpy(dev->netdev.d_mac.ether.ether_addr_octet, mac, IFHWADDRLEN);
     }
 
   ninfo("Bringing up wlan%d %02x:%02x:%02x:%02x:%02x:%02x\n", priv->devnum,
-        dev->d_mac.ether.ether_addr_octet[0],
-        dev->d_mac.ether.ether_addr_octet[1],
-        dev->d_mac.ether.ether_addr_octet[2],
-        dev->d_mac.ether.ether_addr_octet[3],
-        dev->d_mac.ether.ether_addr_octet[4],
-        dev->d_mac.ether.ether_addr_octet[5]);
+        dev->netdev.d_mac.ether.ether_addr_octet[0],
+        dev->netdev.d_mac.ether.ether_addr_octet[1],
+        dev->netdev.d_mac.ether.ether_addr_octet[2],
+        dev->netdev.d_mac.ether.ether_addr_octet[3],
+        dev->netdev.d_mac.ether.ether_addr_octet[4],
+        dev->netdev.d_mac.ether.ether_addr_octet[5]);
 
   priv->bifup = true;
 
@@ -496,30 +343,27 @@ static int ameba_wlan_ifup(struct net_driver_s *dev)
    * which is what blocked DHCP DISCOVER from ever being transmitted).
    */
 
-  netdev_carrier_on(dev);
+  netdev_lower_carrier_on(dev);
   return OK;
 }
 
-static int ameba_wlan_ifdown(struct net_driver_s *dev)
+static int ameba_wlan_ifdown(struct netdev_lowerhalf_s *dev)
 {
-  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev->d_private;
+  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev;
   irqstate_t flags;
 
-  flags = enter_critical_section();
   priv->bifup = false;
-  leave_critical_section(flags);
 
-  /* Stop the deferred RX worker and drop any frames it had not yet drained
-   * so the IOBs are not leaked across an ifdown/ifup cycle.
+  /* Drop any frames the upper half had not yet drained so the IOBs are not
+   * leaked across an ifdown/ifup cycle.  The upper half has already stopped
+   * the RX worker before calling us.
    */
 
-  work_cancel(HPWORK, &priv->rxwork);
+  flags = spin_lock_irqsave(&priv->rx_lock);
+  netpkt_free_queue(&priv->rxq);
+  spin_unlock_irqrestore(&priv->rx_lock, flags);
 
-  flags = enter_critical_section();
-  iob_free_queue(&priv->rxq);
-  leave_critical_section(flags);
-
-  netdev_carrier_off(dev);
+  netdev_lower_carrier_off(dev);
   return OK;
 }
 
@@ -662,10 +506,10 @@ static uint8_t ameba_wlan_freq2channel(const struct 
iw_freq *f)
   return 0;
 }
 
-static int ameba_wlan_ioctl(struct net_driver_s *dev, int cmd,
+static int ameba_wlan_ioctl(struct netdev_lowerhalf_s *dev, int cmd,
                             unsigned long arg)
 {
-  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev->d_private;
+  struct ameba_wlan_s *priv = (struct ameba_wlan_s *)dev;
   struct iwreq *iwr = (struct iwreq *)((uintptr_t)arg);
   int ret = OK;
 
@@ -751,7 +595,7 @@ static int ameba_wlan_ioctl(struct net_driver_s *dev, int 
cmd,
 
               priv->devnum = AMEBA_WLAN_AP_IDX;
               ameba_wifi_get_mac(priv->devnum,
-                                 dev->d_mac.ether.ether_addr_octet);
+                        dev->netdev.d_mac.ether.ether_addr_octet);
               return OK;
             }
 
@@ -803,6 +647,21 @@ static int ameba_wlan_ioctl(struct net_driver_s *dev, int 
cmd,
 }
 #endif
 
+/****************************************************************************
+ * Network Device Operations
+ ****************************************************************************/
+
+static const struct netdev_ops_s g_ameba_wlan_ops =
+{
+  .ifup     = ameba_wlan_ifup,
+  .ifdown   = ameba_wlan_ifdown,
+  .transmit = ameba_wlan_transmit,
+  .receive  = ameba_wlan_receive,
+#ifdef CONFIG_NETDEV_IOCTL
+  .ioctl    = ameba_wlan_ioctl,
+#endif
+};
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -810,20 +669,26 @@ static int ameba_wlan_ioctl(struct net_driver_s *dev, int 
cmd,
 int ameba_wlan_initialize(void)
 {
   struct ameba_wlan_s *priv = &g_ameba_wlan;
-  struct net_driver_s *dev  = &priv->dev;
+  struct netdev_lowerhalf_s *dev = &priv->dev;
 
   memset(priv, 0, sizeof(*priv));
   priv->devnum   = AMEBA_WLAN_DEVNUM;
   priv->mode     = IW_MODE_INFRA;   /* STA by default; wapi can switch to AP */
+  spin_lock_init(&priv->rx_lock);
 
-  dev->d_ifup    = ameba_wlan_ifup;
-  dev->d_ifdown  = ameba_wlan_ifdown;
-  dev->d_txavail = ameba_wlan_txavail;
-#ifdef CONFIG_NETDEV_IOCTL
-  dev->d_ioctl   = ameba_wlan_ioctl;
-#endif
-  dev->d_private = priv;
-  dev->d_buf     = g_txbuf;
+  dev->ops              = &g_ameba_wlan_ops;
+  dev->quota[NETPKT_TX] = AMEBA_WLAN_TX_QUOTA;
+  dev->quota[NETPKT_RX] = AMEBA_WLAN_RX_QUOTA;
+
+  /* Dedicated RX/TX thread at a moderate priority (not HPWORK/192): HPWORK
+   * would preempt the prebuilt WHC IPC RX-delivery task, which then cannot
+   * drain the NP->AP ring in time and the NP silently drops incoming frames
+   * upstream of ameba_wlan_rxframe (measured ~11% loss -> TCP RX collapse).
+   * A lower priority lets the WHC RX task keep the NP ring drained.
+   */
+
+  dev->rxtype           = NETDEV_RX_THREAD;
+  dev->priority         = 100;
 
-  return netdev_register(dev, NET_LL_IEEE80211);
+  return netdev_lower_register(dev, NET_LL_IEEE80211);
 }
diff --git a/arch/arm/src/common/ameba/wifi/ameba_wifi.c 
b/arch/arm/src/common/ameba/wifi/ameba_wifi.c
index b4d32ff21ee..0a9eba93013 100644
--- a/arch/arm/src/common/ameba/wifi/ameba_wifi.c
+++ b/arch/arm/src/common/ameba/wifi/ameba_wifi.c
@@ -108,6 +108,19 @@ int ameba_wifi_start(void)
       g_rtw_task_size.ipc_unblk_api_task = 4096;
     }
 
+  /* Host TX skb pool: the SDK default (4) is too small for sustained TCP
+   * TX.  The pool drains, whc_ipc_host_send() returns -2 (drops the frame),
+   * TCP retransmits, and under load the retransmits exhaust and the link is
+   * torn down (send -> ENOTCONN).  UDP tolerates the drops so is unaffected.
+   * A modest pool keeps TCP TX stable; 16 skbs ~= 27 KB of AP heap (vs 53 KB
+   * at 32).
+   */
+
+  if (wifi_user_config.skb_num_ap < 16)
+    {
+      wifi_user_config.skb_num_ap = 16;
+    }
+
   whc_ipc_host_init();
 
   /* Keep the vendor's default power-save (IPS) config: the WHC driver wakes
diff --git a/boards/arm/rtl8720f/rtl8720f_evb/configs/nsh/defconfig 
b/boards/arm/rtl8720f/rtl8720f_evb/configs/nsh/defconfig
index 73734b6145c..c5fd399080f 100644
--- a/boards/arm/rtl8720f/rtl8720f_evb/configs/nsh/defconfig
+++ b/boards/arm/rtl8720f/rtl8720f_evb/configs/nsh/defconfig
@@ -50,6 +50,7 @@ CONFIG_NET_TCP=y
 CONFIG_NET_TCP_DELAYED_ACK=y
 CONFIG_NET_TCP_KEEPALIVE=y
 CONFIG_NET_TCP_NOTIFIER=y
+CONFIG_NET_TCP_SELECTIVE_ACK=y
 CONFIG_NET_TCP_WRITE_BUFFERS=y
 CONFIG_NET_UDP=y
 CONFIG_NSH_BUILTIN_APPS=y
diff --git a/boards/arm/rtl8721dx/pke8721daf/configs/nsh/defconfig 
b/boards/arm/rtl8721dx/pke8721daf/configs/nsh/defconfig
index 2f53e98bbcd..55f3b8e5013 100644
--- a/boards/arm/rtl8721dx/pke8721daf/configs/nsh/defconfig
+++ b/boards/arm/rtl8721dx/pke8721daf/configs/nsh/defconfig
@@ -50,6 +50,7 @@ CONFIG_NET_TCP=y
 CONFIG_NET_TCP_DELAYED_ACK=y
 CONFIG_NET_TCP_KEEPALIVE=y
 CONFIG_NET_TCP_NOTIFIER=y
+CONFIG_NET_TCP_SELECTIVE_ACK=y
 CONFIG_NET_TCP_WRITE_BUFFERS=y
 CONFIG_NET_UDP=y
 CONFIG_NSH_BUILTIN_APPS=y

Reply via email to