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 */