|
|
@@ -0,0 +1,279 @@
|
|
|
+--- a/drivers/net/wireless/ath/ath9k/mac.c
|
|
|
++++ b/drivers/net/wireless/ath/ath9k/mac.c
|
|
|
+@@ -766,14 +766,6 @@ void ath9k_hw_startpcureceive(struct ath
|
|
|
+ }
|
|
|
+ EXPORT_SYMBOL(ath9k_hw_startpcureceive);
|
|
|
+
|
|
|
+-void ath9k_hw_stoppcurecv(struct ath_hw *ah)
|
|
|
+-{
|
|
|
+- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
|
|
|
+-
|
|
|
+- ath9k_hw_disable_mib_counters(ah);
|
|
|
+-}
|
|
|
+-EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
|
|
|
+-
|
|
|
+ void ath9k_hw_abortpcurecv(struct ath_hw *ah)
|
|
|
+ {
|
|
|
+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
|
|
|
+--- a/drivers/net/wireless/ath/ath9k/mac.h
|
|
|
++++ b/drivers/net/wireless/ath/ath9k/mac.h
|
|
|
+@@ -691,7 +691,6 @@ void ath9k_hw_setuprxdesc(struct ath_hw
|
|
|
+ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
|
|
|
+ void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
|
|
|
+ void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning);
|
|
|
+-void ath9k_hw_stoppcurecv(struct ath_hw *ah);
|
|
|
+ void ath9k_hw_abortpcurecv(struct ath_hw *ah);
|
|
|
+ bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
|
|
|
+ int ath9k_hw_beaconq_setup(struct ath_hw *ah);
|
|
|
+--- a/drivers/net/wireless/ath/ath9k/recv.c
|
|
|
++++ b/drivers/net/wireless/ath/ath9k/recv.c
|
|
|
+@@ -518,7 +518,7 @@ bool ath_stoprecv(struct ath_softc *sc)
|
|
|
+ bool stopped;
|
|
|
+
|
|
|
+ spin_lock_bh(&sc->rx.rxbuflock);
|
|
|
+- ath9k_hw_stoppcurecv(ah);
|
|
|
++ ath9k_hw_abortpcurecv(ah);
|
|
|
+ ath9k_hw_setrxfilter(ah, 0);
|
|
|
+ stopped = ath9k_hw_stopdmarecv(ah);
|
|
|
+
|
|
|
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
|
|
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
|
|
+@@ -163,6 +163,7 @@ static void ath_tx_flush_tid(struct ath_
|
|
|
+ bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
|
|
|
+ list_move_tail(&bf->list, &bf_head);
|
|
|
+
|
|
|
++ spin_unlock_bh(&txq->axq_lock);
|
|
|
+ fi = get_frame_info(bf->bf_mpdu);
|
|
|
+ if (fi->retries) {
|
|
|
+ ath_tx_update_baw(sc, tid, fi->seqno);
|
|
|
+@@ -170,6 +171,7 @@ static void ath_tx_flush_tid(struct ath_
|
|
|
+ } else {
|
|
|
+ ath_tx_send_normal(sc, txq, tid, &bf_head);
|
|
|
+ }
|
|
|
++ spin_lock_bh(&txq->axq_lock);
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_unlock_bh(&txq->axq_lock);
|
|
|
+--- a/net/mac80211/ieee80211_i.h
|
|
|
++++ b/net/mac80211/ieee80211_i.h
|
|
|
+@@ -349,6 +349,7 @@ struct ieee80211_if_managed {
|
|
|
+ struct work_struct chswitch_work;
|
|
|
+ struct work_struct beacon_connection_loss_work;
|
|
|
+
|
|
|
++ unsigned long beacon_timeout;
|
|
|
+ unsigned long probe_timeout;
|
|
|
+ int probe_send_count;
|
|
|
+
|
|
|
+@@ -1269,6 +1270,8 @@ void ieee80211_send_nullfunc(struct ieee
|
|
|
+ int powersave);
|
|
|
+ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
|
|
|
+ struct ieee80211_hdr *hdr);
|
|
|
++void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
|
|
|
++ struct ieee80211_hdr *hdr);
|
|
|
+ void ieee80211_beacon_connection_loss_work(struct work_struct *work);
|
|
|
+
|
|
|
+ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
|
|
|
+--- a/net/mac80211/mlme.c
|
|
|
++++ b/net/mac80211/mlme.c
|
|
|
+@@ -28,13 +28,19 @@
|
|
|
+ #include "rate.h"
|
|
|
+ #include "led.h"
|
|
|
+
|
|
|
++#define IEEE80211_MAX_NULLFUNC_TRIES 2
|
|
|
+ #define IEEE80211_MAX_PROBE_TRIES 5
|
|
|
+
|
|
|
+ /*
|
|
|
+- * beacon loss detection timeout
|
|
|
+- * XXX: should depend on beacon interval
|
|
|
++ * Beacon loss timeout is calculated as N frames times the
|
|
|
++ * advertised beacon interval. This may need to be somewhat
|
|
|
++ * higher than what hardware might detect to account for
|
|
|
++ * delays in the host processing frames. But since we also
|
|
|
++ * probe on beacon miss before declaring the connection lost
|
|
|
++ * default to what we want.
|
|
|
+ */
|
|
|
+-#define IEEE80211_BEACON_LOSS_TIME (2 * HZ)
|
|
|
++#define IEEE80211_BEACON_LOSS_COUNT 7
|
|
|
++
|
|
|
+ /*
|
|
|
+ * Time the connection can be idle before we probe
|
|
|
+ * it to see if we can still talk to the AP.
|
|
|
+@@ -45,7 +51,7 @@
|
|
|
+ * a probe request because of beacon loss or for
|
|
|
+ * checking the connection still works.
|
|
|
+ */
|
|
|
+-#define IEEE80211_PROBE_WAIT (HZ / 2)
|
|
|
++#define IEEE80211_PROBE_WAIT (HZ / 5)
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Weight given to the latest Beacon frame when calculating average signal
|
|
|
+@@ -121,7 +127,7 @@ void ieee80211_sta_reset_beacon_monitor(
|
|
|
+ return;
|
|
|
+
|
|
|
+ mod_timer(&sdata->u.mgd.bcn_mon_timer,
|
|
|
+- round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME));
|
|
|
++ round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout));
|
|
|
+ }
|
|
|
+
|
|
|
+ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata)
|
|
|
+@@ -871,6 +877,9 @@ static void ieee80211_set_associated(str
|
|
|
+ bss_info_changed |= ieee80211_handle_bss_capability(sdata,
|
|
|
+ cbss->capability, bss->has_erp_value, bss->erp_value);
|
|
|
+
|
|
|
++ sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(
|
|
|
++ IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int));
|
|
|
++
|
|
|
+ sdata->u.mgd.associated = cbss;
|
|
|
+ memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
|
|
|
+
|
|
|
+@@ -1026,6 +1035,50 @@ void ieee80211_sta_rx_notify(struct ieee
|
|
|
+ ieee80211_sta_reset_conn_monitor(sdata);
|
|
|
+ }
|
|
|
+
|
|
|
++static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
|
|
|
++{
|
|
|
++ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
|
|
++
|
|
|
++ if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
|
|
|
++ IEEE80211_STA_CONNECTION_POLL)))
|
|
|
++ return;
|
|
|
++
|
|
|
++ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
|
|
|
++ IEEE80211_STA_BEACON_POLL);
|
|
|
++ mutex_lock(&sdata->local->iflist_mtx);
|
|
|
++ ieee80211_recalc_ps(sdata->local, -1);
|
|
|
++ mutex_unlock(&sdata->local->iflist_mtx);
|
|
|
++
|
|
|
++ if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
|
|
|
++ return;
|
|
|
++
|
|
|
++ /*
|
|
|
++ * We've received a probe response, but are not sure whether
|
|
|
++ * we have or will be receiving any beacons or data, so let's
|
|
|
++ * schedule the timers again, just in case.
|
|
|
++ */
|
|
|
++ ieee80211_sta_reset_beacon_monitor(sdata);
|
|
|
++
|
|
|
++ mod_timer(&ifmgd->conn_mon_timer,
|
|
|
++ round_jiffies_up(jiffies +
|
|
|
++ IEEE80211_CONNECTION_IDLE_TIME));
|
|
|
++}
|
|
|
++
|
|
|
++void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
|
|
|
++ struct ieee80211_hdr *hdr)
|
|
|
++{
|
|
|
++ if (!ieee80211_is_data(hdr->frame_control) &&
|
|
|
++ !ieee80211_is_nullfunc(hdr->frame_control))
|
|
|
++ return;
|
|
|
++
|
|
|
++ ieee80211_sta_reset_conn_monitor(sdata);
|
|
|
++
|
|
|
++ if (ieee80211_is_nullfunc(hdr->frame_control)) {
|
|
|
++ sdata->u.mgd.probe_send_count = 0;
|
|
|
++ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
|
|
++ }
|
|
|
++}
|
|
|
++
|
|
|
+ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
|
|
|
+ {
|
|
|
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
|
|
+@@ -1041,8 +1094,19 @@ static void ieee80211_mgd_probe_ap_send(
|
|
|
+ if (ifmgd->probe_send_count >= unicast_limit)
|
|
|
+ dst = NULL;
|
|
|
+
|
|
|
+- ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
|
|
|
+- ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0);
|
|
|
++ /*
|
|
|
++ * When the hardware reports an accurate Tx ACK status, it's
|
|
|
++ * better to send a nullfunc frame instead of a probe request,
|
|
|
++ * as it will kick us off the AP quickly if we aren't associated
|
|
|
++ * anymore. The timeout will be reset if the frame is ACKed by
|
|
|
++ * the AP.
|
|
|
++ */
|
|
|
++ if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
|
|
|
++ ieee80211_send_nullfunc(sdata->local, sdata, 0);
|
|
|
++ else {
|
|
|
++ ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
|
|
|
++ ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0);
|
|
|
++ }
|
|
|
+
|
|
|
+ ifmgd->probe_send_count++;
|
|
|
+ ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
|
|
|
+@@ -1509,29 +1573,8 @@ static void ieee80211_rx_mgmt_probe_resp
|
|
|
+ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
|
|
|
+
|
|
|
+ if (ifmgd->associated &&
|
|
|
+- memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 &&
|
|
|
+- ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
|
|
|
+- IEEE80211_STA_CONNECTION_POLL)) {
|
|
|
+- ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
|
|
|
+- IEEE80211_STA_BEACON_POLL);
|
|
|
+- mutex_lock(&sdata->local->iflist_mtx);
|
|
|
+- ieee80211_recalc_ps(sdata->local, -1);
|
|
|
+- mutex_unlock(&sdata->local->iflist_mtx);
|
|
|
+-
|
|
|
+- if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
|
|
|
+- return;
|
|
|
+-
|
|
|
+- /*
|
|
|
+- * We've received a probe response, but are not sure whether
|
|
|
+- * we have or will be receiving any beacons or data, so let's
|
|
|
+- * schedule the timers again, just in case.
|
|
|
+- */
|
|
|
+- ieee80211_sta_reset_beacon_monitor(sdata);
|
|
|
+-
|
|
|
+- mod_timer(&ifmgd->conn_mon_timer,
|
|
|
+- round_jiffies_up(jiffies +
|
|
|
+- IEEE80211_CONNECTION_IDLE_TIME));
|
|
|
+- }
|
|
|
++ memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0)
|
|
|
++ ieee80211_reset_ap_probe(sdata);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+@@ -1881,12 +1924,22 @@ void ieee80211_sta_work(struct ieee80211
|
|
|
+ IEEE80211_STA_CONNECTION_POLL) &&
|
|
|
+ ifmgd->associated) {
|
|
|
+ u8 bssid[ETH_ALEN];
|
|
|
++ int max_tries;
|
|
|
++
|
|
|
++ /* ACK received for nullfunc probing frame */
|
|
|
++ if (!ifmgd->probe_send_count)
|
|
|
++ ieee80211_reset_ap_probe(sdata);
|
|
|
++
|
|
|
++ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
|
|
|
++ max_tries = IEEE80211_MAX_NULLFUNC_TRIES;
|
|
|
++ else
|
|
|
++ max_tries = IEEE80211_MAX_PROBE_TRIES;
|
|
|
+
|
|
|
+ memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
|
|
|
+ if (time_is_after_jiffies(ifmgd->probe_timeout))
|
|
|
+ run_again(ifmgd, ifmgd->probe_timeout);
|
|
|
+
|
|
|
+- else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) {
|
|
|
++ else if (ifmgd->probe_send_count < max_tries) {
|
|
|
+ #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
|
|
+ wiphy_debug(local->hw.wiphy,
|
|
|
+ "%s: No probe response from AP %pM"
|
|
|
+@@ -2012,6 +2065,8 @@ void ieee80211_sta_restart(struct ieee80
|
|
|
+ add_timer(&ifmgd->timer);
|
|
|
+ if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
|
|
|
+ add_timer(&ifmgd->chswitch_timer);
|
|
|
++ ieee80211_sta_reset_beacon_monitor(sdata);
|
|
|
++ ieee80211_send_nullfunc(sdata->local, sdata, 0);
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+--- a/net/mac80211/status.c
|
|
|
++++ b/net/mac80211/status.c
|
|
|
+@@ -155,6 +155,10 @@ static void ieee80211_frame_acked(struct
|
|
|
+
|
|
|
+ ieee80211_queue_work(&local->hw, &local->recalc_smps);
|
|
|
+ }
|
|
|
++
|
|
|
++ if ((sdata->vif.type == NL80211_IFTYPE_STATION) &&
|
|
|
++ (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
|
|
|
++ ieee80211_sta_tx_notify(sdata, (void *) skb->data);
|
|
|
+ }
|
|
|
+
|
|
|
+ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|