From df40531a070e6048ab749a97755f5187aea7dec7 Mon Sep 17 00:00:00 2001 From: Alexander Lunev Date: Sat, 2 Oct 2021 06:26:43 +0300 Subject: [PATCH] bcm43xxx: fixed an issue with wrong devif_timer() invocations on bcmf_netdev_notify_tx_done events that provoked massive TCP spurious retransmissions; bcm43xxx: fixed an issue with sporadic stalls of TX poll timer. --- .../wireless/ieee80211/bcm43xxx/bcmf_driver.h | 1 + .../wireless/ieee80211/bcm43xxx/bcmf_netdev.c | 71 ++++++++++++++++--- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h index bb46852638..bc465cce63 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h @@ -66,6 +66,7 @@ struct bcmf_dev_s bool bc_bifup; /* true:ifup false:ifdown */ struct wdog_s bc_txpoll; /* TX poll timer */ struct work_s bc_irqwork; /* For deferring interrupt work to the work queue */ + struct work_s bc_rxwork; /* For deferring rx work to the work queue */ struct work_s bc_pollwork; /* For deferring poll work to the work queue */ /* This holds the information visible to the NuttX network */ diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c index 709a138c7c..a6bd1c5788 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c @@ -107,7 +107,7 @@ static int bcmf_transmit(FAR struct bcmf_dev_s *priv, FAR struct bcmf_frame_s *frame); static void bcmf_receive(FAR struct bcmf_dev_s *priv); static int bcmf_txpoll(FAR struct net_driver_s *dev); -static void bcmf_rxpoll(FAR void *arg); +static void bcmf_rxpoll_work(FAR void *arg); /* Watchdog timer expirations */ @@ -484,7 +484,47 @@ static int bcmf_txpoll(FAR struct net_driver_s *dev) } /**************************************************************************** - * Name: bcmf_rxpoll + * Function: bcmf_txdone_poll_work + * + * Description: + * The function is called in order to perform an out-of-sequence TX poll. + * This is done: + * + * 1. After completion of a transmission (bcmf_netdev_notify_tx_done), and + * 2. When new TX data is available (bcmf_txavail). + * + * Input Parameters: + * arg - context of device to use + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void bcmf_txdone_poll_work(FAR void *arg) +{ + FAR struct bcmf_dev_s *priv = (FAR struct bcmf_dev_s *)arg; + + /* Check if there is room in the hardware to hold another packet. */ + + net_lock(); + + if (bcmf_netdev_alloc_tx_frame(priv) == OK) + { + /* If so, then poll the network for new XMIT data */ + + priv->bc_dev.d_buf = priv->cur_tx_frame->data; + priv->bc_dev.d_len = 0; + devif_timer(&priv->bc_dev, 0, bcmf_txpoll); + } + + net_unlock(); +} + +/**************************************************************************** + * Name: bcmf_rxpoll_work * * Description: * Process RX frames @@ -496,11 +536,10 @@ static int bcmf_txpoll(FAR struct net_driver_s *dev) * OK on success * * Assumptions: - * The network is locked. * ****************************************************************************/ -static void bcmf_rxpoll(FAR void *arg) +static void bcmf_rxpoll_work(FAR void *arg) { FAR struct bcmf_dev_s *priv = (FAR struct bcmf_dev_s *)arg; @@ -539,7 +578,11 @@ void bcmf_netdev_notify_tx_done(FAR struct bcmf_dev_s *priv) { /* Schedule to perform a poll for new Tx data the worker thread. */ - work_queue(BCMFWORK, &priv->bc_pollwork, bcmf_poll_work, priv, 0); + if (work_available(&priv->bc_pollwork)) + { + work_queue(BCMFWORK, &priv->bc_pollwork, + bcmf_txdone_poll_work, priv, 0); + } } /**************************************************************************** @@ -556,7 +599,7 @@ void bcmf_netdev_notify_rx(FAR struct bcmf_dev_s *priv) { /* Queue a job to process RX frames */ - work_queue(BCMFWORK, &priv->bc_pollwork, bcmf_rxpoll, priv, 0); + work_queue(BCMFWORK, &priv->bc_rxwork, bcmf_rxpoll_work, priv, 0); } /**************************************************************************** @@ -566,13 +609,12 @@ void bcmf_netdev_notify_rx(FAR struct bcmf_dev_s *priv) * Perform periodic polling from the worker thread * * Input Parameters: - * arg - The argument passed when work_queue() as called. + * arg - The argument passed when work_queue() was called. * * Returned Value: * OK on success * * Assumptions: - * The network is locked. * ****************************************************************************/ @@ -610,9 +652,10 @@ static void bcmf_poll_work(FAR void *arg) /* Setup the watchdog poll timer again */ +exit_unlock: wd_start(&priv->bc_txpoll, BCMF_WDDELAY, bcmf_poll_expiry, (wdparm_t)priv); -exit_unlock: + net_unlock(); } @@ -639,7 +682,15 @@ static void bcmf_poll_expiry(wdparm_t arg) /* Schedule to perform the interrupt processing on the worker thread. */ - work_queue(BCMFWORK, &priv->bc_pollwork, bcmf_poll_work, priv, 0); + if (work_available(&priv->bc_pollwork)) + { + work_queue(BCMFWORK, &priv->bc_pollwork, bcmf_poll_work, priv, 0); + } + else + { + wd_start(&priv->bc_txpoll, BCMF_WDDELAY, + bcmf_poll_expiry, (wdparm_t)priv); + } } /****************************************************************************