openwrt/package/kernel/mac80211/patches/300-pending_work.patch
Felix Fietkau b7ce76b4b9 ath9k: merge a p2p powersave handling fix
Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 41017
2014-06-05 14:55:03 +00:00

748 lines
24 KiB
Diff

commit 60ccc107c9b9fb732fdee1f76bb2dad44f0e1798
Author: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Date: Tue May 27 16:58:02 2014 +0530
ath9k: Fix deadlock while updating p2p beacon timer
pm_lock is taken twice while syncing HW TSF of p2p vif.
Fix this by taking the lock at caller side.
Cc: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
commit f3831a4e3903dbc1a57d5df56deb6a143fd001bc
Author: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Thu Jun 5 13:52:27 2014 +0200
rt2x00: do not initialize BCN_OFFSET registers
We setup BCN_OFFSET{0,1} registers dynamically, don't have to
initialize them.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
commit e5c58ca7a48d4c82f282749a978052c47fd95998
Author: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Thu Jun 5 13:52:26 2014 +0200
rt2x00: change order when stop beaconing
When no beaconing is needed, first stop beacon queue (disable beaconing
globally) to avoid possible sending of not prepared beacon on short
period after clearing beacon and before stop of BCN queue.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
commit 382c1b9e03f52d0cd741ef1d942cad0f649f0744
Author: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Thu Jun 5 13:52:25 2014 +0200
rt2x00: change default MAC_BSSID_DW1_BSS_BCN_NUM
We setup MAC_BSSID_DW1_BSS_BCN_NUM dynamically when numbers of active
beacons increase. Change default to 0 to tell hardware that we want to
send only one beacon as default.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
commit 3b400571dd033e46fa7e76c5bb92a3ce8198afa9
Author: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Thu Jun 5 13:52:24 2014 +0200
rt2x00: change beaconing setup on RT2800
As reported by Matthias, on 5572 chip, even if we clear up TXWI
of corresponding beacon, hardware still try to send it or do other
action that increase power consumption peak up to 1A.
To avoid the issue, setup beaconing dynamically by configuring offsets
of currently active beacons and MAC_BSSID_DW1_BSS_BCN_NUM variable,
which limit number of beacons that hardware will try to send.
Reported-by: Matthias Fend <Matthias.Fend@wolfvision.net>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
commit 916e591b2cc41f7e572992175ca56d866d7bc958
Author: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Thu Jun 5 13:52:23 2014 +0200
rt2x00: change beaconing locking
This patch is needed for further changes to keep global variables
consistent when changing beaconing on diffrent vif's.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
commit 930b0dffd1731f3f418f9132faea720a23b7af61
Author: Johannes Berg <johannes.berg@intel.com>
Date: Tue Jun 3 11:18:47 2014 +0200
mac80211: fix station/driver powersave race
It is currently possible to have a race due to the station PS
unblock work like this:
* station goes to sleep with frames buffered in the driver
* driver blocks wakeup
* station wakes up again
* driver flushes/returns frames, and unblocks, which schedules
the unblock work
* unblock work starts to run, and checks that the station is
awake (i.e. that the WLAN_STA_PS_STA flag isn't set)
* we process a received frame with PM=1, setting the flag again
* ieee80211_sta_ps_deliver_wakeup() runs, delivering all frames
to the driver, and then clearing the WLAN_STA_PS_DRIVER and
WLAN_STA_PS_STA flags
In this scenario, mac80211 will think that the station is awake,
while it really is asleep, and any TX'ed frames should be filtered
by the device (it will know that the station is sleeping) but then
passed to mac80211 again, which will not buffer it either as it
thinks the station is awake, and eventually the packets will be
dropped.
Fix this by moving the clearing of the flags to exactly where we
learn about the situation. This creates a problem of reordering,
so introduce another flag indicating that delivery is being done,
this new flag also queues frames and is cleared only while the
spinlock is held (which the queuing code also holds) so that any
concurrent delivery/TX is handled correctly.
Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873
Author: Felix Fietkau <nbd@openwrt.org>
Date: Fri May 23 19:58:14 2014 +0200
mac80211: reduce packet loss notifications under load
During strong signal fluctuations under high throughput, few consecutive
failed A-MPDU transmissions can easily trigger packet loss notification,
and thus (in AP mode) client disconnection.
Reduce the number of false positives by checking the A-MPDU status flag
and treating a failed A-MPDU as a single packet.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
commit 7b7843a36fbcc568834404c7430ff895d8502131
Author: Felix Fietkau <nbd@openwrt.org>
Date: Fri May 23 19:26:32 2014 +0200
mac80211: fix a memory leak on sta rate selection table
Cc: stable@vger.kernel.org
Reported-by: Christophe Prévotaux <cprevotaux@nltinc.com>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
commit 96892d6aa0a153423070addf3070bc79578b3897
Author: Felix Fietkau <nbd@openwrt.org>
Date: Mon May 19 21:20:49 2014 +0200
ath9k: avoid passing buffers to the hardware during flush
The commit "ath9k: fix possible hang on flush" changed the receive code
to always link rx descriptors of processed frames, even when flushing.
In some cases, this leads to flushed rx buffers being passed to the
hardware while rx is already stopped.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_slee
* buffer (or rx fifo). This can incorrectly acknowledge packets
* to a sender if last desc is self-linked.
*/
-static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf)
+static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf,
+ bool flush)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
@@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_s
common->rx_bufsize,
0);
- if (sc->rx.rxlink == NULL)
- ath9k_hw_putrxbuf(ah, bf->bf_daddr);
- else
+ if (sc->rx.rxlink)
*sc->rx.rxlink = bf->bf_daddr;
+ else if (!flush)
+ ath9k_hw_putrxbuf(ah, bf->bf_daddr);
sc->rx.rxlink = &ds->ds_link;
}
-static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf)
+static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf,
+ bool flush)
{
if (sc->rx.buf_hold)
- ath_rx_buf_link(sc, sc->rx.buf_hold);
+ ath_rx_buf_link(sc, sc->rx.buf_hold, flush);
sc->rx.buf_hold = bf;
}
@@ -442,7 +444,7 @@ int ath_startrecv(struct ath_softc *sc)
sc->rx.buf_hold = NULL;
sc->rx.rxlink = NULL;
list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
- ath_rx_buf_link(sc, bf);
+ ath_rx_buf_link(sc, bf, false);
}
/* We could have deleted elements so the list may be empty now */
@@ -1118,12 +1120,12 @@ requeue_drop_frag:
requeue:
list_add_tail(&bf->list, &sc->rx.rxbuf);
- if (edma) {
- ath_rx_edma_buf_link(sc, qtype);
- } else {
- ath_rx_buf_relink(sc, bf);
+ if (!edma) {
+ ath_rx_buf_relink(sc, bf, flush);
if (!flush)
ath9k_hw_rxena(ah);
+ } else if (!flush) {
+ ath_rx_edma_buf_link(sc, qtype);
}
if (!budget--)
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct
struct ps_data *ps;
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
- test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+ test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
+ test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
@@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct
clear_sta_flag(sta, WLAN_STA_PS_STA);
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+ clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
atomic_dec(&ps->num_sta_ps);
sta_info_recalc_tim(sta);
@@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_sta_cleanup(sta);
- cancel_work_sync(&sta->drv_unblock_wk);
+ cancel_work_sync(&sta->drv_deliver_wk);
/*
* Destroy aggregation state here. It would be nice to wait for the
@@ -227,6 +229,7 @@ struct sta_info *sta_info_get_by_idx(str
*/
void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
{
+ struct ieee80211_sta_rates *rates;
int i;
if (sta->rate_ctrl)
@@ -238,6 +241,10 @@ void sta_info_free(struct ieee80211_loca
kfree(sta->tx_lat);
}
+ rates = rcu_dereference_protected(sta->sta.rates, true);
+ if (rates)
+ kfree(rates);
+
sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
kfree(sta);
@@ -252,33 +259,23 @@ static void sta_info_hash_add(struct iee
rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
}
-static void sta_unblock(struct work_struct *wk)
+static void sta_deliver_ps_frames(struct work_struct *wk)
{
struct sta_info *sta;
- sta = container_of(wk, struct sta_info, drv_unblock_wk);
+ sta = container_of(wk, struct sta_info, drv_deliver_wk);
if (sta->dead)
return;
- if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
- local_bh_disable();
+ local_bh_disable();
+ if (!test_sta_flag(sta, WLAN_STA_PS_STA))
ieee80211_sta_ps_deliver_wakeup(sta);
- local_bh_enable();
- } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) {
- clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-
- local_bh_disable();
+ else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL))
ieee80211_sta_ps_deliver_poll_response(sta);
- local_bh_enable();
- } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) {
- clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-
- local_bh_disable();
+ else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD))
ieee80211_sta_ps_deliver_uapsd(sta);
- local_bh_enable();
- } else
- clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+ local_bh_enable();
}
static int sta_prepare_rate_control(struct ieee80211_local *local,
@@ -340,7 +337,7 @@ struct sta_info *sta_info_alloc(struct i
spin_lock_init(&sta->lock);
spin_lock_init(&sta->ps_lock);
- INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
+ INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx);
#ifdef CPTCFG_MAC80211_MESH
@@ -1140,8 +1137,15 @@ void ieee80211_sta_ps_deliver_wakeup(str
}
ieee80211_add_pending_skbs(local, &pending);
- clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
- clear_sta_flag(sta, WLAN_STA_PS_STA);
+
+ /* now we're no longer in the deliver code */
+ clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
+
+ /* The station might have polled and then woken up before we responded,
+ * so clear these flags now to avoid them sticking around.
+ */
+ clear_sta_flag(sta, WLAN_STA_PSPOLL);
+ clear_sta_flag(sta, WLAN_STA_UAPSD);
spin_unlock(&sta->ps_lock);
atomic_dec(&ps->num_sta_ps);
@@ -1542,10 +1546,26 @@ void ieee80211_sta_block_awake(struct ie
trace_api_sta_block_awake(sta->local, pubsta, block);
- if (block)
+ if (block) {
set_sta_flag(sta, WLAN_STA_PS_DRIVER);
- else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER))
- ieee80211_queue_work(hw, &sta->drv_unblock_wk);
+ return;
+ }
+
+ if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
+ return;
+
+ if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
+ set_sta_flag(sta, WLAN_STA_PS_DELIVER);
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+ ieee80211_queue_work(hw, &sta->drv_deliver_wk);
+ } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) ||
+ test_sta_flag(sta, WLAN_STA_UAPSD)) {
+ /* must be asleep in this case */
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+ ieee80211_queue_work(hw, &sta->drv_deliver_wk);
+ } else {
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+ }
}
EXPORT_SYMBOL(ieee80211_sta_block_awake);
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -541,6 +541,23 @@ static void ieee80211_tx_latency_end_msr
*/
#define STA_LOST_PKT_THRESHOLD 50
+static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ /* This packet was aggregated but doesn't carry status info */
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU))
+ return;
+
+ if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD)
+ return;
+
+ cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
+ sta->lost_packets, GFP_ATOMIC);
+ sta->lost_packets = 0;
+}
+
void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct sk_buff *skb2;
@@ -680,12 +697,8 @@ void ieee80211_tx_status(struct ieee8021
if (info->flags & IEEE80211_TX_STAT_ACK) {
if (sta->lost_packets)
sta->lost_packets = 0;
- } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) {
- cfg80211_cqm_pktloss_notify(sta->sdata->dev,
- sta->sta.addr,
- sta->lost_packets,
- GFP_ATOMIC);
- sta->lost_packets = 0;
+ } else {
+ ieee80211_lost_packet(sta, skb);
}
}
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info *
return;
}
+ set_sta_flag(sta, WLAN_STA_PS_DELIVER);
+ clear_sta_flag(sta, WLAN_STA_PS_STA);
ieee80211_sta_ps_deliver_wakeup(sta);
}
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -82,6 +82,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_TOFFSET_KNOWN,
WLAN_STA_MPSP_OWNER,
WLAN_STA_MPSP_RECIPIENT,
+ WLAN_STA_PS_DELIVER,
};
#define ADDBA_RESP_INTERVAL HZ
@@ -265,7 +266,7 @@ struct ieee80211_tx_latency_stat {
* @last_rx_rate_vht_nss: rx status nss of last data packet
* @lock: used for locking all fields that require locking, see comments
* in the header file.
- * @drv_unblock_wk: used for driver PS unblocking
+ * @drv_deliver_wk: used for delivering frames after 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
@@ -345,7 +346,7 @@ struct sta_info {
void *rate_ctrl_priv;
spinlock_t lock;
- struct work_struct drv_unblock_wk;
+ struct work_struct drv_deliver_wk;
u16 listen_interval;
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -469,7 +469,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
return TX_CONTINUE;
if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
- test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
+ test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
+ test_sta_flag(sta, WLAN_STA_PS_DELIVER)) &&
!(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
int ac = skb_get_queue_mapping(tx->skb);
@@ -486,7 +487,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
* ahead and Tx the packet.
*/
if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
- !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+ !test_sta_flag(sta, WLAN_STA_PS_DRIVER) &&
+ !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
spin_unlock(&sta->ps_lock);
return TX_CONTINUE;
}
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -947,6 +947,40 @@ static inline u8 rt2800_get_beacon_offse
return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index));
}
+static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue = rt2x00dev->bcn;
+ struct queue_entry *entry;
+ int i, bcn_num = 0;
+ u64 off, reg = 0;
+ u32 bssid_dw1;
+
+ /*
+ * Setup offsets of all active beacons in BCN_OFFSET{0,1} registers.
+ */
+ for (i = 0; i < queue->limit; i++) {
+ entry = &queue->entries[i];
+ if (!test_bit(ENTRY_BCN_ENABLED, &entry->flags))
+ continue;
+ off = rt2800_get_beacon_offset(rt2x00dev, entry->entry_idx);
+ reg |= off << (8 * bcn_num);
+ bcn_num++;
+ }
+
+ WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing);
+
+ rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg);
+ rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32));
+
+ /*
+ * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons.
+ */
+ rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1);
+ rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM,
+ bcn_num > 0 ? bcn_num - 1 : 0);
+ rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1);
+}
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -1003,6 +1037,12 @@ void rt2800_write_beacon(struct queue_en
rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
entry->skb->len + padding_len);
+ __set_bit(ENTRY_BCN_ENABLED, &entry->flags);
+
+ /*
+ * Change global beacons settings.
+ */
+ rt2800_update_beacons_setup(rt2x00dev);
/*
* Restore beaconing state.
@@ -1053,8 +1093,13 @@ void rt2800_clear_beacon(struct queue_en
* Clear beacon.
*/
rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx);
+ __clear_bit(ENTRY_BCN_ENABLED, &entry->flags);
/*
+ * Change global beacons settings.
+ */
+ rt2800_update_beacons_setup(rt2x00dev);
+ /*
* Restore beaconing state.
*/
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
@@ -1556,7 +1601,7 @@ void rt2800_config_intf(struct rt2x00_de
if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
reg = le32_to_cpu(conf->bssid[1]);
rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
- rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
conf->bssid[1] = cpu_to_le32(reg);
}
@@ -4517,28 +4562,6 @@ static int rt2800_init_registers(struct
if (ret)
return ret;
- rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
- rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0,
- rt2800_get_beacon_offset(rt2x00dev, 0));
- rt2x00_set_field32(&reg, BCN_OFFSET0_BCN1,
- rt2800_get_beacon_offset(rt2x00dev, 1));
- rt2x00_set_field32(&reg, BCN_OFFSET0_BCN2,
- rt2800_get_beacon_offset(rt2x00dev, 2));
- rt2x00_set_field32(&reg, BCN_OFFSET0_BCN3,
- rt2800_get_beacon_offset(rt2x00dev, 3));
- rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg);
-
- rt2800_register_read(rt2x00dev, BCN_OFFSET1, &reg);
- rt2x00_set_field32(&reg, BCN_OFFSET1_BCN4,
- rt2800_get_beacon_offset(rt2x00dev, 4));
- rt2x00_set_field32(&reg, BCN_OFFSET1_BCN5,
- rt2800_get_beacon_offset(rt2x00dev, 5));
- rt2x00_set_field32(&reg, BCN_OFFSET1_BCN6,
- rt2800_get_beacon_offset(rt2x00dev, 6));
- rt2x00_set_field32(&reg, BCN_OFFSET1_BCN7,
- rt2800_get_beacon_offset(rt2x00dev, 7));
- rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg);
-
rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -141,8 +141,11 @@ static void rt2x00lib_intf_scheduled_ite
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
+ if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) {
+ mutex_lock(&intf->beacon_skb_mutex);
rt2x00queue_update_beacon(rt2x00dev, vif);
+ mutex_unlock(&intf->beacon_skb_mutex);
+ }
}
static void rt2x00lib_intf_scheduled(struct work_struct *work)
@@ -216,7 +219,7 @@ static void rt2x00lib_beaconupdate_iter(
* never be called for USB devices.
*/
WARN_ON(rt2x00_is_usb(rt2x00dev));
- rt2x00queue_update_beacon_locked(rt2x00dev, vif);
+ rt2x00queue_update_beacon(rt2x00dev, vif);
}
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -624,25 +624,24 @@ void rt2x00mac_bss_info_changed(struct i
* Start/stop beaconing.
*/
if (changes & BSS_CHANGED_BEACON_ENABLED) {
+ mutex_lock(&intf->beacon_skb_mutex);
if (!bss_conf->enable_beacon && intf->enable_beacon) {
rt2x00dev->intf_beaconing--;
intf->enable_beacon = false;
- /*
- * Clear beacon in the H/W for this vif. This is needed
- * to disable beaconing on this particular interface
- * and keep it running on other interfaces.
- */
- rt2x00queue_clear_beacon(rt2x00dev, vif);
if (rt2x00dev->intf_beaconing == 0) {
/*
* Last beaconing interface disabled
* -> stop beacon queue.
*/
- mutex_lock(&intf->beacon_skb_mutex);
rt2x00queue_stop_queue(rt2x00dev->bcn);
- mutex_unlock(&intf->beacon_skb_mutex);
}
+ /*
+ * Clear beacon in the H/W for this vif. This is needed
+ * to disable beaconing on this particular interface
+ * and keep it running on other interfaces.
+ */
+ rt2x00queue_clear_beacon(rt2x00dev, vif);
} else if (bss_conf->enable_beacon && !intf->enable_beacon) {
rt2x00dev->intf_beaconing++;
intf->enable_beacon = true;
@@ -658,11 +657,10 @@ void rt2x00mac_bss_info_changed(struct i
* First beaconing interface enabled
* -> start beacon queue.
*/
- mutex_lock(&intf->beacon_skb_mutex);
rt2x00queue_start_queue(rt2x00dev->bcn);
- mutex_unlock(&intf->beacon_skb_mutex);
}
}
+ mutex_unlock(&intf->beacon_skb_mutex);
}
/*
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -754,8 +754,6 @@ int rt2x00queue_clear_beacon(struct rt2x
if (unlikely(!intf->beacon))
return -ENOBUFS;
- mutex_lock(&intf->beacon_skb_mutex);
-
/*
* Clean up the beacon skb.
*/
@@ -768,13 +766,11 @@ int rt2x00queue_clear_beacon(struct rt2x
if (rt2x00dev->ops->lib->clear_beacon)
rt2x00dev->ops->lib->clear_beacon(intf->beacon);
- mutex_unlock(&intf->beacon_skb_mutex);
-
return 0;
}
-int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_vif *vif)
+int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_vif *vif)
{
struct rt2x00_intf *intf = vif_to_intf(vif);
struct skb_frame_desc *skbdesc;
@@ -815,19 +811,6 @@ int rt2x00queue_update_beacon_locked(str
}
-int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_vif *vif)
-{
- struct rt2x00_intf *intf = vif_to_intf(vif);
- int ret;
-
- mutex_lock(&intf->beacon_skb_mutex);
- ret = rt2x00queue_update_beacon_locked(rt2x00dev, vif);
- mutex_unlock(&intf->beacon_skb_mutex);
-
- return ret;
-}
-
bool rt2x00queue_for_each_entry(struct data_queue *queue,
enum queue_index start,
enum queue_index end,
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -353,6 +353,7 @@ struct txentry_desc {
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
+ ENTRY_BCN_ENABLED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_DATA_PENDING,
ENTRY_DATA_IO_FAILED,
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1757,7 +1757,6 @@ out:
void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
{
struct ath_vif *avp = (void *)vif->drv_priv;
- unsigned long flags;
u32 tsf;
if (!sc->p2p_ps_timer)
@@ -1767,14 +1766,9 @@ void ath9k_update_p2p_ps(struct ath_soft
return;
sc->p2p_ps_vif = avp;
-
- spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (!(sc->ps_flags & PS_BEACON_SYNC)) {
- tsf = ath9k_hw_gettsf32(sc->sc_ah);
- ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
- ath9k_update_p2p_ps_timer(sc, avp);
- }
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+ tsf = ath9k_hw_gettsf32(sc->sc_ah);
+ ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
+ ath9k_update_p2p_ps_timer(sc, avp);
}
static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
@@ -1791,6 +1785,7 @@ static void ath9k_bss_info_changed(struc
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
+ unsigned long flags;
int slottime;
ath9k_ps_wakeup(sc);
@@ -1853,7 +1848,10 @@ static void ath9k_bss_info_changed(struc
if (changed & BSS_CHANGED_P2P_PS) {
spin_lock_bh(&sc->sc_pcu_lock);
- ath9k_update_p2p_ps(sc, vif);
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (!(sc->ps_flags & PS_BEACON_SYNC))
+ ath9k_update_p2p_ps(sc, vif);
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
spin_unlock_bh(&sc->sc_pcu_lock);
}