diff options
Diffstat (limited to 'drivers/net/wireless/ti/wlcore/main.c')
-rw-r--r-- | drivers/net/wireless/ti/wlcore/main.c | 77 |
1 files changed, 45 insertions, 32 deletions
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2240cca597a..9f04b64dfa3 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -62,7 +62,7 @@ static bool no_recovery; static void __wl1271_op_remove_interface(struct wl1271 *wl, struct ieee80211_vif *vif, bool reset_tx_queues); -static void wl1271_op_stop(struct ieee80211_hw *hw); +static void wlcore_op_stop_locked(struct wl1271 *wl); static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); static int wl12xx_set_authorized(struct wl1271 *wl, @@ -916,16 +916,16 @@ static void wl1271_recovery_work(struct work_struct *work) if (wl->state != WL1271_STATE_ON || wl->plt) goto out_unlock; - wl12xx_read_fwlog_panic(wl); - - wlcore_print_recovery(wl); + if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) { + wl12xx_read_fwlog_panic(wl); + wlcore_print_recovery(wl); + } BUG_ON(bug_on_recovery && !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); if (no_recovery) { wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); - clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); goto out_unlock; } @@ -956,9 +956,8 @@ static void wl1271_recovery_work(struct work_struct *work) vif = wl12xx_wlvif_to_vif(wlvif); __wl1271_op_remove_interface(wl, vif, false); } - wl->watchdog_recovery = false; - mutex_unlock(&wl->mutex); - wl1271_op_stop(wl->hw); + + wlcore_op_stop_locked(wl); ieee80211_restart_hw(wl->hw); @@ -967,9 +966,10 @@ static void wl1271_recovery_work(struct work_struct *work) * to restart the HW. */ wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); - return; + out_unlock: - wl->watchdog_recovery = false; + wl->watchdog_recovery = false; + clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); mutex_unlock(&wl->mutex); } @@ -1211,7 +1211,9 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * The workqueue is slow to process the tx_queue and we need stop * the queue here, otherwise the queue will get too long. */ - if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { + if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK && + !wlcore_is_queue_stopped_by_reason(wl, q, + WLCORE_QUEUE_STOP_REASON_WATERMARK)) { wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); wlcore_stop_queue_locked(wl, q, WLCORE_QUEUE_STOP_REASON_WATERMARK); @@ -1797,33 +1799,15 @@ static int wl1271_op_start(struct ieee80211_hw *hw) return 0; } -static void wl1271_op_stop(struct ieee80211_hw *hw) +static void wlcore_op_stop_locked(struct wl1271 *wl) { - struct wl1271 *wl = hw->priv; int i; - wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); - - /* - * Interrupts must be disabled before setting the state to OFF. - * Otherwise, the interrupt handler might be called and exit without - * reading the interrupt status. - */ - wlcore_disable_interrupts(wl); - mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) { if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) wlcore_enable_interrupts(wl); - mutex_unlock(&wl->mutex); - - /* - * This will not necessarily enable interrupts as interrupts - * may have been disabled when op_stop was called. It will, - * however, balance the above call to disable_interrupts(). - */ - wlcore_enable_interrupts(wl); return; } @@ -1832,8 +1816,16 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) * functions don't perform further work. */ wl->state = WL1271_STATE_OFF; + + /* + * Use the nosync variant to disable interrupts, so the mutex could be + * held while doing so without deadlocking. + */ + wlcore_disable_interrupts_nosync(wl); + mutex_unlock(&wl->mutex); + wlcore_synchronize_interrupts(wl); wl1271_flush_deferred_work(wl); cancel_delayed_work_sync(&wl->scan_complete_work); cancel_work_sync(&wl->netstack_work); @@ -1900,6 +1892,17 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->tx_res_if = NULL; kfree(wl->target_mem_map); wl->target_mem_map = NULL; +} + +static void wlcore_op_stop(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + + wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + wlcore_op_stop_locked(wl); mutex_unlock(&wl->mutex); } @@ -4566,7 +4569,7 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - for (i = 0; i < IEEE80211_NUM_BANDS; i++) + for (i = 0; i < WLCORE_NUM_BANDS; i++) wlvif->bitrate_masks[i] = wl1271_tx_enabled_rates_get(wl, mask->control[i].legacy, @@ -4634,6 +4637,13 @@ out: mutex_unlock(&wl->mutex); } +static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) +{ + struct wl1271 *wl = hw->priv; + + wl1271_tx_flush(wl); +} + static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -4796,7 +4806,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = { static const struct ieee80211_ops wl1271_ops = { .start = wl1271_op_start, - .stop = wl1271_op_stop, + .stop = wlcore_op_stop, .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, .change_interface = wl12xx_op_change_interface, @@ -4824,6 +4834,7 @@ static const struct ieee80211_ops wl1271_ops = { .tx_frames_pending = wl1271_tx_frames_pending, .set_bitrate_mask = wl12xx_set_bitrate_mask, .channel_switch = wl12xx_op_channel_switch, + .flush = wlcore_op_flush, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -5504,6 +5515,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) goto out_free_hw; } +#ifdef CONFIG_PM ret = enable_irq_wake(wl->irq); if (!ret) { wl->irq_wake_enabled = true; @@ -5517,6 +5529,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) WL1271_RX_FILTER_MAX_PATTERN_SIZE; } } +#endif disable_irq(wl->irq); ret = wl12xx_get_hw_info(wl); |