You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/09/17 02:59:29 UTC

[incubator-nuttx] branch master updated: bcm43xxx: fixed an issue with abrupt stall of receiving new credits (via sdpcm header) from bcm43362 chip/firmware as soon as a high network traffic started

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/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new e5af776  bcm43xxx: fixed an issue with abrupt stall of receiving new credits (via sdpcm header) from bcm43362 chip/firmware as soon as a high network traffic started
e5af776 is described below

commit e5af7766bb3fbe6d575937b0995e7b2568f7a632
Author: Alexander Lunev <al...@mail.ru>
AuthorDate: Thu Sep 16 06:19:44 2021 +0300

    bcm43xxx: fixed an issue with abrupt stall of receiving new credits (via sdpcm header)
    from bcm43362 chip/firmware as soon as a high network traffic started
---
 drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.c  |   1 +
 drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h  |   6 +-
 drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c | 119 ++++++++++++++++++-----
 3 files changed, 98 insertions(+), 28 deletions(-)

diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.c
index d46d7c1..4a57749 100644
--- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.c
+++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.c
@@ -643,6 +643,7 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv,
   sbus->minor              = minor;
   sbus->ready              = false;
   sbus->sleeping           = true;
+  sbus->flow_ctrl          = false;
 
   sbus->bus.txframe        = bcmf_sdpcm_queue_frame;
   sbus->bus.rxframe        = bcmf_sdpcm_get_rx_frame;
diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h
index 33b0c74..ba5af0b 100644
--- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h
+++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdio.h
@@ -41,8 +41,9 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define HEADER_SIZE        0x12 /* Default sdpcm + bdc header size */
-#define FIRST_WORD_SIZE    4
+#define HEADER_SIZE          0x12 /* Default sdpcm + bdc header size */
+#define FIRST_WORD_SIZE      4
+#define FC_UPDATE_PKT_LENGTH 12
 
 /****************************************************************************
  * Public Types
@@ -97,6 +98,7 @@ struct bcmf_sdio_dev_s
   uint8_t max_seq;                 /* Maximum transmit sequence allowed */
   uint8_t tx_seq;                  /* Transmit sequence number (next) */
   uint8_t rx_seq;                  /* Receive sequence number (expected) */
+  bool    flow_ctrl;               /* Current flow control status */
 
   sem_t queue_mutex;               /* Lock for TX/RX/free queues */
   dq_queue_t free_queue;           /* Queue of available frames */
diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c
index ce3cba3..94ecd9a 100644
--- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c
+++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_sdpcm.c
@@ -125,6 +125,10 @@ int bcmf_sdpcm_process_header(FAR struct bcmf_sdio_dev_s *sbus,
 
   sbus->max_seq = header->credit;
 
+  /* Update flow control status */
+
+  sbus->flow_ctrl = (header->flow_control != 0);
+
   return OK;
 }
 
@@ -138,71 +142,129 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
   uint16_t len;
   uint16_t checksum;
   struct bcmf_sdpcm_header *header;
+  struct bcmf_sdpcm_header tmp_hdr;
   struct bcmf_sdio_frame *sframe;
   FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
 
-  /* Request free frame buffer */
-
-  sframe = bcmf_sdio_allocate_frame(priv, false, false);
-
-  if (sframe == NULL)
-    {
-      wlinfo("fail alloc\n");
-      return -EAGAIN;
-    }
-
-  header = (struct bcmf_sdpcm_header *)sframe->data;
-
   /* Read the first 4 bytes of sdpcm header
    * to get the length of the following data to be read
    */
 
   ret = bcmf_transfer_bytes(sbus, false, 2, 0,
-                            (uint8_t *)header,
+                            (uint8_t *)&tmp_hdr,
                             FIRST_WORD_SIZE);
   if (ret != OK)
     {
-      wlinfo("failread size\n");
-      ret = -EIO;
-      goto exit_abort;
+      wlinfo("Failed to read size\n");
+      bcmf_sdpcm_rxfail(sbus, false);
+      return -EIO;
     }
 
-  len = header->size;
-  checksum = header->checksum;
+  len = tmp_hdr.size;
+  checksum = tmp_hdr.checksum;
 
   /* All zero means no more to read */
 
   if (!(len | checksum))
     {
-      ret = -ENODATA;
-      goto exit_free_frame;
+      return -ENODATA;
     }
 
   if (((~len & 0xffff) ^ checksum) || len < sizeof(struct bcmf_sdpcm_header))
     {
       wlerr("Invalid header checksum or len %x %x\n", len, checksum);
-      ret = -EINVAL;
-      goto exit_abort;
+      bcmf_sdpcm_rxfail(sbus, false);
+      return -EINVAL;
     }
 
-  if (len > sframe->header.len)
+  if (len == FC_UPDATE_PKT_LENGTH)
     {
-      wlerr("Frame is too large, cancel %d %d\n", len, sframe->header.len);
-      ret = -ENOMEM;
-      goto exit_abort;
+      /* Flow control update packet with no data */
+
+      ret = bcmf_transfer_bytes(sbus, false, 2, 0,
+                                (uint8_t *)&tmp_hdr + FIRST_WORD_SIZE,
+                                FC_UPDATE_PKT_LENGTH - FIRST_WORD_SIZE);
+      if (ret != OK)
+        {
+          wlinfo("Failed to read the rest 8 bytes\n");
+          bcmf_sdpcm_rxfail(sbus, false);
+          return -EIO;
+        }
+
+      ret = bcmf_sdpcm_process_header(sbus, &tmp_hdr);
+
+      if (ret != OK)
+        {
+          wlerr("Error while processing header %d\n", ret);
+          return -EINVAL;
+        }
+
+      return OK;
+    }
+
+  /* Request free frame buffer */
+
+  sframe = bcmf_sdio_allocate_frame(priv, false, false);
+
+  if (sframe == NULL)
+    {
+      wlinfo("fail alloc\n");
+
+      /* Read out the rest of the header to get the bus credit information */
+
+      ret = bcmf_transfer_bytes(sbus, false, 2, 0,
+                                (uint8_t *)&tmp_hdr + FIRST_WORD_SIZE,
+                                FC_UPDATE_PKT_LENGTH - FIRST_WORD_SIZE);
+
+      if (ret != OK)
+        {
+          wlinfo("Failed to read the rest 8 bytes\n");
+          bcmf_sdpcm_rxfail(sbus, false);
+          return -EIO;
+        }
+
+      bcmf_sdpcm_rxfail(sbus, false);
+
+      ret = bcmf_sdpcm_process_header(sbus, &tmp_hdr);
+
+      if (ret != OK)
+        {
+          wlerr("Error while processing header %d\n", ret);
+          return -EINVAL;
+        }
+
+      return -EAGAIN;
     }
 
+  header = (struct bcmf_sdpcm_header *)sframe->data;
+
   /* Read the remaining frame data (the buffer is DMA aligned here) */
 
+  if (len <= FIRST_WORD_SIZE)
+    {
+      ret = OK;
+      goto exit_free_frame;
+    }
+
   ret = bcmf_transfer_bytes(sbus, false, 2, 0,
                            (uint8_t *)header + FIRST_WORD_SIZE,
                            len - FIRST_WORD_SIZE);
   if (ret != OK)
     {
+      wlinfo("Failed to read remaining frame data\n");
       ret = -EIO;
       goto exit_abort;
     }
 
+  memcpy(header, &tmp_hdr, FIRST_WORD_SIZE);
+
+  if (len > sframe->header.len)
+    {
+      wlerr("Frame is too large, cancel %d %d\n", len, sframe->header.len);
+      ret = -ENOMEM;
+      goto exit_abort;
+    }
+
 #if 0
   wlinfo("Receive frame %p %d\n", sframe, len);
 
@@ -296,6 +358,11 @@ int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv)
       return -ENODATA;
     }
 
+  if (sbus->flow_ctrl)
+    {
+      return -EAGAIN;
+    }
+
   if (sbus->tx_seq == sbus->max_seq)
     {
       /* TODO handle this case */