aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorEyal Shapira <eyal@wizery.com>2012-06-26 03:41:15 -0400
committerLuciano Coelho <coelho@ti.com>2012-06-26 13:30:03 -0400
commit7a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0c (patch)
treeee18c7f890c3fc16223270a3e44e06897a2d3be3 /drivers/net
parent8b425e62d96a3b3a3cc68e6203267f92d1a01946 (diff)
wlcore: fix broken TX due to wrong queuing of recovery
commit 14bba17b "wl12xx: Propagate errors from wl1271_raw_write32" breaks down TX in certain scenarios. wl1271_irq_locked() propagates errors from wl1271_tx_work_locked however it may return -EBUSY when the FW queues are full which is a legitimate case and not a a real error. In this case a recovery is triggered by wl1271_irq and this keeps repeating itself so TX is completely broken. Fix it by avoiding propagating return values as errors even if they aren't. Only bus (SDIO or SPI) ops failures would be progagated as only these should trigger recovery. Signed-off-by: Eyal Shapira <eyal@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index b5211be229d9..6a28aeecf004 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -352,8 +352,10 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
352 bool is_dummy; 352 bool is_dummy;
353 bool is_gem = false; 353 bool is_gem = false;
354 354
355 if (!skb) 355 if (!skb) {
356 wl1271_error("discarding null skb");
356 return -EINVAL; 357 return -EINVAL;
358 }
357 359
358 info = IEEE80211_SKB_CB(skb); 360 info = IEEE80211_SKB_CB(skb);
359 361
@@ -662,6 +664,16 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)
662 } 664 }
663} 665}
664 666
667/*
668 * Returns failure values only in case of failed bus ops within this function.
669 * wl1271_prepare_tx_frame retvals won't be returned in order to avoid
670 * triggering recovery by higher layers when not necessary.
671 * In case a FW command fails within wl1271_prepare_tx_frame fails a recovery
672 * will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame
673 * can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING
674 * within prepare_tx_frame code but there's nothing we should do about those
675 * as well.
676 */
665int wlcore_tx_work_locked(struct wl1271 *wl) 677int wlcore_tx_work_locked(struct wl1271 *wl)
666{ 678{
667 struct wl12xx_vif *wlvif; 679 struct wl12xx_vif *wlvif;
@@ -671,9 +683,10 @@ int wlcore_tx_work_locked(struct wl1271 *wl)
671 bool sent_packets = false; 683 bool sent_packets = false;
672 unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; 684 unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
673 int ret = 0; 685 int ret = 0;
686 int bus_ret = 0;
674 687
675 if (unlikely(wl->state == WL1271_STATE_OFF)) 688 if (unlikely(wl->state == WL1271_STATE_OFF))
676 return -EIO; 689 return 0;
677 690
678 while ((skb = wl1271_skb_dequeue(wl))) { 691 while ((skb = wl1271_skb_dequeue(wl))) {
679 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 692 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -694,9 +707,9 @@ int wlcore_tx_work_locked(struct wl1271 *wl)
694 707
695 buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, 708 buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
696 last_len); 709 last_len);
697 ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, 710 bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA,
698 wl->aggr_buf, buf_offset, true); 711 wl->aggr_buf, buf_offset, true);
699 if (ret < 0) 712 if (bus_ret < 0)
700 goto out; 713 goto out;
701 714
702 sent_packets = true; 715 sent_packets = true;
@@ -734,9 +747,9 @@ int wlcore_tx_work_locked(struct wl1271 *wl)
734out_ack: 747out_ack:
735 if (buf_offset) { 748 if (buf_offset) {
736 buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len); 749 buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
737 ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, 750 bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
738 buf_offset, true); 751 buf_offset, true);
739 if (ret < 0) 752 if (bus_ret < 0)
740 goto out; 753 goto out;
741 754
742 sent_packets = true; 755 sent_packets = true;
@@ -747,9 +760,9 @@ out_ack:
747 * required for older hardware revisions 760 * required for older hardware revisions
748 */ 761 */
749 if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) { 762 if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
750 ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS, 763 bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS,
751 wl->tx_packets_count); 764 wl->tx_packets_count);
752 if (ret < 0) 765 if (bus_ret < 0)
753 goto out; 766 goto out;
754 } 767 }
755 768
@@ -758,7 +771,7 @@ out_ack:
758 wl12xx_rearm_rx_streaming(wl, active_hlids); 771 wl12xx_rearm_rx_streaming(wl, active_hlids);
759 772
760out: 773out:
761 return ret; 774 return bus_ret;
762} 775}
763 776
764void wl1271_tx_work(struct work_struct *work) 777void wl1271_tx_work(struct work_struct *work)