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->minor = minor;
|
||||||
sbus->ready = false;
|
sbus->ready = false;
|
||||||
sbus->sleeping = true;
|
sbus->sleeping = true;
|
||||||
|
sbus->flow_ctrl = false;
|
||||||
|
|
||||||
sbus->bus.txframe = bcmf_sdpcm_queue_frame;
|
sbus->bus.txframe = bcmf_sdpcm_queue_frame;
|
||||||
sbus->bus.rxframe = bcmf_sdpcm_get_rx_frame;
|
sbus->bus.rxframe = bcmf_sdpcm_get_rx_frame;
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
#define HEADER_SIZE 0x12 /* Default sdpcm + bdc header size */
|
#define HEADER_SIZE 0x12 /* Default sdpcm + bdc header size */
|
||||||
#define FIRST_WORD_SIZE 4
|
#define FIRST_WORD_SIZE 4
|
||||||
|
#define FC_UPDATE_PKT_LENGTH 12
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
@ -97,6 +98,7 @@ struct bcmf_sdio_dev_s
|
|||||||
uint8_t max_seq; /* Maximum transmit sequence allowed */
|
uint8_t max_seq; /* Maximum transmit sequence allowed */
|
||||||
uint8_t tx_seq; /* Transmit sequence number (next) */
|
uint8_t tx_seq; /* Transmit sequence number (next) */
|
||||||
uint8_t rx_seq; /* Receive sequence number (expected) */
|
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 */
|
sem_t queue_mutex; /* Lock for TX/RX/free queues */
|
||||||
dq_queue_t free_queue; /* Queue of available frames */
|
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;
|
sbus->max_seq = header->credit;
|
||||||
|
|
||||||
|
/* Update flow control status */
|
||||||
|
|
||||||
|
sbus->flow_ctrl = (header->flow_control != 0);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,9 +142,66 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
|
|||||||
uint16_t len;
|
uint16_t len;
|
||||||
uint16_t checksum;
|
uint16_t checksum;
|
||||||
struct bcmf_sdpcm_header *header;
|
struct bcmf_sdpcm_header *header;
|
||||||
|
struct bcmf_sdpcm_header tmp_hdr;
|
||||||
struct bcmf_sdio_frame *sframe;
|
struct bcmf_sdio_frame *sframe;
|
||||||
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
|
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 */
|
/* Request free frame buffer */
|
||||||
|
|
||||||
sframe = bcmf_sdio_allocate_frame(priv, false, false);
|
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)
|
if (sframe == NULL)
|
||||||
{
|
{
|
||||||
wlinfo("fail alloc\n");
|
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;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
header = (struct bcmf_sdpcm_header *)sframe->data;
|
header = (struct bcmf_sdpcm_header *)sframe->data;
|
||||||
|
|
||||||
/* Read the first 4 bytes of sdpcm header
|
/* Read the remaining frame data (the buffer is DMA aligned here) */
|
||||||
* to get the length of the following data to be read
|
|
||||||
*/
|
|
||||||
|
|
||||||
ret = bcmf_transfer_bytes(sbus, false, 2, 0,
|
if (len <= FIRST_WORD_SIZE)
|
||||||
(uint8_t *)header,
|
|
||||||
FIRST_WORD_SIZE);
|
|
||||||
if (ret != OK)
|
|
||||||
{
|
{
|
||||||
wlinfo("failread size\n");
|
ret = OK;
|
||||||
ret = -EIO;
|
|
||||||
goto exit_abort;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = header->size;
|
|
||||||
checksum = header->checksum;
|
|
||||||
|
|
||||||
/* All zero means no more to read */
|
|
||||||
|
|
||||||
if (!(len | checksum))
|
|
||||||
{
|
|
||||||
ret = -ENODATA;
|
|
||||||
goto exit_free_frame;
|
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,
|
ret = bcmf_transfer_bytes(sbus, false, 2, 0,
|
||||||
(uint8_t *)header + FIRST_WORD_SIZE,
|
(uint8_t *)header + FIRST_WORD_SIZE,
|
||||||
len - FIRST_WORD_SIZE);
|
len - FIRST_WORD_SIZE);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
{
|
{
|
||||||
|
wlinfo("Failed to read remaining frame data\n");
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto exit_abort;
|
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
|
#if 0
|
||||||
wlinfo("Receive frame %p %d\n", sframe, len);
|
wlinfo("Receive frame %p %d\n", sframe, len);
|
||||||
|
|
||||||
@ -296,6 +358,11 @@ int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv)
|
|||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sbus->flow_ctrl)
|
||||||
|
{
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
if (sbus->tx_seq == sbus->max_seq)
|
if (sbus->tx_seq == sbus->max_seq)
|
||||||
{
|
{
|
||||||
/* TODO handle this case */
|
/* TODO handle this case */
|
||||||
|
Loading…
Reference in New Issue
Block a user