Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless

Conflicts:
	drivers/net/wireless/ath/ath9k/recv.c
	drivers/net/wireless/mwifiex/pcie.c
This commit is contained in:
John W. Linville 2014-03-04 13:05:12 -05:00
commit f3b6a488a6
33 changed files with 303 additions and 178 deletions

View file

@ -110,7 +110,7 @@ ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20)); ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
if (ah->ah_version == AR5K_AR5210) { if (ah->ah_version == AR5K_AR5210) {
srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf; srev = (ath5k_hw_reg_read(ah, AR5K_PHY(256)) >> 28) & 0xf;
ret = (u16)ath5k_hw_bitswap(srev, 4) + 1; ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
} else { } else {
srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;

View file

@ -57,7 +57,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e}, {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
@ -96,7 +96,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa},
{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
}; };

View file

@ -1533,7 +1533,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav);
bool ath9k_hw_check_alive(struct ath_hw *ah) bool ath9k_hw_check_alive(struct ath_hw *ah)
{ {
int count = 50; int count = 50;
u32 reg; u32 reg, last_val;
if (AR_SREV_9300(ah)) if (AR_SREV_9300(ah))
return !ath9k_hw_detect_mac_hang(ah); return !ath9k_hw_detect_mac_hang(ah);
@ -1541,9 +1541,13 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
if (AR_SREV_9285_12_OR_LATER(ah)) if (AR_SREV_9285_12_OR_LATER(ah))
return true; return true;
last_val = REG_READ(ah, AR_OBS_BUS_1);
do { do {
reg = REG_READ(ah, AR_OBS_BUS_1); reg = REG_READ(ah, AR_OBS_BUS_1);
if (reg != last_val)
return true;
last_val = reg;
if ((reg & 0x7E7FFFEF) == 0x00702400) if ((reg & 0x7E7FFFEF) == 0x00702400)
continue; continue;
@ -1555,6 +1559,8 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
default: default:
return true; return true;
} }
udelay(1);
} while (count-- > 0); } while (count-- > 0);
return false; return false;

View file

@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc,
return NULL; return NULL;
/* /*
* mark descriptor as zero-length and set the 'more' * Re-check previous descriptor, in case it has been filled
* flag to ensure that both buffers get discarded * in the mean time.
*/ */
rs->rs_datalen = 0; ret = ath9k_hw_rxprocdesc(ah, ds, rs);
rs->rs_more = true; if (ret == -EINPROGRESS) {
/*
* mark descriptor as zero-length and set the 'more'
* flag to ensure that both buffers get discarded
*/
rs->rs_datalen = 0;
rs->rs_more = true;
}
} }
list_del(&bf->list); list_del(&bf->list);
@ -787,32 +794,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
bool discard_current = sc->rx.discard_next; bool discard_current = sc->rx.discard_next;
int ret = 0;
/* /*
* Discard corrupt descriptors which are marked in * Discard corrupt descriptors which are marked in
* ath_get_next_rx_buf(). * ath_get_next_rx_buf().
*/ */
sc->rx.discard_next = rx_stats->rs_more;
if (discard_current) if (discard_current)
return -EINVAL; goto corrupt;
sc->rx.discard_next = false;
/* /*
* Discard zero-length packets. * Discard zero-length packets.
*/ */
if (!rx_stats->rs_datalen) { if (!rx_stats->rs_datalen) {
RX_STAT_INC(rx_len_err); RX_STAT_INC(rx_len_err);
return -EINVAL; goto corrupt;
} }
/* /*
* rs_status follows rs_datalen so if rs_datalen is too large * rs_status follows rs_datalen so if rs_datalen is too large
* we can take a hint that hardware corrupted it, so ignore * we can take a hint that hardware corrupted it, so ignore
* those frames. * those frames.
*/ */
if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
RX_STAT_INC(rx_len_err); RX_STAT_INC(rx_len_err);
return -EINVAL; goto corrupt;
} }
/* Only use status info from the last fragment */ /* Only use status info from the last fragment */
@ -826,10 +833,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
* This is different from the other corrupt descriptor * This is different from the other corrupt descriptor
* condition handled above. * condition handled above.
*/ */
if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) { if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
ret = -EINVAL; goto corrupt;
goto exit;
}
hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
@ -845,18 +850,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
RX_STAT_INC(rx_spectral); RX_STAT_INC(rx_spectral);
ret = -EINVAL; return -EINVAL;
goto exit;
} }
/* /*
* everything but the rate is checked here, the rate check is done * everything but the rate is checked here, the rate check is done
* separately to avoid doing two lookups for a rate for each frame. * separately to avoid doing two lookups for a rate for each frame.
*/ */
if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter)) { if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter))
ret = -EINVAL; return -EINVAL;
goto exit;
}
if (ath_is_mybeacon(common, hdr)) { if (ath_is_mybeacon(common, hdr)) {
RX_STAT_INC(rx_beacons); RX_STAT_INC(rx_beacons);
@ -866,10 +868,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
/* /*
* This shouldn't happen, but have a safety check anyway. * This shouldn't happen, but have a safety check anyway.
*/ */
if (WARN_ON(!ah->curchan)) { if (WARN_ON(!ah->curchan))
ret = -EINVAL; return -EINVAL;
goto exit;
}
if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) { if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) {
/* /*
@ -879,8 +879,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
rx_stats->rs_rate); rx_stats->rs_rate);
RX_STAT_INC(rx_rate_err); RX_STAT_INC(rx_rate_err);
ret =-EINVAL; return -EINVAL;
goto exit;
} }
ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
@ -896,9 +895,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
sc->rx.num_pkts++; sc->rx.num_pkts++;
#endif #endif
exit: return 0;
sc->rx.discard_next = false;
return ret; corrupt:
sc->rx.discard_next = rx_stats->rs_more;
return -EINVAL;
} }
/* /*

View file

@ -1445,14 +1445,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
for (tidno = 0, tid = &an->tid[tidno]; for (tidno = 0, tid = &an->tid[tidno];
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
if (!tid->sched)
continue;
ac = tid->ac; ac = tid->ac;
txq = ac->txq; txq = ac->txq;
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
if (!tid->sched) {
ath_txq_unlock(sc, txq);
continue;
}
buffered = ath_tid_has_buffered(tid); buffered = ath_tid_has_buffered(tid);
tid->sched = false; tid->sched = false;
@ -2185,14 +2187,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
txq->stopped = true; txq->stopped = true;
} }
if (txctl->an)
tid = ath_get_skb_tid(sc, txctl->an, skb);
if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
ath_txq_unlock(sc, txq); ath_txq_unlock(sc, txq);
txq = sc->tx.uapsdq; txq = sc->tx.uapsdq;
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
} else if (txctl->an && } else if (txctl->an &&
ieee80211_is_data_present(hdr->frame_control)) { ieee80211_is_data_present(hdr->frame_control)) {
tid = ath_get_skb_tid(sc, txctl->an, skb);
WARN_ON(tid->ac->txq != txctl->txq); WARN_ON(tid->ac->txq != txctl->txq);
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)

View file

@ -482,7 +482,6 @@ struct brcmf_sdio {
u8 tx_hdrlen; /* sdio bus header length for tx packet */ u8 tx_hdrlen; /* sdio bus header length for tx packet */
bool txglom; /* host tx glomming enable flag */ bool txglom; /* host tx glomming enable flag */
struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */
u16 head_align; /* buffer pointer alignment */ u16 head_align; /* buffer pointer alignment */
u16 sgentry_align; /* scatter-gather buffer alignment */ u16 sgentry_align; /* scatter-gather buffer alignment */
}; };
@ -2113,9 +2112,8 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
if (lastfrm && chain_pad) if (lastfrm && chain_pad)
tail_pad += blksize - chain_pad; tail_pad += blksize - chain_pad;
if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) { if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
pkt_pad = bus->txglom_sgpad; pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop +
if (pkt_pad == NULL) bus->head_align);
brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
if (pkt_pad == NULL) if (pkt_pad == NULL)
return -ENOMEM; return -ENOMEM;
ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad); ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
@ -2126,6 +2124,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
tail_chop); tail_chop);
*(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
skb_trim(pkt, pkt->len - tail_chop); skb_trim(pkt, pkt->len - tail_chop);
skb_trim(pkt_pad, tail_pad + tail_chop);
__skb_queue_after(pktq, pkt, pkt_pad); __skb_queue_after(pktq, pkt, pkt_pad);
} else { } else {
ntail = pkt->data_len + tail_pad - ntail = pkt->data_len + tail_pad -
@ -2180,7 +2179,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
return ret; return ret;
head_pad = (u16)ret; head_pad = (u16)ret;
if (head_pad) if (head_pad)
memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen); memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
total_len += pkt_next->len; total_len += pkt_next->len;
@ -3441,10 +3440,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
bus->txglom = false; bus->txglom = false;
value = 1; value = 1;
pad_size = bus->sdiodev->func[2]->cur_blksize << 1; pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size);
if (!bus->txglom_sgpad)
brcmf_err("allocating txglom padding skb failed, reduced performance\n");
err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
&value, sizeof(u32)); &value, sizeof(u32));
if (err < 0) { if (err < 0) {
@ -4167,7 +4162,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
brcmf_chip_detach(bus->ci); brcmf_chip_detach(bus->ci);
} }
brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
kfree(bus->rxbuf); kfree(bus->rxbuf);
kfree(bus->hdrbuf); kfree(bus->hdrbuf);
kfree(bus); kfree(bus);

View file

@ -147,7 +147,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
if (!sta->ap && sta->u.sta.challenge) if (!sta->ap && sta->u.sta.challenge)
kfree(sta->u.sta.challenge); kfree(sta->u.sta.challenge);
del_timer(&sta->timer); del_timer_sync(&sta->timer);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
kfree(sta); kfree(sta);

View file

@ -496,7 +496,7 @@ void hostap_init_proc(local_info_t *local)
void hostap_remove_proc(local_info_t *local) void hostap_remove_proc(local_info_t *local)
{ {
remove_proc_subtree(local->ddev->name, hostap_proc); proc_remove(local->proc);
} }

View file

@ -696,6 +696,24 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret; return ret;
} }
static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg)
{
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
return false;
return true;
}
static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
{
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
return false;
if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG)
return true;
/* disabled by default */
return false;
}
static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
@ -717,7 +735,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) { switch (action) {
case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_START:
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) if (!iwl_enable_rx_ampdu(priv->cfg))
break; break;
IWL_DEBUG_HT(priv, "start Rx\n"); IWL_DEBUG_HT(priv, "start Rx\n");
ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
@ -729,7 +747,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_START: case IEEE80211_AMPDU_TX_START:
if (!priv->trans->ops->txq_enable) if (!priv->trans->ops->txq_enable)
break; break;
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) if (!iwl_enable_tx_ampdu(priv->cfg))
break; break;
IWL_DEBUG_HT(priv, "start Tx\n"); IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);

View file

@ -590,6 +590,7 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
sizeof(priv->tid_data[sta_id][tid])); sizeof(priv->tid_data[sta_id][tid]));
priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
priv->num_stations--; priv->num_stations--;

View file

@ -1291,8 +1291,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data; struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
struct iwl_ht_agg *agg; struct iwl_ht_agg *agg;
struct sk_buff_head reclaimed_skbs; struct sk_buff_head reclaimed_skbs;
struct ieee80211_tx_info *info;
struct ieee80211_hdr *hdr;
struct sk_buff *skb; struct sk_buff *skb;
int sta_id; int sta_id;
int tid; int tid;
@ -1379,22 +1377,28 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
freed = 0; freed = 0;
skb_queue_walk(&reclaimed_skbs, skb) { skb_queue_walk(&reclaimed_skbs, skb) {
hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (ieee80211_is_data_qos(hdr->frame_control)) if (ieee80211_is_data_qos(hdr->frame_control))
freed++; freed++;
else else
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
info = IEEE80211_SKB_CB(skb);
iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]); iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
memset(&info->status, 0, sizeof(info->status));
/* Packet was transmitted successfully, failures come as single
* frames because before failing a frame the firmware transmits
* it without aggregation at least once.
*/
info->flags |= IEEE80211_TX_STAT_ACK;
if (freed == 1) { if (freed == 1) {
/* this is the first skb we deliver in this batch */ /* this is the first skb we deliver in this batch */
/* put the rate scaling data there */ /* put the rate scaling data there */
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
memset(&info->status, 0, sizeof(info->status)); memset(&info->status, 0, sizeof(info->status));
info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU; info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_len = ba_resp->txed_2_done; info->status.ampdu_ack_len = ba_resp->txed_2_done;
info->status.ampdu_len = ba_resp->txed; info->status.ampdu_len = ba_resp->txed;

View file

@ -1337,7 +1337,7 @@ module_param_named(swcrypto, iwlwifi_mod_params.sw_crypto, int, S_IRUGO);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO);
MODULE_PARM_DESC(11n_disable, MODULE_PARM_DESC(11n_disable,
"disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"); "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX");
module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K, module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,
int, S_IRUGO); int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)"); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");

View file

@ -79,9 +79,12 @@ enum iwl_power_level {
IWL_POWER_NUM IWL_POWER_NUM
}; };
#define IWL_DISABLE_HT_ALL BIT(0) enum iwl_disable_11n {
#define IWL_DISABLE_HT_TXAGG BIT(1) IWL_DISABLE_HT_ALL = BIT(0),
#define IWL_DISABLE_HT_RXAGG BIT(2) IWL_DISABLE_HT_TXAGG = BIT(1),
IWL_DISABLE_HT_RXAGG = BIT(2),
IWL_ENABLE_HT_TXAGG = BIT(3),
};
/** /**
* struct iwl_mod_params * struct iwl_mod_params
@ -90,7 +93,7 @@ enum iwl_power_level {
* *
* @sw_crypto: using hardware encryption, default = 0 * @sw_crypto: using hardware encryption, default = 0
* @disable_11n: disable 11n capabilities, default = 0, * @disable_11n: disable 11n capabilities, default = 0,
* use IWL_DISABLE_HT_* constants * use IWL_[DIS,EN]ABLE_HT_* constants
* @amsdu_size_8K: enable 8K amsdu size, default = 0 * @amsdu_size_8K: enable 8K amsdu size, default = 0
* @restart_fw: restart firmware, default = 1 * @restart_fw: restart firmware, default = 1
* @wd_disable: disable stuck queue check, default = 1 * @wd_disable: disable stuck queue check, default = 1

View file

@ -463,6 +463,24 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
ieee80211_free_txskb(hw, skb); ieee80211_free_txskb(hw, skb);
} }
static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg)
{
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
return false;
return true;
}
static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
{
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
return false;
if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG)
return true;
/* enabled by default */
return true;
}
static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
@ -482,7 +500,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) { switch (action) {
case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_START:
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) { if (!iwl_enable_rx_ampdu(mvm->cfg)) {
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
@ -492,7 +510,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
break; break;
case IEEE80211_AMPDU_TX_START: case IEEE80211_AMPDU_TX_START:
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) { if (!iwl_enable_tx_ampdu(mvm->cfg)) {
ret = -EINVAL; ret = -EINVAL;
break; break;
} }

View file

@ -150,7 +150,7 @@ enum iwl_power_scheme {
IWL_POWER_SCHEME_LP IWL_POWER_SCHEME_LP
}; };
#define IWL_CONN_MAX_LISTEN_INTERVAL 70 #define IWL_CONN_MAX_LISTEN_INTERVAL 10
#define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ #define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\

View file

@ -845,16 +845,12 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data;
struct sk_buff_head reclaimed_skbs; struct sk_buff_head reclaimed_skbs;
struct iwl_mvm_tid_data *tid_data; struct iwl_mvm_tid_data *tid_data;
struct ieee80211_tx_info *info;
struct ieee80211_sta *sta; struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta; struct iwl_mvm_sta *mvmsta;
struct ieee80211_hdr *hdr;
struct sk_buff *skb; struct sk_buff *skb;
int sta_id, tid, freed; int sta_id, tid, freed;
/* "flow" corresponds to Tx queue */ /* "flow" corresponds to Tx queue */
u16 scd_flow = le16_to_cpu(ba_notif->scd_flow); u16 scd_flow = le16_to_cpu(ba_notif->scd_flow);
/* "ssn" is start of block-ack Tx window, corresponds to index /* "ssn" is start of block-ack Tx window, corresponds to index
* (in Tx queue's circular buffer) of first TFD/frame in window */ * (in Tx queue's circular buffer) of first TFD/frame in window */
u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn); u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn);
@ -911,22 +907,26 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
freed = 0; freed = 0;
skb_queue_walk(&reclaimed_skbs, skb) { skb_queue_walk(&reclaimed_skbs, skb) {
hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (ieee80211_is_data_qos(hdr->frame_control)) if (ieee80211_is_data_qos(hdr->frame_control))
freed++; freed++;
else else
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
info = IEEE80211_SKB_CB(skb);
iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
memset(&info->status, 0, sizeof(info->status));
/* Packet was transmitted successfully, failures come as single
* frames because before failing a frame the firmware transmits
* it without aggregation at least once.
*/
info->flags |= IEEE80211_TX_STAT_ACK;
if (freed == 1) { if (freed == 1) {
/* this is the first skb we deliver in this batch */ /* this is the first skb we deliver in this batch */
/* put the rate scaling data there */ /* put the rate scaling data there */
info = IEEE80211_SKB_CB(skb);
memset(&info->status, 0, sizeof(info->status));
info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU; info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_len = ba_notif->txed_2_done; info->status.ampdu_ack_len = ba_notif->txed_2_done;
info->status.ampdu_len = ba_notif->txed; info->status.ampdu_len = ba_notif->txed;

View file

@ -621,7 +621,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
id = *pos++; id = *pos++;
elen = *pos++; elen = *pos++;
left -= 2; left -= 2;
if (elen > left || elen == 0) { if (elen > left) {
lbs_deb_scan("scan response: invalid IE fmt\n"); lbs_deb_scan("scan response: invalid IE fmt\n");
goto done; goto done;
} }

View file

@ -1213,6 +1213,12 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
rd_index = card->rxbd_rdptr & reg->rx_mask; rd_index = card->rxbd_rdptr & reg->rx_mask;
skb_data = card->rx_buf_list[rd_index]; skb_data = card->rx_buf_list[rd_index];
/* If skb allocation was failed earlier for Rx packet,
* rx_buf_list[rd_index] would have been left with a NULL.
*/
if (!skb_data)
return -ENOMEM;
mwifiex_unmap_pci_memory(adapter, skb_data, PCI_DMA_FROMDEVICE); mwifiex_unmap_pci_memory(adapter, skb_data, PCI_DMA_FROMDEVICE);
card->rx_buf_list[rd_index] = NULL; card->rx_buf_list[rd_index] = NULL;
@ -1525,6 +1531,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
if (adapter->ps_state == PS_STATE_SLEEP_CFM) { if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
mwifiex_process_sleep_confirm_resp(adapter, skb->data, mwifiex_process_sleep_confirm_resp(adapter, skb->data,
skb->len); skb->len);
mwifiex_pcie_enable_host_int(adapter);
if (mwifiex_write_reg(adapter,
PCIE_CPU_INT_EVENT,
CPU_INTR_SLEEP_CFM_DONE)) {
dev_warn(adapter->dev,
"Write register failed\n");
return -1;
}
while (reg->sleep_cookie && (count++ < 10) && while (reg->sleep_cookie && (count++ < 10) &&
mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pcie_ok_to_access_hw(adapter))
usleep_range(50, 60); usleep_range(50, 60);
@ -1971,23 +1985,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
adapter->int_status |= pcie_ireg; adapter->int_status |= pcie_ireg;
spin_unlock_irqrestore(&adapter->int_lock, flags); spin_unlock_irqrestore(&adapter->int_lock, flags);
if (pcie_ireg & HOST_INTR_CMD_DONE) { if (!adapter->pps_uapsd_mode &&
if ((adapter->ps_state == PS_STATE_SLEEP_CFM) || adapter->ps_state == PS_STATE_SLEEP &&
(adapter->ps_state == PS_STATE_SLEEP)) { mwifiex_pcie_ok_to_access_hw(adapter)) {
mwifiex_pcie_enable_host_int(adapter);
if (mwifiex_write_reg(adapter,
PCIE_CPU_INT_EVENT,
CPU_INTR_SLEEP_CFM_DONE)
) {
dev_warn(adapter->dev,
"Write register failed\n");
return;
}
}
} else if (!adapter->pps_uapsd_mode &&
adapter->ps_state == PS_STATE_SLEEP &&
mwifiex_pcie_ok_to_access_hw(adapter)) {
/* Potentially for PCIe we could get other /* Potentially for PCIe we could get other
* interrupts like shared. Don't change power * interrupts like shared. Don't change power
* state until cookie is set */ * state until cookie is set */

View file

@ -22,8 +22,6 @@
#define USB_VERSION "1.0" #define USB_VERSION "1.0"
static const char usbdriver_name[] = "usb8xxx";
static struct mwifiex_if_ops usb_ops; static struct mwifiex_if_ops usb_ops;
static struct semaphore add_remove_card_sem; static struct semaphore add_remove_card_sem;
static struct usb_card_rec *usb_card; static struct usb_card_rec *usb_card;
@ -527,13 +525,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
MWIFIEX_BSS_ROLE_ANY), MWIFIEX_BSS_ROLE_ANY),
MWIFIEX_ASYNC_CMD); MWIFIEX_ASYNC_CMD);
#ifdef CONFIG_PM
/* Resume handler may be called due to remote wakeup,
* force to exit suspend anyway
*/
usb_disable_autosuspend(card->udev);
#endif /* CONFIG_PM */
return 0; return 0;
} }
@ -567,13 +558,12 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
} }
static struct usb_driver mwifiex_usb_driver = { static struct usb_driver mwifiex_usb_driver = {
.name = usbdriver_name, .name = "mwifiex_usb",
.probe = mwifiex_usb_probe, .probe = mwifiex_usb_probe,
.disconnect = mwifiex_usb_disconnect, .disconnect = mwifiex_usb_disconnect,
.id_table = mwifiex_usb_table, .id_table = mwifiex_usb_table,
.suspend = mwifiex_usb_suspend, .suspend = mwifiex_usb_suspend,
.resume = mwifiex_usb_resume, .resume = mwifiex_usb_resume,
.supports_autosuspend = 1,
}; };
static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)

View file

@ -554,7 +554,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
mwifiex_wmm_delete_all_ralist(priv); mwifiex_wmm_delete_all_ralist(priv);
memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
if (priv->adapter->if_ops.clean_pcie_ring) if (priv->adapter->if_ops.clean_pcie_ring &&
!priv->adapter->surprise_removed)
priv->adapter->if_ops.clean_pcie_ring(priv->adapter); priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);

View file

@ -15,6 +15,8 @@
#ifndef RTL8187_H #ifndef RTL8187_H
#define RTL8187_H #define RTL8187_H
#include <linux/cache.h>
#include "rtl818x.h" #include "rtl818x.h"
#include "leds.h" #include "leds.h"
@ -139,7 +141,10 @@ struct rtl8187_priv {
u8 aifsn[4]; u8 aifsn[4];
u8 rfkill_mask; u8 rfkill_mask;
struct { struct {
__le64 buf; union {
__le64 buf;
u8 dummy1[L1_CACHE_BYTES];
} ____cacheline_aligned;
struct sk_buff_head queue; struct sk_buff_head queue;
} b_tx_status; /* This queue is used by both -b and non-b devices */ } b_tx_status; /* This queue is used by both -b and non-b devices */
struct mutex io_mutex; struct mutex io_mutex;
@ -147,7 +152,8 @@ struct rtl8187_priv {
u8 bits8; u8 bits8;
__le16 bits16; __le16 bits16;
__le32 bits32; __le32 bits32;
} *io_dmabuf; u8 dummy2[L1_CACHE_BYTES];
} *io_dmabuf ____cacheline_aligned;
bool rfkill_off; bool rfkill_off;
u16 seqno; u16 seqno;
}; };

View file

@ -48,7 +48,7 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
/*<2> Enable Adapter */ /*<2> Enable Adapter */
if (rtlpriv->cfg->ops->hw_init(hw)) if (rtlpriv->cfg->ops->hw_init(hw))
return 1; return false;
RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
/*<3> Enable Interrupt */ /*<3> Enable Interrupt */

View file

@ -937,14 +937,26 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
bool is92c; bool is92c;
int err; int err;
u8 tmp_u1b; u8 tmp_u1b;
unsigned long flags;
rtlpci->being_init_adapter = true; rtlpci->being_init_adapter = true;
/* Since this function can take a very long time (up to 350 ms)
* and can be called with irqs disabled, reenable the irqs
* to let the other devices continue being serviced.
*
* It is safe doing so since our own interrupts will only be enabled
* in a subsequent step.
*/
local_save_flags(flags);
local_irq_enable();
rtlpriv->intf_ops->disable_aspm(hw); rtlpriv->intf_ops->disable_aspm(hw);
rtstatus = _rtl92ce_init_mac(hw); rtstatus = _rtl92ce_init_mac(hw);
if (!rtstatus) { if (!rtstatus) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
err = 1; err = 1;
return err; goto exit;
} }
err = rtl92c_download_fw(hw); err = rtl92c_download_fw(hw);
@ -952,7 +964,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n"); "Failed to download FW. Init HW without FW now..\n");
err = 1; err = 1;
return err; goto exit;
} }
rtlhal->last_hmeboxnum = 0; rtlhal->last_hmeboxnum = 0;
@ -1032,6 +1044,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
} }
rtl92c_dm_init(hw); rtl92c_dm_init(hw);
exit:
local_irq_restore(flags);
rtlpci->being_init_adapter = false; rtlpci->being_init_adapter = false;
return err; return err;
} }

View file

@ -1700,14 +1700,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
void ieee80211_add_pending_skb(struct ieee80211_local *local, void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct sk_buff *skb); struct sk_buff *skb);
void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, void ieee80211_add_pending_skbs(struct ieee80211_local *local,
struct sk_buff_head *skbs, struct sk_buff_head *skbs);
void (*fn)(void *data), void *data);
static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
struct sk_buff_head *skbs)
{
ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
}
void ieee80211_flush_queues(struct ieee80211_local *local, void ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata); struct ieee80211_sub_if_data *sdata);

View file

@ -222,6 +222,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
switch (vht_oper->chan_width) { switch (vht_oper->chan_width) {
case IEEE80211_VHT_CHANWIDTH_USE_HT: case IEEE80211_VHT_CHANWIDTH_USE_HT:
vht_chandef.width = chandef->width; vht_chandef.width = chandef->width;
vht_chandef.center_freq1 = chandef->center_freq1;
break; break;
case IEEE80211_VHT_CHANWIDTH_80MHZ: case IEEE80211_VHT_CHANWIDTH_80MHZ:
vht_chandef.width = NL80211_CHAN_WIDTH_80; vht_chandef.width = NL80211_CHAN_WIDTH_80;
@ -271,6 +272,28 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
ret = 0; ret = 0;
out: out:
/*
* When tracking the current AP, don't do any further checks if the
* new chandef is identical to the one we're currently using for the
* connection. This keeps us from playing ping-pong with regulatory,
* without it the following can happen (for example):
* - connect to an AP with 80 MHz, world regdom allows 80 MHz
* - AP advertises regdom US
* - CRDA loads regdom US with 80 MHz prohibited (old database)
* - the code below detects an unsupported channel, downgrades, and
* we disconnect from the AP in the caller
* - disconnect causes CRDA to reload world regdomain and the game
* starts anew.
* (see https://bugzilla.kernel.org/show_bug.cgi?id=70881)
*
* It seems possible that there are still scenarios with CSA or real
* bandwidth changes where a this could happen, but those cases are
* less common and wouldn't completely prevent using the AP.
*/
if (tracking &&
cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef))
return ret;
/* don't print the message below for VHT mismatch if VHT is disabled */ /* don't print the message below for VHT mismatch if VHT is disabled */
if (ret & IEEE80211_STA_DISABLE_VHT) if (ret & IEEE80211_STA_DISABLE_VHT)
vht_chandef = *chandef; vht_chandef = *chandef;
@ -3848,6 +3871,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) { if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock(); rcu_read_unlock();
sta_info_free(local, new_sta);
return -EINVAL; return -EINVAL;
} }
rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);

View file

@ -1092,6 +1092,13 @@ static void sta_ps_end(struct sta_info *sta)
sta->sta.addr, sta->sta.aid); sta->sta.addr, sta->sta.aid);
if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
/*
* Clear the flag only if the other one is still set
* so that the TX path won't start TX'ing new frames
* directly ... In the case that the driver flag isn't
* set ieee80211_sta_ps_deliver_wakeup() will clear it.
*/
clear_sta_flag(sta, WLAN_STA_PS_STA);
ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
sta->sta.addr, sta->sta.aid); sta->sta.addr, sta->sta.aid);
return; return;

View file

@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
return -ENOENT; return -ENOENT;
} }
static void cleanup_single_sta(struct sta_info *sta) static void __cleanup_single_sta(struct sta_info *sta)
{ {
int ac, i; int ac, i;
struct tid_ampdu_tx *tid_tx; struct tid_ampdu_tx *tid_tx;
@ -99,7 +99,8 @@ static void cleanup_single_sta(struct sta_info *sta)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ps_data *ps; struct ps_data *ps;
if (test_sta_flag(sta, WLAN_STA_PS_STA)) { if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP || if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps; ps = &sdata->bss->ps;
@ -109,6 +110,7 @@ static void cleanup_single_sta(struct sta_info *sta)
return; return;
clear_sta_flag(sta, WLAN_STA_PS_STA); clear_sta_flag(sta, WLAN_STA_PS_STA);
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
atomic_dec(&ps->num_sta_ps); atomic_dec(&ps->num_sta_ps);
sta_info_recalc_tim(sta); sta_info_recalc_tim(sta);
@ -139,7 +141,14 @@ static void cleanup_single_sta(struct sta_info *sta)
ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
kfree(tid_tx); kfree(tid_tx);
} }
}
static void cleanup_single_sta(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
__cleanup_single_sta(sta);
sta_info_free(local, sta); sta_info_free(local, sta);
} }
@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock(); rcu_read_unlock();
spin_lock_init(&sta->lock); spin_lock_init(&sta->lock);
spin_lock_init(&sta->ps_lock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock); INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx); mutex_init(&sta->ampdu_mlme.mtx);
@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
goto out_err; goto out_err;
} }
/* notify driver */
err = sta_info_insert_drv_state(local, sdata, sta);
if (err)
goto out_err;
local->num_sta++; local->num_sta++;
local->sta_generation++; local->sta_generation++;
smp_mb(); smp_mb();
/* simplify things and don't accept BA sessions yet */
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
/* make the station visible */ /* make the station visible */
sta_info_hash_add(local, sta); sta_info_hash_add(local, sta);
list_add_rcu(&sta->list, &local->sta_list); list_add_rcu(&sta->list, &local->sta_list);
/* notify driver */
err = sta_info_insert_drv_state(local, sdata, sta);
if (err)
goto out_remove;
set_sta_flag(sta, WLAN_STA_INSERTED); set_sta_flag(sta, WLAN_STA_INSERTED);
/* accept BA sessions now */
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_recalc_min_chandef(sdata); ieee80211_recalc_min_chandef(sdata);
ieee80211_sta_debugfs_add(sta); ieee80211_sta_debugfs_add(sta);
@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
mesh_accept_plinks_update(sdata); mesh_accept_plinks_update(sdata);
return 0; return 0;
out_remove:
sta_info_hash_del(local, sta);
list_del_rcu(&sta->list);
local->num_sta--;
synchronize_net();
__cleanup_single_sta(sta);
out_err: out_err:
mutex_unlock(&local->sta_mtx); mutex_unlock(&local->sta_mtx);
rcu_read_lock(); rcu_read_lock();
@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
} }
EXPORT_SYMBOL(ieee80211_find_sta); EXPORT_SYMBOL(ieee80211_find_sta);
static void clear_sta_ps_flags(void *_sta) /* powersave support code */
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{ {
struct sta_info *sta = _sta;
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff_head pending;
int filtered = 0, buffered = 0, ac;
unsigned long flags;
struct ps_data *ps; struct ps_data *ps;
if (sdata->vif.type == NL80211_IFTYPE_AP || if (sdata->vif.type == NL80211_IFTYPE_AP ||
@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta)
else else
return; return;
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
atomic_dec(&ps->num_sta_ps);
}
/* powersave support code */
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff_head pending;
int filtered = 0, buffered = 0, ac;
unsigned long flags;
clear_sta_flag(sta, WLAN_STA_SP); clear_sta_flag(sta, WLAN_STA_SP);
BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
skb_queue_head_init(&pending); skb_queue_head_init(&pending);
/* sync with ieee80211_tx_h_unicast_ps_buf */
spin_lock(&sta->ps_lock);
/* Send all buffered frames to the station */ /* Send all buffered frames to the station */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
int count = skb_queue_len(&pending), tmp; int count = skb_queue_len(&pending), tmp;
@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
buffered += tmp - count; buffered += tmp - count;
} }
ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); ieee80211_add_pending_skbs(local, &pending);
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
clear_sta_flag(sta, WLAN_STA_PS_STA);
spin_unlock(&sta->ps_lock);
atomic_dec(&ps->num_sta_ps);
/* This station just woke up and isn't aware of our SMPS state */ /* This station just woke up and isn't aware of our SMPS state */
if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,

View file

@ -268,6 +268,7 @@ struct ieee80211_tx_latency_stat {
* @drv_unblock_wk: used for driver PS unblocking * @drv_unblock_wk: used for driver PS unblocking
* @listen_interval: listen interval of this station, when we're acting as AP * @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 * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
* @ps_lock: used for powersave (when mac80211 is the AP) related locking
* @ps_tx_buf: buffers (per AC) of frames to transmit to this station * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
* when it leaves power saving state or polls * when it leaves power saving state or polls
* @tx_filtered: buffers (per AC) of frames we already tried to * @tx_filtered: buffers (per AC) of frames we already tried to
@ -357,10 +358,8 @@ struct sta_info {
/* use the accessors defined below */ /* use the accessors defined below */
unsigned long _flags; unsigned long _flags;
/* /* STA powersave lock and frame queues */
* STA powersave frame queues, no more than the internal spinlock_t ps_lock;
* locking required.
*/
struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
unsigned long driver_buffered_tids; unsigned long driver_buffered_tids;

View file

@ -477,6 +477,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta->sta.addr, sta->sta.aid, ac); sta->sta.addr, sta->sta.aid, ac);
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local); purge_old_ps_buffers(tx->local);
/* sync with ieee80211_sta_ps_deliver_wakeup */
spin_lock(&sta->ps_lock);
/*
* STA woke up the meantime and all the frames on ps_tx_buf have
* been queued to pending queue. No reordering can happen, go
* ahead and Tx the packet.
*/
if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
spin_unlock(&sta->ps_lock);
return TX_CONTINUE;
}
if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
ps_dbg(tx->sdata, ps_dbg(tx->sdata,
@ -491,6 +505,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
spin_unlock(&sta->ps_lock);
if (!timer_pending(&local->sta_cleanup)) if (!timer_pending(&local->sta_cleanup))
mod_timer(&local->sta_cleanup, mod_timer(&local->sta_cleanup,

View file

@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
} }
void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, void ieee80211_add_pending_skbs(struct ieee80211_local *local,
struct sk_buff_head *skbs, struct sk_buff_head *skbs)
void (*fn)(void *data), void *data)
{ {
struct ieee80211_hw *hw = &local->hw; struct ieee80211_hw *hw = &local->hw;
struct sk_buff *skb; struct sk_buff *skb;
@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
__skb_queue_tail(&local->pending[queue], skb); __skb_queue_tail(&local->pending[queue], skb);
} }
if (fn)
fn(data);
for (i = 0; i < hw->queues; i++) for (i = 0; i < hw->queues; i++)
__ieee80211_wake_queue(hw, i, __ieee80211_wake_queue(hw, i,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD); IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
@ -1766,6 +1762,26 @@ int ieee80211_reconfig(struct ieee80211_local *local)
ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_SUSPEND); IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/*
* Reconfigure sched scan if it was interrupted by FW restart or
* suspend.
*/
mutex_lock(&local->mtx);
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
lockdep_is_held(&local->mtx));
if (sched_scan_sdata && local->sched_scan_req)
/*
* Sched scan stopped, but we don't want to report it. Instead,
* we're trying to reschedule.
*/
if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
local->sched_scan_req))
sched_scan_stopped = true;
mutex_unlock(&local->mtx);
if (sched_scan_stopped)
cfg80211_sched_scan_stopped(local->hw.wiphy);
/* /*
* If this is for hw restart things are still running. * If this is for hw restart things are still running.
* We may want to change that later, however. * We may want to change that later, however.
@ -1794,26 +1810,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
WARN_ON(1); WARN_ON(1);
#endif #endif
/*
* Reconfigure sched scan if it was interrupted by FW restart or
* suspend.
*/
mutex_lock(&local->mtx);
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
lockdep_is_held(&local->mtx));
if (sched_scan_sdata && local->sched_scan_req)
/*
* Sched scan stopped, but we don't want to report it. Instead,
* we're trying to reschedule.
*/
if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
local->sched_scan_req))
sched_scan_stopped = true;
mutex_unlock(&local->mtx);
if (sched_scan_stopped)
cfg80211_sched_scan_stopped(local->hw.wiphy);
return 0; return 0;
} }

View file

@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
return IEEE80211_AC_BE; return IEEE80211_AC_BE;
} }
if (skb->protocol == sdata->control_port_protocol) {
skb->priority = 7;
return ieee80211_downgrade_queue(sdata, skb);
}
/* use the data classifier to determine what 802.1d tag the /* use the data classifier to determine what 802.1d tag the
* data frame has */ * data frame has */
rcu_read_lock(); rcu_read_lock();

View file

@ -301,7 +301,7 @@ static int nci_open_device(struct nci_dev *ndev)
rc = __nci_request(ndev, nci_reset_req, 0, rc = __nci_request(ndev, nci_reset_req, 0,
msecs_to_jiffies(NCI_RESET_TIMEOUT)); msecs_to_jiffies(NCI_RESET_TIMEOUT));
if (ndev->ops->setup(ndev)) if (ndev->ops->setup)
ndev->ops->setup(ndev); ndev->ops->setup(ndev);
if (!rc) { if (!rc) {

View file

@ -1798,7 +1798,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
return; return;
case NL80211_REGDOM_SET_BY_USER: case NL80211_REGDOM_SET_BY_USER:
treatment = reg_process_hint_user(reg_request); treatment = reg_process_hint_user(reg_request);
if (treatment == REG_REQ_OK || if (treatment == REG_REQ_IGNORE ||
treatment == REG_REQ_ALREADY_SET) treatment == REG_REQ_ALREADY_SET)
return; return;
queue_delayed_work(system_power_efficient_wq, queue_delayed_work(system_power_efficient_wq,
@ -2492,6 +2492,7 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
int set_regdom(const struct ieee80211_regdomain *rd) int set_regdom(const struct ieee80211_regdomain *rd)
{ {
struct regulatory_request *lr; struct regulatory_request *lr;
bool user_reset = false;
int r; int r;
if (!reg_is_valid_request(rd->alpha2)) { if (!reg_is_valid_request(rd->alpha2)) {
@ -2508,6 +2509,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
break; break;
case NL80211_REGDOM_SET_BY_USER: case NL80211_REGDOM_SET_BY_USER:
r = reg_set_rd_user(rd, lr); r = reg_set_rd_user(rd, lr);
user_reset = true;
break; break;
case NL80211_REGDOM_SET_BY_DRIVER: case NL80211_REGDOM_SET_BY_DRIVER:
r = reg_set_rd_driver(rd, lr); r = reg_set_rd_driver(rd, lr);
@ -2521,8 +2523,14 @@ int set_regdom(const struct ieee80211_regdomain *rd)
} }
if (r) { if (r) {
if (r == -EALREADY) switch (r) {
case -EALREADY:
reg_set_request_processed(); reg_set_request_processed();
break;
default:
/* Back to world regulatory in case of errors */
restore_regulatory_settings(user_reset);
}
kfree(rd); kfree(rd);
return r; return r;