Commit e4a668c5 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

carl9170: fix spurious restart due to high latency

RX Stress tests of unidirectional bulk traffic with
bitrates of up to 220Mbit/s have revealed that the
fatal-event recovery logic [which was solely triggered
by an out-of-rx-buffer situation] is too aggressive.

The new method now "pings" the device and then
decides - based on the response - whenever
a restart is needed or not.
Signed-off-by: default avatarChristian Lamparter <chunkeey@googlemail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e2776905
...@@ -215,7 +215,7 @@ enum carl9170_restart_reasons { ...@@ -215,7 +215,7 @@ enum carl9170_restart_reasons {
CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS, CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS,
CARL9170_RR_WATCHDOG, CARL9170_RR_WATCHDOG,
CARL9170_RR_STUCK_TX, CARL9170_RR_STUCK_TX,
CARL9170_RR_SLOW_SYSTEM, CARL9170_RR_UNRESPONSIVE_DEVICE,
CARL9170_RR_COMMAND_TIMEOUT, CARL9170_RR_COMMAND_TIMEOUT,
CARL9170_RR_TOO_MANY_PHY_ERRORS, CARL9170_RR_TOO_MANY_PHY_ERRORS,
CARL9170_RR_LOST_RSP, CARL9170_RR_LOST_RSP,
...@@ -287,6 +287,7 @@ struct ar9170 { ...@@ -287,6 +287,7 @@ struct ar9170 {
/* reset / stuck frames/queue detection */ /* reset / stuck frames/queue detection */
struct work_struct restart_work; struct work_struct restart_work;
struct work_struct ping_work;
unsigned int restart_counter; unsigned int restart_counter;
unsigned long queue_stop_timeout[__AR9170_NUM_TXQ]; unsigned long queue_stop_timeout[__AR9170_NUM_TXQ];
unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ]; unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ];
......
...@@ -428,6 +428,7 @@ static void carl9170_cancel_worker(struct ar9170 *ar) ...@@ -428,6 +428,7 @@ static void carl9170_cancel_worker(struct ar9170 *ar)
cancel_delayed_work_sync(&ar->led_work); cancel_delayed_work_sync(&ar->led_work);
#endif /* CONFIG_CARL9170_LEDS */ #endif /* CONFIG_CARL9170_LEDS */
cancel_work_sync(&ar->ps_work); cancel_work_sync(&ar->ps_work);
cancel_work_sync(&ar->ping_work);
cancel_work_sync(&ar->ampdu_work); cancel_work_sync(&ar->ampdu_work);
} }
...@@ -533,6 +534,21 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r) ...@@ -533,6 +534,21 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
*/ */
} }
static void carl9170_ping_work(struct work_struct *work)
{
struct ar9170 *ar = container_of(work, struct ar9170, ping_work);
int err;
if (!IS_STARTED(ar))
return;
mutex_lock(&ar->mutex);
err = carl9170_echo_test(ar, 0xdeadbeef);
if (err)
carl9170_restart(ar, CARL9170_RR_UNRESPONSIVE_DEVICE);
mutex_unlock(&ar->mutex);
}
static int carl9170_init_interface(struct ar9170 *ar, static int carl9170_init_interface(struct ar9170 *ar,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
...@@ -1614,6 +1630,7 @@ void *carl9170_alloc(size_t priv_size) ...@@ -1614,6 +1630,7 @@ void *carl9170_alloc(size_t priv_size)
skb_queue_head_init(&ar->tx_pending[i]); skb_queue_head_init(&ar->tx_pending[i]);
} }
INIT_WORK(&ar->ps_work, carl9170_ps_work); INIT_WORK(&ar->ps_work, carl9170_ps_work);
INIT_WORK(&ar->ping_work, carl9170_ping_work);
INIT_WORK(&ar->restart_work, carl9170_restart_work); INIT_WORK(&ar->restart_work, carl9170_restart_work);
INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work); INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor); INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
......
...@@ -431,7 +431,7 @@ static void carl9170_usb_rx_complete(struct urb *urb) ...@@ -431,7 +431,7 @@ static void carl9170_usb_rx_complete(struct urb *urb)
* device. * device.
*/ */
carl9170_restart(ar, CARL9170_RR_SLOW_SYSTEM); ieee80211_queue_work(ar->hw, &ar->ping_work);
} }
} else { } else {
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment