mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-25 16:31:13 +00:00
c78c2f80a1
SVN-Revision: 32684
2008 lines
59 KiB
Diff
2008 lines
59 KiB
Diff
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
@@ -360,7 +360,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
|
|
|
struct ath_vif {
|
|
int av_bslot;
|
|
- bool is_bslot_active, primary_sta_vif;
|
|
+ bool primary_sta_vif;
|
|
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
|
|
struct ath_buf *av_bcbuf;
|
|
};
|
|
@@ -386,6 +386,7 @@ struct ath_beacon_config {
|
|
u16 dtim_period;
|
|
u16 bmiss_timeout;
|
|
u8 dtim_count;
|
|
+ bool enable_beacon;
|
|
};
|
|
|
|
struct ath_beacon {
|
|
@@ -397,7 +398,6 @@ struct ath_beacon {
|
|
|
|
u32 beaconq;
|
|
u32 bmisscnt;
|
|
- u32 ast_be_xmit;
|
|
u32 bc_tstamp;
|
|
struct ieee80211_vif *bslot[ATH_BCBUF];
|
|
int slottime;
|
|
@@ -411,12 +411,14 @@ struct ath_beacon {
|
|
bool tx_last;
|
|
};
|
|
|
|
-void ath_beacon_tasklet(unsigned long data);
|
|
-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
-int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
-void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
|
|
-int ath_beaconq_config(struct ath_softc *sc);
|
|
-void ath_set_beacon(struct ath_softc *sc);
|
|
+void ath9k_beacon_tasklet(unsigned long data);
|
|
+bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|
+ u32 changed);
|
|
+void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
+void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
+void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
+void ath9k_set_beacon(struct ath_softc *sc);
|
|
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
|
|
|
|
/*******************/
|
|
@@ -442,9 +444,12 @@ void ath_rx_poll(unsigned long data);
|
|
void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
|
|
void ath_paprd_calibrate(struct work_struct *work);
|
|
void ath_ani_calibrate(unsigned long data);
|
|
-void ath_start_ani(struct ath_common *common);
|
|
+void ath_start_ani(struct ath_softc *sc);
|
|
+void ath_stop_ani(struct ath_softc *sc);
|
|
+void ath_check_ani(struct ath_softc *sc);
|
|
int ath_update_survey_stats(struct ath_softc *sc);
|
|
void ath_update_survey_nf(struct ath_softc *sc, int channel);
|
|
+void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
|
|
|
|
/**********/
|
|
/* BTCOEX */
|
|
@@ -613,7 +618,6 @@ enum sc_op_flags {
|
|
SC_OP_INVALID,
|
|
SC_OP_BEACONS,
|
|
SC_OP_RXFLUSH,
|
|
- SC_OP_TSF_RESET,
|
|
SC_OP_ANI_RUN,
|
|
SC_OP_PRIM_STA_VIF,
|
|
SC_OP_HW_RESET,
|
|
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
|
@@ -30,7 +30,7 @@ static void ath9k_reset_beacon_status(st
|
|
* the operating mode of the station (AP or AdHoc). Parameters are AIFS
|
|
* settings and channel width min/max
|
|
*/
|
|
-int ath_beaconq_config(struct ath_softc *sc)
|
|
+static void ath9k_beaconq_config(struct ath_softc *sc)
|
|
{
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
@@ -38,6 +38,7 @@ int ath_beaconq_config(struct ath_softc
|
|
struct ath_txq *txq;
|
|
|
|
ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
|
|
+
|
|
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
|
/* Always burst out beacon and CAB traffic. */
|
|
qi.tqi_aifs = 1;
|
|
@@ -56,12 +57,9 @@ int ath_beaconq_config(struct ath_softc
|
|
}
|
|
|
|
if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
|
|
- ath_err(common,
|
|
- "Unable to update h/w beacon queue parameters\n");
|
|
- return 0;
|
|
+ ath_err(common, "Unable to update h/w beacon queue parameters\n");
|
|
} else {
|
|
ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
|
|
- return 1;
|
|
}
|
|
}
|
|
|
|
@@ -70,7 +68,7 @@ int ath_beaconq_config(struct ath_softc
|
|
* up rate codes, and channel flags. Beacons are always sent out at the
|
|
* lowest rate, and are not retried.
|
|
*/
|
|
-static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|
+static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|
struct ath_buf *bf, int rateidx)
|
|
{
|
|
struct sk_buff *skb = bf->bf_mpdu;
|
|
@@ -81,8 +79,6 @@ static void ath_beacon_setup(struct ath_
|
|
u8 chainmask = ah->txchainmask;
|
|
u8 rate = 0;
|
|
|
|
- ath9k_reset_beacon_status(sc);
|
|
-
|
|
sband = &sc->sbands[common->hw->conf.channel->band];
|
|
rate = sband->bitrates[rateidx].hw_value;
|
|
if (vif->bss_conf.use_short_preamble)
|
|
@@ -111,7 +107,7 @@ static void ath_beacon_setup(struct ath_
|
|
ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
|
|
}
|
|
|
|
-static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|
+static void ath9k_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|
{
|
|
struct ath_softc *sc = hw->priv;
|
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
@@ -128,28 +124,22 @@ static void ath_tx_cabq(struct ieee80211
|
|
}
|
|
}
|
|
|
|
-static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
|
|
- struct ieee80211_vif *vif)
|
|
+static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
|
|
+ struct ieee80211_vif *vif)
|
|
{
|
|
struct ath_softc *sc = hw->priv;
|
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
struct ath_buf *bf;
|
|
- struct ath_vif *avp;
|
|
+ struct ath_vif *avp = (void *)vif->drv_priv;
|
|
struct sk_buff *skb;
|
|
- struct ath_txq *cabq;
|
|
+ struct ath_txq *cabq = sc->beacon.cabq;
|
|
struct ieee80211_tx_info *info;
|
|
+ struct ieee80211_mgmt *mgmt_hdr;
|
|
int cabq_depth;
|
|
|
|
- ath9k_reset_beacon_status(sc);
|
|
-
|
|
- avp = (void *)vif->drv_priv;
|
|
- cabq = sc->beacon.cabq;
|
|
-
|
|
- if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active)
|
|
+ if (avp->av_bcbuf == NULL)
|
|
return NULL;
|
|
|
|
- /* Release the old beacon first */
|
|
-
|
|
bf = avp->av_bcbuf;
|
|
skb = bf->bf_mpdu;
|
|
if (skb) {
|
|
@@ -159,14 +149,14 @@ static struct ath_buf *ath_beacon_genera
|
|
bf->bf_buf_addr = 0;
|
|
}
|
|
|
|
- /* Get a new beacon from mac80211 */
|
|
-
|
|
skb = ieee80211_beacon_get(hw, vif);
|
|
- bf->bf_mpdu = skb;
|
|
if (skb == NULL)
|
|
return NULL;
|
|
- ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
|
|
- avp->tsf_adjust;
|
|
+
|
|
+ bf->bf_mpdu = skb;
|
|
+
|
|
+ mgmt_hdr = (struct ieee80211_mgmt *)skb->data;
|
|
+ mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;
|
|
|
|
info = IEEE80211_SKB_CB(skb);
|
|
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
|
|
@@ -212,61 +202,52 @@ static struct ath_buf *ath_beacon_genera
|
|
}
|
|
}
|
|
|
|
- ath_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
|
|
+ ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
|
|
|
|
while (skb) {
|
|
- ath_tx_cabq(hw, skb);
|
|
+ ath9k_tx_cabq(hw, skb);
|
|
skb = ieee80211_get_buffered_bc(hw, vif);
|
|
}
|
|
|
|
return bf;
|
|
}
|
|
|
|
-int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
+void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
{
|
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
- struct ath_vif *avp;
|
|
- struct ath_buf *bf;
|
|
- struct sk_buff *skb;
|
|
- struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
- __le64 tstamp;
|
|
+ struct ath_vif *avp = (void *)vif->drv_priv;
|
|
+ int slot;
|
|
|
|
- avp = (void *)vif->drv_priv;
|
|
+ avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list);
|
|
+ list_del(&avp->av_bcbuf->list);
|
|
|
|
- /* Allocate a beacon descriptor if we haven't done so. */
|
|
- if (!avp->av_bcbuf) {
|
|
- /* Allocate beacon state for hostap/ibss. We know
|
|
- * a buffer is available. */
|
|
- avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf,
|
|
- struct ath_buf, list);
|
|
- list_del(&avp->av_bcbuf->list);
|
|
-
|
|
- if (ath9k_uses_beacons(vif->type)) {
|
|
- int slot;
|
|
- /*
|
|
- * Assign the vif to a beacon xmit slot. As
|
|
- * above, this cannot fail to find one.
|
|
- */
|
|
- avp->av_bslot = 0;
|
|
- for (slot = 0; slot < ATH_BCBUF; slot++)
|
|
- if (sc->beacon.bslot[slot] == NULL) {
|
|
- avp->av_bslot = slot;
|
|
- avp->is_bslot_active = false;
|
|
-
|
|
- /* NB: keep looking for a double slot */
|
|
- if (slot == 0 || !sc->beacon.bslot[slot-1])
|
|
- break;
|
|
- }
|
|
- BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
|
|
- sc->beacon.bslot[avp->av_bslot] = vif;
|
|
- sc->nbcnvifs++;
|
|
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
|
|
+ if (sc->beacon.bslot[slot] == NULL) {
|
|
+ avp->av_bslot = slot;
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
- /* release the previous beacon frame, if it already exists. */
|
|
- bf = avp->av_bcbuf;
|
|
- if (bf->bf_mpdu != NULL) {
|
|
- skb = bf->bf_mpdu;
|
|
+ sc->beacon.bslot[avp->av_bslot] = vif;
|
|
+ sc->nbcnvifs++;
|
|
+
|
|
+ ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
|
|
+ avp->av_bslot);
|
|
+}
|
|
+
|
|
+void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
+{
|
|
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
+ struct ath_vif *avp = (void *)vif->drv_priv;
|
|
+ struct ath_buf *bf = avp->av_bcbuf;
|
|
+
|
|
+ ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
|
|
+ avp->av_bslot);
|
|
+
|
|
+ tasklet_disable(&sc->bcon_tasklet);
|
|
+
|
|
+ if (bf && bf->bf_mpdu) {
|
|
+ struct sk_buff *skb = bf->bf_mpdu;
|
|
dma_unmap_single(sc->dev, bf->bf_buf_addr,
|
|
skb->len, DMA_TO_DEVICE);
|
|
dev_kfree_skb_any(skb);
|
|
@@ -274,99 +255,74 @@ int ath_beacon_alloc(struct ath_softc *s
|
|
bf->bf_buf_addr = 0;
|
|
}
|
|
|
|
- /* NB: the beacon data buffer must be 32-bit aligned. */
|
|
- skb = ieee80211_beacon_get(sc->hw, vif);
|
|
- if (skb == NULL)
|
|
- return -ENOMEM;
|
|
-
|
|
- tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
|
|
- sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp);
|
|
- /* Calculate a TSF adjustment factor required for staggered beacons. */
|
|
- if (avp->av_bslot > 0) {
|
|
- u64 tsfadjust;
|
|
- int intval;
|
|
+ avp->av_bcbuf = NULL;
|
|
+ sc->beacon.bslot[avp->av_bslot] = NULL;
|
|
+ sc->nbcnvifs--;
|
|
+ list_add_tail(&bf->list, &sc->beacon.bbuf);
|
|
|
|
- intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
|
|
+ tasklet_enable(&sc->bcon_tasklet);
|
|
+}
|
|
|
|
- /*
|
|
- * Calculate the TSF offset for this beacon slot, i.e., the
|
|
- * number of usecs that need to be added to the timestamp field
|
|
- * in Beacon and Probe Response frames. Beacon slot 0 is
|
|
- * processed at the correct offset, so it does not require TSF
|
|
- * adjustment. Other slots are adjusted to get the timestamp
|
|
- * close to the TBTT for the BSS.
|
|
- */
|
|
- tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
|
|
- avp->tsf_adjust = cpu_to_le64(tsfadjust);
|
|
+static int ath9k_beacon_choose_slot(struct ath_softc *sc)
|
|
+{
|
|
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
+ u16 intval;
|
|
+ u32 tsftu;
|
|
+ u64 tsf;
|
|
+ int slot;
|
|
|
|
- ath_dbg(common, BEACON,
|
|
- "stagger beacons, bslot %d intval %u tsfadjust %llu\n",
|
|
- avp->av_bslot, intval, (unsigned long long)tsfadjust);
|
|
+ if (sc->sc_ah->opmode != NL80211_IFTYPE_AP) {
|
|
+ ath_dbg(common, BEACON, "slot 0, tsf: %llu\n",
|
|
+ ath9k_hw_gettsf64(sc->sc_ah));
|
|
+ return 0;
|
|
+ }
|
|
|
|
- ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
|
|
- avp->tsf_adjust;
|
|
- } else
|
|
- avp->tsf_adjust = cpu_to_le64(0);
|
|
+ intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
|
|
+ tsf = ath9k_hw_gettsf64(sc->sc_ah);
|
|
+ tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time);
|
|
+ tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
|
|
+ slot = (tsftu % (intval * ATH_BCBUF)) / intval;
|
|
|
|
- bf->bf_mpdu = skb;
|
|
- bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
|
|
- skb->len, DMA_TO_DEVICE);
|
|
- if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
|
|
- dev_kfree_skb_any(skb);
|
|
- bf->bf_mpdu = NULL;
|
|
- bf->bf_buf_addr = 0;
|
|
- ath_err(common, "dma_mapping_error on beacon alloc\n");
|
|
- return -ENOMEM;
|
|
- }
|
|
- avp->is_bslot_active = true;
|
|
+ ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n",
|
|
+ slot, tsf, tsftu / ATH_BCBUF);
|
|
|
|
- return 0;
|
|
+ return slot;
|
|
}
|
|
|
|
-void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
|
|
+void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
{
|
|
- if (avp->av_bcbuf != NULL) {
|
|
- struct ath_buf *bf;
|
|
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
+ struct ath_vif *avp = (void *)vif->drv_priv;
|
|
+ u64 tsfadjust;
|
|
|
|
- avp->is_bslot_active = false;
|
|
- if (avp->av_bslot != -1) {
|
|
- sc->beacon.bslot[avp->av_bslot] = NULL;
|
|
- sc->nbcnvifs--;
|
|
- avp->av_bslot = -1;
|
|
- }
|
|
+ if (avp->av_bslot == 0)
|
|
+ return;
|
|
|
|
- bf = avp->av_bcbuf;
|
|
- if (bf->bf_mpdu != NULL) {
|
|
- struct sk_buff *skb = bf->bf_mpdu;
|
|
- dma_unmap_single(sc->dev, bf->bf_buf_addr,
|
|
- skb->len, DMA_TO_DEVICE);
|
|
- dev_kfree_skb_any(skb);
|
|
- bf->bf_mpdu = NULL;
|
|
- bf->bf_buf_addr = 0;
|
|
- }
|
|
- list_add_tail(&bf->list, &sc->beacon.bbuf);
|
|
+ tsfadjust = cur_conf->beacon_interval * avp->av_bslot / ATH_BCBUF;
|
|
+ avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
|
|
|
|
- avp->av_bcbuf = NULL;
|
|
- }
|
|
+ ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
|
|
+ (unsigned long long)tsfadjust, avp->av_bslot);
|
|
}
|
|
|
|
-void ath_beacon_tasklet(unsigned long data)
|
|
+void ath9k_beacon_tasklet(unsigned long data)
|
|
{
|
|
struct ath_softc *sc = (struct ath_softc *)data;
|
|
- struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
struct ath_buf *bf = NULL;
|
|
struct ieee80211_vif *vif;
|
|
bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
|
|
int slot;
|
|
- u32 bfaddr, bc = 0;
|
|
|
|
- if (work_pending(&sc->hw_reset_work)) {
|
|
+ if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) {
|
|
ath_dbg(common, RESET,
|
|
"reset work is pending, skip beaconing now\n");
|
|
return;
|
|
}
|
|
+
|
|
/*
|
|
* Check if the previous beacon has gone out. If
|
|
* not don't try to post another, skip this period
|
|
@@ -390,55 +346,25 @@ void ath_beacon_tasklet(unsigned long da
|
|
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
|
ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
|
|
sc->beacon.bmisscnt = 0;
|
|
- set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
|
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
+ ath9k_queue_reset(sc, RESET_TYPE_BEACON_STUCK);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
- /*
|
|
- * Generate beacon frames. we are sending frames
|
|
- * staggered so calculate the slot for this frame based
|
|
- * on the tsf to safeguard against missing an swba.
|
|
- */
|
|
-
|
|
-
|
|
- if (ah->opmode == NL80211_IFTYPE_AP) {
|
|
- u16 intval;
|
|
- u32 tsftu;
|
|
- u64 tsf;
|
|
-
|
|
- intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
|
|
- tsf = ath9k_hw_gettsf64(ah);
|
|
- tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
|
|
- tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
|
|
- slot = (tsftu % (intval * ATH_BCBUF)) / intval;
|
|
- vif = sc->beacon.bslot[slot];
|
|
-
|
|
- ath_dbg(common, BEACON,
|
|
- "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
|
|
- slot, tsf, tsftu / ATH_BCBUF, intval, vif);
|
|
- } else {
|
|
- slot = 0;
|
|
- vif = sc->beacon.bslot[slot];
|
|
- }
|
|
+ slot = ath9k_beacon_choose_slot(sc);
|
|
+ vif = sc->beacon.bslot[slot];
|
|
|
|
+ if (!vif || !vif->bss_conf.enable_beacon)
|
|
+ return;
|
|
|
|
- bfaddr = 0;
|
|
- if (vif) {
|
|
- bf = ath_beacon_generate(sc->hw, vif);
|
|
- if (bf != NULL) {
|
|
- bfaddr = bf->bf_daddr;
|
|
- bc = 1;
|
|
- }
|
|
+ bf = ath9k_beacon_generate(sc->hw, vif);
|
|
+ WARN_ON(!bf);
|
|
|
|
- if (sc->beacon.bmisscnt != 0) {
|
|
- ath_dbg(common, BSTUCK,
|
|
- "resume beacon xmit after %u misses\n",
|
|
- sc->beacon.bmisscnt);
|
|
- sc->beacon.bmisscnt = 0;
|
|
- }
|
|
+ if (sc->beacon.bmisscnt != 0) {
|
|
+ ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
|
|
+ sc->beacon.bmisscnt);
|
|
+ sc->beacon.bmisscnt = 0;
|
|
}
|
|
|
|
/*
|
|
@@ -458,39 +384,37 @@ void ath_beacon_tasklet(unsigned long da
|
|
* set to ATH_BCBUF so this check is a noop.
|
|
*/
|
|
if (sc->beacon.updateslot == UPDATE) {
|
|
- sc->beacon.updateslot = COMMIT; /* commit next beacon */
|
|
+ sc->beacon.updateslot = COMMIT;
|
|
sc->beacon.slotupdate = slot;
|
|
- } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
|
|
+ } else if (sc->beacon.updateslot == COMMIT &&
|
|
+ sc->beacon.slotupdate == slot) {
|
|
ah->slottime = sc->beacon.slottime;
|
|
ath9k_hw_init_global_settings(ah);
|
|
sc->beacon.updateslot = OK;
|
|
}
|
|
- if (bfaddr != 0) {
|
|
+
|
|
+ if (bf) {
|
|
+ ath9k_reset_beacon_status(sc);
|
|
+
|
|
/* NB: cabq traffic should already be queued and primed */
|
|
- ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
|
|
+ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
|
|
|
|
if (!edma)
|
|
ath9k_hw_txstart(ah, sc->beacon.beaconq);
|
|
-
|
|
- sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */
|
|
}
|
|
}
|
|
|
|
-static void ath9k_beacon_init(struct ath_softc *sc,
|
|
- u32 next_beacon,
|
|
- u32 beacon_period)
|
|
+static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
|
|
{
|
|
- if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
|
|
- ath9k_ps_wakeup(sc);
|
|
- ath9k_hw_reset_tsf(sc->sc_ah);
|
|
- }
|
|
-
|
|
- ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
|
|
+ struct ath_hw *ah = sc->sc_ah;
|
|
|
|
- if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
|
|
- ath9k_ps_restore(sc);
|
|
- clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
|
- }
|
|
+ ath9k_hw_disable_interrupts(ah);
|
|
+ ath9k_hw_reset_tsf(ah);
|
|
+ ath9k_beaconq_config(sc);
|
|
+ ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
|
+ sc->beacon.bmisscnt = 0;
|
|
+ ath9k_hw_set_interrupts(ah);
|
|
+ ath9k_hw_enable_interrupts(ah);
|
|
}
|
|
|
|
/*
|
|
@@ -498,32 +422,27 @@ static void ath9k_beacon_init(struct ath
|
|
* burst together. For the former arrange for the SWBA to be delivered for each
|
|
* slot. Slots that are not occupied will generate nothing.
|
|
*/
|
|
-static void ath_beacon_config_ap(struct ath_softc *sc,
|
|
- struct ath_beacon_config *conf)
|
|
+static void ath9k_beacon_config_ap(struct ath_softc *sc,
|
|
+ struct ath_beacon_config *conf)
|
|
{
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
u32 nexttbtt, intval;
|
|
|
|
/* NB: the beacon interval is kept internally in TU's */
|
|
intval = TU_TO_USEC(conf->beacon_interval);
|
|
- intval /= ATH_BCBUF; /* for staggered beacons */
|
|
+ intval /= ATH_BCBUF;
|
|
nexttbtt = intval;
|
|
|
|
- /*
|
|
- * In AP mode we enable the beacon timers and SWBA interrupts to
|
|
- * prepare beacon frames.
|
|
- */
|
|
- ah->imask |= ATH9K_INT_SWBA;
|
|
- ath_beaconq_config(sc);
|
|
+ if (conf->enable_beacon)
|
|
+ ah->imask |= ATH9K_INT_SWBA;
|
|
+ else
|
|
+ ah->imask &= ~ATH9K_INT_SWBA;
|
|
|
|
- /* Set the computed AP beacon timers */
|
|
+ ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
|
|
+ nexttbtt, intval, conf->beacon_interval);
|
|
|
|
- ath9k_hw_disable_interrupts(ah);
|
|
- set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
|
ath9k_beacon_init(sc, nexttbtt, intval);
|
|
- sc->beacon.bmisscnt = 0;
|
|
- ath9k_hw_set_interrupts(ah);
|
|
- ath9k_hw_enable_interrupts(ah);
|
|
}
|
|
|
|
/*
|
|
@@ -534,8 +453,8 @@ static void ath_beacon_config_ap(struct
|
|
* we'll receive a BMISS interrupt when we stop seeing beacons from the AP
|
|
* we've associated with.
|
|
*/
|
|
-static void ath_beacon_config_sta(struct ath_softc *sc,
|
|
- struct ath_beacon_config *conf)
|
|
+static void ath9k_beacon_config_sta(struct ath_softc *sc,
|
|
+ struct ath_beacon_config *conf)
|
|
{
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
@@ -654,8 +573,8 @@ static void ath_beacon_config_sta(struct
|
|
ath9k_hw_enable_interrupts(ah);
|
|
}
|
|
|
|
-static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
|
- struct ath_beacon_config *conf)
|
|
+static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
|
|
+ struct ath_beacon_config *conf)
|
|
{
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
@@ -669,82 +588,53 @@ static void ath_beacon_config_adhoc(stru
|
|
tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
|
|
nexttbtt = tsf + intval;
|
|
|
|
- ath_dbg(common, BEACON, "IBSS nexttbtt %u intval %u (%u)\n",
|
|
- nexttbtt, intval, conf->beacon_interval);
|
|
-
|
|
- /*
|
|
- * In IBSS mode enable the beacon timers but only enable SWBA interrupts
|
|
- * if we need to manually prepare beacon frames. Otherwise we use a
|
|
- * self-linked tx descriptor and let the hardware deal with things.
|
|
- */
|
|
- ah->imask |= ATH9K_INT_SWBA;
|
|
-
|
|
- ath_beaconq_config(sc);
|
|
+ if (conf->enable_beacon)
|
|
+ ah->imask |= ATH9K_INT_SWBA;
|
|
+ else
|
|
+ ah->imask &= ~ATH9K_INT_SWBA;
|
|
|
|
- /* Set the computed ADHOC beacon timers */
|
|
+ ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n",
|
|
+ nexttbtt, intval, conf->beacon_interval);
|
|
|
|
- ath9k_hw_disable_interrupts(ah);
|
|
ath9k_beacon_init(sc, nexttbtt, intval);
|
|
- sc->beacon.bmisscnt = 0;
|
|
-
|
|
- ath9k_hw_set_interrupts(ah);
|
|
- ath9k_hw_enable_interrupts(ah);
|
|
}
|
|
|
|
-static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
|
- struct ieee80211_vif *vif)
|
|
+bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
{
|
|
- struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
|
struct ath_vif *avp = (void *)vif->drv_priv;
|
|
|
|
- /*
|
|
- * Can not have different beacon interval on multiple
|
|
- * AP interface case
|
|
- */
|
|
- if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
|
|
- (sc->nbcnvifs > 1) &&
|
|
- (vif->type == NL80211_IFTYPE_AP) &&
|
|
- (cur_conf->beacon_interval != bss_conf->beacon_int)) {
|
|
- ath_dbg(common, CONFIG,
|
|
- "Changing beacon interval of multiple AP interfaces !\n");
|
|
- return false;
|
|
- }
|
|
- /*
|
|
- * Can not configure station vif's beacon config
|
|
- * while on AP opmode
|
|
- */
|
|
- if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
|
|
- (vif->type != NL80211_IFTYPE_AP)) {
|
|
- ath_dbg(common, CONFIG,
|
|
- "STA vif's beacon not allowed on AP mode\n");
|
|
- return false;
|
|
+ if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
|
+ if ((vif->type != NL80211_IFTYPE_AP) ||
|
|
+ (sc->nbcnvifs > 1)) {
|
|
+ ath_dbg(common, CONFIG,
|
|
+ "An AP interface is already present !\n");
|
|
+ return false;
|
|
+ }
|
|
}
|
|
- /*
|
|
- * Do not allow beacon config if HW was already configured
|
|
- * with another STA vif
|
|
- */
|
|
- if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
|
|
- (vif->type == NL80211_IFTYPE_STATION) &&
|
|
- test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
|
|
- !avp->primary_sta_vif) {
|
|
- ath_dbg(common, CONFIG,
|
|
- "Beacon already configured for a station interface\n");
|
|
- return false;
|
|
+
|
|
+ if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
|
+ if ((vif->type == NL80211_IFTYPE_STATION) &&
|
|
+ test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
|
|
+ !avp->primary_sta_vif) {
|
|
+ ath_dbg(common, CONFIG,
|
|
+ "Beacon already configured for a station interface\n");
|
|
+ return false;
|
|
+ }
|
|
}
|
|
+
|
|
return true;
|
|
}
|
|
|
|
-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
+static void ath9k_cache_beacon_config(struct ath_softc *sc,
|
|
+ struct ieee80211_bss_conf *bss_conf)
|
|
{
|
|
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
|
|
|
- if (!ath9k_allow_beacon_config(sc, vif))
|
|
- return;
|
|
+ ath_dbg(common, BEACON,
|
|
+ "Caching beacon data for BSS: %pM\n", bss_conf->bssid);
|
|
|
|
- /* Setup the beacon configuration parameters */
|
|
cur_conf->beacon_interval = bss_conf->beacon_int;
|
|
cur_conf->dtim_period = bss_conf->dtim_period;
|
|
cur_conf->listen_interval = 1;
|
|
@@ -769,73 +659,59 @@ void ath_beacon_config(struct ath_softc
|
|
if (cur_conf->dtim_period == 0)
|
|
cur_conf->dtim_period = 1;
|
|
|
|
- ath_set_beacon(sc);
|
|
}
|
|
|
|
-static bool ath_has_valid_bslot(struct ath_softc *sc)
|
|
+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|
+ u32 changed)
|
|
{
|
|
- struct ath_vif *avp;
|
|
- int slot;
|
|
- bool found = false;
|
|
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
|
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
|
|
- for (slot = 0; slot < ATH_BCBUF; slot++) {
|
|
- if (sc->beacon.bslot[slot]) {
|
|
- avp = (void *)sc->beacon.bslot[slot]->drv_priv;
|
|
- if (avp->is_bslot_active) {
|
|
- found = true;
|
|
- break;
|
|
- }
|
|
+ ath9k_cache_beacon_config(sc, bss_conf);
|
|
+
|
|
+ if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
|
+ ath9k_set_beacon(sc);
|
|
+ set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
|
+ } else {
|
|
+ /*
|
|
+ * Take care of multiple interfaces when
|
|
+ * enabling/disabling SWBA.
|
|
+ */
|
|
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
|
+ if (!bss_conf->enable_beacon &&
|
|
+ (sc->nbcnvifs <= 1))
|
|
+ cur_conf->enable_beacon = false;
|
|
+ else if (bss_conf->enable_beacon)
|
|
+ cur_conf->enable_beacon = true;
|
|
}
|
|
+
|
|
+ ath9k_set_beacon(sc);
|
|
+
|
|
+ if (cur_conf->enable_beacon)
|
|
+ set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
|
+ else
|
|
+ clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
|
}
|
|
- return found;
|
|
}
|
|
|
|
-
|
|
-void ath_set_beacon(struct ath_softc *sc)
|
|
+void ath9k_set_beacon(struct ath_softc *sc)
|
|
{
|
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
|
|
switch (sc->sc_ah->opmode) {
|
|
case NL80211_IFTYPE_AP:
|
|
- if (ath_has_valid_bslot(sc))
|
|
- ath_beacon_config_ap(sc, cur_conf);
|
|
+ ath9k_beacon_config_ap(sc, cur_conf);
|
|
break;
|
|
case NL80211_IFTYPE_ADHOC:
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
- ath_beacon_config_adhoc(sc, cur_conf);
|
|
+ ath9k_beacon_config_adhoc(sc, cur_conf);
|
|
break;
|
|
case NL80211_IFTYPE_STATION:
|
|
- ath_beacon_config_sta(sc, cur_conf);
|
|
+ ath9k_beacon_config_sta(sc, cur_conf);
|
|
break;
|
|
default:
|
|
ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
|
|
return;
|
|
}
|
|
-
|
|
- set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
|
-}
|
|
-
|
|
-void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
|
|
-{
|
|
- struct ath_hw *ah = sc->sc_ah;
|
|
-
|
|
- if (!ath_has_valid_bslot(sc)) {
|
|
- clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
|
- return;
|
|
- }
|
|
-
|
|
- ath9k_ps_wakeup(sc);
|
|
- if (status) {
|
|
- /* Re-enable beaconing */
|
|
- ah->imask |= ATH9K_INT_SWBA;
|
|
- ath9k_hw_set_interrupts(ah);
|
|
- } else {
|
|
- /* Disable SWBA interrupt */
|
|
- ah->imask &= ~ATH9K_INT_SWBA;
|
|
- ath9k_hw_set_interrupts(ah);
|
|
- tasklet_kill(&sc->bcon_tasklet);
|
|
- ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
|
|
- }
|
|
- ath9k_ps_restore(sc);
|
|
}
|
|
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
|
@@ -206,10 +206,9 @@ static ssize_t write_file_disable_ani(st
|
|
|
|
if (disable_ani) {
|
|
clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
- del_timer_sync(&common->ani.timer);
|
|
+ ath_stop_ani(sc);
|
|
} else {
|
|
- set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
- ath_start_ani(common);
|
|
+ ath_check_ani(sc);
|
|
}
|
|
|
|
return count;
|
|
--- a/drivers/net/wireless/ath/ath9k/debug.h
|
|
+++ b/drivers/net/wireless/ath/ath9k/debug.h
|
|
@@ -32,6 +32,19 @@ struct ath_buf;
|
|
#define RESET_STAT_INC(sc, type) do { } while (0)
|
|
#endif
|
|
|
|
+enum ath_reset_type {
|
|
+ RESET_TYPE_BB_HANG,
|
|
+ RESET_TYPE_BB_WATCHDOG,
|
|
+ RESET_TYPE_FATAL_INT,
|
|
+ RESET_TYPE_TX_ERROR,
|
|
+ RESET_TYPE_TX_HANG,
|
|
+ RESET_TYPE_PLL_HANG,
|
|
+ RESET_TYPE_MAC_HANG,
|
|
+ RESET_TYPE_BEACON_STUCK,
|
|
+ RESET_TYPE_MCI,
|
|
+ __RESET_TYPE_MAX
|
|
+};
|
|
+
|
|
#ifdef CONFIG_ATH9K_DEBUGFS
|
|
|
|
/**
|
|
@@ -209,17 +222,6 @@ struct ath_rx_stats {
|
|
u32 rx_frags;
|
|
};
|
|
|
|
-enum ath_reset_type {
|
|
- RESET_TYPE_BB_HANG,
|
|
- RESET_TYPE_BB_WATCHDOG,
|
|
- RESET_TYPE_FATAL_INT,
|
|
- RESET_TYPE_TX_ERROR,
|
|
- RESET_TYPE_TX_HANG,
|
|
- RESET_TYPE_PLL_HANG,
|
|
- RESET_TYPE_MAC_HANG,
|
|
- __RESET_TYPE_MAX
|
|
-};
|
|
-
|
|
struct ath_stats {
|
|
struct ath_interrupt_stats istats;
|
|
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
|
|
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
|
@@ -1111,7 +1111,7 @@ static int ath9k_htc_add_interface(struc
|
|
|
|
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
|
|
!test_bit(OP_ANI_RUNNING, &priv->op_flags)) {
|
|
- ath9k_hw_set_tsfadjust(priv->ah, 1);
|
|
+ ath9k_hw_set_tsfadjust(priv->ah, true);
|
|
ath9k_htc_start_ani(priv);
|
|
}
|
|
|
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
|
@@ -2908,9 +2908,9 @@ void ath9k_hw_reset_tsf(struct ath_hw *a
|
|
}
|
|
EXPORT_SYMBOL(ath9k_hw_reset_tsf);
|
|
|
|
-void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
|
|
+void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set)
|
|
{
|
|
- if (setting)
|
|
+ if (set)
|
|
ah->misc_mode |= AR_PCU_TX_ADD_TSF;
|
|
else
|
|
ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
|
|
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
|
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
|
@@ -943,7 +943,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah)
|
|
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
|
|
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
|
|
void ath9k_hw_reset_tsf(struct ath_hw *ah);
|
|
-void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
|
|
+void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set);
|
|
void ath9k_hw_init_global_settings(struct ath_hw *ah);
|
|
u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
|
|
void ath9k_hw_set11nmac2040(struct ath_hw *ah);
|
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
|
@@ -560,7 +560,7 @@ static int ath9k_init_softc(u16 devid, s
|
|
spin_lock_init(&sc->debug.samp_lock);
|
|
#endif
|
|
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
|
|
- tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
|
|
+ tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
|
|
(unsigned long)sc);
|
|
|
|
INIT_WORK(&sc->hw_reset_work, ath_reset_work);
|
|
--- a/drivers/net/wireless/ath/ath9k/link.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/link.c
|
|
@@ -50,8 +50,7 @@ void ath_tx_complete_poll_work(struct wo
|
|
if (needreset) {
|
|
ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
|
|
"tx hung, resetting the chip\n");
|
|
- RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
|
|
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
+ ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
|
|
return;
|
|
}
|
|
|
|
@@ -69,6 +68,7 @@ void ath_hw_check(struct work_struct *wo
|
|
unsigned long flags;
|
|
int busy;
|
|
u8 is_alive, nbeacon = 1;
|
|
+ enum ath_reset_type type;
|
|
|
|
ath9k_ps_wakeup(sc);
|
|
is_alive = ath9k_hw_check_alive(sc->sc_ah);
|
|
@@ -78,7 +78,7 @@ void ath_hw_check(struct work_struct *wo
|
|
else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
|
|
ath_dbg(common, RESET,
|
|
"DCU stuck is detected. Schedule chip reset\n");
|
|
- RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
|
|
+ type = RESET_TYPE_MAC_HANG;
|
|
goto sched_reset;
|
|
}
|
|
|
|
@@ -90,7 +90,7 @@ void ath_hw_check(struct work_struct *wo
|
|
busy, sc->hw_busy_count + 1);
|
|
if (busy >= 99) {
|
|
if (++sc->hw_busy_count >= 3) {
|
|
- RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
|
|
+ type = RESET_TYPE_BB_HANG;
|
|
goto sched_reset;
|
|
}
|
|
} else if (busy >= 0) {
|
|
@@ -102,7 +102,7 @@ void ath_hw_check(struct work_struct *wo
|
|
goto out;
|
|
|
|
sched_reset:
|
|
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
+ ath9k_queue_reset(sc, type);
|
|
out:
|
|
ath9k_ps_restore(sc);
|
|
}
|
|
@@ -119,8 +119,7 @@ static bool ath_hw_pll_rx_hang_check(str
|
|
count++;
|
|
if (count == 3) {
|
|
ath_dbg(common, RESET, "PLL WAR, resetting the chip\n");
|
|
- RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
|
|
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
+ ath9k_queue_reset(sc, RESET_TYPE_PLL_HANG);
|
|
count = 0;
|
|
return true;
|
|
}
|
|
@@ -432,26 +431,69 @@ set_timer:
|
|
}
|
|
}
|
|
|
|
-void ath_start_ani(struct ath_common *common)
|
|
+void ath_start_ani(struct ath_softc *sc)
|
|
{
|
|
- struct ath_hw *ah = common->ah;
|
|
+ struct ath_hw *ah = sc->sc_ah;
|
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
unsigned long timestamp = jiffies_to_msecs(jiffies);
|
|
- struct ath_softc *sc = (struct ath_softc *) common->priv;
|
|
|
|
- if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags))
|
|
- return;
|
|
-
|
|
- if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
|
+ if (common->disable_ani ||
|
|
+ !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) ||
|
|
+ (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
|
|
return;
|
|
|
|
common->ani.longcal_timer = timestamp;
|
|
common->ani.shortcal_timer = timestamp;
|
|
common->ani.checkani_timer = timestamp;
|
|
|
|
+ ath_dbg(common, ANI, "Starting ANI\n");
|
|
mod_timer(&common->ani.timer,
|
|
jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval));
|
|
}
|
|
|
|
+void ath_stop_ani(struct ath_softc *sc)
|
|
+{
|
|
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
+
|
|
+ ath_dbg(common, ANI, "Stopping ANI\n");
|
|
+ del_timer_sync(&common->ani.timer);
|
|
+}
|
|
+
|
|
+void ath_check_ani(struct ath_softc *sc)
|
|
+{
|
|
+ struct ath_hw *ah = sc->sc_ah;
|
|
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
|
+
|
|
+ /*
|
|
+ * Check for the various conditions in which ANI has to
|
|
+ * be stopped.
|
|
+ */
|
|
+ if (ah->opmode == NL80211_IFTYPE_ADHOC) {
|
|
+ if (!cur_conf->enable_beacon)
|
|
+ goto stop_ani;
|
|
+ } else if (ah->opmode == NL80211_IFTYPE_AP) {
|
|
+ if (!cur_conf->enable_beacon) {
|
|
+ /*
|
|
+ * Disable ANI only when there are no
|
|
+ * associated stations.
|
|
+ */
|
|
+ if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
|
|
+ goto stop_ani;
|
|
+ }
|
|
+ } else if (ah->opmode == NL80211_IFTYPE_STATION) {
|
|
+ if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
|
|
+ goto stop_ani;
|
|
+ }
|
|
+
|
|
+ set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
+ ath_start_ani(sc);
|
|
+ return;
|
|
+
|
|
+stop_ani:
|
|
+ clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
+ ath_stop_ani(sc);
|
|
+}
|
|
+
|
|
void ath_update_survey_nf(struct ath_softc *sc, int channel)
|
|
{
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
@@ -167,8 +167,6 @@ static void ath_cancel_work(struct ath_s
|
|
|
|
static void ath_restart_work(struct ath_softc *sc)
|
|
{
|
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
-
|
|
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
|
|
|
if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) ||
|
|
@@ -177,21 +175,18 @@ static void ath_restart_work(struct ath_
|
|
msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
|
|
|
|
ath_start_rx_poll(sc, 3);
|
|
-
|
|
- if (!common->disable_ani)
|
|
- ath_start_ani(common);
|
|
+ ath_start_ani(sc);
|
|
}
|
|
|
|
static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
|
|
{
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
- struct ath_common *common = ath9k_hw_common(ah);
|
|
bool ret = true;
|
|
|
|
ieee80211_stop_queues(sc->hw);
|
|
|
|
sc->hw_busy_count = 0;
|
|
- del_timer_sync(&common->ani.timer);
|
|
+ ath_stop_ani(sc);
|
|
del_timer_sync(&sc->rx_poll_timer);
|
|
|
|
ath9k_debug_samp_bb_mac(sc);
|
|
@@ -236,7 +231,7 @@ static bool ath_complete_reset(struct at
|
|
if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
|
|
goto work;
|
|
|
|
- ath_set_beacon(sc);
|
|
+ ath9k_set_beacon(sc);
|
|
|
|
if (ah->opmode == NL80211_IFTYPE_STATION &&
|
|
test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
|
|
@@ -365,6 +360,7 @@ void ath9k_tasklet(unsigned long data)
|
|
struct ath_softc *sc = (struct ath_softc *)data;
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
+ enum ath_reset_type type;
|
|
unsigned long flags;
|
|
u32 status = sc->intrstatus;
|
|
u32 rxmask;
|
|
@@ -374,18 +370,13 @@ void ath9k_tasklet(unsigned long data)
|
|
|
|
if ((status & ATH9K_INT_FATAL) ||
|
|
(status & ATH9K_INT_BB_WATCHDOG)) {
|
|
-#ifdef CONFIG_ATH9K_DEBUGFS
|
|
- enum ath_reset_type type;
|
|
|
|
if (status & ATH9K_INT_FATAL)
|
|
type = RESET_TYPE_FATAL_INT;
|
|
else
|
|
type = RESET_TYPE_BB_WATCHDOG;
|
|
|
|
- RESET_STAT_INC(sc, type);
|
|
-#endif
|
|
- set_bit(SC_OP_HW_RESET, &sc->sc_flags);
|
|
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
+ ath9k_queue_reset(sc, type);
|
|
goto out;
|
|
}
|
|
|
|
@@ -575,6 +566,15 @@ static int ath_reset(struct ath_softc *s
|
|
return r;
|
|
}
|
|
|
|
+void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
|
|
+{
|
|
+#ifdef CONFIG_ATH9K_DEBUGFS
|
|
+ RESET_STAT_INC(sc, type);
|
|
+#endif
|
|
+ set_bit(SC_OP_HW_RESET, &sc->sc_flags);
|
|
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
+}
|
|
+
|
|
void ath_reset_work(struct work_struct *work)
|
|
{
|
|
struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
|
|
@@ -841,16 +841,6 @@ bool ath9k_uses_beacons(int type)
|
|
}
|
|
}
|
|
|
|
-static void ath9k_reclaim_beacon(struct ath_softc *sc,
|
|
- struct ieee80211_vif *vif)
|
|
-{
|
|
- struct ath_vif *avp = (void *)vif->drv_priv;
|
|
-
|
|
- ath9k_set_beaconing_status(sc, false);
|
|
- ath_beacon_return(sc, avp);
|
|
- ath9k_set_beaconing_status(sc, true);
|
|
-}
|
|
-
|
|
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|
{
|
|
struct ath9k_vif_iter_data *iter_data = data;
|
|
@@ -918,18 +908,14 @@ static void ath9k_calculate_summary_stat
|
|
|
|
ath9k_calculate_iter_data(hw, vif, &iter_data);
|
|
|
|
- /* Set BSSID mask. */
|
|
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
|
|
ath_hw_setbssidmask(common);
|
|
|
|
- /* Set op-mode & TSF */
|
|
if (iter_data.naps > 0) {
|
|
- ath9k_hw_set_tsfadjust(ah, 1);
|
|
- set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
|
+ ath9k_hw_set_tsfadjust(ah, true);
|
|
ah->opmode = NL80211_IFTYPE_AP;
|
|
} else {
|
|
- ath9k_hw_set_tsfadjust(ah, 0);
|
|
- clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
|
+ ath9k_hw_set_tsfadjust(ah, false);
|
|
|
|
if (iter_data.nmeshes)
|
|
ah->opmode = NL80211_IFTYPE_MESH_POINT;
|
|
@@ -941,45 +927,14 @@ static void ath9k_calculate_summary_stat
|
|
ah->opmode = NL80211_IFTYPE_STATION;
|
|
}
|
|
|
|
- /*
|
|
- * Enable MIB interrupts when there are hardware phy counters.
|
|
- */
|
|
+ ath9k_hw_setopmode(ah);
|
|
+
|
|
if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
|
|
ah->imask |= ATH9K_INT_TSFOOR;
|
|
else
|
|
ah->imask &= ~ATH9K_INT_TSFOOR;
|
|
|
|
ath9k_hw_set_interrupts(ah);
|
|
-
|
|
- /* Set up ANI */
|
|
- if (iter_data.naps > 0) {
|
|
- sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
|
-
|
|
- if (!common->disable_ani) {
|
|
- set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
- ath_start_ani(common);
|
|
- }
|
|
-
|
|
- } else {
|
|
- clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
- del_timer_sync(&common->ani.timer);
|
|
- }
|
|
-}
|
|
-
|
|
-/* Called with sc->mutex held, vif counts set up properly. */
|
|
-static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
|
|
- struct ieee80211_vif *vif)
|
|
-{
|
|
- struct ath_softc *sc = hw->priv;
|
|
-
|
|
- ath9k_calculate_summary_state(hw, vif);
|
|
-
|
|
- if (ath9k_uses_beacons(vif->type)) {
|
|
- /* Reserve a beacon slot for the vif */
|
|
- ath9k_set_beaconing_status(sc, false);
|
|
- ath_beacon_alloc(sc, vif);
|
|
- ath9k_set_beaconing_status(sc, true);
|
|
- }
|
|
}
|
|
|
|
static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|
@@ -1021,7 +976,10 @@ static int ath9k_add_interface(struct ie
|
|
|
|
sc->nvifs++;
|
|
|
|
- ath9k_do_vif_add_setup(hw, vif);
|
|
+ ath9k_calculate_summary_state(hw, vif);
|
|
+ if (ath9k_uses_beacons(vif->type))
|
|
+ ath9k_beacon_assign_slot(sc, vif);
|
|
+
|
|
out:
|
|
mutex_unlock(&sc->mutex);
|
|
ath9k_ps_restore(sc);
|
|
@@ -1038,6 +996,7 @@ static int ath9k_change_interface(struct
|
|
int ret = 0;
|
|
|
|
ath_dbg(common, CONFIG, "Change Interface\n");
|
|
+
|
|
mutex_lock(&sc->mutex);
|
|
ath9k_ps_wakeup(sc);
|
|
|
|
@@ -1050,15 +1009,16 @@ static int ath9k_change_interface(struct
|
|
}
|
|
}
|
|
|
|
- /* Clean up old vif stuff */
|
|
if (ath9k_uses_beacons(vif->type))
|
|
- ath9k_reclaim_beacon(sc, vif);
|
|
+ ath9k_beacon_remove_slot(sc, vif);
|
|
|
|
- /* Add new settings */
|
|
vif->type = new_type;
|
|
vif->p2p = p2p;
|
|
|
|
- ath9k_do_vif_add_setup(hw, vif);
|
|
+ ath9k_calculate_summary_state(hw, vif);
|
|
+ if (ath9k_uses_beacons(vif->type))
|
|
+ ath9k_beacon_assign_slot(sc, vif);
|
|
+
|
|
out:
|
|
ath9k_ps_restore(sc);
|
|
mutex_unlock(&sc->mutex);
|
|
@@ -1078,9 +1038,8 @@ static void ath9k_remove_interface(struc
|
|
|
|
sc->nvifs--;
|
|
|
|
- /* Reclaim beacon resources */
|
|
if (ath9k_uses_beacons(vif->type))
|
|
- ath9k_reclaim_beacon(sc, vif);
|
|
+ ath9k_beacon_remove_slot(sc, vif);
|
|
|
|
ath9k_calculate_summary_state(hw, NULL);
|
|
|
|
@@ -1388,10 +1347,6 @@ static int ath9k_conf_tx(struct ieee8021
|
|
if (ret)
|
|
ath_err(common, "TXQ Update failed\n");
|
|
|
|
- if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
|
|
- if (queue == WME_AC_BE && !ret)
|
|
- ath_beaconq_config(sc);
|
|
-
|
|
mutex_unlock(&sc->mutex);
|
|
ath9k_ps_restore(sc);
|
|
|
|
@@ -1460,85 +1415,36 @@ static int ath9k_set_key(struct ieee8021
|
|
|
|
return ret;
|
|
}
|
|
-static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|
+
|
|
+static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|
{
|
|
struct ath_softc *sc = data;
|
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
|
struct ath_vif *avp = (void *)vif->drv_priv;
|
|
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
|
unsigned long flags;
|
|
- /*
|
|
- * Skip iteration if primary station vif's bss info
|
|
- * was not changed
|
|
- */
|
|
+
|
|
if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
|
|
return;
|
|
|
|
if (bss_conf->assoc) {
|
|
set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
|
|
avp->primary_sta_vif = true;
|
|
+
|
|
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
|
common->curaid = bss_conf->aid;
|
|
ath9k_hw_write_associd(sc->sc_ah);
|
|
- ath_dbg(common, CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
|
|
- bss_conf->aid, common->curbssid);
|
|
- ath_beacon_config(sc, vif);
|
|
- /*
|
|
- * Request a re-configuration of Beacon related timers
|
|
- * on the receipt of the first Beacon frame (i.e.,
|
|
- * after time sync with the AP).
|
|
- */
|
|
- spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
|
- sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
|
|
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
|
|
|
- /* Reset rssi stats */
|
|
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
|
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
|
|
|
- ath_start_rx_poll(sc, 3);
|
|
-
|
|
- if (!common->disable_ani) {
|
|
- set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
- ath_start_ani(common);
|
|
- }
|
|
-
|
|
- }
|
|
-}
|
|
-
|
|
-static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
-{
|
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
|
- struct ath_vif *avp = (void *)vif->drv_priv;
|
|
-
|
|
- if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
|
|
- return;
|
|
-
|
|
- /* Reconfigure bss info */
|
|
- if (avp->primary_sta_vif && !bss_conf->assoc) {
|
|
- ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n",
|
|
- common->curaid, common->curbssid);
|
|
- clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
|
|
- clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
|
- avp->primary_sta_vif = false;
|
|
- memset(common->curbssid, 0, ETH_ALEN);
|
|
- common->curaid = 0;
|
|
- }
|
|
-
|
|
- ieee80211_iterate_active_interfaces_atomic(
|
|
- sc->hw, ath9k_bss_iter, sc);
|
|
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
|
+ sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
|
|
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
|
|
|
- /*
|
|
- * None of station vifs are associated.
|
|
- * Clear bssid & aid
|
|
- */
|
|
- if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
|
|
- ath9k_hw_write_associd(sc->sc_ah);
|
|
- clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
- del_timer_sync(&common->ani.timer);
|
|
- del_timer_sync(&sc->rx_poll_timer);
|
|
- memset(&sc->caldata, 0, sizeof(sc->caldata));
|
|
+ ath_dbg(common, CONFIG,
|
|
+ "Primary Station interface: %pM, BSSID: %pM\n",
|
|
+ vif->addr, common->curbssid);
|
|
}
|
|
}
|
|
|
|
@@ -1547,6 +1453,11 @@ static void ath9k_bss_info_changed(struc
|
|
struct ieee80211_bss_conf *bss_conf,
|
|
u32 changed)
|
|
{
|
|
+#define CHECK_ANI \
|
|
+ (BSS_CHANGED_ASSOC | \
|
|
+ BSS_CHANGED_IBSS | \
|
|
+ BSS_CHANGED_BEACON_ENABLED)
|
|
+
|
|
struct ath_softc *sc = hw->priv;
|
|
struct ath_hw *ah = sc->sc_ah;
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
@@ -1557,53 +1468,43 @@ static void ath9k_bss_info_changed(struc
|
|
mutex_lock(&sc->mutex);
|
|
|
|
if (changed & BSS_CHANGED_ASSOC) {
|
|
- ath9k_config_bss(sc, vif);
|
|
+ ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
|
|
+ bss_conf->bssid, bss_conf->assoc);
|
|
|
|
- ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n",
|
|
- common->curbssid, common->curaid);
|
|
+ /*
|
|
+ * Do not do anything when the opmode is not STATION.
|
|
+ */
|
|
+ if (ah->opmode == NL80211_IFTYPE_STATION) {
|
|
+ if (avp->primary_sta_vif && !bss_conf->assoc) {
|
|
+ clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
|
|
+ clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
|
+ avp->primary_sta_vif = false;
|
|
+ }
|
|
+
|
|
+ ieee80211_iterate_active_interfaces_atomic(sc->hw,
|
|
+ ath9k_bss_assoc_iter, sc);
|
|
+
|
|
+ if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
|
|
+ memset(common->curbssid, 0, ETH_ALEN);
|
|
+ common->curaid = 0;
|
|
+ ath9k_hw_write_associd(sc->sc_ah);
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
if (changed & BSS_CHANGED_IBSS) {
|
|
- /* There can be only one vif available */
|
|
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
|
common->curaid = bss_conf->aid;
|
|
ath9k_hw_write_associd(sc->sc_ah);
|
|
-
|
|
- if (bss_conf->ibss_joined) {
|
|
- sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
|
-
|
|
- if (!common->disable_ani) {
|
|
- set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
- ath_start_ani(common);
|
|
- }
|
|
-
|
|
- } else {
|
|
- clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
|
- del_timer_sync(&common->ani.timer);
|
|
- del_timer_sync(&sc->rx_poll_timer);
|
|
- }
|
|
}
|
|
|
|
- /*
|
|
- * In case of AP mode, the HW TSF has to be reset
|
|
- * when the beacon interval changes.
|
|
- */
|
|
- if ((changed & BSS_CHANGED_BEACON_INT) &&
|
|
- (vif->type == NL80211_IFTYPE_AP))
|
|
- set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
|
-
|
|
- /* Configure beaconing (AP, IBSS, MESH) */
|
|
- if (ath9k_uses_beacons(vif->type) &&
|
|
- ((changed & BSS_CHANGED_BEACON) ||
|
|
- (changed & BSS_CHANGED_BEACON_ENABLED) ||
|
|
- (changed & BSS_CHANGED_BEACON_INT))) {
|
|
- ath9k_set_beaconing_status(sc, false);
|
|
- if (bss_conf->enable_beacon)
|
|
- ath_beacon_alloc(sc, vif);
|
|
- else
|
|
- avp->is_bslot_active = false;
|
|
- ath_beacon_config(sc, vif);
|
|
- ath9k_set_beaconing_status(sc, true);
|
|
+ if ((changed & BSS_CHANGED_BEACON) ||
|
|
+ (changed & BSS_CHANGED_BEACON_ENABLED) ||
|
|
+ (changed & BSS_CHANGED_BEACON_INT)) {
|
|
+ if (ah->opmode == NL80211_IFTYPE_AP)
|
|
+ ath9k_set_tsfadjust(sc, vif);
|
|
+ if (ath9k_allow_beacon_config(sc, vif))
|
|
+ ath9k_beacon_config(sc, vif, changed);
|
|
}
|
|
|
|
if (changed & BSS_CHANGED_ERP_SLOT) {
|
|
@@ -1625,8 +1526,13 @@ static void ath9k_bss_info_changed(struc
|
|
}
|
|
}
|
|
|
|
+ if (changed & CHECK_ANI)
|
|
+ ath_check_ani(sc);
|
|
+
|
|
mutex_unlock(&sc->mutex);
|
|
ath9k_ps_restore(sc);
|
|
+
|
|
+#undef CHECK_ANI
|
|
}
|
|
|
|
static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|
@@ -1855,10 +1761,11 @@ static int ath9k_tx_last_beacon(struct i
|
|
if (!vif)
|
|
return 0;
|
|
|
|
- avp = (void *)vif->drv_priv;
|
|
- if (!avp->is_bslot_active)
|
|
+ if (!vif->bss_conf.enable_beacon)
|
|
return 0;
|
|
|
|
+ avp = (void *)vif->drv_priv;
|
|
+
|
|
if (!sc->beacon.tx_processed && !edma) {
|
|
tasklet_disable(&sc->bcon_tasklet);
|
|
|
|
--- a/drivers/net/wireless/ath/ath9k/mci.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/mci.c
|
|
@@ -202,7 +202,7 @@ static void ath_mci_cal_msg(struct ath_s
|
|
case MCI_GPM_BT_CAL_REQ:
|
|
if (mci_hw->bt_state == MCI_BT_AWAKE) {
|
|
ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START);
|
|
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
+ ath9k_queue_reset(sc, RESET_TYPE_MCI);
|
|
}
|
|
ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
|
|
break;
|
|
--- a/drivers/net/wireless/ath/ath9k/recv.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/recv.c
|
|
@@ -553,7 +553,7 @@ static void ath_rx_ps_beacon(struct ath_
|
|
sc->ps_flags &= ~PS_BEACON_SYNC;
|
|
ath_dbg(common, PS,
|
|
"Reconfigure Beacon timers based on timestamp from the AP\n");
|
|
- ath_set_beacon(sc);
|
|
+ ath9k_set_beacon(sc);
|
|
}
|
|
|
|
if (ath_beacon_dtim_pending_cab(skb)) {
|
|
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
|
@@ -614,10 +614,8 @@ static void ath_tx_complete_aggr(struct
|
|
|
|
rcu_read_unlock();
|
|
|
|
- if (needreset) {
|
|
- RESET_STAT_INC(sc, RESET_TYPE_TX_ERROR);
|
|
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
- }
|
|
+ if (needreset)
|
|
+ ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR);
|
|
}
|
|
|
|
static bool ath_lookup_legacy(struct ath_buf *bf)
|
|
@@ -1586,7 +1584,8 @@ void ath_txq_schedule(struct ath_softc *
|
|
struct ath_atx_ac *ac, *ac_tmp, *last_ac;
|
|
struct ath_atx_tid *tid, *last_tid;
|
|
|
|
- if (work_pending(&sc->hw_reset_work) || list_empty(&txq->axq_acq) ||
|
|
+ if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) ||
|
|
+ list_empty(&txq->axq_acq) ||
|
|
txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
|
|
return;
|
|
|
|
@@ -2191,7 +2190,7 @@ static void ath_tx_processq(struct ath_s
|
|
|
|
ath_txq_lock(sc, txq);
|
|
for (;;) {
|
|
- if (work_pending(&sc->hw_reset_work))
|
|
+ if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
|
|
break;
|
|
|
|
if (list_empty(&txq->axq_q)) {
|
|
@@ -2274,7 +2273,7 @@ void ath_tx_edma_tasklet(struct ath_soft
|
|
int status;
|
|
|
|
for (;;) {
|
|
- if (work_pending(&sc->hw_reset_work))
|
|
+ if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
|
|
break;
|
|
|
|
status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
|
|
--- a/include/net/mac80211.h
|
|
+++ b/include/net/mac80211.h
|
|
@@ -3596,22 +3596,6 @@ void ieee80211_request_smps(struct ieee8
|
|
enum ieee80211_smps_mode smps_mode);
|
|
|
|
/**
|
|
- * ieee80211_key_removed - disable hw acceleration for key
|
|
- * @key_conf: The key hw acceleration should be disabled for
|
|
- *
|
|
- * This allows drivers to indicate that the given key has been
|
|
- * removed from hardware acceleration, due to a new key that
|
|
- * was added. Don't use this if the key can continue to be used
|
|
- * for TX, if the key restriction is on RX only it is permitted
|
|
- * to keep the key for TX only and not call this function.
|
|
- *
|
|
- * Due to locking constraints, it may only be called during
|
|
- * @set_key. This function must be allowed to sleep, and the
|
|
- * key it tries to disable may still be used until it returns.
|
|
- */
|
|
-void ieee80211_key_removed(struct ieee80211_key_conf *key_conf);
|
|
-
|
|
-/**
|
|
* ieee80211_ready_on_channel - notification of remain-on-channel start
|
|
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
|
*/
|
|
--- a/net/mac80211/agg-rx.c
|
|
+++ b/net/mac80211/agg-rx.c
|
|
@@ -203,6 +203,8 @@ static void ieee80211_send_addba_resp(st
|
|
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
|
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
|
memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
|
|
+ else if (sdata->vif.type == NL80211_IFTYPE_WDS)
|
|
+ memcpy(mgmt->bssid, da, ETH_ALEN);
|
|
|
|
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
|
IEEE80211_STYPE_ACTION);
|
|
--- a/net/mac80211/agg-tx.c
|
|
+++ b/net/mac80211/agg-tx.c
|
|
@@ -81,7 +81,8 @@ static void ieee80211_send_addba_request
|
|
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
|
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
|
sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
|
- sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
|
+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
|
|
+ sdata->vif.type == NL80211_IFTYPE_WDS)
|
|
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
|
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
|
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
|
@@ -459,6 +460,7 @@ int ieee80211_start_tx_ba_session(struct
|
|
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
|
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
|
sdata->vif.type != NL80211_IFTYPE_AP &&
|
|
+ sdata->vif.type != NL80211_IFTYPE_WDS &&
|
|
sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
|
return -EINVAL;
|
|
|
|
--- a/net/mac80211/cfg.c
|
|
+++ b/net/mac80211/cfg.c
|
|
@@ -1741,6 +1741,8 @@ static int ieee80211_set_txq_params(stru
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
--- a/net/mac80211/debugfs_sta.c
|
|
+++ b/net/mac80211/debugfs_sta.c
|
|
@@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil
|
|
test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
|
|
|
|
int res = scnprintf(buf, sizeof(buf),
|
|
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
|
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
|
TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
|
|
TEST(PS_DRIVER), TEST(AUTHORIZED),
|
|
TEST(SHORT_PREAMBLE),
|
|
- TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
|
|
+ TEST(WME), TEST(CLEAR_PS_FILT),
|
|
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
|
|
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
|
|
TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
|
|
--- a/net/mac80211/iface.c
|
|
+++ b/net/mac80211/iface.c
|
|
@@ -400,7 +400,6 @@ static int ieee80211_do_open(struct net_
|
|
{
|
|
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
struct ieee80211_local *local = sdata->local;
|
|
- struct sta_info *sta;
|
|
u32 changed = 0;
|
|
int res;
|
|
u32 hw_reconf_flags = 0;
|
|
@@ -538,28 +537,6 @@ static int ieee80211_do_open(struct net_
|
|
|
|
set_bit(SDATA_STATE_RUNNING, &sdata->state);
|
|
|
|
- if (sdata->vif.type == NL80211_IFTYPE_WDS) {
|
|
- /* Create STA entry for the WDS peer */
|
|
- sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
|
|
- GFP_KERNEL);
|
|
- if (!sta) {
|
|
- res = -ENOMEM;
|
|
- goto err_del_interface;
|
|
- }
|
|
-
|
|
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
|
- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
|
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
|
-
|
|
- res = sta_info_insert(sta);
|
|
- if (res) {
|
|
- /* STA has been freed */
|
|
- goto err_del_interface;
|
|
- }
|
|
-
|
|
- rate_control_rate_init(sta);
|
|
- }
|
|
-
|
|
/*
|
|
* set_multicast_list will be invoked by the networking core
|
|
* which will check whether any increments here were done in
|
|
@@ -949,6 +926,72 @@ static void ieee80211_if_setup(struct ne
|
|
dev->destructor = free_netdev;
|
|
}
|
|
|
|
+static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|
+ struct sk_buff *skb)
|
|
+{
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
+ struct ieee80211_rx_status *rx_status;
|
|
+ struct ieee802_11_elems elems;
|
|
+ struct ieee80211_mgmt *mgmt;
|
|
+ struct sta_info *sta;
|
|
+ size_t baselen;
|
|
+ u32 rates = 0;
|
|
+ u16 stype;
|
|
+ bool new = false;
|
|
+ enum ieee80211_band band = local->hw.conf.channel->band;
|
|
+ struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
|
|
+
|
|
+ rx_status = IEEE80211_SKB_RXCB(skb);
|
|
+ mgmt = (struct ieee80211_mgmt *) skb->data;
|
|
+ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
|
|
+
|
|
+ if (stype != IEEE80211_STYPE_BEACON)
|
|
+ return;
|
|
+
|
|
+ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
|
|
+ if (baselen > skb->len)
|
|
+ return;
|
|
+
|
|
+ ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
|
|
+ skb->len - baselen, &elems);
|
|
+
|
|
+ rates = ieee80211_sta_get_rates(local, &elems, band, NULL);
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+ sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
|
|
+
|
|
+ if (!sta) {
|
|
+ rcu_read_unlock();
|
|
+ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
|
|
+ GFP_KERNEL);
|
|
+ if (!sta)
|
|
+ return;
|
|
+
|
|
+ new = true;
|
|
+ }
|
|
+
|
|
+ sta->last_rx = jiffies;
|
|
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
|
|
+
|
|
+ if (elems.ht_cap_elem)
|
|
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
|
+ elems.ht_cap_elem, &sta->sta.ht_cap);
|
|
+
|
|
+ if (elems.wmm_param)
|
|
+ set_sta_flag(sta, WLAN_STA_WME);
|
|
+
|
|
+ if (new) {
|
|
+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
|
+ sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
|
+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
|
+ rate_control_rate_init(sta);
|
|
+ sta_info_insert_rcu(sta);
|
|
+ }
|
|
+
|
|
+ rcu_read_unlock();
|
|
+}
|
|
+
|
|
static void ieee80211_iface_work(struct work_struct *work)
|
|
{
|
|
struct ieee80211_sub_if_data *sdata =
|
|
@@ -1053,6 +1096,9 @@ static void ieee80211_iface_work(struct
|
|
break;
|
|
ieee80211_mesh_rx_queued_mgmt(sdata, skb);
|
|
break;
|
|
+ case NL80211_IFTYPE_WDS:
|
|
+ ieee80211_wds_rx_queued_mgmt(sdata, skb);
|
|
+ break;
|
|
default:
|
|
WARN(1, "frame for unexpected interface type");
|
|
break;
|
|
--- a/net/mac80211/key.c
|
|
+++ b/net/mac80211/key.c
|
|
@@ -197,26 +197,6 @@ static void ieee80211_key_disable_hw_acc
|
|
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
|
}
|
|
|
|
-void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
|
|
-{
|
|
- struct ieee80211_key *key;
|
|
-
|
|
- key = container_of(key_conf, struct ieee80211_key, conf);
|
|
-
|
|
- might_sleep();
|
|
- assert_key_lock(key->local);
|
|
-
|
|
- key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
|
-
|
|
- /*
|
|
- * Flush TX path to avoid attempts to use this key
|
|
- * after this function returns. Until then, drivers
|
|
- * must be prepared to handle the key.
|
|
- */
|
|
- synchronize_rcu();
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(ieee80211_key_removed);
|
|
-
|
|
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
|
|
int idx, bool uni, bool multi)
|
|
{
|
|
--- a/net/mac80211/mlme.c
|
|
+++ b/net/mac80211/mlme.c
|
|
@@ -1108,7 +1108,7 @@ void ieee80211_dynamic_ps_timer(unsigned
|
|
}
|
|
|
|
/* MLME */
|
|
-static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|
+static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
|
struct ieee80211_sub_if_data *sdata,
|
|
u8 *wmm_param, size_t wmm_param_len)
|
|
{
|
|
@@ -1119,23 +1119,23 @@ static void ieee80211_sta_wmm_params(str
|
|
u8 *pos, uapsd_queues = 0;
|
|
|
|
if (!local->ops->conf_tx)
|
|
- return;
|
|
+ return false;
|
|
|
|
if (local->hw.queues < IEEE80211_NUM_ACS)
|
|
- return;
|
|
+ return false;
|
|
|
|
if (!wmm_param)
|
|
- return;
|
|
+ return false;
|
|
|
|
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
|
|
- return;
|
|
+ return false;
|
|
|
|
if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
|
|
uapsd_queues = ifmgd->uapsd_queues;
|
|
|
|
count = wmm_param[6] & 0x0f;
|
|
if (count == ifmgd->wmm_last_param_set)
|
|
- return;
|
|
+ return false;
|
|
ifmgd->wmm_last_param_set = count;
|
|
|
|
pos = wmm_param + 8;
|
|
@@ -1202,6 +1202,7 @@ static void ieee80211_sta_wmm_params(str
|
|
|
|
/* enable WMM or activate new settings */
|
|
sdata->vif.bss_conf.qos = true;
|
|
+ return true;
|
|
}
|
|
|
|
static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
|
|
@@ -2435,14 +2436,6 @@ static void ieee80211_rx_mgmt_beacon(str
|
|
directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
|
|
ifmgd->aid);
|
|
|
|
- if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) {
|
|
- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
|
|
- true);
|
|
-
|
|
- ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
|
|
- elems.wmm_param_len);
|
|
- }
|
|
-
|
|
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
|
|
if (directed_tim) {
|
|
if (local->hw.conf.dynamic_ps_timeout > 0) {
|
|
@@ -2473,6 +2466,13 @@ static void ieee80211_rx_mgmt_beacon(str
|
|
ifmgd->beacon_crc = ncrc;
|
|
ifmgd->beacon_crc_valid = true;
|
|
|
|
+ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
|
|
+ true);
|
|
+
|
|
+ if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
|
|
+ elems.wmm_param_len))
|
|
+ changed |= BSS_CHANGED_QOS;
|
|
+
|
|
if (elems.erp_info && elems.erp_info_len >= 1) {
|
|
erp_valid = true;
|
|
erp_value = elems.erp_info[0];
|
|
--- a/net/mac80211/rc80211_minstrel_ht.c
|
|
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
|
@@ -626,8 +626,12 @@ minstrel_ht_get_rate(void *priv, struct
|
|
|
|
#ifdef CONFIG_MAC80211_DEBUGFS
|
|
/* use fixed index if set */
|
|
- if (mp->fixed_rate_idx != -1)
|
|
- sample_idx = mp->fixed_rate_idx;
|
|
+ if (mp->fixed_rate_idx != -1) {
|
|
+ mi->max_tp_rate = mp->fixed_rate_idx;
|
|
+ mi->max_tp_rate2 = mp->fixed_rate_idx;
|
|
+ mi->max_prob_rate = mp->fixed_rate_idx;
|
|
+ sample_idx = -1;
|
|
+ }
|
|
#endif
|
|
|
|
if (sample_idx >= 0) {
|
|
--- a/net/mac80211/rx.c
|
|
+++ b/net/mac80211/rx.c
|
|
@@ -2262,6 +2262,7 @@ ieee80211_rx_h_action(struct ieee80211_r
|
|
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
|
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
|
sdata->vif.type != NL80211_IFTYPE_AP &&
|
|
+ sdata->vif.type != NL80211_IFTYPE_WDS &&
|
|
sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
|
break;
|
|
|
|
@@ -2479,14 +2480,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
|
|
|
|
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
|
|
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
|
- sdata->vif.type != NL80211_IFTYPE_STATION)
|
|
+ sdata->vif.type != NL80211_IFTYPE_STATION &&
|
|
+ sdata->vif.type != NL80211_IFTYPE_WDS)
|
|
return RX_DROP_MONITOR;
|
|
|
|
switch (stype) {
|
|
case cpu_to_le16(IEEE80211_STYPE_AUTH):
|
|
case cpu_to_le16(IEEE80211_STYPE_BEACON):
|
|
case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
|
|
- /* process for all: mesh, mlme, ibss */
|
|
+ /* process for all: mesh, mlme, ibss, wds */
|
|
break;
|
|
case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
|
|
case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
|
|
@@ -2817,10 +2819,16 @@ static int prepare_for_handlers(struct i
|
|
}
|
|
break;
|
|
case NL80211_IFTYPE_WDS:
|
|
- if (bssid || !ieee80211_is_data(hdr->frame_control))
|
|
- return 0;
|
|
if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
|
|
return 0;
|
|
+
|
|
+ if (ieee80211_is_data(hdr->frame_control) ||
|
|
+ ieee80211_is_action(hdr->frame_control)) {
|
|
+ if (compare_ether_addr(sdata->vif.addr, hdr->addr1))
|
|
+ return 0;
|
|
+ } else if (!ieee80211_is_beacon(hdr->frame_control))
|
|
+ return 0;
|
|
+
|
|
break;
|
|
default:
|
|
/* should never get here */
|
|
--- a/net/mac80211/sta_info.h
|
|
+++ b/net/mac80211/sta_info.h
|
|
@@ -32,7 +32,6 @@
|
|
* @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
|
|
* frames.
|
|
* @WLAN_STA_WME: Station is a QoS-STA.
|
|
- * @WLAN_STA_WDS: Station is one of our WDS peers.
|
|
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
|
|
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
|
|
* frame to this station is transmitted.
|
|
@@ -64,7 +63,6 @@ enum ieee80211_sta_info_flags {
|
|
WLAN_STA_AUTHORIZED,
|
|
WLAN_STA_SHORT_PREAMBLE,
|
|
WLAN_STA_WME,
|
|
- WLAN_STA_WDS,
|
|
WLAN_STA_CLEAR_PS_FILT,
|
|
WLAN_STA_MFP,
|
|
WLAN_STA_BLOCK_BA,
|
|
--- a/net/mac80211/tx.c
|
|
+++ b/net/mac80211/tx.c
|
|
@@ -2716,7 +2716,7 @@ EXPORT_SYMBOL(ieee80211_get_buffered_bc)
|
|
void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
|
|
struct sk_buff *skb, int tid)
|
|
{
|
|
- int ac = ieee802_1d_to_ac[tid];
|
|
+ int ac = ieee802_1d_to_ac[tid & 7];
|
|
|
|
skb_set_mac_header(skb, 0);
|
|
skb_set_network_header(skb, 0);
|
|
--- a/net/wireless/chan.c
|
|
+++ b/net/wireless/chan.c
|
|
@@ -136,9 +136,16 @@ cfg80211_get_chan_state(struct cfg80211_
|
|
break;
|
|
case NL80211_IFTYPE_AP:
|
|
case NL80211_IFTYPE_P2P_GO:
|
|
+ if (wdev->beacon_interval) {
|
|
+ *chan = wdev->channel;
|
|
+ *chanmode = CHAN_MODE_SHARED;
|
|
+ }
|
|
+ return;
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
- *chan = wdev->channel;
|
|
- *chanmode = CHAN_MODE_SHARED;
|
|
+ if (wdev->mesh_id_len) {
|
|
+ *chan = wdev->channel;
|
|
+ *chanmode = CHAN_MODE_SHARED;
|
|
+ }
|
|
return;
|
|
case NL80211_IFTYPE_MONITOR:
|
|
case NL80211_IFTYPE_AP_VLAN:
|