From 32769814d54a5a360b83811b4039c776ec953c71 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 11 Feb 2014 12:27:19 +0200 Subject: [PATCH 01/21] mac80211: fix sched_scan restart on recovery In case we were not suspended, the reconfig function returns without configuring the scheduled scan. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- net/mac80211/util.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 676dc0967f37..1d1bb7084c05 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1740,6 +1740,26 @@ int ieee80211_reconfig(struct ieee80211_local *local) ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_SUSPEND); + /* + * Reconfigure sched scan if it was interrupted by FW restart or + * suspend. + */ + mutex_lock(&local->mtx); + sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, + lockdep_is_held(&local->mtx)); + if (sched_scan_sdata && local->sched_scan_req) + /* + * Sched scan stopped, but we don't want to report it. Instead, + * we're trying to reschedule. + */ + if (__ieee80211_request_sched_scan_start(sched_scan_sdata, + local->sched_scan_req)) + sched_scan_stopped = true; + mutex_unlock(&local->mtx); + + if (sched_scan_stopped) + cfg80211_sched_scan_stopped(local->hw.wiphy); + /* * If this is for hw restart things are still running. * We may want to change that later, however. @@ -1768,26 +1788,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) WARN_ON(1); #endif - /* - * Reconfigure sched scan if it was interrupted by FW restart or - * suspend. - */ - mutex_lock(&local->mtx); - sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, - lockdep_is_held(&local->mtx)); - if (sched_scan_sdata && local->sched_scan_req) - /* - * Sched scan stopped, but we don't want to report it. Instead, - * we're trying to reschedule. - */ - if (__ieee80211_request_sched_scan_start(sched_scan_sdata, - local->sched_scan_req)) - sched_scan_stopped = true; - mutex_unlock(&local->mtx); - - if (sched_scan_stopped) - cfg80211_sched_scan_stopped(local->hw.wiphy); - return 0; } From c368ddaa9ad79fdffde4756804321feba6725c75 Mon Sep 17 00:00:00 2001 From: Eytan Lifshitz Date: Thu, 6 Feb 2014 21:01:32 +0200 Subject: [PATCH 02/21] mac80211: fix memory leak In case ieee80211_prep_connection() fails to dereference sdata->vif.chanctx_conf, the function returns and doesn't free new_sta. fixed. Signed-off-by: Eytan Lifshitz Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fc1d82465b3c..57d5482b10fa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3753,6 +3753,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); + sta_info_free(local, new_sta); return -EINVAL; } rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); From 1bf4bbb4024dcdab5e57634dd8ae1072d42a53ac Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 11 Feb 2014 16:02:47 +0100 Subject: [PATCH 03/21] mac80211: send control port protocol frames to the VO queue Improves reliability of wifi connections with WPA, since authentication frames are prioritized over normal traffic and also typically exempt from aggregation. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/wme.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 21211c60ca98..d51422c778de 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, return IEEE80211_AC_BE; } + if (skb->protocol == sdata->control_port_protocol) { + skb->priority = 7; + return ieee80211_downgrade_queue(sdata, skb); + } + /* use the data classifier to determine what 802.1d tag the * data frame has */ rcu_read_lock(); From 50c11eb9982554e9f99b7bab322c517cbe5ce1a1 Mon Sep 17 00:00:00 2001 From: Inbal Hacohen Date: Wed, 12 Feb 2014 09:32:27 +0200 Subject: [PATCH 04/21] cfg80211: bugfix in regulatory user hint process After processing hint_user, we would want to schedule the timeout work only if we are actually waiting to CRDA. This happens when the status is not "IGNORE" nor "ALREADY_SET". Signed-off-by: Inbal Hacohen Signed-off-by: Johannes Berg --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9b897fca7487..4c50c21d6f52 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) return; case NL80211_REGDOM_SET_BY_USER: treatment = reg_process_hint_user(reg_request); - if (treatment == REG_REQ_OK || + if (treatment == REG_REQ_IGNORE || treatment == REG_REQ_ALREADY_SET) return; schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); From 1d147bfa64293b2723c4fec50922168658e613ba Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 20 Feb 2014 09:22:11 +0200 Subject: [PATCH 05/21] mac80211: fix AP powersave TX vs. wakeup race There is a race between the TX path and the STA wakeup: while a station is sleeping, mac80211 buffers frames until it wakes up, then the frames are transmitted. However, the RX and TX path are concurrent, so the packet indicating wakeup can be processed while a packet is being transmitted. This can lead to a situation where the buffered frames list is emptied on the one side, while a frame is being added on the other side, as the station is still seen as sleeping in the TX path. As a result, the newly added frame will not be send anytime soon. It might be sent much later (and out of order) when the station goes to sleep and wakes up the next time. Additionally, it can lead to the crash below. Fix all this by synchronising both paths with a new lock. Both path are not fastpath since they handle PS situations. In a later patch we'll remove the extra skb queue locks to reduce locking overhead. BUG: unable to handle kernel NULL pointer dereference at 000000b0 IP: [] ieee80211_report_used_skb+0x11/0x3e0 [mac80211] *pde = 00000000 Oops: 0000 [#1] SMP DEBUG_PAGEALLOC EIP: 0060:[] EFLAGS: 00210282 CPU: 1 EIP is at ieee80211_report_used_skb+0x11/0x3e0 [mac80211] EAX: e5900da0 EBX: 00000000 ECX: 00000001 EDX: 00000000 ESI: e41d00c0 EDI: e5900da0 EBP: ebe458e4 ESP: ebe458b0 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 CR0: 8005003b CR2: 000000b0 CR3: 25a78000 CR4: 000407d0 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Process iperf (pid: 3934, ti=ebe44000 task=e757c0b0 task.ti=ebe44000) iwlwifi 0000:02:00.0: I iwl_pcie_enqueue_hcmd Sending command LQ_CMD (#4e), seq: 0x0903, 92 bytes at 3[3]:9 Stack: e403b32c ebe458c4 00200002 00200286 e403b338 ebe458cc c10960bb e5900da0 ff76a6ec ebe458d8 00000000 e41d00c0 e5900da0 ebe458f0 ff6f1b75 e403b210 ebe4598c ff723dc1 00000000 ff76a6ec e597c978 e403b758 00000002 00000002 Call Trace: [] ieee80211_free_txskb+0x15/0x20 [mac80211] [] invoke_tx_handlers+0x1661/0x1780 [mac80211] [] ieee80211_tx+0x75/0x100 [mac80211] [] ieee80211_xmit+0x8f/0xc0 [mac80211] [] ieee80211_subif_start_xmit+0x4fe/0xe20 [mac80211] [] dev_hard_start_xmit+0x450/0x950 [] sch_direct_xmit+0xa9/0x250 [] __qdisc_run+0x4b/0x150 [] dev_queue_xmit+0x2c2/0xca0 Cc: stable@vger.kernel.org Reported-by: Yaara Rozenblum Signed-off-by: Emmanuel Grumbach Reviewed-by: Stanislaw Gruszka [reword commit log, use a separate lock] Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 4 ++++ net/mac80211/sta_info.h | 7 +++---- net/mac80211/tx.c | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index decd30c1e290..62a5f0889583 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -330,6 +330,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); spin_lock_init(&sta->lock); + spin_lock_init(&sta->ps_lock); INIT_WORK(&sta->drv_unblock_wk, sta_unblock); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); mutex_init(&sta->ampdu_mlme.mtx); @@ -1109,6 +1110,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) skb_queue_head_init(&pending); + /* sync with ieee80211_tx_h_unicast_ps_buf */ + spin_lock(&sta->ps_lock); /* Send all buffered frames to the station */ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { int count = skb_queue_len(&pending), tmp; @@ -1128,6 +1131,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) } ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); + spin_unlock(&sta->ps_lock); /* This station just woke up and isn't aware of our SMPS state */ if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d77ff7090630..d3a6d8208f2f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat { * @drv_unblock_wk: used for driver PS unblocking * @listen_interval: listen interval of this station, when we're acting as AP * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly + * @ps_lock: used for powersave (when mac80211 is the AP) related locking * @ps_tx_buf: buffers (per AC) of frames to transmit to this station * when it leaves power saving state or polls * @tx_filtered: buffers (per AC) of frames we already tried to @@ -356,10 +357,8 @@ struct sta_info { /* use the accessors defined below */ unsigned long _flags; - /* - * STA powersave frame queues, no more than the internal - * locking required. - */ + /* STA powersave lock and frame queues */ + spinlock_t ps_lock; struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; unsigned long driver_buffered_tids; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 97a02d3f7d87..4080c615636f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -478,6 +478,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta->sta.addr, sta->sta.aid, ac); if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); + + /* sync with ieee80211_sta_ps_deliver_wakeup */ + spin_lock(&sta->ps_lock); + /* + * STA woke up the meantime and all the frames on ps_tx_buf have + * been queued to pending queue. No reordering can happen, go + * ahead and Tx the packet. + */ + if (!test_sta_flag(sta, WLAN_STA_PS_STA) && + !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { + spin_unlock(&sta->ps_lock); + return TX_CONTINUE; + } + if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); ps_dbg(tx->sdata, @@ -492,6 +506,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); + spin_unlock(&sta->ps_lock); if (!timer_pending(&local->sta_cleanup)) mod_timer(&local->sta_cleanup, From 5108ca828017120981880eeec8a9ec369334a899 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Feb 2014 20:49:03 +0100 Subject: [PATCH 06/21] mac80211: insert stations before adding to driver There's a race condition in mac80211 because we add stations to the internal lists after adding them to the driver, which means that (for example) the following can happen: 1. a station connects and is added 2. first, it is added to the driver 3. then, it is added to the mac80211 lists If the station goes to sleep between steps 2 and 3, and the firmware/hardware records it as being asleep, mac80211 will never instruct the driver to wake it up again as it never realized it went to sleep since the RX path discarded the frame as a "spurious class 3 frame", no station entry was present yet. Fix this by adding the station in software first, and only then adding it to the driver. That way, any state that the driver changes will be reflected properly in mac80211's station state. The problematic part is the roll-back if the driver fails to add the station, in that case a bit more is needed. To not make that overly complex prevent starting BA sessions in the meantime. Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 62a5f0889583..ffc1ee6a2ec1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local, return -ENOENT; } -static void cleanup_single_sta(struct sta_info *sta) +static void __cleanup_single_sta(struct sta_info *sta) { int ac, i; struct tid_ampdu_tx *tid_tx; @@ -139,7 +139,14 @@ static void cleanup_single_sta(struct sta_info *sta) ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); kfree(tid_tx); } +} +static void cleanup_single_sta(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; + + __cleanup_single_sta(sta); sta_info_free(local, sta); } @@ -488,21 +495,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) goto out_err; } - /* notify driver */ - err = sta_info_insert_drv_state(local, sdata, sta); - if (err) - goto out_err; - local->num_sta++; local->sta_generation++; smp_mb(); + /* simplify things and don't accept BA sessions yet */ + set_sta_flag(sta, WLAN_STA_BLOCK_BA); + /* make the station visible */ sta_info_hash_add(local, sta); list_add_rcu(&sta->list, &local->sta_list); + /* notify driver */ + err = sta_info_insert_drv_state(local, sdata, sta); + if (err) + goto out_remove; + set_sta_flag(sta, WLAN_STA_INSERTED); + /* accept BA sessions now */ + clear_sta_flag(sta, WLAN_STA_BLOCK_BA); ieee80211_recalc_min_chandef(sdata); ieee80211_sta_debugfs_add(sta); @@ -523,6 +535,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) mesh_accept_plinks_update(sdata); return 0; + out_remove: + sta_info_hash_del(local, sta); + list_del_rcu(&sta->list); + local->num_sta--; + synchronize_net(); + __cleanup_single_sta(sta); out_err: mutex_unlock(&local->sta_mtx); rcu_read_lock(); From e3685e03b40f5ec7926d9a75bf63467fc4071df9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Feb 2014 11:19:58 +0100 Subject: [PATCH 07/21] mac80211: fix station wakeup powersave race Consider the following (relatively unlikely) scenario: 1) station goes to sleep while frames are buffered in driver 2) driver blocks wakeup (until no more frames are buffered) 3) station wakes up again 4) driver unblocks wakeup In this case, the current mac80211 code will do the following: 1) WLAN_STA_PS_STA set 2) WLAN_STA_PS_DRIVER set 3) - nothing - 4) WLAN_STA_PS_DRIVER cleared As a result, no frames will be delivered to the client, even though it is awake, until it sends another frame to us that triggers ieee80211_sta_ps_deliver_wakeup() in sta_ps_end(). Since we now take the PS spinlock, we can fix this while at the same time removing the complexity with the pending skb queue function. This was broken since my commit 50a9432daeec ("mac80211: fix powersaving clients races") due to removing the clearing of WLAN_STA_PS_STA in the RX path. While at it, fix a cleanup path issue when a station is removed while the driver is still blocking its wakeup. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 10 ++-------- net/mac80211/rx.c | 7 +++++++ net/mac80211/sta_info.c | 32 ++++++++++++++------------------ net/mac80211/util.c | 8 ++------ 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3701930c6649..5e44e3179e02 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1692,14 +1692,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); void ieee80211_add_pending_skb(struct ieee80211_local *local, struct sk_buff *skb); -void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, - struct sk_buff_head *skbs, - void (*fn)(void *data), void *data); -static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, - struct sk_buff_head *skbs) -{ - ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); -} +void ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs); void ieee80211_flush_queues(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c24ca0d0f469..3e57f96c9666 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *sta) sta->sta.addr, sta->sta.aid); if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { + /* + * Clear the flag only if the other one is still set + * so that the TX path won't start TX'ing new frames + * directly ... In the case that the driver flag isn't + * set ieee80211_sta_ps_deliver_wakeup() will clear it. + */ + clear_sta_flag(sta, WLAN_STA_PS_STA); ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", sta->sta.addr, sta->sta.aid); return; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ffc1ee6a2ec1..a023b432143b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -99,7 +99,8 @@ static void __cleanup_single_sta(struct sta_info *sta) struct ieee80211_local *local = sdata->local; struct ps_data *ps; - if (test_sta_flag(sta, WLAN_STA_PS_STA)) { + if (test_sta_flag(sta, WLAN_STA_PS_STA) || + test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { if (sta->sdata->vif.type == NL80211_IFTYPE_AP || sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ps = &sdata->bss->ps; @@ -109,6 +110,7 @@ static void __cleanup_single_sta(struct sta_info *sta) return; clear_sta_flag(sta, WLAN_STA_PS_STA); + clear_sta_flag(sta, WLAN_STA_PS_DRIVER); atomic_dec(&ps->num_sta_ps); sta_info_recalc_tim(sta); @@ -1090,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, } EXPORT_SYMBOL(ieee80211_find_sta); -static void clear_sta_ps_flags(void *_sta) +/* powersave support code */ +void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) { - struct sta_info *sta = _sta; struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; + struct sk_buff_head pending; + int filtered = 0, buffered = 0, ac; + unsigned long flags; struct ps_data *ps; if (sdata->vif.type == NL80211_IFTYPE_AP || @@ -1104,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta) else return; - clear_sta_flag(sta, WLAN_STA_PS_DRIVER); - if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA)) - atomic_dec(&ps->num_sta_ps); -} - -/* powersave support code */ -void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata = sta->sdata; - struct ieee80211_local *local = sdata->local; - struct sk_buff_head pending; - int filtered = 0, buffered = 0, ac; - unsigned long flags; - clear_sta_flag(sta, WLAN_STA_SP); BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); @@ -1148,9 +1140,13 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) buffered += tmp - count; } - ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); + ieee80211_add_pending_skbs(local, &pending); + clear_sta_flag(sta, WLAN_STA_PS_DRIVER); + clear_sta_flag(sta, WLAN_STA_PS_STA); spin_unlock(&sta->ps_lock); + atomic_dec(&ps->num_sta_ps); + /* This station just woke up and isn't aware of our SMPS state */ if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, sdata->smps_mode) && diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1d1bb7084c05..b8700d417a9c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } -void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, - struct sk_buff_head *skbs, - void (*fn)(void *data), void *data) +void ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs) { struct ieee80211_hw *hw = &local->hw; struct sk_buff *skb; @@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, __skb_queue_tail(&local->pending[queue], skb); } - if (fn) - fn(data); - for (i = 0; i < hw->queues; i++) __ieee80211_wake_queue(hw, i, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); From ec6f678c74dbdb06a6a775bbb00f1d26c17c404b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 18 Feb 2014 10:30:18 +0200 Subject: [PATCH 08/21] iwlwifi: dvm: clear IWL_STA_UCODE_INPROGRESS when assoc fails We set IWL_STA_UCODE_INPROGRESS flag when we add a station and clear it when we send the LQ command for it. But the LQ command is sent only when the association succeeds. If the association doesn't succeed, we would leave this flag set and that wouldn't indicate the station entry as vacant. This probably fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1065663 Cc: Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/sta.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index c0d070c5df5e..9cdd91cdf661 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -590,6 +590,7 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id, sizeof(priv->tid_data[sta_id][tid])); priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; + priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; priv->num_stations--; From 72471c0d3197d02da53897868692f0b91042f8a5 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 14 Feb 2014 16:17:49 +0400 Subject: [PATCH 09/21] hostap: Do not free priv until timer handler has actually stopped using it Function del_timer() does not guarantee that timer was really deleted. If the timer handler is beeing executed at the moment, the function does nothing. So, it's possible to use already freed memory in the handler: [ref: Documentation/DocBook/kernel-locking.tmpl] This was found using grep and compile-tested only. Please, consider applying or something similar to it. Signed-off-by: Kirill Tkhai CC: Jouni Malinen CC: John W. Linville Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_ap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index d36e252d2ccb..596525528f50 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -147,7 +147,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) if (!sta->ap && sta->u.sta.challenge) kfree(sta->u.sta.challenge); - del_timer(&sta->timer); + del_timer_sync(&sta->timer); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ kfree(sta); From 95320774fae71d7b22b970ef4267fcc4d1ad23d8 Mon Sep 17 00:00:00 2001 From: James Cameron Date: Mon, 17 Feb 2014 10:25:53 +1100 Subject: [PATCH 10/21] libertas: fix scan result loss if SSID IE len 0 Scan results from Marvell 8388 and 8686 have probe responses from hidden APs and OLPC XO-1 mesh with a zero length SSID IE. Bug in lbs_ret_scan discarded any remaining BSS in scan response, leading to user not seeing APs in dense environments. With LBS_DEB_SCAN, dmesg shows libertas scan: scan response: 5 BSSs (419 bytes); resp size 474 bytes libertas scan: scan: 00:1a:2b:84:de:e8, capa 0401, chan 1, qz, -51 dBm libertas scan: scan: 5c:63:bf:d8:eb:0c, capa 0411, chan 1, qw129, -23 dBm libertas scan: scan response: invalid IE fmt With LBS_DEB_HEX, dmesg shows valid BSS in scan response were not processed. Change is to ignore zero length IE and continue processing. Fixes OLPC 12757, http://dev.laptop.org/ticket/12757 Signed-off-by: James Cameron Reported-by: T Gillett Tested-by: T Gillett CC: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 32f75007a825..cb6d189bc3e6 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -621,7 +621,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, id = *pos++; elen = *pos++; left -= 2; - if (elen > left || elen == 0) { + if (elen > left) { lbs_deb_scan("scan response: invalid IE fmt\n"); goto done; } From 4f7ba432202c8330cc03ab959c6228d0de5dc4a3 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Tue, 18 Feb 2014 15:41:54 -0800 Subject: [PATCH 11/21] mwifiex: clean pcie ring only when device is present Write io memory to clean PCIe buffer only when PCIe device is present else this results into crash because of invalid memory access. Cc: # 3.9+ Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 13eaeed03898..981cf6e7c73b 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -559,7 +559,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) mwifiex_wmm_delete_all_ralist(priv); memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); - if (priv->adapter->if_ops.clean_pcie_ring) + if (priv->adapter->if_ops.clean_pcie_ring && + !priv->adapter->surprise_removed) priv->adapter->if_ops.clean_pcie_ring(priv->adapter); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } From bb8e6a1ee881d131e404f0f1f5e8dc9281002771 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 18 Feb 2014 15:41:55 -0800 Subject: [PATCH 12/21] mwifiex: add NULL check for PCIe Rx skb We may get a NULL pointer here if skb allocation for Rx packet was failed earlier. Cc: # 3.9+ Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 03688aa14e8a..28029b7522c2 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1211,6 +1211,12 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) rd_index = card->rxbd_rdptr & reg->rx_mask; skb_data = card->rx_buf_list[rd_index]; + /* If skb allocation was failed earlier for Rx packet, + * rx_buf_list[rd_index] would have been left with a NULL. + */ + if (!skb_data) + return -ENOMEM; + MWIFIEX_SKB_PACB(skb_data, &buf_pa); pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE, PCI_DMA_FROMDEVICE); From 1c97560f6d751a620978504a4a888c631192b71a Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 18 Feb 2014 15:41:56 -0800 Subject: [PATCH 13/21] mwifiex: fix cmd and Tx data timeout issue for PCIe cards We are sending sleep confirm done interrupt in the middle of sleep handshake. There is a corner case when Tx done interrupt is received from firmware during sleep handshake due to which host and firmware power states go out of sync causing cmd and Tx data timeout problem. Hence sleep confirm done interrupt is sent at the end of sleep handshake to fix the problem. Cc: # 3.10+ Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 28029b7522c2..7fe7b53fb17a 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1531,6 +1531,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) if (adapter->ps_state == PS_STATE_SLEEP_CFM) { mwifiex_process_sleep_confirm_resp(adapter, skb->data, skb->len); + mwifiex_pcie_enable_host_int(adapter); + if (mwifiex_write_reg(adapter, + PCIE_CPU_INT_EVENT, + CPU_INTR_SLEEP_CFM_DONE)) { + dev_warn(adapter->dev, + "Write register failed\n"); + return -1; + } while (reg->sleep_cookie && (count++ < 10) && mwifiex_pcie_ok_to_access_hw(adapter)) usleep_range(50, 60); @@ -1999,23 +2007,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) adapter->int_status |= pcie_ireg; spin_unlock_irqrestore(&adapter->int_lock, flags); - if (pcie_ireg & HOST_INTR_CMD_DONE) { - if ((adapter->ps_state == PS_STATE_SLEEP_CFM) || - (adapter->ps_state == PS_STATE_SLEEP)) { - mwifiex_pcie_enable_host_int(adapter); - if (mwifiex_write_reg(adapter, - PCIE_CPU_INT_EVENT, - CPU_INTR_SLEEP_CFM_DONE) - ) { - dev_warn(adapter->dev, - "Write register failed\n"); - return; - - } - } - } else if (!adapter->pps_uapsd_mode && - adapter->ps_state == PS_STATE_SLEEP && - mwifiex_pcie_ok_to_access_hw(adapter)) { + if (!adapter->pps_uapsd_mode && + adapter->ps_state == PS_STATE_SLEEP && + mwifiex_pcie_ok_to_access_hw(adapter)) { /* Potentially for PCIe we could get other * interrupts like shared. Don't change power * state until cookie is set */ From 21f8aaee0c62708654988ce092838aa7df4d25d8 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 19 Feb 2014 13:15:17 +0100 Subject: [PATCH 14/21] ath9k: protect tid->sched check We check tid->sched without a lock taken on ath_tx_aggr_sleep(). That is race condition which can result of doing list_del(&tid->list) twice (second time with poisoned list node) and cause crash like shown below: [424271.637220] BUG: unable to handle kernel paging request at 00100104 [424271.637328] IP: [] ath_tx_aggr_sleep+0x62/0xe0 [ath9k] ... [424271.639953] Call Trace: [424271.639998] [] ? ath9k_get_survey+0x110/0x110 [ath9k] [424271.640083] [] ath9k_sta_notify+0x42/0x50 [ath9k] [424271.640177] [] sta_ps_start+0x8f/0x1c0 [mac80211] [424271.640258] [] ? free_compound_page+0x2e/0x40 [424271.640346] [] ieee80211_rx_handlers+0x9d5/0x2340 [mac80211] [424271.640437] [] ? kmem_cache_free+0x1d8/0x1f0 [424271.640510] [] ? kfree_skbmem+0x34/0x90 [424271.640578] [] ? put_page+0x2c/0x40 [424271.640640] [] ? kfree_skbmem+0x34/0x90 [424271.640706] [] ? kfree_skbmem+0x34/0x90 [424271.640787] [] ? ieee80211_rx_handlers_result+0x73/0x1d0 [mac80211] [424271.640897] [] ieee80211_prepare_and_rx_handle+0x520/0xad0 [mac80211] [424271.641009] [] ? ieee80211_rx_handlers+0x2ed/0x2340 [mac80211] [424271.641104] [] ? ip_output+0x7e/0xd0 [424271.641182] [] ieee80211_rx+0x307/0x7c0 [mac80211] [424271.641266] [] ath_rx_tasklet+0x88e/0xf70 [ath9k] [424271.641358] [] ? ieee80211_rx+0x1dc/0x7c0 [mac80211] [424271.641445] [] ath9k_tasklet+0xcb/0x130 [ath9k] Bug report: https://bugzilla.kernel.org/show_bug.cgi?id=70551 Reported-and-tested-by: Max Sydorenko Cc: stable@vger.kernel.org Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 0a75e2f68c9d..4f4ce83f7ab4 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1444,14 +1444,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - if (!tid->sched) - continue; - ac = tid->ac; txq = ac->txq; ath_txq_lock(sc, txq); + if (!tid->sched) { + ath_txq_unlock(sc, txq); + continue; + } + buffered = ath_tid_has_buffered(tid); tid->sched = false; From 1eb43018673e735ea9cd756970f4e71ca01a5f21 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 20 Feb 2014 18:55:55 +0100 Subject: [PATCH 15/21] brcmfmac: fix txglomming scatter-gather packet transfers The driver concatenates multiple packets in one MMC transfer. For scatter-gather to work the total length need to be multiple of 512 bytes. A pre-allocated buffer was used to add padding to accomplish that. However, the length was not properly set and it was freed after the first transfer causing a crash. Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 3e991897d7ca..119ee6eaf1c3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -457,7 +457,6 @@ struct brcmf_sdio { u8 tx_hdrlen; /* sdio bus header length for tx packet */ bool txglom; /* host tx glomming enable flag */ - struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */ u16 head_align; /* buffer pointer alignment */ u16 sgentry_align; /* scatter-gather buffer alignment */ }; @@ -1944,9 +1943,8 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, if (lastfrm && chain_pad) tail_pad += blksize - chain_pad; if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) { - pkt_pad = bus->txglom_sgpad; - if (pkt_pad == NULL) - brcmu_pkt_buf_get_skb(tail_pad + tail_chop); + pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop + + bus->head_align); if (pkt_pad == NULL) return -ENOMEM; ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad); @@ -1957,6 +1955,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, tail_chop); *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; skb_trim(pkt, pkt->len - tail_chop); + skb_trim(pkt_pad, tail_pad + tail_chop); __skb_queue_after(pktq, pkt, pkt_pad); } else { ntail = pkt->data_len + tail_pad - @@ -2011,7 +2010,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, return ret; head_pad = (u16)ret; if (head_pad) - memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen); + memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad); total_len += pkt_next->len; @@ -3486,10 +3485,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev) bus->txglom = false; value = 1; pad_size = bus->sdiodev->func[2]->cur_blksize << 1; - bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size); - if (!bus->txglom_sgpad) - brcmf_err("allocating txglom padding skb failed, reduced performance\n"); - err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", &value, sizeof(u32)); if (err < 0) { @@ -4053,7 +4048,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) brcmf_sdio_chip_detach(&bus->ci); } - brcmu_pkt_buf_free_skb(bus->txglom_sgpad); kfree(bus->rxbuf); kfree(bus->hdrbuf); kfree(bus); From b3050248c167871ca52cfdb2ce78aa2460249346 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 14 Feb 2014 08:15:20 +0530 Subject: [PATCH 16/21] ath9k: Fix ETSI compliance for AR9462 2.0 The minimum CCA power threshold values have to be adjusted for existing cards to be in compliance with new regulations. Newer cards will make use of the values obtained from EEPROM, support for this was added earlier. To make sure that cards that are already in use and don't have proper values in EEPROM, do not violate regulations, use the initvals instead. Cc: stable@vger.kernel.org Reported-by: Jeang Daniel Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 1cc13569b17b..1b6b4d0cfa97 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -57,7 +57,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, @@ -96,7 +96,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa}, {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, }; From 44a589ca2de4d7980f8b335481a09bf818065dbe Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 6 Feb 2014 11:28:31 -0800 Subject: [PATCH 17/21] NFC: NCI: Fix NULL pointer dereference The check should be for setup function pointer. This patch fixes NULL pointer dereference issue for NCI based NFC driver which doesn't define setup handler. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Samuel Ortiz --- net/nfc/nci/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 46bda010bf11..56db888b1cd5 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -301,7 +301,7 @@ static int nci_open_device(struct nci_dev *ndev) rc = __nci_request(ndev, nci_reset_req, 0, msecs_to_jiffies(NCI_RESET_TIMEOUT)); - if (ndev->ops->setup(ndev)) + if (ndev->ops->setup) ndev->ops->setup(ndev); if (!rc) { From e4ceb0f40da5dc26f84025d121c2fe6ff7d8a947 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 21 Feb 2014 12:23:00 -0800 Subject: [PATCH 18/21] mwifiex: rename usb driver name registerring to usb core Both libertas USB driver and mwifiex_usb driver are registerring with name 'usb8xxx'. The following conflict happens while trying to load both drivers. [6.211307] Error: Driver 'usb8xxx' is already registered... [6.217261] mwifiex_usb: Driver register failed! Fix it by renaming mwifiex_usb driver's name. Reported-by: Fengguang Wu Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index e8ebbd4bc3cd..cb6b70a1b34d 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -22,8 +22,6 @@ #define USB_VERSION "1.0" -static const char usbdriver_name[] = "usb8xxx"; - static struct mwifiex_if_ops usb_ops; static struct semaphore add_remove_card_sem; static struct usb_card_rec *usb_card; @@ -567,7 +565,7 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) } static struct usb_driver mwifiex_usb_driver = { - .name = usbdriver_name, + .name = "mwifiex_usb", .probe = mwifiex_usb_probe, .disconnect = mwifiex_usb_disconnect, .id_table = mwifiex_usb_table, From 558ff225de80ac95b132d3a115ddadcd64498b4f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 22 Feb 2014 13:48:19 +0100 Subject: [PATCH 19/21] ath9k: fix ps-poll responses under a-mpdu sessions When passing tx frames to the U-APSD queue for powersave poll responses, the ath_atx_tid pointer needs to be passed to ath_tx_setup_buffer for proper sequence number accounting. This fixes high latency and connection stability issues with ath9k running as AP and a few kinds of mobile phones as client, when PS-Poll is heavily used Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 4f4ce83f7ab4..f042a18c8495 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2186,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, txq->stopped = true; } + if (txctl->an) + tid = ath_get_skb_tid(sc, txctl->an, skb); + if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { ath_txq_unlock(sc, txq); txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); } else if (txctl->an && ieee80211_is_data_present(hdr->frame_control)) { - tid = ath_get_skb_tid(sc, txctl->an, skb); - WARN_ON(tid->ac->txq != txctl->txq); if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) From d31a36a6d87f68c3b97193bfca11e99d0cc385f7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 24 Feb 2014 22:26:05 +0100 Subject: [PATCH 20/21] ath9k: reduce baseband hang detection false positive rate Check if the baseband state remains stable, and add a small delay between register reads. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 11eab9f01fd8..303ce27964c1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1534,7 +1534,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav); bool ath9k_hw_check_alive(struct ath_hw *ah) { int count = 50; - u32 reg; + u32 reg, last_val; if (AR_SREV_9300(ah)) return !ath9k_hw_detect_mac_hang(ah); @@ -1542,9 +1542,13 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) if (AR_SREV_9285_12_OR_LATER(ah)) return true; + last_val = REG_READ(ah, AR_OBS_BUS_1); do { reg = REG_READ(ah, AR_OBS_BUS_1); + if (reg != last_val) + return true; + last_val = reg; if ((reg & 0x7E7FFFEF) == 0x00702400) continue; @@ -1556,6 +1560,8 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) default: return true; } + + udelay(1); } while (count-- > 0); return false; From b7b146c9c9a0248cc57da71244f672ebc54bbef1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 24 Feb 2014 22:26:06 +0100 Subject: [PATCH 21/21] ath9k: fix invalid descriptor discarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only set sc->rx.discard_next to rx_stats->rs_more when actually discarding the current descriptor. Also, fix a detection of broken descriptors: First the code checks if the current descriptor is not done. Then it checks if the next descriptor is done. Add a check that afterwards checks the first descriptor again, because it might have been completed in the mean time. This fixes a regression introduced in commit 723e711356b5a8a95728a890e254e8b0d47b55cf "ath9k: fix handling of broken descriptors" Cc: stable@vger.kernel.org Reported-by: Marco AndrĂ© Dinis Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 70 +++++++++++++-------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a0ebdd000fc2..82e340d3ec60 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc, return NULL; /* - * mark descriptor as zero-length and set the 'more' - * flag to ensure that both buffers get discarded + * Re-check previous descriptor, in case it has been filled + * in the mean time. */ - rs->rs_datalen = 0; - rs->rs_more = true; + ret = ath9k_hw_rxprocdesc(ah, ds, rs); + if (ret == -EINPROGRESS) { + /* + * mark descriptor as zero-length and set the 'more' + * flag to ensure that both buffers get discarded + */ + rs->rs_datalen = 0; + rs->rs_more = true; + } } list_del(&bf->list); @@ -985,32 +992,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hdr *hdr; bool discard_current = sc->rx.discard_next; - int ret = 0; /* * Discard corrupt descriptors which are marked in * ath_get_next_rx_buf(). */ - sc->rx.discard_next = rx_stats->rs_more; if (discard_current) - return -EINVAL; + goto corrupt; + + sc->rx.discard_next = false; /* * Discard zero-length packets. */ if (!rx_stats->rs_datalen) { RX_STAT_INC(rx_len_err); - return -EINVAL; + goto corrupt; } - /* - * rs_status follows rs_datalen so if rs_datalen is too large - * we can take a hint that hardware corrupted it, so ignore - * those frames. - */ + /* + * rs_status follows rs_datalen so if rs_datalen is too large + * we can take a hint that hardware corrupted it, so ignore + * those frames. + */ if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { RX_STAT_INC(rx_len_err); - return -EINVAL; + goto corrupt; } /* Only use status info from the last fragment */ @@ -1024,10 +1031,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, * This is different from the other corrupt descriptor * condition handled above. */ - if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) { - ret = -EINVAL; - goto exit; - } + if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) + goto corrupt; hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); @@ -1043,18 +1048,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) RX_STAT_INC(rx_spectral); - ret = -EINVAL; - goto exit; + return -EINVAL; } /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. */ - if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) { - ret = -EINVAL; - goto exit; - } + if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) + return -EINVAL; if (ath_is_mybeacon(common, hdr)) { RX_STAT_INC(rx_beacons); @@ -1064,15 +1066,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, /* * This shouldn't happen, but have a safety check anyway. */ - if (WARN_ON(!ah->curchan)) { - ret = -EINVAL; - goto exit; - } + if (WARN_ON(!ah->curchan)) + return -EINVAL; - if (ath9k_process_rate(common, hw, rx_stats, rx_status)) { - ret =-EINVAL; - goto exit; - } + if (ath9k_process_rate(common, hw, rx_stats, rx_status)) + return -EINVAL; ath9k_process_rssi(common, hw, rx_stats, rx_status); @@ -1087,9 +1085,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, sc->rx.num_pkts++; #endif -exit: - sc->rx.discard_next = false; - return ret; + return 0; + +corrupt: + sc->rx.discard_next = rx_stats->rs_more; + return -EINVAL; } static void ath9k_rx_skb_postprocess(struct ath_common *common,