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 commit is contained in:
parent
51c185b3b5
commit
e5af7766bb
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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,9 +142,66 @@ 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;
|
||||
|
||||
/* 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 *)&tmp_hdr,
|
||||
FIRST_WORD_SIZE);
|
||||
if (ret != OK)
|
||||
{
|
||||
wlinfo("Failed to read size\n");
|
||||
bcmf_sdpcm_rxfail(sbus, false);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
len = tmp_hdr.size;
|
||||
checksum = tmp_hdr.checksum;
|
||||
|
||||
/* All zero means no more to read */
|
||||
|
||||
if (!(len | checksum))
|
||||
{
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (((~len & 0xffff) ^ checksum) || len < sizeof(struct bcmf_sdpcm_header))
|
||||
{
|
||||
wlerr("Invalid header checksum or len %x %x\n", len, checksum);
|
||||
bcmf_sdpcm_rxfail(sbus, false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len == FC_UPDATE_PKT_LENGTH)
|
||||
{
|
||||
/* 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);
|
||||
@ -148,61 +209,62 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
|
||||
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 first 4 bytes of sdpcm header
|
||||
* to get the length of the following data to be read
|
||||
*/
|
||||
/* Read the remaining frame data (the buffer is DMA aligned here) */
|
||||
|
||||
ret = bcmf_transfer_bytes(sbus, false, 2, 0,
|
||||
(uint8_t *)header,
|
||||
FIRST_WORD_SIZE);
|
||||
if (ret != OK)
|
||||
if (len <= FIRST_WORD_SIZE)
|
||||
{
|
||||
wlinfo("failread size\n");
|
||||
ret = -EIO;
|
||||
goto exit_abort;
|
||||
}
|
||||
|
||||
len = header->size;
|
||||
checksum = header->checksum;
|
||||
|
||||
/* All zero means no more to read */
|
||||
|
||||
if (!(len | checksum))
|
||||
{
|
||||
ret = -ENODATA;
|
||||
ret = OK;
|
||||
goto exit_free_frame;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (len > sframe->header.len)
|
||||
{
|
||||
wlerr("Frame is too large, cancel %d %d\n", len, sframe->header.len);
|
||||
ret = -ENOMEM;
|
||||
goto exit_abort;
|
||||
}
|
||||
|
||||
/* Read the remaining frame data (the buffer is DMA aligned here) */
|
||||
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user