aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/main.c
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2011-10-03 06:33:02 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-10-03 15:22:41 -0400
commit8f641d93c38ae93c67263d4e03f793092d471b12 (patch)
tree396a99a8dfa0d9fd56706b325ca10086cc0ff237 /drivers/net/wireless/libertas/main.c
parent8a3a3c85e44d58f5af0adac74a0b866ba89a1978 (diff)
libertas: detect TX lockups and reset hardware
Recent patches added support for resetting the SD8686 hardware when commands time out, which seems to happen quite frequently soon after resuming the system from a Wake-on-WLAN-triggered resume. At http://dev.laptop.org/ticket/10969 we see the same thing happen with transmits. In this case, the hardware will fail to respond to a frame passed for transmission, and libertas (correctly) will block all further commands and transmissions as the hardware can only deal with one thing at a time. This results in a lockup while the system waits indefinitely for the dead card to respond. Hook up a TX lockup timer to detect this and reset the hardware. Signed-off-by: Daniel Drake <dsd@laptop.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r--drivers/net/wireless/libertas/main.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index d62d1fb4177f..6a326233391f 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -188,6 +188,7 @@ int lbs_stop_iface(struct lbs_private *priv)
188 spin_unlock_irqrestore(&priv->driver_lock, flags); 188 spin_unlock_irqrestore(&priv->driver_lock, flags);
189 189
190 cancel_work_sync(&priv->mcast_work); 190 cancel_work_sync(&priv->mcast_work);
191 del_timer_sync(&priv->tx_lockup_timer);
191 192
192 /* Disable command processing, and wait for all commands to complete */ 193 /* Disable command processing, and wait for all commands to complete */
193 lbs_deb_main("waiting for commands to complete\n"); 194 lbs_deb_main("waiting for commands to complete\n");
@@ -243,6 +244,7 @@ void lbs_host_to_card_done(struct lbs_private *priv)
243 lbs_deb_enter(LBS_DEB_THREAD); 244 lbs_deb_enter(LBS_DEB_THREAD);
244 245
245 spin_lock_irqsave(&priv->driver_lock, flags); 246 spin_lock_irqsave(&priv->driver_lock, flags);
247 del_timer(&priv->tx_lockup_timer);
246 248
247 priv->dnld_sent = DNLD_RES_RECEIVED; 249 priv->dnld_sent = DNLD_RES_RECEIVED;
248 250
@@ -585,6 +587,9 @@ static int lbs_thread(void *data)
585 if (ret) { 587 if (ret) {
586 lbs_deb_tx("host_to_card failed %d\n", ret); 588 lbs_deb_tx("host_to_card failed %d\n", ret);
587 priv->dnld_sent = DNLD_RES_RECEIVED; 589 priv->dnld_sent = DNLD_RES_RECEIVED;
590 } else {
591 mod_timer(&priv->tx_lockup_timer,
592 jiffies + (HZ * 5));
588 } 593 }
589 priv->tx_pending_len = 0; 594 priv->tx_pending_len = 0;
590 if (!priv->currenttxskb) { 595 if (!priv->currenttxskb) {
@@ -601,6 +606,7 @@ static int lbs_thread(void *data)
601 } 606 }
602 607
603 del_timer(&priv->command_timer); 608 del_timer(&priv->command_timer);
609 del_timer(&priv->tx_lockup_timer);
604 del_timer(&priv->auto_deepsleep_timer); 610 del_timer(&priv->auto_deepsleep_timer);
605 611
606 lbs_deb_leave(LBS_DEB_THREAD); 612 lbs_deb_leave(LBS_DEB_THREAD);
@@ -735,6 +741,32 @@ out:
735} 741}
736 742
737/** 743/**
744 * lbs_tx_lockup_handler - handles the timeout of the passing of TX frames
745 * to the hardware. This is known to frequently happen with SD8686 when
746 * waking up after a Wake-on-WLAN-triggered resume.
747 *
748 * @data: &struct lbs_private pointer
749 */
750static void lbs_tx_lockup_handler(unsigned long data)
751{
752 struct lbs_private *priv = (struct lbs_private *)data;
753 unsigned long flags;
754
755 lbs_deb_enter(LBS_DEB_TX);
756 spin_lock_irqsave(&priv->driver_lock, flags);
757
758 netdev_info(priv->dev, "TX lockup detected\n");
759 if (priv->reset_card)
760 priv->reset_card(priv);
761
762 priv->dnld_sent = DNLD_RES_RECEIVED;
763 wake_up_interruptible(&priv->waitq);
764
765 spin_unlock_irqrestore(&priv->driver_lock, flags);
766 lbs_deb_leave(LBS_DEB_TX);
767}
768
769/**
738 * auto_deepsleep_timer_fn - put the device back to deep sleep mode when 770 * auto_deepsleep_timer_fn - put the device back to deep sleep mode when
739 * timer expires and no activity (command, event, data etc.) is detected. 771 * timer expires and no activity (command, event, data etc.) is detected.
740 * @data: &struct lbs_private pointer 772 * @data: &struct lbs_private pointer
@@ -820,6 +852,8 @@ static int lbs_init_adapter(struct lbs_private *priv)
820 852
821 setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, 853 setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
822 (unsigned long)priv); 854 (unsigned long)priv);
855 setup_timer(&priv->tx_lockup_timer, lbs_tx_lockup_handler,
856 (unsigned long)priv);
823 setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, 857 setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
824 (unsigned long)priv); 858 (unsigned long)priv);
825 859
@@ -857,6 +891,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
857 lbs_free_cmd_buffer(priv); 891 lbs_free_cmd_buffer(priv);
858 kfifo_free(&priv->event_fifo); 892 kfifo_free(&priv->event_fifo);
859 del_timer(&priv->command_timer); 893 del_timer(&priv->command_timer);
894 del_timer(&priv->tx_lockup_timer);
860 del_timer(&priv->auto_deepsleep_timer); 895 del_timer(&priv->auto_deepsleep_timer);
861 896
862 lbs_deb_leave(LBS_DEB_MAIN); 897 lbs_deb_leave(LBS_DEB_MAIN);