You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem
This commit is contained in:
@@ -84,6 +84,8 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = {
|
||||
{ BCMA_CORE_I2S, "I2S" },
|
||||
{ BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
|
||||
{ BCMA_CORE_SHIM, "SHIM" },
|
||||
{ BCMA_CORE_PCIE2, "PCIe Gen2" },
|
||||
{ BCMA_CORE_ARM_CR4, "ARM CR4" },
|
||||
{ BCMA_CORE_DEFAULT, "Default" },
|
||||
};
|
||||
|
||||
|
||||
@@ -965,7 +965,7 @@ static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah))
|
||||
if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah))
|
||||
return;
|
||||
|
||||
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
||||
|
||||
@@ -1020,7 +1020,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
|
||||
{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
|
||||
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
||||
@@ -254,6 +254,7 @@ struct ath_atx_tid {
|
||||
int sched;
|
||||
int paused;
|
||||
u8 state;
|
||||
bool stop_cb;
|
||||
};
|
||||
|
||||
struct ath_node {
|
||||
@@ -351,7 +352,8 @@ void ath_tx_tasklet(struct ath_softc *sc);
|
||||
void ath_tx_edma_tasklet(struct ath_softc *sc);
|
||||
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn);
|
||||
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid,
|
||||
bool flush);
|
||||
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
|
||||
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
|
||||
|
||||
@@ -2008,6 +2008,14 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
|
||||
WARN_ON(i != ATH9K_SSTATS_LEN);
|
||||
}
|
||||
|
||||
void ath9k_deinit_debug(struct ath_softc *sc)
|
||||
{
|
||||
if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
|
||||
relay_close(sc->rfs_chan_spec_scan);
|
||||
sc->rfs_chan_spec_scan = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ath9k_init_debug(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
@@ -304,6 +304,7 @@ struct ath9k_debug {
|
||||
};
|
||||
|
||||
int ath9k_init_debug(struct ath_hw *ah);
|
||||
void ath9k_deinit_debug(struct ath_softc *sc);
|
||||
|
||||
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
|
||||
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
|
||||
@@ -339,6 +340,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath9k_deinit_debug(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
|
||||
enum ath9k_int status)
|
||||
{
|
||||
|
||||
@@ -906,7 +906,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
|
||||
if (!ath_is_world_regd(reg)) {
|
||||
error = regulatory_hint(hw->wiphy, reg->alpha2);
|
||||
if (error)
|
||||
goto unregister;
|
||||
goto debug_cleanup;
|
||||
}
|
||||
|
||||
ath_init_leds(sc);
|
||||
@@ -914,6 +914,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
|
||||
|
||||
return 0;
|
||||
|
||||
debug_cleanup:
|
||||
ath9k_deinit_debug(sc);
|
||||
unregister:
|
||||
ieee80211_unregister_hw(hw);
|
||||
rx_cleanup:
|
||||
@@ -942,11 +944,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
|
||||
sc->dfs_detector->exit(sc->dfs_detector);
|
||||
|
||||
ath9k_eeprom_release(sc);
|
||||
|
||||
if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
|
||||
relay_close(sc->rfs_chan_spec_scan);
|
||||
sc->rfs_chan_spec_scan = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_deinit_device(struct ath_softc *sc)
|
||||
@@ -960,6 +957,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
ath9k_deinit_debug(sc);
|
||||
ieee80211_unregister_hw(hw);
|
||||
ath_rx_cleanup(sc);
|
||||
ath9k_deinit_softc(sc);
|
||||
|
||||
@@ -1687,6 +1687,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||
u16 tid, u16 *ssn, u8 buf_size)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
bool flush = false;
|
||||
int ret = 0;
|
||||
|
||||
local_bh_disable();
|
||||
@@ -1703,12 +1704,13 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
ath9k_ps_restore(sc);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_CONT:
|
||||
case IEEE80211_AMPDU_TX_STOP_FLUSH:
|
||||
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
|
||||
flush = true;
|
||||
case IEEE80211_AMPDU_TX_STOP_CONT:
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath_tx_aggr_stop(sc, sta, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
if (ath_tx_aggr_stop(sc, sta, tid, flush))
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
ath9k_ps_restore(sc);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
|
||||
@@ -164,7 +164,20 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||
ARRAY_SIZE(bf->rates));
|
||||
}
|
||||
|
||||
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
static void ath_tx_clear_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
{
|
||||
tid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
tid->state &= ~AGGR_CLEANUP;
|
||||
if (!tid->stop_cb)
|
||||
return;
|
||||
|
||||
ieee80211_start_tx_ba_cb_irqsafe(tid->an->vif, tid->an->sta->addr,
|
||||
tid->tidno);
|
||||
tid->stop_cb = false;
|
||||
}
|
||||
|
||||
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid,
|
||||
bool flush_packets)
|
||||
{
|
||||
struct ath_txq *txq = tid->ac->txq;
|
||||
struct sk_buff *skb;
|
||||
@@ -181,16 +194,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
while ((skb = __skb_dequeue(&tid->buf_q))) {
|
||||
fi = get_frame_info(skb);
|
||||
bf = fi->bf;
|
||||
if (!bf && !flush_packets)
|
||||
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
|
||||
|
||||
if (!bf) {
|
||||
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
|
||||
if (!bf) {
|
||||
ieee80211_free_txskb(sc->hw, skb);
|
||||
continue;
|
||||
}
|
||||
ieee80211_free_txskb(sc->hw, skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fi->retries) {
|
||||
if (fi->retries || flush_packets) {
|
||||
list_add_tail(&bf->list, &bf_head);
|
||||
ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
|
||||
@@ -201,12 +213,10 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
}
|
||||
}
|
||||
|
||||
if (tid->baw_head == tid->baw_tail) {
|
||||
tid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
tid->state &= ~AGGR_CLEANUP;
|
||||
}
|
||||
if (tid->baw_head == tid->baw_tail)
|
||||
ath_tx_clear_tid(sc, tid);
|
||||
|
||||
if (sendbar) {
|
||||
if (sendbar && !flush_packets) {
|
||||
ath_txq_unlock(sc, txq);
|
||||
ath_send_bar(tid, tid->seq_start);
|
||||
ath_txq_lock(sc, txq);
|
||||
@@ -277,9 +287,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
|
||||
|
||||
list_add_tail(&bf->list, &bf_head);
|
||||
|
||||
if (fi->retries)
|
||||
ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
|
||||
|
||||
ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
|
||||
}
|
||||
|
||||
@@ -602,7 +610,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
}
|
||||
|
||||
if (tid->state & AGGR_CLEANUP)
|
||||
ath_tx_flush_tid(sc, tid);
|
||||
ath_tx_flush_tid(sc, tid, false);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -620,6 +628,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ath_tx_status *ts, struct ath_buf *bf,
|
||||
struct list_head *bf_head)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
bool txok, flush;
|
||||
|
||||
txok = !(ts->ts_status & ATH9K_TXERR_MASK);
|
||||
@@ -631,8 +640,12 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
|
||||
txq->axq_ampdu_depth--;
|
||||
|
||||
if (!bf_isampdu(bf)) {
|
||||
if (!flush)
|
||||
if (!flush) {
|
||||
info = IEEE80211_SKB_CB(bf->bf_mpdu);
|
||||
memcpy(info->control.rates, bf->rates,
|
||||
sizeof(info->control.rates));
|
||||
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
|
||||
}
|
||||
ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
|
||||
} else
|
||||
ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
|
||||
@@ -676,7 +689,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
||||
|
||||
skb = bf->bf_mpdu;
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
rates = tx_info->control.rates;
|
||||
rates = bf->rates;
|
||||
|
||||
/*
|
||||
* Find the lowest frame length among the rate series that will have a
|
||||
@@ -1256,18 +1269,23 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
||||
bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid,
|
||||
bool flush)
|
||||
{
|
||||
struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
||||
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
|
||||
struct ath_txq *txq = txtid->ac->txq;
|
||||
bool ret = !flush;
|
||||
|
||||
if (flush)
|
||||
txtid->stop_cb = false;
|
||||
|
||||
if (txtid->state & AGGR_CLEANUP)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
|
||||
txtid->state &= ~AGGR_ADDBA_PROGRESS;
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
@@ -1279,13 +1297,17 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
||||
* TID can only be reused after all in-progress subframes have been
|
||||
* completed.
|
||||
*/
|
||||
if (txtid->baw_head != txtid->baw_tail)
|
||||
if (txtid->baw_head != txtid->baw_tail) {
|
||||
txtid->state |= AGGR_CLEANUP;
|
||||
else
|
||||
ret = false;
|
||||
txtid->stop_cb = !flush;
|
||||
} else {
|
||||
txtid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
}
|
||||
|
||||
ath_tx_flush_tid(sc, txtid);
|
||||
ath_tx_flush_tid(sc, txtid, flush);
|
||||
ath_txq_unlock_complete(sc, txq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
|
||||
@@ -2415,6 +2437,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
|
||||
tid->ac = &an->ac[acno];
|
||||
tid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
tid->state &= ~AGGR_ADDBA_PROGRESS;
|
||||
tid->stop_cb = false;
|
||||
}
|
||||
|
||||
for (acno = 0, ac = &an->ac[acno];
|
||||
@@ -2451,8 +2474,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
|
||||
}
|
||||
|
||||
ath_tid_drain(sc, txq, tid);
|
||||
tid->state &= ~AGGR_ADDBA_COMPLETE;
|
||||
tid->state &= ~AGGR_CLEANUP;
|
||||
ath_tx_clear_tid(sc, tid);
|
||||
|
||||
ath_txq_unlock(sc, txq);
|
||||
}
|
||||
|
||||
@@ -4140,6 +4140,10 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
|
||||
.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO)
|
||||
},
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
|
||||
}
|
||||
};
|
||||
static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
|
||||
{
|
||||
@@ -4197,7 +4201,8 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_P2P_DEVICE);
|
||||
wiphy->iface_combinations = brcmf_iface_combos;
|
||||
wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
|
||||
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
|
||||
|
||||
@@ -1423,7 +1423,7 @@ il_setup_rx_scan_handlers(struct il_priv *il)
|
||||
}
|
||||
EXPORT_SYMBOL(il_setup_rx_scan_handlers);
|
||||
|
||||
inline u16
|
||||
u16
|
||||
il_get_active_dwell_time(struct il_priv *il, enum ieee80211_band band,
|
||||
u8 n_probes)
|
||||
{
|
||||
|
||||
@@ -173,6 +173,8 @@ enum {
|
||||
REPLY_DEBUG_CMD = 0xf0,
|
||||
DEBUG_LOG_MSG = 0xf7,
|
||||
|
||||
MCAST_FILTER_CMD = 0xd0,
|
||||
|
||||
/* D3 commands/notifications */
|
||||
D3_CONFIG_CMD = 0xd3,
|
||||
PROT_OFFLOAD_CONFIG_CMD = 0xd4,
|
||||
@@ -948,4 +950,29 @@ struct iwl_set_calib_default_cmd {
|
||||
u8 data[0];
|
||||
} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
|
||||
|
||||
#define MAX_PORT_ID_NUM 2
|
||||
|
||||
/**
|
||||
* struct iwl_mcast_filter_cmd - configure multicast filter.
|
||||
* @filter_own: Set 1 to filter out multicast packets sent by station itself
|
||||
* @port_id: Multicast MAC addresses array specifier. This is a strange way
|
||||
* to identify network interface adopted in host-device IF.
|
||||
* It is used by FW as index in array of addresses. This array has
|
||||
* MAX_PORT_ID_NUM members.
|
||||
* @count: Number of MAC addresses in the array
|
||||
* @pass_all: Set 1 to pass all multicast packets.
|
||||
* @bssid: current association BSSID.
|
||||
* @addr_list: Place holder for array of MAC addresses.
|
||||
* IMPORTANT: add padding if necessary to ensure DWORD alignment.
|
||||
*/
|
||||
struct iwl_mcast_filter_cmd {
|
||||
u8 filter_own;
|
||||
u8 port_id;
|
||||
u8 count;
|
||||
u8 pass_all;
|
||||
u8 bssid[6];
|
||||
u8 reserved[2];
|
||||
u8 addr_list[0];
|
||||
} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
|
||||
|
||||
#endif /* __fw_api_h__ */
|
||||
|
||||
@@ -586,10 +586,12 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
|
||||
*/
|
||||
static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_mac_data_sta *ctxt_sta)
|
||||
struct iwl_mac_data_sta *ctxt_sta,
|
||||
bool force_assoc_off)
|
||||
{
|
||||
/* We need the dtim_period to set the MAC as associated */
|
||||
if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) {
|
||||
if (vif->bss_conf.assoc && vif->bss_conf.dtim_period &&
|
||||
!force_assoc_off) {
|
||||
u32 dtim_offs;
|
||||
|
||||
/*
|
||||
@@ -659,7 +661,8 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
|
||||
cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON);
|
||||
|
||||
/* Fill the data specific for station mode */
|
||||
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta);
|
||||
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta,
|
||||
action == FW_CTXT_ACTION_ADD);
|
||||
|
||||
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
|
||||
}
|
||||
@@ -677,7 +680,8 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm,
|
||||
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
|
||||
|
||||
/* Fill the data specific for station mode */
|
||||
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta);
|
||||
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta,
|
||||
action == FW_CTXT_ACTION_ADD);
|
||||
|
||||
cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow &
|
||||
IEEE80211_P2P_OPPPS_CTWINDOW_MASK);
|
||||
|
||||
@@ -701,6 +701,20 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
|
||||
*total_flags = 0;
|
||||
}
|
||||
|
||||
static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mcast_filter_cmd mcast_filter_cmd = {
|
||||
.pass_all = 1,
|
||||
};
|
||||
|
||||
memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC,
|
||||
sizeof(mcast_filter_cmd),
|
||||
&mcast_filter_cmd);
|
||||
}
|
||||
|
||||
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
@@ -722,6 +736,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
return;
|
||||
}
|
||||
iwl_mvm_bt_coex_vif_assoc(mvm, vif);
|
||||
iwl_mvm_configure_mcast_filter(mvm, vif);
|
||||
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
|
||||
/* remove AP station now that the MAC is unassoc */
|
||||
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
|
||||
@@ -931,7 +946,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
|
||||
switch (cmd) {
|
||||
case STA_NOTIFY_SLEEP:
|
||||
if (atomic_read(&mvmsta->pending_frames) > 0)
|
||||
if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
|
||||
ieee80211_sta_block_awake(hw, sta, true);
|
||||
/*
|
||||
* The fw updates the STA to be asleep. Tx packets on the Tx
|
||||
|
||||
@@ -292,6 +292,7 @@ struct iwl_mvm {
|
||||
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
|
||||
struct work_struct sta_drained_wk;
|
||||
unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
|
||||
atomic_t pending_frames[IWL_MVM_STATION_COUNT];
|
||||
|
||||
/* configured by mac80211 */
|
||||
u32 rts_threshold;
|
||||
|
||||
@@ -292,6 +292,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
|
||||
CMD(BT_COEX_PROT_ENV),
|
||||
CMD(BT_PROFILE_NOTIFICATION),
|
||||
CMD(BT_CONFIG),
|
||||
CMD(MCAST_FILTER_CMD),
|
||||
};
|
||||
#undef CMD
|
||||
|
||||
|
||||
@@ -298,6 +298,12 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
||||
else
|
||||
cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
|
||||
|
||||
/*
|
||||
* TODO: This is a WA due to a bug in the FW AUX framework that does not
|
||||
* properly handle time events that fail to be scheduled
|
||||
*/
|
||||
cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
|
||||
|
||||
cmd->repeats = cpu_to_le32(1);
|
||||
|
||||
/*
|
||||
|
||||
@@ -219,7 +219,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
||||
mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
|
||||
|
||||
/* HW restart, don't assume the memory has been zeroed */
|
||||
atomic_set(&mvm_sta->pending_frames, 0);
|
||||
atomic_set(&mvm->pending_frames[sta_id], 0);
|
||||
mvm_sta->tid_disable_agg = 0;
|
||||
mvm_sta->tfd_queue_msk = 0;
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++)
|
||||
@@ -406,15 +406,22 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
|
||||
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the tx response code sees the station as -EBUSY and
|
||||
* calls the drain worker.
|
||||
*/
|
||||
spin_lock_bh(&mvm_sta->lock);
|
||||
/*
|
||||
* There are frames pending on the AC queues for this station.
|
||||
* We need to wait until all the frames are drained...
|
||||
*/
|
||||
if (atomic_read(&mvm_sta->pending_frames)) {
|
||||
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
|
||||
if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) {
|
||||
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
|
||||
ERR_PTR(-EBUSY));
|
||||
spin_unlock_bh(&mvm_sta->lock);
|
||||
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
|
||||
} else {
|
||||
spin_unlock_bh(&mvm_sta->lock);
|
||||
ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
|
||||
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
|
||||
}
|
||||
|
||||
@@ -274,7 +274,6 @@ struct iwl_mvm_tid_data {
|
||||
* @bt_reduced_txpower: is reduced tx power enabled for this station
|
||||
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx
|
||||
* and from Tx response flow, it needs a spinlock.
|
||||
* @pending_frames: number of frames for this STA on the shared Tx queues.
|
||||
* @tid_data: per tid data. Look at %iwl_mvm_tid_data.
|
||||
*
|
||||
* When mac80211 creates a station it reserves some space (hw->sta_data_size)
|
||||
@@ -290,7 +289,6 @@ struct iwl_mvm_sta {
|
||||
u8 max_agg_bufsize;
|
||||
bool bt_reduced_txpower;
|
||||
spinlock_t lock;
|
||||
atomic_t pending_frames;
|
||||
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
|
||||
struct iwl_lq_sta lq_sta;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
@@ -416,9 +416,8 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
|
||||
spin_unlock(&mvmsta->lock);
|
||||
|
||||
if (mvmsta->vif->type == NL80211_IFTYPE_AP &&
|
||||
txq_id < IWL_MVM_FIRST_AGG_QUEUE)
|
||||
atomic_inc(&mvmsta->pending_frames);
|
||||
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE)
|
||||
atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -680,16 +679,41 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
||||
/*
|
||||
* If the txq is not an AMPDU queue, there is no chance we freed
|
||||
* several skbs. Check that out...
|
||||
* If there are no pending frames for this STA, notify mac80211 that
|
||||
* this station can go to sleep in its STA table.
|
||||
*/
|
||||
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta &&
|
||||
!WARN_ON(skb_freed > 1) &&
|
||||
mvmsta->vif->type == NL80211_IFTYPE_AP &&
|
||||
atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) {
|
||||
ieee80211_sta_block_awake(mvm->hw, sta, false);
|
||||
set_bit(sta_id, mvm->sta_drained);
|
||||
schedule_work(&mvm->sta_drained_wk);
|
||||
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) &&
|
||||
atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) {
|
||||
if (mvmsta) {
|
||||
/*
|
||||
* If there are no pending frames for this STA, notify
|
||||
* mac80211 that this station can go to sleep in its
|
||||
* STA table.
|
||||
*/
|
||||
if (mvmsta->vif->type == NL80211_IFTYPE_AP)
|
||||
ieee80211_sta_block_awake(mvm->hw, sta, false);
|
||||
/*
|
||||
* We might very well have taken mvmsta pointer while
|
||||
* the station was being removed. The remove flow might
|
||||
* have seen a pending_frame (because we didn't take
|
||||
* the lock) even if now the queues are drained. So make
|
||||
* really sure now that this the station is not being
|
||||
* removed. If it is, run the drain worker to remove it.
|
||||
*/
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
if (IS_ERR_OR_NULL(sta)) {
|
||||
/*
|
||||
* Station disappeared in the meantime:
|
||||
* so we are draining.
|
||||
*/
|
||||
set_bit(sta_id, mvm->sta_drained);
|
||||
schedule_work(&mvm->sta_drained_wk);
|
||||
}
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
} else if (!mvmsta) {
|
||||
/* Tx response without STA, so we are draining */
|
||||
set_bit(sta_id, mvm->sta_drained);
|
||||
schedule_work(&mvm->sta_drained_wk);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user