From 50ac6607845755e594c8a39b9c6a00d1c9b48ea4 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 25 Jun 2013 19:03:56 -0700 Subject: cfg80211/nl80211: rename packet pattern related structures and enums Currently packet patterns and it's enum/structures are used only for WoWLAN feature. As we intend to reuse them for new feature packet coalesce, they are renamed in this patch. Older names are kept for backward compatibility purpose. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/mwifiex/cfg80211.c | 3 +-- drivers/net/wireless/ti/wlcore/main.c | 10 +++++----- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1737a3e33685..1adb803a9d86 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2094,7 +2094,7 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath9k_wow_pattern *wow_pattern = NULL; - struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns; + struct cfg80211_pkt_pattern *patterns = wowlan->patterns; int mask_len; s8 i = 0; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ef5fa890a286..0bd631fd556c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2298,8 +2298,7 @@ EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); #ifdef CONFIG_PM static bool -mwifiex_is_pattern_supported(struct cfg80211_wowlan_trig_pkt_pattern *pat, - s8 *byte_seq) +mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq) { int j, k, valid_byte_cnt = 0; bool dont_care_byte = false; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index b8db55c868c7..d1b19c38a907 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1315,7 +1315,7 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) #ifdef CONFIG_PM static int -wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p) +wl1271_validate_wowlan_pattern(struct cfg80211_pkt_pattern *p) { int num_fields = 0, in_field = 0, fields_size = 0; int i, pattern_len = 0; @@ -1458,9 +1458,9 @@ void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter, * Allocates an RX filter returned through f * which needs to be freed using rx_filter_free() */ -static int wl1271_convert_wowlan_pattern_to_rx_filter( - struct cfg80211_wowlan_trig_pkt_pattern *p, - struct wl12xx_rx_filter **f) +static int +wl1271_convert_wowlan_pattern_to_rx_filter(struct cfg80211_pkt_pattern *p, + struct wl12xx_rx_filter **f) { int i, j, ret = 0; struct wl12xx_rx_filter *filter; @@ -1562,7 +1562,7 @@ static int wl1271_configure_wowlan(struct wl1271 *wl, /* Translate WoWLAN patterns into filters */ for (i = 0; i < wow->n_patterns; i++) { - struct cfg80211_wowlan_trig_pkt_pattern *p; + struct cfg80211_pkt_pattern *p; struct wl12xx_rx_filter *filter = NULL; p = &wow->patterns[i]; -- cgit v1.2.3 From 3de805cf965d69c8d3d7d69368d5fd2c925a2d5a Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 8 Jul 2013 16:55:50 +0200 Subject: mac80211/rc80211: add chandef to rate initialization 5 and 10 MHz support needs to know the current operating channel width, add the chandef to the rate control API. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath9k/rc.c | 2 ++ drivers/net/wireless/iwlegacy/3945-rs.c | 1 + drivers/net/wireless/iwlegacy/4965-rs.c | 1 + drivers/net/wireless/iwlwifi/dvm/rs.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/rs.c | 5 +++-- drivers/net/wireless/rtlwifi/rc.c | 1 + include/net/mac80211.h | 2 ++ net/mac80211/rate.h | 22 +++++++++++++++++----- net/mac80211/rc80211_minstrel.c | 3 ++- net/mac80211/rc80211_minstrel_ht.c | 10 +++++++--- net/mac80211/rc80211_pid_algo.c | 1 + 11 files changed, 39 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 7eb1f4b458e4..a3c4ca0c94bf 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1275,6 +1275,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, } static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta) { struct ath_softc *sc = priv; @@ -1313,6 +1314,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, } static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta, u32 changed) { diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c index fe31590a51b2..aea667b430c3 100644 --- a/drivers/net/wireless/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/iwlegacy/3945-rs.c @@ -887,6 +887,7 @@ il3945_remove_debugfs(void *il, void *il_sta) */ static void il3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *il_sta) { } diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index ed3c42a63a43..3ccbaf791b48 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c @@ -2803,6 +2803,7 @@ il4965_rs_remove_debugfs(void *il, void *il_sta) */ static void il4965_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *il_sta) { } diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 1b693944123b..91eb09b9b56f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -3319,7 +3319,8 @@ static void rs_remove_debugfs(void *priv, void *priv_sta) * station is added we ignore it. */ static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta) + struct cfg80211_chan_def *chandef, + struct ieee80211_sta *sta, void *priv_sta) { } static struct rate_control_ops rs_ops = { diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index b328a988c130..376ea2112de2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -3159,8 +3159,9 @@ static void rs_remove_debugfs(void *mvm, void *mvm_sta) * station is added we ignore it. */ static void rs_rate_init_stub(void *mvm_r, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *mvm_sta) + struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, + struct ieee80211_sta *sta, void *mvm_sta) { } static struct rate_control_ops rs_mvm_ops = { diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index f9f059dadb73..a98acefb8c06 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -218,6 +218,7 @@ static void rtl_tx_status(void *ppriv, static void rtl_rate_init(void *ppriv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta) { } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7c5dc787a8e8..fe5fee830aa8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4204,8 +4204,10 @@ struct rate_control_ops { void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); void (*rate_init)(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta); void (*rate_update)(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta, u32 changed); void (*free_sta)(void *priv, struct ieee80211_sta *sta, diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index d35a5dd3fb13..5dedc56c94db 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -66,11 +66,12 @@ static inline void rate_control_rate_init(struct sta_info *sta) } sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; - rcu_read_unlock(); ieee80211_sta_set_rx_nss(sta); - ref->ops->rate_init(ref->priv, sband, ista, priv_sta); + ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, + priv_sta); + rcu_read_unlock(); set_sta_flag(sta, WLAN_STA_RATE_CONTROL); } @@ -81,10 +82,21 @@ static inline void rate_control_rate_update(struct ieee80211_local *local, struct rate_control_ref *ref = local->rate_ctrl; struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; + struct ieee80211_chanctx_conf *chanctx_conf; + + if (ref && ref->ops->rate_update) { + rcu_read_lock(); - if (ref && ref->ops->rate_update) - ref->ops->rate_update(ref->priv, sband, ista, - priv_sta, changed); + chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return; + } + + ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def, + ista, priv_sta, changed); + rcu_read_unlock(); + } drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); } diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index ac7ef5414bde..5b25966add10 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -417,7 +417,8 @@ init_sample_table(struct minstrel_sta_info *mi) static void minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta) + struct cfg80211_chan_def *chandef, + struct ieee80211_sta *sta, void *priv_sta) { struct minstrel_sta_info *mi = priv_sta; struct minstrel_priv *mp = priv; diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 5b2d3012b983..52562973fbd1 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -836,6 +836,7 @@ minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, static void minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta) { struct minstrel_priv *mp = priv; @@ -931,22 +932,25 @@ use_legacy: memset(&msp->legacy, 0, sizeof(msp->legacy)); msp->legacy.r = msp->ratelist; msp->legacy.sample_table = msp->sample_table; - return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy); + return mac80211_minstrel.rate_init(priv, sband, chandef, sta, + &msp->legacy); } static void minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta) { - minstrel_ht_update_caps(priv, sband, sta, priv_sta); + minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta); } static void minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta, u32 changed) { - minstrel_ht_update_caps(priv, sband, sta, priv_sta); + minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta); } static void * diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 502d3ecc4a79..958fad07b54c 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -293,6 +293,7 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, static void rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, struct ieee80211_sta *sta, void *priv_sta) { struct rc_pid_sta_info *spinfo = priv_sta; -- cgit v1.2.3 From fe0f3cd2a6a1f16fcaffec3e69e918bcf40ec76d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 14 Jul 2013 23:37:14 +0300 Subject: mac80211_hwsim: use ieee80211_free_txskb These are only strange error cases, so it's not really all that important, but the driver really should use ieee80211_free_txskb() instead of just dev_kfree_skb(). Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index cb34c7895f2a..11adae804564 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -867,7 +867,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, if (WARN_ON(skb->len < 10)) { /* Should not happen; just a sanity check for addr1 use */ - dev_kfree_skb(skb); + ieee80211_free_txskb(hw, skb); return; } @@ -884,13 +884,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, } if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { - dev_kfree_skb(skb); + ieee80211_free_txskb(hw, skb); return; } if (data->idle && !data->tmp_chan) { wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); - dev_kfree_skb(skb); + ieee80211_free_txskb(hw, skb); return; } -- cgit v1.2.3 From 2f5286e819b16f5dbf793f97f841333eedab5d68 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 14 Jul 2013 23:38:33 +0300 Subject: mac80211_hwsim: claim uAPSD support Since mac80211 does everything, we can just claim it. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 11adae804564..0a439f8c887c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2309,7 +2309,8 @@ static int __init init_mac80211_hwsim(void) hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_AP_UAPSD; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); -- cgit v1.2.3 From 5fd91aac790d6817dc99032d2774bc88f6ee4805 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 14 Jul 2013 23:42:08 +0300 Subject: mac80211_hwsim: claim active monitor support It seems to actually work this way already, so we may need to do some work to make monitor interfaces be _not_ active in hwsim instead. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 0a439f8c887c..7b2a6229eedb 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2311,6 +2311,7 @@ static int __init init_mac80211_hwsim(void) hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_AP_UAPSD; + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); -- cgit v1.2.3 From 313b0a294f8cc92be4387186e8c9eef59c1c198a Mon Sep 17 00:00:00 2001 From: Inbal Hacohen Date: Mon, 24 Jun 2013 10:35:53 +0300 Subject: iwlwifi: move dump_fh into common code This means it can be shared for different transport layers in the future. Signed-off-by: Inbal Hacohen Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-io.c | 67 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-io.h | 3 ++ drivers/net/wireless/iwlwifi/pcie/internal.h | 1 - drivers/net/wireless/iwlwifi/pcie/rx.c | 2 +- drivers/net/wireless/iwlwifi/pcie/trans.c | 67 +--------------------------- 5 files changed, 72 insertions(+), 68 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 305c81f2c2b4..dfa4d2e3aaa2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -33,6 +33,8 @@ #include "iwl-io.h" #include "iwl-csr.h" #include "iwl-debug.h" +#include "iwl-fh.h" +#include "iwl-csr.h" #define IWL_POLL_INTERVAL 10 /* microseconds */ @@ -166,3 +168,68 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) } } IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); + +static const char *get_fh_string(int cmd) +{ +#define IWL_CMD(x) case x: return #x + switch (cmd) { + IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); + IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); + IWL_CMD(FH_RSCSR_CHNL0_WPTR); + IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); + IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); + IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); + IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); + IWL_CMD(FH_TSSR_TX_STATUS_REG); + IWL_CMD(FH_TSSR_TX_ERROR_REG); + default: + return "UNKNOWN"; + } +#undef IWL_CMD +} + +int iwl_dump_fh(struct iwl_trans *trans, char **buf) +{ + int i; + static const u32 fh_tbl[] = { + FH_RSCSR_CHNL0_STTS_WPTR_REG, + FH_RSCSR_CHNL0_RBDCB_BASE_REG, + FH_RSCSR_CHNL0_WPTR, + FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_MEM_RSSR_SHARED_CTRL_REG, + FH_MEM_RSSR_RX_STATUS_REG, + FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, + FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_ERROR_REG + }; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (buf) { + int pos = 0; + size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; + + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return -ENOMEM; + + pos += scnprintf(*buf + pos, bufsz - pos, + "FH register values:\n"); + + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) + pos += scnprintf(*buf + pos, bufsz - pos, + " %34s: 0X%08x\n", + get_fh_string(fh_tbl[i]), + iwl_read_direct32(trans, fh_tbl[i])); + + return pos; + } +#endif + + IWL_ERR(trans, "FH register values:\n"); + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) + IWL_ERR(trans, " %34s: 0X%08x\n", + get_fh_string(fh_tbl[i]), + iwl_read_direct32(trans, fh_tbl[i])); + + return 0; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index fd9f5b97fff3..63d10ec08dbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -77,4 +77,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, u32 bits, u32 mask); void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); +/* Error handling */ +int iwl_dump_fh(struct iwl_trans *trans, char **buf); + #endif diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index b654dcdd048a..fa22639b63c9 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -392,7 +392,6 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); /***************************************************** * Error handling ******************************************************/ -int iwl_pcie_dump_fh(struct iwl_trans *trans, char **buf); void iwl_pcie_dump_csr(struct iwl_trans *trans); /***************************************************** diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index fd848cd1583e..5fdb4eea146d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -793,7 +793,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) } iwl_pcie_dump_csr(trans); - iwl_pcie_dump_fh(trans, NULL); + iwl_dump_fh(trans, NULL); set_bit(STATUS_FW_ERROR, &trans_pcie->status); clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 826c15602c46..82194e8daee4 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1033,71 +1033,6 @@ static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); } -static const char *get_fh_string(int cmd) -{ -#define IWL_CMD(x) case x: return #x - switch (cmd) { - IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); - IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); - IWL_CMD(FH_RSCSR_CHNL0_WPTR); - IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); - IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); - IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); - IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); - IWL_CMD(FH_TSSR_TX_STATUS_REG); - IWL_CMD(FH_TSSR_TX_ERROR_REG); - default: - return "UNKNOWN"; - } -#undef IWL_CMD -} - -int iwl_pcie_dump_fh(struct iwl_trans *trans, char **buf) -{ - int i; - static const u32 fh_tbl[] = { - FH_RSCSR_CHNL0_STTS_WPTR_REG, - FH_RSCSR_CHNL0_RBDCB_BASE_REG, - FH_RSCSR_CHNL0_WPTR, - FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_MEM_RSSR_SHARED_CTRL_REG, - FH_MEM_RSSR_RX_STATUS_REG, - FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, - FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_ERROR_REG - }; - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (buf) { - int pos = 0; - size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; - - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - - pos += scnprintf(*buf + pos, bufsz - pos, - "FH register values:\n"); - - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) - pos += scnprintf(*buf + pos, bufsz - pos, - " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(trans, fh_tbl[i])); - - return pos; - } -#endif - - IWL_ERR(trans, "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) - IWL_ERR(trans, " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(trans, fh_tbl[i])); - - return 0; -} - static const char *get_csr_string(int cmd) { #define IWL_CMD(x) case x: return #x @@ -1390,7 +1325,7 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, int pos = 0; ssize_t ret = -EFAULT; - ret = pos = iwl_pcie_dump_fh(trans, &buf); + ret = pos = iwl_dump_fh(trans, &buf); if (buf) { ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); -- cgit v1.2.3 From 2be01fa8f5cd6feffb6c50dae20d846dad8b37ba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Jun 2013 13:46:20 +0200 Subject: iwlwifi: remove forward debugfs function declarations There's no need to have 'forward' debugfs function declarations as part of the macros because the macros are always used after the static functions are defined already, so remove them. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/debugfs.c | 15 --------------- drivers/net/wireless/iwlwifi/pcie/trans.c | 14 -------------- 2 files changed, 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index d5329489245a..d94f8ab15004 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -69,19 +69,7 @@ } while (0) /* file operation */ -#define DEBUGFS_READ_FUNC(name) \ -static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ - char __user *user_buf, \ - size_t count, loff_t *ppos); - -#define DEBUGFS_WRITE_FUNC(name) \ -static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ - const char __user *user_buf, \ - size_t count, loff_t *ppos); - - #define DEBUGFS_READ_FILE_OPS(name) \ - DEBUGFS_READ_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .read = iwl_dbgfs_##name##_read, \ .open = simple_open, \ @@ -89,7 +77,6 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ }; #define DEBUGFS_WRITE_FILE_OPS(name) \ - DEBUGFS_WRITE_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .open = simple_open, \ @@ -98,8 +85,6 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ - DEBUGFS_READ_FUNC(name); \ - DEBUGFS_WRITE_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .read = iwl_dbgfs_##name##_read, \ diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 82194e8daee4..bc908d39dac1 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1113,18 +1113,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans) } while (0) /* file operation */ -#define DEBUGFS_READ_FUNC(name) \ -static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ - char __user *user_buf, \ - size_t count, loff_t *ppos); - -#define DEBUGFS_WRITE_FUNC(name) \ -static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ - const char __user *user_buf, \ - size_t count, loff_t *ppos); - #define DEBUGFS_READ_FILE_OPS(name) \ - DEBUGFS_READ_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .read = iwl_dbgfs_##name##_read, \ .open = simple_open, \ @@ -1132,7 +1121,6 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ }; #define DEBUGFS_WRITE_FILE_OPS(name) \ - DEBUGFS_WRITE_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .open = simple_open, \ @@ -1140,8 +1128,6 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ }; #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ - DEBUGFS_READ_FUNC(name); \ - DEBUGFS_WRITE_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .read = iwl_dbgfs_##name##_read, \ -- cgit v1.2.3 From e126b5d9c58870c0866357c951b4da9ed005f364 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Jun 2013 13:39:18 +0200 Subject: iwlwifi: mvm: remove unneeded argument from iwl_mvm_tx_protection() The LQ command argument isn't needed, it's always taken from the station struct that's already passed, remove the argument. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rs.c | 7 ++++--- drivers/net/wireless/iwlwifi/mvm/rs.h | 4 ++-- drivers/net/wireless/iwlwifi/mvm/sta.c | 3 +-- drivers/net/wireless/iwlwifi/mvm/tt.c | 3 +-- 4 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index b328a988c130..3856c285c69a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -3193,13 +3193,14 @@ void iwl_mvm_rate_control_unregister(void) * iwl_mvm_tx_protection - Gets LQ command, change it to enable/disable * Tx protection, according to this rquest and previous requests, * and send the LQ command. - * @lq: The LQ command * @mvmsta: The station * @enable: Enable Tx protection? */ -int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, - struct iwl_mvm_sta *mvmsta, bool enable) +int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, + bool enable) { + struct iwl_lq_cmd *lq = &mvmsta->lq_sta.lq; + lockdep_assert_held(&mvm->mutex); if (enable) { diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index cff4f6da7733..29d699ac07c9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -404,7 +404,7 @@ extern void iwl_mvm_rate_control_unregister(void); struct iwl_mvm_sta; -int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, - struct iwl_mvm_sta *mvmsta, bool enable); +int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, + bool enable); #endif /* __rs__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 62fe5209093b..0321bd37aa02 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -807,8 +807,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * method for HT traffic * this function also sends the LQ command */ - return iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq, - mvmsta, true); + return iwl_mvm_tx_protection(mvm, mvmsta, true); /* * TODO: remove the TLC_RTS flag when we tear down the last * AGG session (agg_tids_count in DVM) diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index d6ae7f16ac11..f5ba185f09b1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -391,8 +391,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) mvmsta = (void *)sta->drv_priv; if (enable == mvmsta->tt_tx_protection) continue; - err = iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq, - mvmsta, enable); + err = iwl_mvm_tx_protection(mvm, mvmsta, enable); if (err) { IWL_ERR(mvm, "Failed to %s Tx protection\n", enable ? "enable" : "disable"); -- cgit v1.2.3 From f2532b04b2ecde7c71ff30d0b26bd6d6166c4bf6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 2 Jul 2013 15:47:29 +0300 Subject: iwlwifi: pcie: don't disable L1 for newest NICs In newest NICs (7000 family and up), L1 is supported, so avoid to disable it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-7000.c | 1 + drivers/net/wireless/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/iwlwifi/pcie/trans.c | 14 ++++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 22b7fa5b971a..7f61674685c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -99,6 +99,7 @@ static const struct iwl_base_params iwl7000_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .shadow_reg_enable = true, + .pcie_l1_allowed = true, }; static const struct iwl_ht_params iwl7000_ht_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 83b9ff6ff3ad..87fe955e2a91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -152,6 +152,7 @@ struct iwl_base_params { unsigned int wd_timeout; u32 max_event_log_size; const bool shadow_reg_enable; + const bool pcie_l1_allowed; }; /* diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index bc908d39dac1..cec0c8991285 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1418,10 +1418,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->reg_lock); init_waitqueue_head(&trans_pcie->ucode_write_waitq); - /* W/A - seems to solve weird behavior. We need to remove this if we - * don't want to stay in L1 all the time. This wastes a lot of power */ - pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | - PCIE_LINK_STATE_CLKPM); + if (!cfg->base_params->pcie_l1_allowed) { + /* + * W/A - seems to solve weird behavior. We need to remove this + * if we don't want to stay in L1 all the time. This wastes a + * lot of power. + */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | + PCIE_LINK_STATE_L1 | + PCIE_LINK_STATE_CLKPM); + } if (pci_enable_device(pdev)) { err = -ENODEV; -- cgit v1.2.3 From 961de6a5ee568881321cf97e826cc37e6f9bcf84 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 Jul 2013 18:00:08 +0200 Subject: iwlwifi: pcie: make unused queue warning more readable Use the return value of WARN_ONCE() and add a message with the queue ID that's getting used. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/tx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index c47c92165aba..134f7a109f47 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1619,10 +1619,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, txq = &trans_pcie->txq[txq_id]; q = &txq->q; - if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) { - WARN_ON_ONCE(1); + if (WARN_ONCE(!test_bit(txq_id, trans_pcie->queue_used), + "TX on unused queue %d\n", txq_id)) return -EINVAL; - } spin_lock(&txq->lock); -- cgit v1.2.3 From 0c393d4eac31912ad6ea362d4f9bf78aa1fe9a69 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Thu, 4 Jul 2013 14:47:30 +0300 Subject: iwlwifi: mvm: sram hex dump on NIC error Add sram dump on NIC error for debug improvement. Signed-off-by: Matti Gottlieb Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/ops.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/utils.c | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d40d7db185d6..3aaecbcdc551 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -524,6 +524,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); +void iwl_mvm_dump_sram(struct iwl_mvm *mvm); u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index af79a14063a9..0a4eb278f789 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -678,6 +678,8 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); iwl_mvm_dump_nic_error_log(mvm); + if (!iwlwifi_mod_params.restart_fw) + iwl_mvm_dump_sram(mvm); iwl_mvm_nic_restart(mvm); } diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 1e1332839e4a..a9c357491434 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -453,6 +453,29 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); } +void iwl_mvm_dump_sram(struct iwl_mvm *mvm) +{ + const struct fw_img *img; + int ofs, len = 0; + u8 *buf; + + if (!mvm->ucode_loaded) + return; + + img = &mvm->fw->img[mvm->cur_ucode]; + ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; + len = img->sec[IWL_UCODE_SECTION_DATA].len; + + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + return; + + iwl_trans_read_mem_bytes(mvm->trans, ofs, buf, len); + iwl_print_hex_error(mvm->trans, buf, len); + + kfree(buf); +} + /** * iwl_mvm_send_lq_cmd() - Send link quality command * @init: This command is sent as part of station initialization right -- cgit v1.2.3 From e811ada7a6a3f720c178ba29998ce9f9685f9df3 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Sun, 10 Mar 2013 15:29:44 +0200 Subject: iwlwifi: mvm: Upgrade to a new power management uAPSD API Change power management implementation to support new host-device API containing uAPSD parameters. Verify FW support for this new API. Use the new power table command (0xA9) to configure power management. Use the legacy command (0x77) if FW does not support the new API. New file power_legacy.c is introduced for legacy implementation. Signed-off-by: Alexander Bondar Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-fw.h | 2 + drivers/net/wireless/iwlwifi/mvm/Makefile | 2 +- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 33 +-- drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 75 +++++- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 5 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 11 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 46 +++- drivers/net/wireless/iwlwifi/mvm/ops.c | 6 + drivers/net/wireless/iwlwifi/mvm/power.c | 128 +++++++--- drivers/net/wireless/iwlwifi/mvm/power_legacy.c | 319 ++++++++++++++++++++++++ 10 files changed, 546 insertions(+), 81 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/mvm/power_legacy.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index f844d5c748c0..f26f12689969 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -74,6 +74,7 @@ * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS + * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), @@ -81,6 +82,7 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_MFP = BIT(2), IWL_UCODE_TLV_FLAGS_P2P = BIT(3), IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), + IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), }; /* The default calibrate table size if not specified by firmware file */ diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index ff856e543ae8..6d73817850ce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o iwlmvm-y += scan.o time-event.o rs.o -iwlmvm-y += power.o bt-coex.o +iwlmvm-y += power.o power_legacy.o bt-coex.o iwlmvm-y += led.o tt.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index e56ed2a84888..5d669da09afe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -424,40 +424,11 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file, struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->dbgfs_data; - struct iwl_powertable_cmd cmd = {}; char buf[256]; int bufsz = sizeof(buf); - int pos = 0; + int pos; - iwl_mvm_power_build_cmd(mvm, vif, &cmd); - - pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", - (cmd.flags & - cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? - 0 : 1); - pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", - le32_to_cpu(cmd.skip_dtim_periods)); - pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", - iwlmvm_mod_params.power_scheme); - pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", - le16_to_cpu(cmd.flags)); - pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", - cmd.keep_alive_seconds); - - if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { - pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", - (cmd.flags & - cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? - 1 : 0); - pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", - le32_to_cpu(cmd.rx_data_timeout)); - pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", - le32_to_cpu(cmd.tx_data_timeout)); - if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) - pos += scnprintf(buf+pos, bufsz-pos, - "lprx_rssi_threshold = %d\n", - le32_to_cpu(cmd.lprx_rssi_threshold)); - } + pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index a6da359a80c3..300211d79f2a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -79,6 +79,10 @@ * '1' Driver enables PM (use rest of parameters) * @POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, * '1' PM could sleep over DTIM till listen Interval. + * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all + * access categories are both delivery and trigger enabled. + * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and + * PBW Snoozing enabled * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. */ @@ -86,6 +90,8 @@ enum iwl_power_flags { POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(1), POWER_FLAGS_SKIP_OVER_DTIM_MSK = BIT(2), + POWER_FLAGS_SNOOZE_ENA_MSK = BIT(5), + POWER_FLAGS_BT_SCO_ENA = BIT(8), POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9), POWER_FLAGS_LPRX_ENA_MSK = BIT(11), }; @@ -93,7 +99,8 @@ enum iwl_power_flags { #define IWL_POWER_VEC_SIZE 5 /** - * struct iwl_powertable_cmd - Power Table Command + * struct iwl_powertable_cmd - legacy power command. Beside old API support this + * is used also with a new power API for device wide power settings. * POWER_TABLE_CMD = 0x77 (command, has simple generic response) * * @flags: Power table command flags from POWER_FLAGS_* @@ -124,6 +131,72 @@ struct iwl_powertable_cmd { __le32 lprx_rssi_threshold; } __packed; +/** + * struct iwl_mac_power_cmd - New power command containing uAPSD support + * MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) + * @id_and_color: MAC contex identifier + * @flags: Power table command flags from POWER_FLAGS_* + * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. + * Minimum allowed:- 3 * DTIM. Keep alive period must be + * set regardless of power scheme or current power state. + * FW use this value also when PM is disabled. + * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to + * PSM transition - legacy PM + * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to + * PSM transition - legacy PM + * @sleep_interval: not in use + * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag + * is set. For example, if it is required to skip over + * one DTIM, this value need to be set to 2 (DTIM periods). + * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to + * PSM transition - uAPSD + * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to + * PSM transition - uAPSD + * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. + * Default: 80dbm + * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set + * @snooze_interval: TBD + * @snooze_window: TBD + * @snooze_step: TBD + * @qndp_tid: TID client shall use for uAPSD QNDP triggers + * @uapsd_ac_flags: Set trigger-enabled and delivery-enabled indication for + * each corresponding AC. + * Use IEEE80211_WMM_IE_STA_QOSINFO_AC* for correct values. + * @uapsd_max_sp: Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct + * values. + * @heavy_traffic_thr_tx_pkts: TX threshold measured in number of packets + * @heavy_traffic_thr_rx_pkts: RX threshold measured in number of packets + * @heavy_traffic_thr_tx_load: TX threshold measured in load's percentage + * @heavy_traffic_thr_rx_load: RX threshold measured in load's percentage + * @limited_ps_threshold: +*/ +struct iwl_mac_power_cmd { + /* CONTEXT_DESC_API_T_VER_1 */ + __le32 id_and_color; + + /* CLIENT_PM_POWER_TABLE_S_VER_1 */ + __le16 flags; + __le16 keep_alive_seconds; + __le32 rx_data_timeout; + __le32 tx_data_timeout; + __le32 rx_data_timeout_uapsd; + __le32 tx_data_timeout_uapsd; + u8 lprx_rssi_threshold; + u8 skip_dtim_periods; + __le16 snooze_interval; + __le16 snooze_window; + u8 snooze_step; + u8 qndp_tid; + u8 uapsd_ac_flags; + u8 uapsd_max_sp; + u8 heavy_traffic_threshold_tx_packets; + u8 heavy_traffic_threshold_rx_packets; + u8 heavy_traffic_threshold_tx_percentage; + u8 heavy_traffic_threshold_rx_percentage; + u8 limited_ps_threshold; + u8 reserved; +} __packed; + /** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index cbfb3beae783..44614f5e4485 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -136,7 +136,7 @@ enum { CALIB_RES_NOTIF_PHY_DB = 0x6b, /* PHY_DB_CMD = 0x6c, */ - /* Power */ + /* Power - legacy power table command */ POWER_TABLE_CMD = 0x77, /* Thermal Throttling*/ @@ -166,6 +166,9 @@ enum { MISSED_BEACONS_NOTIFICATION = 0xa2, + /* Power - new power table command */ + MAC_PM_POWER_TABLE = 0xa9, + REPLY_RX_PHY_CMD = 0xc0, REPLY_RX_MPDU_CMD = 0xc1, BA_NOTIF = 0xc5, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e08683b20531..2d07605eaabf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -774,9 +774,14 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to update quotas\n"); } - ret = iwl_mvm_power_update_mode(mvm, vif); - if (ret) - IWL_ERR(mvm, "failed to update power mode\n"); + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD)) { + /* Workaround for FW bug, otherwise FW disables device + * power save upon disassociation + */ + ret = iwl_mvm_power_update_mode(mvm, vif); + if (ret) + IWL_ERR(mvm, "failed to update power mode\n"); + } } else if (changes & BSS_CHANGED_BEACON_INFO) { /* * We received a beacon _after_ association so diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 3aaecbcdc551..caa6a1758172 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -91,6 +91,9 @@ enum iwl_mvm_tx_fifo { }; extern struct ieee80211_ops iwl_mvm_hw_ops; +extern const struct iwl_mvm_power_ops pm_legacy_ops; +extern const struct iwl_mvm_power_ops pm_mac_ops; + /** * struct iwl_mvm_mod_params - module parameters for iwlmvm * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted. @@ -150,6 +153,17 @@ enum iwl_power_scheme { #define IWL_CONN_MAX_LISTEN_INTERVAL 70 +struct iwl_mvm_power_ops { + int (*power_update_mode)(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); + int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +#ifdef CONFIG_IWLWIFI_DEBUGFS + int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + char *buf, int bufsz); +#endif +}; + + #ifdef CONFIG_IWLWIFI_DEBUGFS enum iwl_dbgfs_pm_mask { MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0), @@ -163,7 +177,7 @@ enum iwl_dbgfs_pm_mask { }; struct iwl_dbgfs_pm { - u8 keep_alive_seconds; + u16 keep_alive_seconds; u32 rx_data_timeout; u32 tx_data_timeout; bool skip_over_dtim; @@ -481,6 +495,8 @@ struct iwl_mvm { /* Thermal Throttling and CTkill */ struct iwl_mvm_tt_mgmt thermal_throttle; s32 temperature; /* Celsius */ + + const struct iwl_mvm_power_ops *pm_ops; }; /* Extract MVM priv from op_mode and _hw */ @@ -660,10 +676,26 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, u8 flags, bool init); /* power managment */ -int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_powertable_cmd *cmd); +static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + return mvm->pm_ops->power_update_mode(mvm, vif); +} + +static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + return mvm->pm_ops->power_disable(mvm, vif); +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + char *buf, int bufsz) +{ + return mvm->pm_ops->power_dbgfs_read(mvm, vif, buf, bufsz); +} +#endif int iwl_mvm_leds_init(struct iwl_mvm *mvm); void iwl_mvm_leds_exit(struct iwl_mvm *mvm); @@ -707,6 +739,10 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, + struct iwl_beacon_filter_cmd *cmd); +int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, bool enable); /* SMPS */ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 0a4eb278f789..fa1e1ce9f2be 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -301,6 +301,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(MCAST_FILTER_CMD), CMD(REPLY_BEACON_FILTERING_CMD), CMD(REPLY_THERMAL_MNG_BACKOFF), + CMD(MAC_PM_POWER_TABLE), }; #undef CMD @@ -431,6 +432,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (err) goto out_unregister; + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD) + mvm->pm_ops = &pm_mac_ops; + else + mvm->pm_ops = &pm_legacy_ops; + return op_mode; out_unregister: diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index e7ca965a89b8..644bf476921a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -75,8 +75,8 @@ #define POWER_KEEP_ALIVE_PERIOD_SEC 25 -static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, - struct iwl_beacon_filter_cmd *cmd) +int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, + struct iwl_beacon_filter_cmd *cmd) { int ret; @@ -106,8 +106,8 @@ static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, return ret; } -static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, bool enable) +int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, bool enable) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_beacon_filter_cmd cmd = { @@ -124,13 +124,14 @@ static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, } static void iwl_mvm_power_log(struct iwl_mvm *mvm, - struct iwl_powertable_cmd *cmd) + struct iwl_mac_power_cmd *cmd) { IWL_DEBUG_POWER(mvm, - "Sending power table command for power level %d, flags = 0x%X\n", - iwlmvm_mod_params.power_scheme, + "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", + cmd->id_and_color, iwlmvm_mod_params.power_scheme, le16_to_cpu(cmd->flags)); - IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds); + IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", + le16_to_cpu(cmd->keep_alive_seconds)); if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", @@ -139,15 +140,16 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm, le32_to_cpu(cmd->tx_data_timeout)); if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", - le32_to_cpu(cmd->skip_dtim_periods)); + cmd->skip_dtim_periods); if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", - le32_to_cpu(cmd->lprx_rssi_threshold)); + cmd->lprx_rssi_threshold); } } -void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_powertable_cmd *cmd) +static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_mac_power_cmd *cmd) { struct ieee80211_hw *hw = mvm->hw; struct ieee80211_chanctx_conf *chanctx_conf; @@ -158,19 +160,26 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif __maybe_unused = iwl_mvm_vif_from_mac80211(vif); + cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)); + dtimper = hw->conf.ps_dtim_period ?: 1; + /* * Regardless of power management state the driver must set * keep alive period. FW will use it for sending keep alive NDPs - * immediately after association. + * immediately after association. Check that keep alive period + * is at least 3 * DTIM */ - cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; + dtimper_msec = dtimper * vif->bss_conf.beacon_int; + keep_alive = max_t(int, 3 * dtimper_msec, + MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); + keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); + cmd->keep_alive_seconds = cpu_to_le16(keep_alive); if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); - if (!vif->bss_conf.assoc) - cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); #ifdef CONFIG_IWLWIFI_DEBUGFS if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && @@ -186,12 +195,9 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, (vif->bss_conf.beacon_rate->bitrate == 10 || vif->bss_conf.beacon_rate->bitrate == 60)) { cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); - cmd->lprx_rssi_threshold = - cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD); + cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; } - dtimper = hw->conf.ps_dtim_period ?: 1; - /* Check if radar detection is required on current channel */ rcu_read_lock(); chanctx_conf = rcu_dereference(vif->chanctx_conf); @@ -207,16 +213,9 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || mvm->cur_ucode == IWL_UCODE_WOWLAN)) { cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); - cmd->skip_dtim_periods = cpu_to_le32(3); + cmd->skip_dtim_periods = 3; } - /* Check that keep alive period is at least 3 * DTIM */ - dtimper_msec = dtimper * vif->bss_conf.beacon_int; - keep_alive = max_t(int, 3 * dtimper_msec, - MSEC_PER_SEC * cmd->keep_alive_seconds); - keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); - cmd->keep_alive_seconds = keep_alive; - if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); @@ -227,7 +226,8 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, #ifdef CONFIG_IWLWIFI_DEBUGFS if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) - cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; + cmd->keep_alive_seconds = + cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds); if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { if (mvmvif->dbgfs_pm.skip_over_dtim) cmd->flags |= @@ -243,8 +243,7 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->tx_data_timeout = cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) - cmd->skip_dtim_periods = - cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); + cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods; if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { if (mvmvif->dbgfs_pm.lprx_ena) cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); @@ -252,16 +251,16 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); } if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) - cmd->lprx_rssi_threshold = - cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold); + cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold; #endif /* CONFIG_IWLWIFI_DEBUGFS */ } -int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { int ret; bool ba_enable; - struct iwl_powertable_cmd cmd = {}; + struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; @@ -280,7 +279,7 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); - ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, + ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, sizeof(cmd), &cmd); if (ret) return ret; @@ -291,15 +290,19 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); } -int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { - struct iwl_powertable_cmd cmd = {}; + struct iwl_mac_power_cmd cmd = {}; struct iwl_mvm_vif *mvmvif __maybe_unused = iwl_mvm_vif_from_mac80211(vif); if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; + cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)); + if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); @@ -310,11 +313,50 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) #endif iwl_mvm_power_log(mvm, &cmd); - return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, + return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC, sizeof(cmd), &cmd); } #ifdef CONFIG_IWLWIFI_DEBUGFS +static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, char *buf, + int bufsz) +{ + struct iwl_mac_power_cmd cmd = {}; + int pos = 0; + + iwl_mvm_power_build_cmd(mvm, vif, &cmd); + + pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", + (cmd.flags & + cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? + 0 : 1); + pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", + cmd.skip_dtim_periods); + pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", + iwlmvm_mod_params.power_scheme); + pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", + le16_to_cpu(cmd.flags)); + pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", + le16_to_cpu(cmd.keep_alive_seconds)); + + if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { + pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", + (cmd.flags & + cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? + 1 : 0); + pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", + le32_to_cpu(cmd.rx_data_timeout)); + pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", + le32_to_cpu(cmd.tx_data_timeout)); + if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) + pos += scnprintf(buf+pos, bufsz-pos, + "lprx_rssi_threshold = %d\n", + cmd.lprx_rssi_threshold); + } + return pos; +} + void iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, struct iwl_beacon_filter_cmd *cmd) @@ -382,3 +424,11 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, return ret; } + +const struct iwl_mvm_power_ops pm_mac_ops = { + .power_update_mode = iwl_mvm_power_mac_update_mode, + .power_disable = iwl_mvm_power_mac_disable, +#ifdef CONFIG_IWLWIFI_DEBUGFS + .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read, +#endif +}; diff --git a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c new file mode 100644 index 000000000000..2ce79bad5845 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c @@ -0,0 +1,319 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "iwl-debug.h" +#include "mvm.h" +#include "iwl-modparams.h" +#include "fw-api-power.h" + +#define POWER_KEEP_ALIVE_PERIOD_SEC 25 + +static void iwl_mvm_power_log(struct iwl_mvm *mvm, + struct iwl_powertable_cmd *cmd) +{ + IWL_DEBUG_POWER(mvm, + "Sending power table command for power level %d, flags = 0x%X\n", + iwlmvm_mod_params.power_scheme, + le16_to_cpu(cmd->flags)); + IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds); + + if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { + IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", + le32_to_cpu(cmd->rx_data_timeout)); + IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", + le32_to_cpu(cmd->tx_data_timeout)); + if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) + IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", + le32_to_cpu(cmd->skip_dtim_periods)); + if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) + IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", + le32_to_cpu(cmd->lprx_rssi_threshold)); + } +} + +static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_powertable_cmd *cmd) +{ + struct ieee80211_hw *hw = mvm->hw; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; + int dtimper, dtimper_msec; + int keep_alive; + bool radar_detect = false; + struct iwl_mvm_vif *mvmvif __maybe_unused = + iwl_mvm_vif_from_mac80211(vif); + + /* + * Regardless of power management state the driver must set + * keep alive period. FW will use it for sending keep alive NDPs + * immediately after association. + */ + cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; + + if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) + return; + + cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); + if (!vif->bss_conf.assoc) + cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && + mvmvif->dbgfs_pm.disable_power_off) + cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); +#endif + if (!vif->bss_conf.ps) + return; + + cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); + + if (vif->bss_conf.beacon_rate && + (vif->bss_conf.beacon_rate->bitrate == 10 || + vif->bss_conf.beacon_rate->bitrate == 60)) { + cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); + cmd->lprx_rssi_threshold = + cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD); + } + + dtimper = hw->conf.ps_dtim_period ?: 1; + + /* Check if radar detection is required on current channel */ + rcu_read_lock(); + chanctx_conf = rcu_dereference(vif->chanctx_conf); + WARN_ON(!chanctx_conf); + if (chanctx_conf) { + chan = chanctx_conf->def.chan; + radar_detect = chan->flags & IEEE80211_CHAN_RADAR; + } + rcu_read_unlock(); + + /* Check skip over DTIM conditions */ + if (!radar_detect && (dtimper <= 10) && + (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || + mvm->cur_ucode == IWL_UCODE_WOWLAN)) { + cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + cmd->skip_dtim_periods = cpu_to_le32(3); + } + + /* Check that keep alive period is at least 3 * DTIM */ + dtimper_msec = dtimper * vif->bss_conf.beacon_int; + keep_alive = max_t(int, 3 * dtimper_msec, + MSEC_PER_SEC * cmd->keep_alive_seconds); + keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); + cmd->keep_alive_seconds = keep_alive; + + if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { + cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); + cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); + } else { + cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); + cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); + } + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) + cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { + if (mvmvif->dbgfs_pm.skip_over_dtim) + cmd->flags |= + cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + else + cmd->flags &= + cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); + } + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) + cmd->rx_data_timeout = + cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) + cmd->tx_data_timeout = + cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) + cmd->skip_dtim_periods = + cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { + if (mvmvif->dbgfs_pm.lprx_ena) + cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); + else + cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); + } + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) + cmd->lprx_rssi_threshold = + cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold); +#endif /* CONFIG_IWLWIFI_DEBUGFS */ +} + +static int iwl_mvm_power_legacy_update_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + int ret; + bool ba_enable; + struct iwl_powertable_cmd cmd = {}; + + if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) + return 0; + + /* + * TODO: The following vif_count verification is temporary condition. + * Avoid power mode update if more than one interface is currently + * active. Remove this condition when FW will support power management + * on multiple MACs. + */ + IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n", + mvm->vif_count); + if (mvm->vif_count > 1) + return 0; + + iwl_mvm_power_build_cmd(mvm, vif, &cmd); + iwl_mvm_power_log(mvm, &cmd); + + ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, + sizeof(cmd), &cmd); + if (ret) + return ret; + + ba_enable = !!(cmd.flags & + cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); + + return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); +} + +static int iwl_mvm_power_legacy_disable(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_powertable_cmd cmd = {}; + struct iwl_mvm_vif *mvmvif __maybe_unused = + iwl_mvm_vif_from_mac80211(vif); + + if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) + return 0; + + if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) + cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && + mvmvif->dbgfs_pm.disable_power_off) + cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); +#endif + iwl_mvm_power_log(mvm, &cmd); + + return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, + sizeof(cmd), &cmd); +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +static int iwl_mvm_power_legacy_dbgfs_read(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, char *buf, + int bufsz) +{ + struct iwl_powertable_cmd cmd = {}; + int pos = 0; + + iwl_mvm_power_build_cmd(mvm, vif, &cmd); + + pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", + (cmd.flags & + cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? + 0 : 1); + pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", + le32_to_cpu(cmd.skip_dtim_periods)); + pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", + iwlmvm_mod_params.power_scheme); + pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", + le16_to_cpu(cmd.flags)); + pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", + cmd.keep_alive_seconds); + + if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { + pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", + (cmd.flags & + cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? + 1 : 0); + pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", + le32_to_cpu(cmd.rx_data_timeout)); + pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", + le32_to_cpu(cmd.tx_data_timeout)); + if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) + pos += scnprintf(buf+pos, bufsz-pos, + "lprx_rssi_threshold = %d\n", + le32_to_cpu(cmd.lprx_rssi_threshold)); + } + return pos; +} +#endif + +const struct iwl_mvm_power_ops pm_legacy_ops = { + .power_update_mode = iwl_mvm_power_legacy_update_mode, + .power_disable = iwl_mvm_power_legacy_disable, +#ifdef CONFIG_IWLWIFI_DEBUGFS + .power_dbgfs_read = iwl_mvm_power_legacy_dbgfs_read, +#endif +}; -- cgit v1.2.3 From 41069b4631b98646b530bdbd545b7574faccecf9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 25 Jun 2013 21:49:19 +0300 Subject: iwlwifi: mvm: better handle several several vifs in BT Coex When there one vif on 5GHz associating, it would clear all the BT Coex constraints. This can't work if there is another vif on 2.4GHz. Fix that. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 22 ++++------------------ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- 2 files changed, 5 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index dbd622a3929c..9195779a9d3f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -384,6 +384,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode = IEEE80211_SMPS_AUTOMATIC; + /* non associated BSSes aren't to be considered */ + if (!vif->bss_conf.assoc) + return; + if (band != IEEE80211_BAND_2GHZ) { iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); @@ -588,23 +592,5 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - struct ieee80211_chanctx_conf *chanctx_conf; - enum ieee80211_band band; - - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); - if (chanctx_conf && chanctx_conf->def.chan) - band = chanctx_conf->def.chan->band; - else - band = -1; - rcu_read_unlock(); - - /* if we are in 2GHz we will get a notification from the fw */ - if (band == IEEE80211_BAND_2GHZ) - return; - - /* else, we can remove all the constraints */ - memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); - iwl_mvm_bt_coex_notif_handle(mvm); } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2d07605eaabf..30319e069f45 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -761,7 +761,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_ERR(mvm, "failed to update quotas\n"); 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 */ @@ -782,6 +781,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to update power mode\n"); } + iwl_mvm_bt_coex_vif_assoc(mvm, vif); } else if (changes & BSS_CHANGED_BEACON_INFO) { /* * We received a beacon _after_ association so -- cgit v1.2.3 From 8e0366f9c7ceefaa1c9fdb9529d23011d655d49c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 25 Jun 2013 21:57:08 +0300 Subject: iwlwifi: mvm: fix the ACK / CTS kill mask upon RSSI event If a vif's RSSI gets good enough, we can enable reduced Tx power. If so, we need to update the ACK / CTS kill mask accordingly. Since the auditing for the interfaces was bad, we enabled reduced Tx power, but didn't update the ACK / CTS kill mask. This is harmless since the firmware is most likely to discard this setting anyway, but it is a good practice to update it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 9195779a9d3f..3a48cd98170e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -527,6 +527,8 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, lockdep_is_held(&mvm->mutex)); mvmsta = (void *)sta->drv_priv; + data->num_bss_ifaces++; + /* * This interface doesn't support reduced Tx power (because of low * RSSI probably), then set bt_kill_msk to default values. -- cgit v1.2.3 From 03e304e4e7ace25a532bfed51c7737d4aec768cd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 26 Jun 2013 15:54:34 +0300 Subject: iwlwifi: mvm: don't allocate BT_COEX cmd on stack This command will change and be much bigger. Prepare to that by stop allocating on the stack. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 138 +++++++++++++++++++---------- 1 file changed, 92 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 3a48cd98170e..0fad98b85f60 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -220,66 +220,87 @@ static const __le32 iwl_single_shared_ant_lookup[BT_COEX_LUT_SIZE] = { int iwl_send_bt_init_conf(struct iwl_mvm *mvm) { - struct iwl_bt_coex_cmd cmd = { - .max_kill = 5, - .bt3_time_t7_value = 1, - .bt3_prio_sample_time = 2, - .bt3_timer_t2_value = 0xc, + struct iwl_bt_coex_cmd *bt_cmd; + struct iwl_host_cmd cmd = { + .id = BT_CONFIG, + .len = { sizeof(*bt_cmd), }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + .flags = CMD_SYNC, }; int ret; - cmd.flags = iwlwifi_mod_params.bt_coex_active ? + /* go to CALIB state in internal BT-Coex state machine */ + ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; + + ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; + + bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); + if (!bt_cmd) + return -ENOMEM; + cmd.data[0] = bt_cmd; + + bt_cmd->max_kill = 5; + bt_cmd->bt3_time_t7_value = 1; + bt_cmd->bt3_prio_sample_time = 2; + bt_cmd->bt3_timer_t2_value = 0xc; + + bt_cmd->flags = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; - cmd.flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE; + bt_cmd->flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE; - cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | - BT_VALID_BT_PRIO_BOOST | - BT_VALID_MAX_KILL | - BT_VALID_3W_TMRS | - BT_VALID_KILL_ACK | - BT_VALID_KILL_CTS | - BT_VALID_REDUCED_TX_POWER | - BT_VALID_LUT); + bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | + BT_VALID_BT_PRIO_BOOST | + BT_VALID_MAX_KILL | + BT_VALID_3W_TMRS | + BT_VALID_KILL_ACK | + BT_VALID_KILL_CTS | + BT_VALID_REDUCED_TX_POWER | + BT_VALID_LUT); if (mvm->cfg->bt_shared_single_ant) - memcpy(&cmd.decision_lut, iwl_single_shared_ant_lookup, + memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant_lookup, sizeof(iwl_single_shared_ant_lookup)); else if (is_loose_coex()) - memcpy(&cmd.decision_lut, iwl_loose_lookup, + memcpy(&bt_cmd->decision_lut, iwl_loose_lookup, sizeof(iwl_tight_lookup)); else - memcpy(&cmd.decision_lut, iwl_tight_lookup, + memcpy(&bt_cmd->decision_lut, iwl_tight_lookup, sizeof(iwl_tight_lookup)); - cmd.bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST); - cmd.kill_ack_msk = + bt_cmd->bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST); + bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); - cmd.kill_cts_msk = + bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); - /* go to CALIB state in internal BT-Coex state machine */ - ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); - if (ret) - return ret; - - ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); - if (ret) - return ret; + ret = iwl_mvm_send_cmd(mvm, &cmd); - return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, - sizeof(cmd), &cmd); + kfree(bt_cmd); + return ret; } static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, bool reduced_tx_power) { enum iwl_bt_kill_msk bt_kill_msk; - struct iwl_bt_coex_cmd cmd = {}; + struct iwl_bt_coex_cmd *bt_cmd; struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; + struct iwl_host_cmd cmd = { + .id = BT_CONFIG, + .data[0] = &bt_cmd, + .len = { sizeof(*bt_cmd), }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + .flags = CMD_SYNC, + }; + int ret = 0; lockdep_assert_held(&mvm->mutex); @@ -308,24 +329,40 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, return 0; mvm->bt_kill_msk = bt_kill_msk; - cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); - cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); - cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); + + bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); + if (!bt_cmd) + return -ENOMEM; + cmd.data[0] = bt_cmd; + + bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); + bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); + bt_cmd->valid_bit_msk = + cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk); - return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, - sizeof(cmd), &cmd); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + + kfree(bt_cmd); + return ret; } static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) { - struct iwl_bt_coex_cmd cmd = { - .valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER), - .bt_reduced_tx_power = sta_id, + struct iwl_bt_coex_cmd *bt_cmd; + /* Send ASYNC since this can be sent from an atomic context */ + struct iwl_host_cmd cmd = { + .id = BT_CONFIG, + .len = { sizeof(*bt_cmd), }, + .dataflags = { IWL_HCMD_DFL_DUP, }, + .flags = CMD_ASYNC, }; + struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; + int ret; /* This can happen if the station has been removed right now */ if (sta_id == IWL_MVM_STATION_COUNT) @@ -339,17 +376,26 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, if (mvmsta->bt_reduced_txpower == enable) return 0; + bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); + if (!bt_cmd) + return -ENOMEM; + cmd.data[0] = bt_cmd; + + bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER), + bt_cmd->bt_reduced_tx_power = sta_id; + if (enable) - cmd.bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; + bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", enable ? "en" : "dis", sta_id); mvmsta->bt_reduced_txpower = enable; - /* Send ASYNC since this can be sent from an atomic context */ - return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_ASYNC, - sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd(mvm, &cmd); + + kfree(bt_cmd); + return ret; } struct iwl_bt_iterator_data { -- cgit v1.2.3 From 3266d73237a7441a30d64a97327738e70f1b5254 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 3 Jul 2013 10:47:10 -0600 Subject: wireless: Convert mwifiex/pcie to dev_pm_ops from legacy pm_ops Convert the mwifiex/pci driver to use dev_pm_ops for power management and remove Legacy PM handling. This change re-uses existing suspend and resume interfaces for dev_pm_ops, and changes CONFIG_PM ifdefs to CONFIG_PM_SLEEP as the driver does not support run-time PM. Signed-off-by: Shuah Khan Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 20c9c4c7b0b2..4a57eb45f9a8 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -76,7 +76,7 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) return false; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP /* * Kernel needs to suspend all functions separately. Therefore all * registered functions must have drivers with suspend and resume @@ -85,11 +85,12 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) * If already not suspended, this function allocates and sends a host * sleep activate request to the firmware and turns off the traffic. */ -static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state) +static int mwifiex_pcie_suspend(struct device *dev) { struct mwifiex_adapter *adapter; struct pcie_service_card *card; int hs_actived; + struct pci_dev *pdev = to_pci_dev(dev); if (pdev) { card = (struct pcie_service_card *) pci_get_drvdata(pdev); @@ -120,10 +121,11 @@ static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state) * If already not resumed, this function turns on the traffic and * sends a host sleep cancel request to the firmware. */ -static int mwifiex_pcie_resume(struct pci_dev *pdev) +static int mwifiex_pcie_resume(struct device *dev) { struct mwifiex_adapter *adapter; struct pcie_service_card *card; + struct pci_dev *pdev = to_pci_dev(dev); if (pdev) { card = (struct pcie_service_card *) pci_get_drvdata(pdev); @@ -211,9 +213,9 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) wait_for_completion(&adapter->fw_load); if (user_rmmod) { -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP if (adapter->is_suspended) - mwifiex_pcie_resume(pdev); + mwifiex_pcie_resume(&pdev->dev); #endif for (i = 0; i < adapter->priv_num; i++) @@ -249,16 +251,22 @@ static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = { MODULE_DEVICE_TABLE(pci, mwifiex_ids); +#ifdef CONFIG_PM_SLEEP +/* Power Management Hooks */ +static SIMPLE_DEV_PM_OPS(mwifiex_pcie_pm_ops, mwifiex_pcie_suspend, + mwifiex_pcie_resume); +#endif + /* PCI Device Driver */ static struct pci_driver __refdata mwifiex_pcie = { .name = "mwifiex_pcie", .id_table = mwifiex_ids, .probe = mwifiex_pcie_probe, .remove = mwifiex_pcie_remove, -#ifdef CONFIG_PM - /* Power Management Hooks */ - .suspend = mwifiex_pcie_suspend, - .resume = mwifiex_pcie_resume, +#ifdef CONFIG_PM_SLEEP + .driver = { + .pm = &mwifiex_pcie_pm_ops, + }, #endif }; -- cgit v1.2.3 From 74e13060f11dbf4028b810e34c359f64929415f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2013 20:55:38 +0200 Subject: ath9k: make rfkill configurable When the platform doesn't have rfkill support, i.e. nothing is connected to the rfkill GPIO, there's little value in polling the GPIO. Add a Kconfig option to allow disabling the polling in ath9k. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 10 ++++++++++ drivers/net/wireless/ath/ath9k/hw.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index d491a3178986..c91bc6111c23 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -96,6 +96,16 @@ config ATH9K_LEGACY_RATE_CONTROL has to be passed to mac80211 using the module parameter, ieee80211_default_rc_algo. +config ATH9K_RFKILL + bool "Atheros ath9k rfkill support" if EXPERT + depends on ATH9K + depends on RFKILL=y || RFKILL=ATH9K + default y + help + Say Y to have ath9k poll the RF-Kill GPIO every couple of + seconds. Turn off to save power, but enable it if you have + a platform that can toggle the RF-Kill GPIO. + config ATH9K_HTC tristate "Atheros HTC based wireless cards support" depends on USB && MAC80211 diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4ca0cb060106..e420c6ba62a7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2504,7 +2504,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->rts_aggr_limit = (8 * 1024); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +#ifdef CONFIG_ATH9K_RFKILL ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); if (ah->rfsilent & EEP_RFSILENT_ENABLED) { ah->rfkill_gpio = -- cgit v1.2.3 From a3835e9fa72956a9a348079f8161e6a5057b5c88 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 4 Jul 2013 12:59:47 +0530 Subject: ath9k: Fix RTS threshold Currently, RTS threshold is not handled for HT. Handle user-specified threshold values for both aggregated and unaggregated frames. Use the wiphy's threshold parameter for now, it can be made per-VIF later on. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 36 +++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c59ae43b9b35..e347d8ceb682 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -999,7 +999,7 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop) } static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_info *info, int len) + struct ath_tx_info *info, int len, bool rts) { struct ath_hw *ah = sc->sc_ah; struct sk_buff *skb; @@ -1008,6 +1008,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, const struct ieee80211_rate *rate; struct ieee80211_hdr *hdr; struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); + u32 rts_thresh = sc->hw->wiphy->rts_threshold; int i; u8 rix = 0; @@ -1030,7 +1031,17 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, rix = rates[i].idx; info->rates[i].Tries = rates[i].count; - if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { + /* + * Handle RTS threshold for unaggregated HT frames. + */ + if (bf_isampdu(bf) && !bf_isaggr(bf) && + (rates[i].flags & IEEE80211_TX_RC_MCS) && + unlikely(rts_thresh != (u32) -1)) { + if (!rts_thresh || (len > rts_thresh)) + rts = true; + } + + if (rts || rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; info->flags |= ATH9K_TXDESC_RTSENA; } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { @@ -1123,6 +1134,8 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, struct ath_hw *ah = sc->sc_ah; struct ath_buf *bf_first = NULL; struct ath_tx_info info; + u32 rts_thresh = sc->hw->wiphy->rts_threshold; + bool rts = false; memset(&info, 0, sizeof(info)); info.is_first = true; @@ -1159,7 +1172,22 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, info.flags |= (u32) bf->bf_state.bfs_paprd << ATH9K_TXDESC_PAPRD_S; - ath_buf_set_rate(sc, bf, &info, len); + /* + * mac80211 doesn't handle RTS threshold for HT because + * the decision has to be taken based on AMPDU length + * and aggregation is done entirely inside ath9k. + * Set the RTS/CTS flag for the first subframe based + * on the threshold. + */ + if (aggr && (bf == bf_first) && + unlikely(rts_thresh != (u32) -1)) { + /* + * "len" is the size of the entire AMPDU. + */ + if (!rts_thresh || (len > rts_thresh)) + rts = true; + } + ath_buf_set_rate(sc, bf, &info, len, rts); } info.buf_addr[0] = bf->bf_buf_addr; @@ -2142,7 +2170,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bf->bf_lastbf = bf; ath_set_rates(vif, NULL, bf); - ath_buf_set_rate(sc, bf, &info, fi->framelen); + ath_buf_set_rate(sc, bf, &info, fi->framelen, false); duration += info.rates[0].PktDuration; if (bf_tail) bf_tail->bf_next = bf; -- cgit v1.2.3 From 8951b79a4e6d8228babf56ae79a345e4abc5ac82 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 11:25:52 +0200 Subject: rt2x00: rt2800lib: introduce rt2800_eeprom_word enum The patch converts the EEPROM_* word address defines into new enum values. The new enum type will be used by new functions which will be introduced in subsequent changes. The patch contains no functional changes. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 79 ++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index d78c495a86a0..064703933f7c 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2206,28 +2206,59 @@ struct mac_iveiv_entry { * The wordsize of the EEPROM is 16 bits. */ -/* - * Chip ID - */ -#define EEPROM_CHIP_ID 0x0000 +enum rt2800_eeprom_word { + EEPROM_CHIP_ID = 0x0000, + EEPROM_VERSION = 0x0001, + EEPROM_MAC_ADDR_0 = 0x0002, + EEPROM_MAC_ADDR_1 = 0x0003, + EEPROM_MAC_ADDR_2 = 0x0004, + EEPROM_NIC_CONF0 = 0x001a, + EEPROM_NIC_CONF1 = 0x001b, + EEPROM_FREQ = 0x001d, + EEPROM_LED_AG_CONF = 0x001e, + EEPROM_LED_ACT_CONF = 0x001f, + EEPROM_LED_POLARITY = 0x0020, + EEPROM_NIC_CONF2 = 0x0021, + EEPROM_LNA = 0x0022, + EEPROM_RSSI_BG = 0x0023, + EEPROM_RSSI_BG2 = 0x0024, + EEPROM_TXMIXER_GAIN_BG = 0x0024, /* overlaps with RSSI_BG2 */ + EEPROM_RSSI_A = 0x0025, + EEPROM_RSSI_A2 = 0x0026, + EEPROM_TXMIXER_GAIN_A = 0x0026, /* overlaps with RSSI_A2 */ + EEPROM_EIRP_MAX_TX_POWER = 0x0027, + EEPROM_TXPOWER_DELTA = 0x0028, + EEPROM_TXPOWER_BG1 = 0x0029, + EEPROM_TXPOWER_BG2 = 0x0030, + EEPROM_TSSI_BOUND_BG1 = 0x0037, + EEPROM_TSSI_BOUND_BG2 = 0x0038, + EEPROM_TSSI_BOUND_BG3 = 0x0039, + EEPROM_TSSI_BOUND_BG4 = 0x003a, + EEPROM_TSSI_BOUND_BG5 = 0x003b, + EEPROM_TXPOWER_A1 = 0x003c, + EEPROM_TXPOWER_A2 = 0x0053, + EEPROM_TSSI_BOUND_A1 = 0x006a, + EEPROM_TSSI_BOUND_A2 = 0x006b, + EEPROM_TSSI_BOUND_A3 = 0x006c, + EEPROM_TSSI_BOUND_A4 = 0x006d, + EEPROM_TSSI_BOUND_A5 = 0x006e, + EEPROM_TXPOWER_BYRATE = 0x006f, + EEPROM_BBP_START = 0x0078, +}; /* * EEPROM Version */ -#define EEPROM_VERSION 0x0001 #define EEPROM_VERSION_FAE FIELD16(0x00ff) #define EEPROM_VERSION_VERSION FIELD16(0xff00) /* * HW MAC address. */ -#define EEPROM_MAC_ADDR_0 0x0002 #define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) #define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) -#define EEPROM_MAC_ADDR_1 0x0003 #define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) #define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) -#define EEPROM_MAC_ADDR_2 0x0004 #define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) #define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) @@ -2237,7 +2268,6 @@ struct mac_iveiv_entry { * TXPATH: 1: 1T, 2: 2T, 3: 3T * RF_TYPE: RFIC type */ -#define EEPROM_NIC_CONF0 0x001a #define EEPROM_NIC_CONF0_RXPATH FIELD16(0x000f) #define EEPROM_NIC_CONF0_TXPATH FIELD16(0x00f0) #define EEPROM_NIC_CONF0_RF_TYPE FIELD16(0x0f00) @@ -2261,7 +2291,6 @@ struct mac_iveiv_entry { * BT_COEXIST: 0: disable, 1: enable * DAC_TEST: 0: disable, 1: enable */ -#define EEPROM_NIC_CONF1 0x001b #define EEPROM_NIC_CONF1_HW_RADIO FIELD16(0x0001) #define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC FIELD16(0x0002) #define EEPROM_NIC_CONF1_EXTERNAL_LNA_2G FIELD16(0x0004) @@ -2281,7 +2310,6 @@ struct mac_iveiv_entry { /* * EEPROM frequency */ -#define EEPROM_FREQ 0x001d #define EEPROM_FREQ_OFFSET FIELD16(0x00ff) #define EEPROM_FREQ_LED_MODE FIELD16(0x7f00) #define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000) @@ -2298,9 +2326,6 @@ struct mac_iveiv_entry { * POLARITY_GPIO_4: Polarity GPIO4 setting. * LED_MODE: Led mode. */ -#define EEPROM_LED_AG_CONF 0x001e -#define EEPROM_LED_ACT_CONF 0x001f -#define EEPROM_LED_POLARITY 0x0020 #define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001) #define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) #define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) @@ -2317,7 +2342,6 @@ struct mac_iveiv_entry { * TX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream * CRYSTAL: 00: Reserved, 01: One crystal, 10: Two crystal, 11: Reserved */ -#define EEPROM_NIC_CONF2 0x0021 #define EEPROM_NIC_CONF2_RX_STREAM FIELD16(0x000f) #define EEPROM_NIC_CONF2_TX_STREAM FIELD16(0x00f0) #define EEPROM_NIC_CONF2_CRYSTAL FIELD16(0x0600) @@ -2325,54 +2349,46 @@ struct mac_iveiv_entry { /* * EEPROM LNA */ -#define EEPROM_LNA 0x0022 #define EEPROM_LNA_BG FIELD16(0x00ff) #define EEPROM_LNA_A0 FIELD16(0xff00) /* * EEPROM RSSI BG offset */ -#define EEPROM_RSSI_BG 0x0023 #define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff) #define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00) /* * EEPROM RSSI BG2 offset */ -#define EEPROM_RSSI_BG2 0x0024 #define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff) #define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00) /* * EEPROM TXMIXER GAIN BG offset (note overlaps with EEPROM RSSI BG2). */ -#define EEPROM_TXMIXER_GAIN_BG 0x0024 #define EEPROM_TXMIXER_GAIN_BG_VAL FIELD16(0x0007) /* * EEPROM RSSI A offset */ -#define EEPROM_RSSI_A 0x0025 #define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff) #define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00) /* * EEPROM RSSI A2 offset */ -#define EEPROM_RSSI_A2 0x0026 #define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff) #define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) /* * EEPROM TXMIXER GAIN A offset (note overlaps with EEPROM RSSI A2). */ -#define EEPROM_TXMIXER_GAIN_A 0x0026 #define EEPROM_TXMIXER_GAIN_A_VAL FIELD16(0x0007) /* * EEPROM EIRP Maximum TX power values(unit: dbm) */ -#define EEPROM_EIRP_MAX_TX_POWER 0x0027 #define EEPROM_EIRP_MAX_TX_POWER_2GHZ FIELD16(0x00ff) #define EEPROM_EIRP_MAX_TX_POWER_5GHZ FIELD16(0xff00) @@ -2383,7 +2399,6 @@ struct mac_iveiv_entry { * TYPE: 1: Plus the delta value, 0: minus the delta value * ENABLE: enable tx power compensation for 40BW */ -#define EEPROM_TXPOWER_DELTA 0x0028 #define EEPROM_TXPOWER_DELTA_VALUE_2G FIELD16(0x003f) #define EEPROM_TXPOWER_DELTA_TYPE_2G FIELD16(0x0040) #define EEPROM_TXPOWER_DELTA_ENABLE_2G FIELD16(0x0080) @@ -2394,8 +2409,6 @@ struct mac_iveiv_entry { /* * EEPROM TXPOWER 802.11BG */ -#define EEPROM_TXPOWER_BG1 0x0029 -#define EEPROM_TXPOWER_BG2 0x0030 #define EEPROM_TXPOWER_BG_SIZE 7 #define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff) #define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) @@ -2407,7 +2420,6 @@ struct mac_iveiv_entry { * MINUS3: If the actual TSSI is below this boundary, tx power needs to be * reduced by (agc_step * -3) */ -#define EEPROM_TSSI_BOUND_BG1 0x0037 #define EEPROM_TSSI_BOUND_BG1_MINUS4 FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_BG1_MINUS3 FIELD16(0xff00) @@ -2418,7 +2430,6 @@ struct mac_iveiv_entry { * MINUS1: If the actual TSSI is below this boundary, tx power needs to be * reduced by (agc_step * -1) */ -#define EEPROM_TSSI_BOUND_BG2 0x0038 #define EEPROM_TSSI_BOUND_BG2_MINUS2 FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_BG2_MINUS1 FIELD16(0xff00) @@ -2428,7 +2439,6 @@ struct mac_iveiv_entry { * PLUS1: If the actual TSSI is above this boundary, tx power needs to be * increased by (agc_step * 1) */ -#define EEPROM_TSSI_BOUND_BG3 0x0039 #define EEPROM_TSSI_BOUND_BG3_REF FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_BG3_PLUS1 FIELD16(0xff00) @@ -2439,7 +2449,6 @@ struct mac_iveiv_entry { * PLUS3: If the actual TSSI is above this boundary, tx power needs to be * increased by (agc_step * 3) */ -#define EEPROM_TSSI_BOUND_BG4 0x003a #define EEPROM_TSSI_BOUND_BG4_PLUS2 FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_BG4_PLUS3 FIELD16(0xff00) @@ -2449,15 +2458,12 @@ struct mac_iveiv_entry { * increased by (agc_step * 4) * AGC_STEP: Temperature compensation step. */ -#define EEPROM_TSSI_BOUND_BG5 0x003b #define EEPROM_TSSI_BOUND_BG5_PLUS4 FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_BG5_AGC_STEP FIELD16(0xff00) /* * EEPROM TXPOWER 802.11A */ -#define EEPROM_TXPOWER_A1 0x003c -#define EEPROM_TXPOWER_A2 0x0053 #define EEPROM_TXPOWER_A_SIZE 6 #define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) #define EEPROM_TXPOWER_A_2 FIELD16(0xff00) @@ -2469,7 +2475,6 @@ struct mac_iveiv_entry { * MINUS3: If the actual TSSI is below this boundary, tx power needs to be * reduced by (agc_step * -3) */ -#define EEPROM_TSSI_BOUND_A1 0x006a #define EEPROM_TSSI_BOUND_A1_MINUS4 FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_A1_MINUS3 FIELD16(0xff00) @@ -2480,7 +2485,6 @@ struct mac_iveiv_entry { * MINUS1: If the actual TSSI is below this boundary, tx power needs to be * reduced by (agc_step * -1) */ -#define EEPROM_TSSI_BOUND_A2 0x006b #define EEPROM_TSSI_BOUND_A2_MINUS2 FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_A2_MINUS1 FIELD16(0xff00) @@ -2490,7 +2494,6 @@ struct mac_iveiv_entry { * PLUS1: If the actual TSSI is above this boundary, tx power needs to be * increased by (agc_step * 1) */ -#define EEPROM_TSSI_BOUND_A3 0x006c #define EEPROM_TSSI_BOUND_A3_REF FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_A3_PLUS1 FIELD16(0xff00) @@ -2501,7 +2504,6 @@ struct mac_iveiv_entry { * PLUS3: If the actual TSSI is above this boundary, tx power needs to be * increased by (agc_step * 3) */ -#define EEPROM_TSSI_BOUND_A4 0x006d #define EEPROM_TSSI_BOUND_A4_PLUS2 FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_A4_PLUS3 FIELD16(0xff00) @@ -2511,14 +2513,12 @@ struct mac_iveiv_entry { * increased by (agc_step * 4) * AGC_STEP: Temperature compensation step. */ -#define EEPROM_TSSI_BOUND_A5 0x006e #define EEPROM_TSSI_BOUND_A5_PLUS4 FIELD16(0x00ff) #define EEPROM_TSSI_BOUND_A5_AGC_STEP FIELD16(0xff00) /* * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode */ -#define EEPROM_TXPOWER_BYRATE 0x006f #define EEPROM_TXPOWER_BYRATE_SIZE 9 #define EEPROM_TXPOWER_BYRATE_RATE0 FIELD16(0x000f) @@ -2529,7 +2529,6 @@ struct mac_iveiv_entry { /* * EEPROM BBP. */ -#define EEPROM_BBP_START 0x0078 #define EEPROM_BBP_SIZE 16 #define EEPROM_BBP_VALUE FIELD16(0x00ff) #define EEPROM_BBP_REG_ID FIELD16(0xff00) -- cgit v1.2.3 From 3e38d3daf881a78ac13e93504a8ac5777040797e Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 11:25:53 +0200 Subject: rt2x00: rt2800lib: introduce local EEPROM access functions The patch adds rt2800 specific functions for EEPROM data access and changes the code to use these instead of the generic rt2x00_eeprom_* variants. To avoid functional changes, the new functions are wrappers around the corresponding generic rt2x00_eeprom_* routines for now. Functional changes will be implemented in additional patches. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 165 ++++++++++++++++++-------------- 1 file changed, 95 insertions(+), 70 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 1f80ea5e29dd..522f0b19cd14 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -221,6 +221,24 @@ static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static void *rt2800_eeprom_addr(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word word) +{ + return rt2x00_eeprom_addr(rt2x00dev, word); +} + +static void rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word word, u16 *data) +{ + rt2x00_eeprom_read(rt2x00dev, word, data); +} + +static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word word, u16 data) +{ + rt2x00_eeprom_write(rt2x00dev, word, data); +} + static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -609,16 +627,16 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2) u8 offset2; if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom); offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0); offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1); - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2); } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom); offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0); offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1); - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2); } @@ -890,6 +908,9 @@ const struct rt2x00debug rt2800_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { + /* NOTE: The local EEPROM access functions can't + * be used here, use the generic versions instead. + */ .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, @@ -1547,7 +1568,7 @@ static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev) led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3; if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) || led_r_mode != rt2x00_get_field32(reg, LED_CFG_R_LED_MODE)) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); led_ctrl = rt2x00_get_field16(eeprom, EEPROM_FREQ_LED_MODE); if (led_ctrl == 0 || led_ctrl > 0x40) { rt2x00_set_field32(®, LED_CFG_G_LED_MODE, led_g_mode); @@ -1622,7 +1643,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) rt2x00_rt(rt2x00dev, RT3090) || rt2x00_rt(rt2x00dev, RT3352) || rt2x00_rt(rt2x00dev, RT3390)) { - rt2x00_eeprom_read(rt2x00dev, + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY)) @@ -1659,16 +1680,16 @@ static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev, short lna_gain; if (libconf->rf.channel <= 14) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); } else if (libconf->rf.channel <= 64) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); } else if (libconf->rf.channel <= 128) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); } @@ -2798,62 +2819,62 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00 */ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); tssi_bounds[0] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG1_MINUS4); tssi_bounds[1] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG1_MINUS3); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); tssi_bounds[2] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG2_MINUS2); tssi_bounds[3] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG2_MINUS1); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); tssi_bounds[4] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG3_REF); tssi_bounds[5] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG3_PLUS1); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); tssi_bounds[6] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG4_PLUS2); tssi_bounds[7] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG4_PLUS3); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); tssi_bounds[8] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG5_PLUS4); step = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG5_AGC_STEP); } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); tssi_bounds[0] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A1_MINUS4); tssi_bounds[1] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A1_MINUS3); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); tssi_bounds[2] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A2_MINUS2); tssi_bounds[3] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A2_MINUS1); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); tssi_bounds[4] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A3_REF); tssi_bounds[5] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A3_PLUS1); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); tssi_bounds[6] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A4_PLUS2); tssi_bounds[7] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A4_PLUS3); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); tssi_bounds[8] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A5_PLUS4); @@ -2899,7 +2920,7 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, u8 comp_type; int comp_value = 0; - rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); /* * HT40 compensation not required. @@ -2974,12 +2995,12 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, * .11b data rate need add additional 4dbm * when calculating eirp txpower. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + 1, + rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + 1, &eeprom); criterion = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - rt2x00_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, + rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, &eeprom); if (band == IEEE80211_BAND_2GHZ) @@ -3080,7 +3101,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, rt2800_register_read(rt2x00dev, offset, ®); /* read the next four txpower values */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i, + rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i, &eeprom); is_rate_b = i ? 0 : 1; @@ -3129,7 +3150,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); /* read the next four txpower values */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i + 1, + rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i + 1, &eeprom); is_rate_b = 0; @@ -3528,7 +3549,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) || rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, + &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST)) rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000002c); @@ -3989,7 +4011,7 @@ static void rt2800_disable_unused_dac_adc(struct rt2x00_dev *rt2x00dev) u8 value; rt2800_bbp_read(rt2x00dev, 138, &value); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) value |= 0x20; if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) @@ -4402,7 +4424,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) rt2800_disable_unused_dac_adc(rt2x00dev); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); ant = (div_mode == 3) ? 1 : 0; @@ -4488,7 +4510,7 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) rt2800_bbp4_mac_if_ctrl(rt2x00dev); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); ant = (div_mode == 3) ? 1 : 0; rt2800_bbp_read(rt2x00dev, 152, &value); @@ -4557,7 +4579,7 @@ static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) } for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -4728,7 +4750,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3090)) { /* Turn off unused DAC1 and ADC1 to reduce power consumption */ rt2800_bbp_read(rt2x00dev, 138, &bbp); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) @@ -4778,7 +4800,7 @@ static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev) /* Turn off unused DAC1 and ADC1 to reduce power consumption */ rt2800_bbp_read(rt2x00dev, 138, ®); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(®, BBP138_RX_ADC1, 0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) @@ -4884,7 +4906,8 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, + &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST)) rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); else @@ -5456,15 +5479,15 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize LED control */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word); rt2800_mcu_request(rt2x00dev, MCU_LED_AG_CONF, 0xff, word & 0xff, (word >> 8) & 0xff); - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word); rt2800_mcu_request(rt2x00dev, MCU_LED_ACT_CONF, 0xff, word & 0xff, (word >> 8) & 0xff); - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word); rt2800_mcu_request(rt2x00dev, MCU_LED_LED_POLARITY, 0xff, word & 0xff, (word >> 8) & 0xff); @@ -5578,18 +5601,18 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) /* * Start validation of the data that has been read. */ - mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + mac = rt2800_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { eth_random_addr(mac); rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2); rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1); rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820); - rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word); rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } else if (rt2x00_rt(rt2x00dev, RT2860) || rt2x00_rt(rt2x00dev, RT2872)) { @@ -5598,10 +5621,10 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ if (rt2x00_get_field16(word, EEPROM_NIC_CONF0_RXPATH) > 2) rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2); - rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CONF1_HW_RADIO, 0); rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC, 0); @@ -5618,24 +5641,24 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_NIC_CONF1_INTERNAL_TX_ALC, 0); rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BT_COEXIST, 0); rt2x00_set_field16(&word, EEPROM_NIC_CONF1_DAC_TEST, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word); rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); if ((word & 0x00ff) == 0x00ff) { rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_FREQ, word); rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word); } if ((word & 0xff00) == 0xff00) { rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, LED_MODE_TXRX_ACTIVITY); rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8); + rt2800_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555); + rt2800_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221); + rt2800_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8); rt2x00_eeprom_dbg(rt2x00dev, "Led Mode: 0x%04x\n", word); } @@ -5644,17 +5667,17 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) * lna0 as correct value. Note that EEPROM_LNA * is never validated. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &word); default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word); if ((word & 0x00ff) != 0x00ff) { drv_data->txmixer_gain_24g = rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL); @@ -5662,16 +5685,16 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) drv_data->txmixer_gain_24g = 0; } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, default_lna_gain); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); - rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word); if ((word & 0x00ff) != 0x00ff) { drv_data->txmixer_gain_5g = rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL); @@ -5679,21 +5702,21 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) drv_data->txmixer_gain_5g = 0; } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, default_lna_gain); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); return 0; } @@ -5707,7 +5730,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); /* * Identify RF chipset by EEPROM value @@ -5717,7 +5740,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3290) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) - rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf); + rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf); else rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE); @@ -5757,7 +5780,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00dev->default_ant.rx_chain_num = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3090) || @@ -5810,7 +5833,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read frequency offset and RF programming sequence. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); /* @@ -5827,7 +5850,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Check if support EIRP tx power limit feature. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) < EIRP_MAX_TX_POWER_LIMIT) @@ -6148,7 +6171,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, - rt2x00_eeprom_addr(rt2x00dev, + rt2800_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); /* @@ -6164,7 +6187,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->max_report_rates = 7; rt2x00dev->hw->max_rate_tries = 1; - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); /* * Initialize hw_mode information. @@ -6264,8 +6287,8 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels_info = info; - default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); - default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); + default_power1 = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); + default_power2 = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); for (i = 0; i < 14; i++) { info[i].default_power1 = default_power1[i]; @@ -6273,8 +6296,10 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) } if (spec->num_channels > 14) { - default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); - default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); + default_power1 = rt2800_eeprom_addr(rt2x00dev, + EEPROM_TXPOWER_A1); + default_power2 = rt2800_eeprom_addr(rt2x00dev, + EEPROM_TXPOWER_A2); for (i = 14; i < spec->num_channels; i++) { info[i].default_power1 = default_power1[i - 14]; -- cgit v1.2.3 From 022138ca93f016374d5d3f69c070c75596c5ecac Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 11:25:54 +0200 Subject: rt2x00: rt2800lib: introduce rt2800_eeprom_read_from_array helper Add a new helper function and use that for reading single elements of various arrays in the EEPROM. The patch does not change the current behaviour, but it allows to use sequential values for the rt2800_eeprom_word enums. The conversion will be implemented in a subsequent change. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 522f0b19cd14..b59772a71b8b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -239,6 +239,14 @@ static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, rt2x00_eeprom_write(rt2x00dev, word, data); } +static void rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word array, + unsigned int offset, + u16 *data) +{ + rt2x00_eeprom_read(rt2x00dev, array + offset, data); +} + static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -2995,8 +3003,8 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, * .11b data rate need add additional 4dbm * when calculating eirp txpower. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + 1, - &eeprom); + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + 1, &eeprom); criterion = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -3101,8 +3109,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, rt2800_register_read(rt2x00dev, offset, ®); /* read the next four txpower values */ - rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i, - &eeprom); + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + i, &eeprom); is_rate_b = i ? 0 : 1; /* @@ -3150,8 +3158,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); /* read the next four txpower values */ - rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i + 1, - &eeprom); + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + i + 1, &eeprom); is_rate_b = 0; /* @@ -4579,7 +4587,8 @@ static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) } for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2800_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_BBP_START, i, + &eeprom); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); -- cgit v1.2.3 From 379448fe34e289fdcc473399d4f6cac19e757fb8 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 11:25:55 +0200 Subject: rt2x00: rt2800lib: introduce rt2800_eeprom_word_index helper Instead of assign the offset value to the enum directly use a new helper function to convert a rt2800_eeprom_word enum into an index of the rt2x00_dev->eeprom array. The patch does not change the existing behaviour, but makes it possible to add support for three-chain devices which are using a different EEPROM layout. Signed-off-by: Gabor Juhos Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 76 ++++++++++++++-------------- drivers/net/wireless/rt2x00/rt2800lib.c | 87 +++++++++++++++++++++++++++++++-- 2 files changed, 122 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 064703933f7c..bc5c69558ea2 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2207,43 +2207,45 @@ struct mac_iveiv_entry { */ enum rt2800_eeprom_word { - EEPROM_CHIP_ID = 0x0000, - EEPROM_VERSION = 0x0001, - EEPROM_MAC_ADDR_0 = 0x0002, - EEPROM_MAC_ADDR_1 = 0x0003, - EEPROM_MAC_ADDR_2 = 0x0004, - EEPROM_NIC_CONF0 = 0x001a, - EEPROM_NIC_CONF1 = 0x001b, - EEPROM_FREQ = 0x001d, - EEPROM_LED_AG_CONF = 0x001e, - EEPROM_LED_ACT_CONF = 0x001f, - EEPROM_LED_POLARITY = 0x0020, - EEPROM_NIC_CONF2 = 0x0021, - EEPROM_LNA = 0x0022, - EEPROM_RSSI_BG = 0x0023, - EEPROM_RSSI_BG2 = 0x0024, - EEPROM_TXMIXER_GAIN_BG = 0x0024, /* overlaps with RSSI_BG2 */ - EEPROM_RSSI_A = 0x0025, - EEPROM_RSSI_A2 = 0x0026, - EEPROM_TXMIXER_GAIN_A = 0x0026, /* overlaps with RSSI_A2 */ - EEPROM_EIRP_MAX_TX_POWER = 0x0027, - EEPROM_TXPOWER_DELTA = 0x0028, - EEPROM_TXPOWER_BG1 = 0x0029, - EEPROM_TXPOWER_BG2 = 0x0030, - EEPROM_TSSI_BOUND_BG1 = 0x0037, - EEPROM_TSSI_BOUND_BG2 = 0x0038, - EEPROM_TSSI_BOUND_BG3 = 0x0039, - EEPROM_TSSI_BOUND_BG4 = 0x003a, - EEPROM_TSSI_BOUND_BG5 = 0x003b, - EEPROM_TXPOWER_A1 = 0x003c, - EEPROM_TXPOWER_A2 = 0x0053, - EEPROM_TSSI_BOUND_A1 = 0x006a, - EEPROM_TSSI_BOUND_A2 = 0x006b, - EEPROM_TSSI_BOUND_A3 = 0x006c, - EEPROM_TSSI_BOUND_A4 = 0x006d, - EEPROM_TSSI_BOUND_A5 = 0x006e, - EEPROM_TXPOWER_BYRATE = 0x006f, - EEPROM_BBP_START = 0x0078, + EEPROM_CHIP_ID = 0, + EEPROM_VERSION, + EEPROM_MAC_ADDR_0, + EEPROM_MAC_ADDR_1, + EEPROM_MAC_ADDR_2, + EEPROM_NIC_CONF0, + EEPROM_NIC_CONF1, + EEPROM_FREQ, + EEPROM_LED_AG_CONF, + EEPROM_LED_ACT_CONF, + EEPROM_LED_POLARITY, + EEPROM_NIC_CONF2, + EEPROM_LNA, + EEPROM_RSSI_BG, + EEPROM_RSSI_BG2, + EEPROM_TXMIXER_GAIN_BG, + EEPROM_RSSI_A, + EEPROM_RSSI_A2, + EEPROM_TXMIXER_GAIN_A, + EEPROM_EIRP_MAX_TX_POWER, + EEPROM_TXPOWER_DELTA, + EEPROM_TXPOWER_BG1, + EEPROM_TXPOWER_BG2, + EEPROM_TSSI_BOUND_BG1, + EEPROM_TSSI_BOUND_BG2, + EEPROM_TSSI_BOUND_BG3, + EEPROM_TSSI_BOUND_BG4, + EEPROM_TSSI_BOUND_BG5, + EEPROM_TXPOWER_A1, + EEPROM_TXPOWER_A2, + EEPROM_TSSI_BOUND_A1, + EEPROM_TSSI_BOUND_A2, + EEPROM_TSSI_BOUND_A3, + EEPROM_TSSI_BOUND_A4, + EEPROM_TSSI_BOUND_A5, + EEPROM_TXPOWER_BYRATE, + EEPROM_BBP_START, + /* New values must be added before this */ + EEPROM_WORD_COUNT }; /* diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b59772a71b8b..41a34de4a3e2 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -221,22 +221,98 @@ static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = { + [EEPROM_CHIP_ID] = 0x0000, + [EEPROM_VERSION] = 0x0001, + [EEPROM_MAC_ADDR_0] = 0x0002, + [EEPROM_MAC_ADDR_1] = 0x0003, + [EEPROM_MAC_ADDR_2] = 0x0004, + [EEPROM_NIC_CONF0] = 0x001a, + [EEPROM_NIC_CONF1] = 0x001b, + [EEPROM_FREQ] = 0x001d, + [EEPROM_LED_AG_CONF] = 0x001e, + [EEPROM_LED_ACT_CONF] = 0x001f, + [EEPROM_LED_POLARITY] = 0x0020, + [EEPROM_NIC_CONF2] = 0x0021, + [EEPROM_LNA] = 0x0022, + [EEPROM_RSSI_BG] = 0x0023, + [EEPROM_RSSI_BG2] = 0x0024, + [EEPROM_TXMIXER_GAIN_BG] = 0x0024, /* overlaps with RSSI_BG2 */ + [EEPROM_RSSI_A] = 0x0025, + [EEPROM_RSSI_A2] = 0x0026, + [EEPROM_TXMIXER_GAIN_A] = 0x0026, /* overlaps with RSSI_A2 */ + [EEPROM_EIRP_MAX_TX_POWER] = 0x0027, + [EEPROM_TXPOWER_DELTA] = 0x0028, + [EEPROM_TXPOWER_BG1] = 0x0029, + [EEPROM_TXPOWER_BG2] = 0x0030, + [EEPROM_TSSI_BOUND_BG1] = 0x0037, + [EEPROM_TSSI_BOUND_BG2] = 0x0038, + [EEPROM_TSSI_BOUND_BG3] = 0x0039, + [EEPROM_TSSI_BOUND_BG4] = 0x003a, + [EEPROM_TSSI_BOUND_BG5] = 0x003b, + [EEPROM_TXPOWER_A1] = 0x003c, + [EEPROM_TXPOWER_A2] = 0x0053, + [EEPROM_TSSI_BOUND_A1] = 0x006a, + [EEPROM_TSSI_BOUND_A2] = 0x006b, + [EEPROM_TSSI_BOUND_A3] = 0x006c, + [EEPROM_TSSI_BOUND_A4] = 0x006d, + [EEPROM_TSSI_BOUND_A5] = 0x006e, + [EEPROM_TXPOWER_BYRATE] = 0x006f, + [EEPROM_BBP_START] = 0x0078, +}; + +static unsigned int rt2800_eeprom_word_index(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word word) +{ + const unsigned int *map; + unsigned int index; + + if (WARN_ONCE(word >= EEPROM_WORD_COUNT, + "%s: invalid EEPROM word %d\n", + wiphy_name(rt2x00dev->hw->wiphy), word)) + return 0; + + map = rt2800_eeprom_map; + index = map[word]; + + /* Index 0 is valid only for EEPROM_CHIP_ID. + * Otherwise it means that the offset of the + * given word is not initialized in the map, + * or that the field is not usable on the + * actual chipset. + */ + WARN_ONCE(word != EEPROM_CHIP_ID && index == 0, + "%s: invalid access of EEPROM word %d\n", + wiphy_name(rt2x00dev->hw->wiphy), word); + + return index; +} + static void *rt2800_eeprom_addr(struct rt2x00_dev *rt2x00dev, const enum rt2800_eeprom_word word) { - return rt2x00_eeprom_addr(rt2x00dev, word); + unsigned int index; + + index = rt2800_eeprom_word_index(rt2x00dev, word); + return rt2x00_eeprom_addr(rt2x00dev, index); } static void rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev, const enum rt2800_eeprom_word word, u16 *data) { - rt2x00_eeprom_read(rt2x00dev, word, data); + unsigned int index; + + index = rt2800_eeprom_word_index(rt2x00dev, word); + rt2x00_eeprom_read(rt2x00dev, index, data); } static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, const enum rt2800_eeprom_word word, u16 data) { - rt2x00_eeprom_write(rt2x00dev, word, data); + unsigned int index; + + index = rt2800_eeprom_word_index(rt2x00dev, word); + rt2x00_eeprom_write(rt2x00dev, index, data); } static void rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, @@ -244,7 +320,10 @@ static void rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, unsigned int offset, u16 *data) { - rt2x00_eeprom_read(rt2x00dev, array + offset, data); + unsigned int index; + + index = rt2800_eeprom_word_index(rt2x00dev, array); + rt2x00_eeprom_read(rt2x00dev, index + offset, data); } static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) -- cgit v1.2.3 From fa31d157f83ef71b6530aacf0400bafe7816acbd Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 11:25:56 +0200 Subject: rt2x00: rt2800lib: add EEPROM map for the RT3593 chipset Three-chain devices are using a different EEPROM layout than the rest of the chipsets. Add a new map which describes the new layout and use that for the RT3593 chipset. The index values has been computed from the EEPROM_EXT_* defines, which can be found in the 'include/chip/rt3593.h' file in the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 6 +++++ drivers/net/wireless/rt2x00/rt2800lib.c | 48 ++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index bc5c69558ea2..92168347125b 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2244,6 +2244,12 @@ enum rt2800_eeprom_word { EEPROM_TSSI_BOUND_A5, EEPROM_TXPOWER_BYRATE, EEPROM_BBP_START, + + /* IDs for extended EEPROM format used by three-chain devices */ + EEPROM_EXT_LNA2, + EEPROM_EXT_TXPOWER_BG3, + EEPROM_EXT_TXPOWER_A3, + /* New values must be added before this */ EEPROM_WORD_COUNT }; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 41a34de4a3e2..d325ca202865 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -261,6 +261,48 @@ static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = { [EEPROM_BBP_START] = 0x0078, }; +static const unsigned int rt2800_eeprom_map_ext[EEPROM_WORD_COUNT] = { + [EEPROM_CHIP_ID] = 0x0000, + [EEPROM_VERSION] = 0x0001, + [EEPROM_MAC_ADDR_0] = 0x0002, + [EEPROM_MAC_ADDR_1] = 0x0003, + [EEPROM_MAC_ADDR_2] = 0x0004, + [EEPROM_NIC_CONF0] = 0x001a, + [EEPROM_NIC_CONF1] = 0x001b, + [EEPROM_NIC_CONF2] = 0x001c, + [EEPROM_EIRP_MAX_TX_POWER] = 0x0020, + [EEPROM_FREQ] = 0x0022, + [EEPROM_LED_AG_CONF] = 0x0023, + [EEPROM_LED_ACT_CONF] = 0x0024, + [EEPROM_LED_POLARITY] = 0x0025, + [EEPROM_LNA] = 0x0026, + [EEPROM_EXT_LNA2] = 0x0027, + [EEPROM_RSSI_BG] = 0x0028, + [EEPROM_TXPOWER_DELTA] = 0x0028, /* Overlaps with RSSI_BG */ + [EEPROM_RSSI_BG2] = 0x0029, + [EEPROM_TXMIXER_GAIN_BG] = 0x0029, /* Overlaps with RSSI_BG2 */ + [EEPROM_RSSI_A] = 0x002a, + [EEPROM_RSSI_A2] = 0x002b, + [EEPROM_TXMIXER_GAIN_A] = 0x002b, /* Overlaps with RSSI_A2 */ + [EEPROM_TXPOWER_BG1] = 0x0030, + [EEPROM_TXPOWER_BG2] = 0x0037, + [EEPROM_EXT_TXPOWER_BG3] = 0x003e, + [EEPROM_TSSI_BOUND_BG1] = 0x0045, + [EEPROM_TSSI_BOUND_BG2] = 0x0046, + [EEPROM_TSSI_BOUND_BG3] = 0x0047, + [EEPROM_TSSI_BOUND_BG4] = 0x0048, + [EEPROM_TSSI_BOUND_BG5] = 0x0049, + [EEPROM_TXPOWER_A1] = 0x004b, + [EEPROM_TXPOWER_A2] = 0x0065, + [EEPROM_EXT_TXPOWER_A3] = 0x007f, + [EEPROM_TSSI_BOUND_A1] = 0x009a, + [EEPROM_TSSI_BOUND_A2] = 0x009b, + [EEPROM_TSSI_BOUND_A3] = 0x009c, + [EEPROM_TSSI_BOUND_A4] = 0x009d, + [EEPROM_TSSI_BOUND_A5] = 0x009e, + [EEPROM_TXPOWER_BYRATE] = 0x00a0, +}; + static unsigned int rt2800_eeprom_word_index(struct rt2x00_dev *rt2x00dev, const enum rt2800_eeprom_word word) { @@ -272,7 +314,11 @@ static unsigned int rt2800_eeprom_word_index(struct rt2x00_dev *rt2x00dev, wiphy_name(rt2x00dev->hw->wiphy), word)) return 0; - map = rt2800_eeprom_map; + if (rt2x00_rt(rt2x00dev, RT3593)) + map = rt2800_eeprom_map_ext; + else + map = rt2800_eeprom_map; + index = map[word]; /* Index 0 is valid only for EEPROM_CHIP_ID. -- cgit v1.2.3 From 1706d15d82f4a579119b419cd673987af60f1d9b Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:16 +0200 Subject: rt2x00: rt2800lib: add MAC register initialization for RT3593 Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: NICInitRT3593MacRegisters in chips/rt3593.c Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 1 + drivers/net/wireless/rt2x00/rt2800lib.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 92168347125b..02bc80dc7b5f 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -88,6 +88,7 @@ #define REV_RT3071E 0x0211 #define REV_RT3090E 0x0211 #define REV_RT3390E 0x0211 +#define REV_RT3593E 0x0211 #define REV_RT5390F 0x0502 #define REV_RT5390R 0x1502 #define REV_RT5592C 0x0221 diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index d325ca202865..bfeca299acb9 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3714,6 +3714,23 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) } else if (rt2x00_rt(rt2x00dev, RT3572)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + } else if (rt2x00_rt(rt2x00dev, RT3593)) { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); + if (rt2x00_rt_rev_lt(rt2x00dev, RT3593, REV_RT3593E)) { + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, + &eeprom); + if (rt2x00_get_field16(eeprom, + EEPROM_NIC_CONF1_DAC_TEST)) + rt2800_register_write(rt2x00dev, TX_SW_CFG2, + 0x0000001f); + else + rt2800_register_write(rt2x00dev, TX_SW_CFG2, + 0x0000000f); + } else { + rt2800_register_write(rt2x00dev, TX_SW_CFG2, + 0x00000000); + } } else if (rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392) || rt2x00_rt(rt2x00dev, RT5592)) { -- cgit v1.2.3 From b189a1814135bc52f516ca61a1fa161914d57a54 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:17 +0200 Subject: rt2x00: rt2800lib: add BBP register initialization for RT3593 Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. References: NICInitRT3593BbpRegisters in chips/rt3593.c NICInitBBP in common/rtmp_init.c NICInitAsicFromEEPROM in common/rtmp_init.c Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index bfeca299acb9..53ebdb96818d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4504,6 +4504,22 @@ static void rt2800_init_bbp_3572(struct rt2x00_dev *rt2x00dev) rt2800_disable_unused_dac_adc(rt2x00dev); } +static void rt2800_init_bbp_3593(struct rt2x00_dev *rt2x00dev) +{ + rt2800_init_bbp_early(rt2x00dev); + + rt2800_bbp_write(rt2x00dev, 79, 0x13); + rt2800_bbp_write(rt2x00dev, 80, 0x05); + rt2800_bbp_write(rt2x00dev, 81, 0x33); + rt2800_bbp_write(rt2x00dev, 137, 0x0f); + + rt2800_bbp_write(rt2x00dev, 84, 0x19); + + /* Enable DC filter */ + if (rt2x00_rt_rev_gte(rt2x00dev, RT3593, REV_RT3593E)) + rt2800_bbp_write(rt2x00dev, 103, 0xc0); +} + static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) { int ant, div_mode; @@ -4719,6 +4735,9 @@ static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) case RT3572: rt2800_init_bbp_3572(rt2x00dev); break; + case RT3593: + rt2800_init_bbp_3593(rt2x00dev); + return; case RT5390: case RT5392: rt2800_init_bbp_53xx(rt2x00dev); -- cgit v1.2.3 From ab7078ac3d920e0d49b17e92f327f3ada25600e8 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:18 +0200 Subject: rt2x00: rt2800lib: add RFCSR register initialization for RT3593 Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. References: NICInitRT3593RFRegisters in chips/rt3593.c RT3593LoadRFNormalModeSetup in chips/rt3593.c Signed-off-by: Gabor Juhos Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 10 +++ drivers/net/wireless/rt2x00/rt2800lib.c | 122 ++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 02bc80dc7b5f..47aceaea5d66 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2093,6 +2093,10 @@ struct mac_iveiv_entry { #define RFCSR17_R FIELD8(0x20) #define RFCSR17_CODE FIELD8(0x7f) +/* RFCSR 18 */ +#define RFCSR18_XO_TUNE_BYPASS FIELD8(0x40) + + /* * RFCSR 20: */ @@ -2174,6 +2178,12 @@ struct mac_iveiv_entry { */ #define RFCSR50_TX FIELD8(0x3f) #define RFCSR50_EP FIELD8(0xc0) +/* bits for RT3593*/ +#define RFCSR50_TX_LO2_EN FIELD8(0x10) + +/* RFCSR 51 */ +/* bits for RT3593*/ +#define RFCSR51_BITS24 FIELD8(0x1c) /* * RF registers diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 53ebdb96818d..b6505699629a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4963,6 +4963,42 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) } } +static void rt2800_normal_mode_setup_3593(struct rt2x00_dev *rt2x00dev) +{ + struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; + u8 rfcsr; + u8 tx_gain; + + rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO2_EN, 0); + rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + tx_gain = rt2x00_get_field8(drv_data->txmixer_gain_24g, + RFCSR17_TXMIXER_GAIN); + rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, tx_gain); + rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0); + rt2800_rfcsr_write(rt2x00dev, 38, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 39, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR39_RX_LO2_EN, 0); + rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); + rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); + rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + + /* TODO: enable stream mode */ +} + static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev) { u8 reg; @@ -5345,6 +5381,89 @@ static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev) rt2800_normal_mode_setup_3xxx(rt2x00dev); } +static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) +{ + struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; + u32 reg; + u8 rfcsr; + + /* Disable GPIO #4 and #7 function for LAN PE control */ + rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + rt2x00_set_field32(®, GPIO_SWITCH_4, 0); + rt2x00_set_field32(®, GPIO_SWITCH_7, 0); + rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); + + /* Initialize default register values */ + rt2800_rfcsr_write(rt2x00dev, 1, 0x03); + rt2800_rfcsr_write(rt2x00dev, 3, 0x80); + rt2800_rfcsr_write(rt2x00dev, 5, 0x00); + rt2800_rfcsr_write(rt2x00dev, 6, 0x40); + rt2800_rfcsr_write(rt2x00dev, 8, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 9, 0x02); + rt2800_rfcsr_write(rt2x00dev, 10, 0xd3); + rt2800_rfcsr_write(rt2x00dev, 11, 0x40); + rt2800_rfcsr_write(rt2x00dev, 12, 0x4e); + rt2800_rfcsr_write(rt2x00dev, 13, 0x12); + rt2800_rfcsr_write(rt2x00dev, 18, 0x40); + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x78); + rt2800_rfcsr_write(rt2x00dev, 33, 0x3b); + rt2800_rfcsr_write(rt2x00dev, 34, 0x3c); + rt2800_rfcsr_write(rt2x00dev, 35, 0xe0); + rt2800_rfcsr_write(rt2x00dev, 38, 0x86); + rt2800_rfcsr_write(rt2x00dev, 39, 0x23); + rt2800_rfcsr_write(rt2x00dev, 44, 0xd3); + rt2800_rfcsr_write(rt2x00dev, 45, 0xbb); + rt2800_rfcsr_write(rt2x00dev, 46, 0x60); + rt2800_rfcsr_write(rt2x00dev, 49, 0x8e); + rt2800_rfcsr_write(rt2x00dev, 50, 0x86); + rt2800_rfcsr_write(rt2x00dev, 51, 0x75); + rt2800_rfcsr_write(rt2x00dev, 52, 0x45); + rt2800_rfcsr_write(rt2x00dev, 53, 0x18); + rt2800_rfcsr_write(rt2x00dev, 54, 0x18); + rt2800_rfcsr_write(rt2x00dev, 55, 0x18); + rt2800_rfcsr_write(rt2x00dev, 56, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 57, 0x6e); + + /* Initiate calibration */ + /* TODO: use rt2800_rf_init_calibration ? */ + rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1); + rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); + + rt2800_adjust_freq_offset(rt2x00dev); + + rt2800_rfcsr_read(rt2x00dev, 18, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR18_XO_TUNE_BYPASS, 1); + rt2800_rfcsr_write(rt2x00dev, 18, rfcsr); + + rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); + rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); + rt2800_register_write(rt2x00dev, LDO_CFG0, reg); + usleep_range(1000, 1500); + rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0); + rt2800_register_write(rt2x00dev, LDO_CFG0, reg); + + /* Set initial values for RX filter calibration */ + drv_data->calibration_bw20 = 0x1f; + drv_data->calibration_bw40 = 0x2f; + + /* Save BBP 25 & 26 values for later use in channel switching */ + rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25); + rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26); + + rt2800_led_open_drain_enable(rt2x00dev); + rt2800_normal_mode_setup_3593(rt2x00dev); + + /* TODO: post BBP initialization */ + + /* TODO: enable stream mode support */ +} + static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) { rt2800_rf_init_calibration(rt2x00dev, 2); @@ -5573,6 +5692,9 @@ static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) case RT3572: rt2800_init_rfcsr_3572(rt2x00dev); break; + case RT3593: + rt2800_init_rfcsr_3593(rt2x00dev); + break; case RT5390: rt2800_init_rfcsr_5390(rt2x00dev); break; -- cgit v1.2.3 From d63f7e8ca560dc9a76a15c323cb9cba14b25f430 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:19 +0200 Subject: rt2x00: rt2800lib: add BBP post initialization for RT3593 Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: RT3593_PostBBPInitialization in chips/rt3553.c Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 48 ++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b6505699629a..7b5c593b6118 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -5381,6 +5381,52 @@ static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev) rt2800_normal_mode_setup_3xxx(rt2x00dev); } +static void rt3593_post_bbp_init(struct rt2x00_dev *rt2x00dev) +{ + u8 bbp; + bool txbf_enabled = false; /* FIXME */ + + rt2800_bbp_read(rt2x00dev, 105, &bbp); + if (rt2x00dev->default_ant.rx_chain_num == 1) + rt2x00_set_field8(&bbp, BBP105_MLD, 0); + else + rt2x00_set_field8(&bbp, BBP105_MLD, 1); + rt2800_bbp_write(rt2x00dev, 105, bbp); + + rt2800_bbp4_mac_if_ctrl(rt2x00dev); + + rt2800_bbp_write(rt2x00dev, 92, 0x02); + rt2800_bbp_write(rt2x00dev, 82, 0x82); + rt2800_bbp_write(rt2x00dev, 106, 0x05); + rt2800_bbp_write(rt2x00dev, 104, 0x92); + rt2800_bbp_write(rt2x00dev, 88, 0x90); + rt2800_bbp_write(rt2x00dev, 148, 0xc8); + rt2800_bbp_write(rt2x00dev, 47, 0x48); + rt2800_bbp_write(rt2x00dev, 120, 0x50); + + if (txbf_enabled) + rt2800_bbp_write(rt2x00dev, 163, 0xbd); + else + rt2800_bbp_write(rt2x00dev, 163, 0x9d); + + /* SNR mapping */ + rt2800_bbp_write(rt2x00dev, 142, 6); + rt2800_bbp_write(rt2x00dev, 143, 160); + rt2800_bbp_write(rt2x00dev, 142, 7); + rt2800_bbp_write(rt2x00dev, 143, 161); + rt2800_bbp_write(rt2x00dev, 142, 8); + rt2800_bbp_write(rt2x00dev, 143, 162); + + /* ADC/DAC control */ + rt2800_bbp_write(rt2x00dev, 31, 0x08); + + /* RX AGC energy lower bound in log2 */ + rt2800_bbp_write(rt2x00dev, 68, 0x0b); + + /* FIXME: BBP 105 owerwrite? */ + rt2800_bbp_write(rt2x00dev, 105, 0x04); +} + static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) { struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; @@ -5459,7 +5505,7 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) rt2800_led_open_drain_enable(rt2x00dev); rt2800_normal_mode_setup_3593(rt2x00dev); - /* TODO: post BBP initialization */ + rt3593_post_bbp_init(rt2x00dev); /* TODO: enable stream mode support */ } -- cgit v1.2.3 From 34542ff5a665061d548c3f860807df341f718adf Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:20 +0200 Subject: rt2x00: rt2800lib: add TX power configuration for RT3593 Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. References: RTMPReadTxPwrPerRateExt in chips/rt3593.c RT3593_AsicGetTxPowerOffset in chips/rt3593.c Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 116 +++++++++ drivers/net/wireless/rt2x00/rt2800lib.c | 425 +++++++++++++++++++++++++++++++- 2 files changed, 538 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 47aceaea5d66..7b7caeb01e5a 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1083,6 +1083,15 @@ #define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000) #define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000) #define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000) +/* bits for 3T devices */ +#define TX_PWR_CFG_0_CCK1_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_0_CCK1_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_0_CCK5_CH0 FIELD32(0x00000f00) +#define TX_PWR_CFG_0_CCK5_CH1 FIELD32(0x0000f000) +#define TX_PWR_CFG_0_OFDM6_CH0 FIELD32(0x000f0000) +#define TX_PWR_CFG_0_OFDM6_CH1 FIELD32(0x00f00000) +#define TX_PWR_CFG_0_OFDM12_CH0 FIELD32(0x0f000000) +#define TX_PWR_CFG_0_OFDM12_CH1 FIELD32(0xf0000000) /* * TX_PWR_CFG_1: @@ -1096,6 +1105,15 @@ #define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000) #define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000) #define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000) +/* bits for 3T devices */ +#define TX_PWR_CFG_1_OFDM24_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_1_OFDM24_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_1_OFDM48_CH0 FIELD32(0x00000f00) +#define TX_PWR_CFG_1_OFDM48_CH1 FIELD32(0x0000f000) +#define TX_PWR_CFG_1_MCS0_CH0 FIELD32(0x000f0000) +#define TX_PWR_CFG_1_MCS0_CH1 FIELD32(0x00f00000) +#define TX_PWR_CFG_1_MCS2_CH0 FIELD32(0x0f000000) +#define TX_PWR_CFG_1_MCS2_CH1 FIELD32(0xf0000000) /* * TX_PWR_CFG_2: @@ -1109,6 +1127,15 @@ #define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000) #define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000) #define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000) +/* bits for 3T devices */ +#define TX_PWR_CFG_2_MCS4_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_2_MCS4_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_2_MCS6_CH0 FIELD32(0x00000f00) +#define TX_PWR_CFG_2_MCS6_CH1 FIELD32(0x0000f000) +#define TX_PWR_CFG_2_MCS8_CH0 FIELD32(0x000f0000) +#define TX_PWR_CFG_2_MCS8_CH1 FIELD32(0x00f00000) +#define TX_PWR_CFG_2_MCS10_CH0 FIELD32(0x0f000000) +#define TX_PWR_CFG_2_MCS10_CH1 FIELD32(0xf0000000) /* * TX_PWR_CFG_3: @@ -1122,6 +1149,15 @@ #define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000) #define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000) #define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000) +/* bits for 3T devices */ +#define TX_PWR_CFG_3_MCS12_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_3_MCS12_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_3_MCS14_CH0 FIELD32(0x00000f00) +#define TX_PWR_CFG_3_MCS14_CH1 FIELD32(0x0000f000) +#define TX_PWR_CFG_3_STBC0_CH0 FIELD32(0x000f0000) +#define TX_PWR_CFG_3_STBC0_CH1 FIELD32(0x00f00000) +#define TX_PWR_CFG_3_STBC2_CH0 FIELD32(0x0f000000) +#define TX_PWR_CFG_3_STBC2_CH1 FIELD32(0xf0000000) /* * TX_PWR_CFG_4: @@ -1131,6 +1167,11 @@ #define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0) #define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00) #define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000) +/* bits for 3T devices */ +#define TX_PWR_CFG_3_STBC4_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_3_STBC4_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_3_STBC6_CH0 FIELD32(0x00000f00) +#define TX_PWR_CFG_3_STBC6_CH1 FIELD32(0x0000f000) /* * TX_PIN_CFG: @@ -1452,6 +1493,81 @@ */ #define EXP_ACK_TIME 0x1380 +/* TX_PWR_CFG_5 */ +#define TX_PWR_CFG_5 0x1384 +#define TX_PWR_CFG_5_MCS16_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_5_MCS16_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_5_MCS16_CH2 FIELD32(0x00000f00) +#define TX_PWR_CFG_5_MCS18_CH0 FIELD32(0x000f0000) +#define TX_PWR_CFG_5_MCS18_CH1 FIELD32(0x00f00000) +#define TX_PWR_CFG_5_MCS18_CH2 FIELD32(0x0f000000) + +/* TX_PWR_CFG_6 */ +#define TX_PWR_CFG_6 0x1388 +#define TX_PWR_CFG_6_MCS20_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_6_MCS20_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_6_MCS20_CH2 FIELD32(0x00000f00) +#define TX_PWR_CFG_6_MCS22_CH0 FIELD32(0x000f0000) +#define TX_PWR_CFG_6_MCS22_CH1 FIELD32(0x00f00000) +#define TX_PWR_CFG_6_MCS22_CH2 FIELD32(0x0f000000) + +/* TX_PWR_CFG_0_EXT */ +#define TX_PWR_CFG_0_EXT 0x1390 +#define TX_PWR_CFG_0_EXT_CCK1_CH2 FIELD32(0x0000000f) +#define TX_PWR_CFG_0_EXT_CCK5_CH2 FIELD32(0x00000f00) +#define TX_PWR_CFG_0_EXT_OFDM6_CH2 FIELD32(0x000f0000) +#define TX_PWR_CFG_0_EXT_OFDM12_CH2 FIELD32(0x0f000000) + +/* TX_PWR_CFG_1_EXT */ +#define TX_PWR_CFG_1_EXT 0x1394 +#define TX_PWR_CFG_1_EXT_OFDM24_CH2 FIELD32(0x0000000f) +#define TX_PWR_CFG_1_EXT_OFDM48_CH2 FIELD32(0x00000f00) +#define TX_PWR_CFG_1_EXT_MCS0_CH2 FIELD32(0x000f0000) +#define TX_PWR_CFG_1_EXT_MCS2_CH2 FIELD32(0x0f000000) + +/* TX_PWR_CFG_2_EXT */ +#define TX_PWR_CFG_2_EXT 0x1398 +#define TX_PWR_CFG_2_EXT_MCS4_CH2 FIELD32(0x0000000f) +#define TX_PWR_CFG_2_EXT_MCS6_CH2 FIELD32(0x00000f00) +#define TX_PWR_CFG_2_EXT_MCS8_CH2 FIELD32(0x000f0000) +#define TX_PWR_CFG_2_EXT_MCS10_CH2 FIELD32(0x0f000000) + +/* TX_PWR_CFG_3_EXT */ +#define TX_PWR_CFG_3_EXT 0x139c +#define TX_PWR_CFG_3_EXT_MCS12_CH2 FIELD32(0x0000000f) +#define TX_PWR_CFG_3_EXT_MCS14_CH2 FIELD32(0x00000f00) +#define TX_PWR_CFG_3_EXT_STBC0_CH2 FIELD32(0x000f0000) +#define TX_PWR_CFG_3_EXT_STBC2_CH2 FIELD32(0x0f000000) + +/* TX_PWR_CFG_4_EXT */ +#define TX_PWR_CFG_4_EXT 0x13a0 +#define TX_PWR_CFG_4_EXT_STBC4_CH2 FIELD32(0x0000000f) +#define TX_PWR_CFG_4_EXT_STBC6_CH2 FIELD32(0x00000f00) + +/* TX_PWR_CFG_7 */ +#define TX_PWR_CFG_7 0x13d4 +#define TX_PWR_CFG_7_OFDM54_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_7_OFDM54_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_7_OFDM54_CH2 FIELD32(0x00000f00) +#define TX_PWR_CFG_7_MCS7_CH0 FIELD32(0x000f0000) +#define TX_PWR_CFG_7_MCS7_CH1 FIELD32(0x00f00000) +#define TX_PWR_CFG_7_MCS7_CH2 FIELD32(0x0f000000) + +/* TX_PWR_CFG_8 */ +#define TX_PWR_CFG_8 0x13d8 +#define TX_PWR_CFG_8_MCS15_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_8_MCS15_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_8_MCS15_CH2 FIELD32(0x00000f00) +#define TX_PWR_CFG_8_MCS23_CH0 FIELD32(0x000f0000) +#define TX_PWR_CFG_8_MCS23_CH1 FIELD32(0x00f00000) +#define TX_PWR_CFG_8_MCS23_CH2 FIELD32(0x0f000000) + +/* TX_PWR_CFG_9 */ +#define TX_PWR_CFG_9 0x13dc +#define TX_PWR_CFG_9_STBC7_CH0 FIELD32(0x0000000f) +#define TX_PWR_CFG_9_STBC7_CH1 FIELD32(0x000000f0) +#define TX_PWR_CFG_9_STBC7_CH2 FIELD32(0x00000f00) + /* * RX_FILTER_CFG: RX configuration register. */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 7b5c593b6118..e817278390f6 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3120,6 +3120,9 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, u8 eirp_txpower_criterion; u8 reg_limit; + if (rt2x00_rt(rt2x00dev, RT3593)) + return min_t(u8, txpower, 0xc); + if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) { /* * Check if eirp txpower exceed txpower_limit. @@ -3155,6 +3158,412 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, return min_t(u8, txpower, 0xc); } + +enum { + TX_PWR_CFG_0_IDX, + TX_PWR_CFG_1_IDX, + TX_PWR_CFG_2_IDX, + TX_PWR_CFG_3_IDX, + TX_PWR_CFG_4_IDX, + TX_PWR_CFG_5_IDX, + TX_PWR_CFG_6_IDX, + TX_PWR_CFG_7_IDX, + TX_PWR_CFG_8_IDX, + TX_PWR_CFG_9_IDX, + TX_PWR_CFG_0_EXT_IDX, + TX_PWR_CFG_1_EXT_IDX, + TX_PWR_CFG_2_EXT_IDX, + TX_PWR_CFG_3_EXT_IDX, + TX_PWR_CFG_4_EXT_IDX, + TX_PWR_CFG_IDX_COUNT, +}; + +static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, + struct ieee80211_channel *chan, + int power_level) +{ + u8 txpower; + u16 eeprom; + u32 regs[TX_PWR_CFG_IDX_COUNT]; + unsigned int offset; + enum ieee80211_band band = chan->band; + int delta; + int i; + + memset(regs, '\0', sizeof(regs)); + + /* TODO: adapt TX power reduction from the rt28xx code */ + + /* calculate temperature compensation delta */ + delta = rt2800_get_gain_calibration_delta(rt2x00dev); + + if (band == IEEE80211_BAND_5GHZ) + offset = 16; + else + offset = 0; + + if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) + offset += 8; + + /* read the next four txpower values */ + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset, &eeprom); + + /* CCK 1MBS,2MBS */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); + txpower = rt2800_compensate_txpower(rt2x00dev, 1, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_0_IDX], + TX_PWR_CFG_0_CCK1_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_0_IDX], + TX_PWR_CFG_0_CCK1_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_0_EXT_IDX], + TX_PWR_CFG_0_EXT_CCK1_CH2, txpower); + + /* CCK 5.5MBS,11MBS */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); + txpower = rt2800_compensate_txpower(rt2x00dev, 1, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_0_IDX], + TX_PWR_CFG_0_CCK5_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_0_IDX], + TX_PWR_CFG_0_CCK5_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_0_EXT_IDX], + TX_PWR_CFG_0_EXT_CCK5_CH2, txpower); + + /* OFDM 6MBS,9MBS */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_0_IDX], + TX_PWR_CFG_0_OFDM6_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_0_IDX], + TX_PWR_CFG_0_OFDM6_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_0_EXT_IDX], + TX_PWR_CFG_0_EXT_OFDM6_CH2, txpower); + + /* OFDM 12MBS,18MBS */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_0_IDX], + TX_PWR_CFG_0_OFDM12_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_0_IDX], + TX_PWR_CFG_0_OFDM12_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_0_EXT_IDX], + TX_PWR_CFG_0_EXT_OFDM12_CH2, txpower); + + /* read the next four txpower values */ + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 1, &eeprom); + + /* OFDM 24MBS,36MBS */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_1_IDX], + TX_PWR_CFG_1_OFDM24_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_1_IDX], + TX_PWR_CFG_1_OFDM24_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_1_EXT_IDX], + TX_PWR_CFG_1_EXT_OFDM24_CH2, txpower); + + /* OFDM 48MBS */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_1_IDX], + TX_PWR_CFG_1_OFDM48_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_1_IDX], + TX_PWR_CFG_1_OFDM48_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_1_EXT_IDX], + TX_PWR_CFG_1_EXT_OFDM48_CH2, txpower); + + /* OFDM 54MBS */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_7_IDX], + TX_PWR_CFG_7_OFDM54_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_7_IDX], + TX_PWR_CFG_7_OFDM54_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_7_IDX], + TX_PWR_CFG_7_OFDM54_CH2, txpower); + + /* read the next four txpower values */ + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 2, &eeprom); + + /* MCS 0,1 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_1_IDX], + TX_PWR_CFG_1_MCS0_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_1_IDX], + TX_PWR_CFG_1_MCS0_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_1_EXT_IDX], + TX_PWR_CFG_1_EXT_MCS0_CH2, txpower); + + /* MCS 2,3 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_1_IDX], + TX_PWR_CFG_1_MCS2_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_1_IDX], + TX_PWR_CFG_1_MCS2_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_1_EXT_IDX], + TX_PWR_CFG_1_EXT_MCS2_CH2, txpower); + + /* MCS 4,5 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_2_IDX], + TX_PWR_CFG_2_MCS4_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_2_IDX], + TX_PWR_CFG_2_MCS4_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_2_EXT_IDX], + TX_PWR_CFG_2_EXT_MCS4_CH2, txpower); + + /* MCS 6 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_2_IDX], + TX_PWR_CFG_2_MCS6_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_2_IDX], + TX_PWR_CFG_2_MCS6_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_2_EXT_IDX], + TX_PWR_CFG_2_EXT_MCS6_CH2, txpower); + + /* read the next four txpower values */ + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 3, &eeprom); + + /* MCS 7 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_7_IDX], + TX_PWR_CFG_7_MCS7_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_7_IDX], + TX_PWR_CFG_7_MCS7_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_7_IDX], + TX_PWR_CFG_7_MCS7_CH2, txpower); + + /* MCS 8,9 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_2_IDX], + TX_PWR_CFG_2_MCS8_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_2_IDX], + TX_PWR_CFG_2_MCS8_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_2_EXT_IDX], + TX_PWR_CFG_2_EXT_MCS8_CH2, txpower); + + /* MCS 10,11 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_2_IDX], + TX_PWR_CFG_2_MCS10_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_2_IDX], + TX_PWR_CFG_2_MCS10_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_2_EXT_IDX], + TX_PWR_CFG_2_EXT_MCS10_CH2, txpower); + + /* MCS 12,13 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_3_IDX], + TX_PWR_CFG_3_MCS12_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_3_IDX], + TX_PWR_CFG_3_MCS12_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_3_EXT_IDX], + TX_PWR_CFG_3_EXT_MCS12_CH2, txpower); + + /* read the next four txpower values */ + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 4, &eeprom); + + /* MCS 14 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_3_IDX], + TX_PWR_CFG_3_MCS14_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_3_IDX], + TX_PWR_CFG_3_MCS14_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_3_EXT_IDX], + TX_PWR_CFG_3_EXT_MCS14_CH2, txpower); + + /* MCS 15 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_8_IDX], + TX_PWR_CFG_8_MCS15_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_8_IDX], + TX_PWR_CFG_8_MCS15_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_8_IDX], + TX_PWR_CFG_8_MCS15_CH2, txpower); + + /* MCS 16,17 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_5_IDX], + TX_PWR_CFG_5_MCS16_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_5_IDX], + TX_PWR_CFG_5_MCS16_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_5_IDX], + TX_PWR_CFG_5_MCS16_CH2, txpower); + + /* MCS 18,19 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_5_IDX], + TX_PWR_CFG_5_MCS18_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_5_IDX], + TX_PWR_CFG_5_MCS18_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_5_IDX], + TX_PWR_CFG_5_MCS18_CH2, txpower); + + /* read the next four txpower values */ + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 5, &eeprom); + + /* MCS 20,21 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_6_IDX], + TX_PWR_CFG_6_MCS20_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_6_IDX], + TX_PWR_CFG_6_MCS20_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_6_IDX], + TX_PWR_CFG_6_MCS20_CH2, txpower); + + /* MCS 22 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_6_IDX], + TX_PWR_CFG_6_MCS22_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_6_IDX], + TX_PWR_CFG_6_MCS22_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_6_IDX], + TX_PWR_CFG_6_MCS22_CH2, txpower); + + /* MCS 23 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_8_IDX], + TX_PWR_CFG_8_MCS23_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_8_IDX], + TX_PWR_CFG_8_MCS23_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_8_IDX], + TX_PWR_CFG_8_MCS23_CH2, txpower); + + /* read the next four txpower values */ + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 6, &eeprom); + + /* STBC, MCS 0,1 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_3_IDX], + TX_PWR_CFG_3_STBC0_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_3_IDX], + TX_PWR_CFG_3_STBC0_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_3_EXT_IDX], + TX_PWR_CFG_3_EXT_STBC0_CH2, txpower); + + /* STBC, MCS 2,3 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_3_IDX], + TX_PWR_CFG_3_STBC2_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_3_IDX], + TX_PWR_CFG_3_STBC2_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_3_EXT_IDX], + TX_PWR_CFG_3_EXT_STBC2_CH2, txpower); + + /* STBC, MCS 4,5 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_4_EXT_IDX], TX_PWR_CFG_RATE0, + txpower); + + /* STBC, MCS 6 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE2, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE3, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_4_EXT_IDX], TX_PWR_CFG_RATE2, + txpower); + + /* read the next four txpower values */ + rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 7, &eeprom); + + /* STBC, MCS 7 */ + txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); + txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level, + txpower, delta); + rt2x00_set_field32(®s[TX_PWR_CFG_9_IDX], + TX_PWR_CFG_9_STBC7_CH0, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_9_IDX], + TX_PWR_CFG_9_STBC7_CH1, txpower); + rt2x00_set_field32(®s[TX_PWR_CFG_9_IDX], + TX_PWR_CFG_9_STBC7_CH2, txpower); + + rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, regs[TX_PWR_CFG_0_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, regs[TX_PWR_CFG_1_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, regs[TX_PWR_CFG_2_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, regs[TX_PWR_CFG_3_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, regs[TX_PWR_CFG_4_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_5, regs[TX_PWR_CFG_5_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_6, regs[TX_PWR_CFG_6_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_7, regs[TX_PWR_CFG_7_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_8, regs[TX_PWR_CFG_8_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_9, regs[TX_PWR_CFG_9_IDX]); + + rt2800_register_write(rt2x00dev, TX_PWR_CFG_0_EXT, + regs[TX_PWR_CFG_0_EXT_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_1_EXT, + regs[TX_PWR_CFG_1_EXT_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_2_EXT, + regs[TX_PWR_CFG_2_EXT_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_3_EXT, + regs[TX_PWR_CFG_3_EXT_IDX]); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_4_EXT, + regs[TX_PWR_CFG_4_EXT_IDX]); + + for (i = 0; i < TX_PWR_CFG_IDX_COUNT; i++) + rt2x00_dbg(rt2x00dev, + "band:%cGHz, BW:%c0MHz, TX_PWR_CFG_%d%s = %08lx\n", + (band == IEEE80211_BAND_5GHZ) ? '5' : '2', + (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) ? + '4' : '2', + (i > TX_PWR_CFG_9_IDX) ? + (i - TX_PWR_CFG_9_IDX - 1) : i, + (i > TX_PWR_CFG_9_IDX) ? "_EXT" : "", + (unsigned long) regs[i]); +} + /* * We configure transmit power using MAC TX_PWR_CFG_{0,...,N} registers and * BBP R1 register. TX_PWR_CFG_X allow to configure per rate TX power values, @@ -3164,9 +3573,9 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, * EEPROM_TXPOWER_BYRATE offset. We adjust them and BBP R1 settings according to * current conditions (i.e. band, bandwidth, temperature, user settings). */ -static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, - struct ieee80211_channel *chan, - int power_level) +static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, + struct ieee80211_channel *chan, + int power_level) { u8 txpower, r1; u16 eeprom; @@ -3338,6 +3747,16 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, } } +static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, + struct ieee80211_channel *chan, + int power_level) +{ + if (rt2x00_rt(rt2x00dev, RT3593)) + rt2800_config_txpower_rt3593(rt2x00dev, chan, power_level); + else + rt2800_config_txpower_rt28xx(rt2x00dev, chan, power_level); +} + void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev) { rt2800_config_txpower(rt2x00dev, rt2x00dev->hw->conf.chandef.chan, -- cgit v1.2.3 From 4788ac1e4842d8ef46ee620cfccf96c426043177 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:21 +0200 Subject: rt2x00: rt2800lib: fix BBP1_TX_ANTENNA field configuration for 3T devices The field must be set to 2 instead of 0 for devices with three TX chains. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index e817278390f6..1a6a4eb25202 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1763,7 +1763,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); break; case 3: - rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); break; } -- cgit v1.2.3 From 5cddb3c2d5102d9a6b1b809e1518da54c8be8296 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:22 +0200 Subject: rt2x00: rt2800lib: fix antenna configuration for RT3593 On the RT3593 chipset, BBP register 86 must be configured by different values based on the RX antenna numbers. Configure this register from the 'rt2800_config_ant' function. Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: RT3593_CONFIG_SET_BY_ANTENNA in include/chip/rt3593.h Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 1a6a4eb25202..958215c44485 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1803,6 +1803,13 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) rt2800_bbp_write(rt2x00dev, 3, r3); rt2800_bbp_write(rt2x00dev, 1, r1); + + if (rt2x00_rt(rt2x00dev, RT3593)) { + if (ant->rx_chain_num == 1) + rt2800_bbp_write(rt2x00dev, 86, 0x00); + else + rt2800_bbp_write(rt2x00dev, 86, 0x46); + } } EXPORT_SYMBOL_GPL(rt2800_config_ant); -- cgit v1.2.3 From 97aa03f15e83174df74aa468eea127c5cee480f0 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:23 +0200 Subject: rt2x00: rt2800lib: add rt2800_txpower_to_dev helper Introduce a new helper function for converting the default TX power values from EEPROM into mac80211 values. The change improves the readability and it makes it easier to add support for other chipsets. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 6 ------ drivers/net/wireless/rt2x00/rt2800lib.c | 21 ++++++++++++++------- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 7b7caeb01e5a..d3e8f6d3531a 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2887,15 +2887,9 @@ enum rt2800_eeprom_word { #define TXPOWER_G_FROM_DEV(__txpower) \ ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) -#define TXPOWER_G_TO_DEV(__txpower) \ - clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER) - #define TXPOWER_A_FROM_DEV(__txpower) \ ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) -#define TXPOWER_A_TO_DEV(__txpower) \ - clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER) - /* * Board's maximun TX power limitation */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 958215c44485..1738a9d232c3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2724,6 +2724,16 @@ static void rt2800_iq_calibrate(struct rt2x00_dev *rt2x00dev, int channel) rt2800_bbp_write(rt2x00dev, 159, cal != 0xff ? cal : 0); } +static char rt2800_txpower_to_dev(struct rt2x00_dev *rt2x00dev, + unsigned int channel, + char txpower) +{ + if (channel <= 14) + return clamp_t(char, txpower, MIN_G_TXPOWER, MAX_G_TXPOWER); + else + return clamp_t(char, txpower, MIN_A_TXPOWER, MAX_A_TXPOWER); +} + static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, struct rf_channel *rf, @@ -2733,13 +2743,10 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, unsigned int tx_pin; u8 bbp, rfcsr; - if (rf->channel <= 14) { - info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1); - info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2); - } else { - info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1); - info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2); - } + info->default_power1 = rt2800_txpower_to_dev(rt2x00dev, rf->channel, + info->default_power1); + info->default_power2 = rt2800_txpower_to_dev(rt2x00dev, rf->channel, + info->default_power2); switch (rt2x00dev->chip.rf) { case RF2020: -- cgit v1.2.3 From fc739cfe0f305647677edbf99a76d9ece96e3795 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:24 +0200 Subject: rt2x00: rt2800lib: fix default TX power values for RT3593 The TX power values in the EEPROM are using a different format for the RT3593 chip. The default TX power value uses bits 0..4 only. Bits 5..8 contains value for fine grained power control. Additionally, the lower and upper limits of the TX power values are the same for both bands. Improve the rt2800_txpower_to_dev function, in order to compute the correct default power values for the RT3593 chip as well. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 7 +++++++ drivers/net/wireless/rt2x00/rt2800lib.c | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index d3e8f6d3531a..69749ba599bc 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2603,6 +2603,10 @@ enum rt2800_eeprom_word { #define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) #define EEPROM_TXPOWER_A_2 FIELD16(0xff00) +/* EEPROM_TXPOWER_{A,G} fields for RT3593 */ +#define EEPROM_TXPOWER_ALC FIELD8(0x1f) +#define EEPROM_TXPOWER_FINE_CTRL FIELD8(0xe0) + /* * EEPROM temperature compensation boundaries 802.11A * MINUS4: If the actual TSSI is below this boundary, tx power needs to be @@ -2884,6 +2888,9 @@ enum rt2800_eeprom_word { #define MAX_A_TXPOWER 15 #define DEFAULT_TXPOWER 5 +#define MIN_A_TXPOWER_3593 0 +#define MAX_A_TXPOWER_3593 31 + #define TXPOWER_G_FROM_DEV(__txpower) \ ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 1738a9d232c3..b11f0b06cc6d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2728,8 +2728,15 @@ static char rt2800_txpower_to_dev(struct rt2x00_dev *rt2x00dev, unsigned int channel, char txpower) { + if (rt2x00_rt(rt2x00dev, RT3593)) + txpower = rt2x00_get_field8(txpower, EEPROM_TXPOWER_ALC); + if (channel <= 14) return clamp_t(char, txpower, MIN_G_TXPOWER, MAX_G_TXPOWER); + + if (rt2x00_rt(rt2x00dev, RT3593)) + return clamp_t(char, txpower, MIN_A_TXPOWER_3593, + MAX_A_TXPOWER_3593); else return clamp_t(char, txpower, MIN_A_TXPOWER, MAX_A_TXPOWER); } -- cgit v1.2.3 From a3f1625dae58f06c5df1ec0094b275e9a46fd8b3 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:25 +0200 Subject: rt2x00: rt2800lib: introduce rt2800_get_txmixer_gain_{24,5}g helpers Move the TX mixer gain reading code into separate helper functions in preparation for RT3593 support. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 38 +++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b11f0b06cc6d..1f327325df52 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -6361,6 +6361,28 @@ int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse); +static u8 rt2800_get_txmixer_gain_24g(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + + rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word); + if ((word & 0x00ff) != 0x00ff) + return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL); + + return 0; +} + +static u8 rt2800_get_txmixer_gain_5g(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + + rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word); + if ((word & 0x00ff) != 0x00ff) + return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL); + + return 0; +} + static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) { struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; @@ -6455,13 +6477,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); - rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word); - if ((word & 0x00ff) != 0x00ff) { - drv_data->txmixer_gain_24g = - rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL); - } else { - drv_data->txmixer_gain_24g = 0; - } + drv_data->txmixer_gain_24g = rt2800_get_txmixer_gain_24g(rt2x00dev); rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) @@ -6472,13 +6488,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) default_lna_gain); rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); - rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word); - if ((word & 0x00ff) != 0x00ff) { - drv_data->txmixer_gain_5g = - rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL); - } else { - drv_data->txmixer_gain_5g = 0; - } + drv_data->txmixer_gain_5g = rt2800_get_txmixer_gain_5g(rt2x00dev); rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) -- cgit v1.2.3 From 6316c786cc8aff762530ea740233bf2da10fea33 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:26 +0200 Subject: rt2x00: rt2800lib: hardcode TX mixer gain values for RT3593 The reference code uses hardcoded zero TX mixer gain value for RT3593. Do the same in the rt2x00 driver. Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: NICReadEEPROMParameters in common/rtmp_init.c Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 1f327325df52..65045e0236fc 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -6365,6 +6365,9 @@ static u8 rt2800_get_txmixer_gain_24g(struct rt2x00_dev *rt2x00dev) { u16 word; + if (rt2x00_rt(rt2x00dev, RT3593)) + return 0; + rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word); if ((word & 0x00ff) != 0x00ff) return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL); @@ -6376,6 +6379,9 @@ static u8 rt2800_get_txmixer_gain_5g(struct rt2x00_dev *rt2x00dev) { u16 word; + if (rt2x00_rt(rt2x00dev, RT3593)) + return 0; + rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word); if ((word & 0x00ff) != 0x00ff) return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL); -- cgit v1.2.3 From f36bb0ca1be5bcb7148ad32263626f8609dfc0d7 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:27 +0200 Subject: rt2x00: rt2800lib: fix LNA_A[12] gain values for RT3593 The LNA_A[12] gain values are stored at a different offset in the EEPROM on RT3593 based devices. However the current code unconditionally reads those values from the location used by other chipsets. Fix the code to use the correct EEPROM offset. Based on the DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. References: RT3593_EEPROM_RSSI2_OFFSET_ALNAGAIN1_24G_READ in include/chip/rt3593.h RT3593_EEPROM_RSSI2_OFFSET_ALNAGAIN2_5G_READ in include/chip/rt3593.h Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 4 +++ drivers/net/wireless/rt2x00/rt2800lib.c | 55 ++++++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 69749ba599bc..7688e1594201 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2672,6 +2672,10 @@ enum rt2800_eeprom_word { #define EEPROM_BBP_VALUE FIELD16(0x00ff) #define EEPROM_BBP_REG_ID FIELD16(0xff00) +/* EEPROM_EXT_LNA2 */ +#define EEPROM_EXT_LNA2_A1 FIELD16(0x00ff) +#define EEPROM_EXT_LNA2_A2 FIELD16(0xff00) + /* * EEPROM IQ Calibration, unlike other entries those are byte addresses. */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 65045e0236fc..419ea05f13a3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1826,11 +1826,25 @@ static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev, rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); } else if (libconf->rf.channel <= 128) { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); + if (rt2x00_rt(rt2x00dev, RT3593)) { + rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, + EEPROM_EXT_LNA2_A1); + } else { + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, + EEPROM_RSSI_BG2_LNA_A1); + } } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); + if (rt2x00_rt(rt2x00dev, RT3593)) { + rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, + EEPROM_EXT_LNA2_A2); + } else { + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, + EEPROM_RSSI_A2_LNA_A2); + } } rt2x00dev->lna_gain = lna_gain; @@ -6488,10 +6502,12 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); - if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || - rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) - rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, - default_lna_gain); + if (!rt2x00_rt(rt2x00dev, RT3593)) { + if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, + default_lna_gain); + } rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); drv_data->txmixer_gain_5g = rt2800_get_txmixer_gain_5g(rt2x00dev); @@ -6506,12 +6522,27 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); - if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || - rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) - rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, - default_lna_gain); + if (!rt2x00_rt(rt2x00dev, RT3593)) { + if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, + default_lna_gain); + } rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + if (rt2x00_rt(rt2x00dev, RT3593)) { + rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &word); + if (rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0x00 || + rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0xff) + rt2x00_set_field16(&word, EEPROM_EXT_LNA2_A1, + default_lna_gain); + if (rt2x00_get_field16(word, EEPROM_EXT_LNA2_A2) == 0x00 || + rt2x00_get_field16(word, EEPROM_EXT_LNA2_A2) == 0xff) + rt2x00_set_field16(&word, EEPROM_EXT_LNA2_A1, + default_lna_gain); + rt2800_eeprom_write(rt2x00dev, EEPROM_EXT_LNA2, word); + } + return 0; } -- cgit v1.2.3 From c0a14369ebd3e7940e70e397ecc3dd7eaf81e9ab Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:28 +0200 Subject: rt2x00: rt2800lib: add default_power3 field for three-chain devices The actual code uses two default TX power values. This is enough for 1T and for 2T devices however on 3T devices another value is needed for the third chain. Add a new field to struct channel_info and initialize it from the 'rt2800_probe_hw_mode' function. Also modify the 'rt2800_config_channel' to handle the new field as well. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 22 ++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00.h | 1 + 2 files changed, 23 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 419ea05f13a3..e3e652db60ac 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2768,6 +2768,10 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, info->default_power1); info->default_power2 = rt2800_txpower_to_dev(rt2x00dev, rf->channel, info->default_power2); + if (rt2x00dev->default_ant.tx_chain_num > 2) + info->default_power3 = + rt2800_txpower_to_dev(rt2x00dev, rf->channel, + info->default_power3); switch (rt2x00dev->chip.rf) { case RF2020: @@ -6963,6 +6967,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) struct channel_info *info; char *default_power1; char *default_power2; + char *default_power3; unsigned int i; u16 eeprom; u32 reg; @@ -7115,9 +7120,17 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) default_power1 = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); default_power2 = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); + if (rt2x00dev->default_ant.tx_chain_num > 2) + default_power3 = rt2800_eeprom_addr(rt2x00dev, + EEPROM_EXT_TXPOWER_BG3); + else + default_power3 = NULL; + for (i = 0; i < 14; i++) { info[i].default_power1 = default_power1[i]; info[i].default_power2 = default_power2[i]; + if (default_power3) + info[i].default_power3 = default_power3[i]; } if (spec->num_channels > 14) { @@ -7126,9 +7139,18 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) default_power2 = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); + if (rt2x00dev->default_ant.tx_chain_num > 2) + default_power3 = + rt2800_eeprom_addr(rt2x00dev, + EEPROM_EXT_TXPOWER_A3); + else + default_power3 = NULL; + for (i = 14; i < spec->num_channels; i++) { info[i].default_power1 = default_power1[i - 14]; info[i].default_power2 = default_power2[i - 14]; + if (default_power3) + info[i].default_power3 = default_power3[i - 14]; } } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ee3fc570b11d..fe4c572db52c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -211,6 +211,7 @@ struct channel_info { short max_power; short default_power1; short default_power2; + short default_power3; }; /* -- cgit v1.2.3 From c8b9d3dc83cab569de6054a10e355a143e2b52a0 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:29 +0200 Subject: rt2x00: rt2800lib: add rf_vals for RF3053 Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. References: FreqItems3053 in chips/rt3593.c Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 70 +++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index e3e652db60ac..5119bf071936 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -6961,6 +6961,72 @@ static const struct rf_channel rf_vals_5592_xtal40[] = { {196, 83, 0, 12, 1}, }; +static const struct rf_channel rf_vals_3053[] = { + /* Channel, N, R, K */ + {1, 241, 2, 2}, + {2, 241, 2, 7}, + {3, 242, 2, 2}, + {4, 242, 2, 7}, + {5, 243, 2, 2}, + {6, 243, 2, 7}, + {7, 244, 2, 2}, + {8, 244, 2, 7}, + {9, 245, 2, 2}, + {10, 245, 2, 7}, + {11, 246, 2, 2}, + {12, 246, 2, 7}, + {13, 247, 2, 2}, + {14, 248, 2, 4}, + + {36, 0x56, 0, 4}, + {38, 0x56, 0, 6}, + {40, 0x56, 0, 8}, + {44, 0x57, 0, 0}, + {46, 0x57, 0, 2}, + {48, 0x57, 0, 4}, + {52, 0x57, 0, 8}, + {54, 0x57, 0, 10}, + {56, 0x58, 0, 0}, + {60, 0x58, 0, 4}, + {62, 0x58, 0, 6}, + {64, 0x58, 0, 8}, + + {100, 0x5B, 0, 8}, + {102, 0x5B, 0, 10}, + {104, 0x5C, 0, 0}, + {108, 0x5C, 0, 4}, + {110, 0x5C, 0, 6}, + {112, 0x5C, 0, 8}, + + /* NOTE: Channel 114 has been removed intentionally. + * The EEPROM contains no TX power values for that, + * and it is disabled in the vendor driver as well. + */ + + {116, 0x5D, 0, 0}, + {118, 0x5D, 0, 2}, + {120, 0x5D, 0, 4}, + {124, 0x5D, 0, 8}, + {126, 0x5D, 0, 10}, + {128, 0x5E, 0, 0}, + {132, 0x5E, 0, 4}, + {134, 0x5E, 0, 6}, + {136, 0x5E, 0, 8}, + {140, 0x5F, 0, 0}, + + {149, 0x5F, 0, 9}, + {151, 0x5F, 0, 11}, + {153, 0x60, 0, 1}, + {157, 0x60, 0, 5}, + {159, 0x60, 0, 7}, + {161, 0x60, 0, 9}, + {165, 0x61, 0, 1}, + {167, 0x61, 0, 3}, + {169, 0x61, 0, 5}, + {171, 0x61, 0, 7}, + {173, 0x61, 0, 9}, +}; + static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; @@ -7052,6 +7118,10 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_3x); spec->channels = rf_vals_3x; + } else if (rt2x00_rf(rt2x00dev, RF3053)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; + spec->num_channels = ARRAY_SIZE(rf_vals_3053); + spec->channels = rf_vals_3053; } else if (rt2x00_rf(rt2x00dev, RF5592)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; -- cgit v1.2.3 From f42b046578efb018064302fd9b66586f5da7d75b Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:30 +0200 Subject: rt2x00: rt2800lib: add channel configuration for RF3053 Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: RT3593_ChipSwitchChannel in chips/rt3593.c Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 46 +++- drivers/net/wireless/rt2x00/rt2800lib.c | 366 +++++++++++++++++++++++++++++++- 2 files changed, 409 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 7688e1594201..1ba797b0e147 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2092,6 +2092,10 @@ struct mac_iveiv_entry { #define BBP109_TX0_POWER FIELD8(0x0f) #define BBP109_TX1_POWER FIELD8(0xf0) +/* BBP 110 */ +#define BBP110_TX2_POWER FIELD8(0x0f) + + /* * BBP 138: Unknown */ @@ -2141,6 +2145,12 @@ struct mac_iveiv_entry { #define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80) /* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */ #define RFCSR3_VCOCAL_EN FIELD8(0x80) +/* Bits for RF3050 */ +#define RFCSR3_BIT1 FIELD8(0x02) +#define RFCSR3_BIT2 FIELD8(0x04) +#define RFCSR3_BIT3 FIELD8(0x08) +#define RFCSR3_BIT4 FIELD8(0x10) +#define RFCSR3_BIT5 FIELD8(0x20) /* * FRCSR 5: @@ -2153,6 +2163,8 @@ struct mac_iveiv_entry { #define RFCSR6_R1 FIELD8(0x03) #define RFCSR6_R2 FIELD8(0x40) #define RFCSR6_TXDIV FIELD8(0x0c) +/* bits for RF3053 */ +#define RFCSR6_VCO_IC FIELD8(0xc0) /* * RFCSR 7: @@ -2177,7 +2189,12 @@ struct mac_iveiv_entry { * RFCSR 11: */ #define RFCSR11_R FIELD8(0x03) +#define RFCSR11_PLL_MOD FIELD8(0x0c) #define RFCSR11_MOD FIELD8(0xc0) +/* bits for RF3053 */ +/* TODO: verify RFCSR11_MOD usage on other chips */ +#define RFCSR11_PLL_IDOH FIELD8(0x40) + /* * RFCSR 12: @@ -2273,6 +2290,12 @@ struct mac_iveiv_entry { #define RFCSR31_RX_H20M FIELD8(0x20) #define RFCSR31_RX_CALIB FIELD8(0x7f) +/* RFCSR 32 bits for RF3053 */ +#define RFCSR32_TX_AGC_FC FIELD8(0xf8) + +/* RFCSR 36 bits for RF3053 */ +#define RFCSR36_RF_BS FIELD8(0x80) + /* * RFCSR 38: */ @@ -2281,6 +2304,7 @@ struct mac_iveiv_entry { /* * RFCSR 39: */ +#define RFCSR39_RX_DIV FIELD8(0x40) #define RFCSR39_RX_LO2_EN FIELD8(0x80) /* @@ -2288,18 +2312,36 @@ struct mac_iveiv_entry { */ #define RFCSR49_TX FIELD8(0x3f) #define RFCSR49_EP FIELD8(0xc0) +/* bits for RT3593 */ +#define RFCSR49_TX_LO1_IC FIELD8(0x1c) +#define RFCSR49_TX_DIV FIELD8(0x20) /* * RFCSR 50: */ #define RFCSR50_TX FIELD8(0x3f) #define RFCSR50_EP FIELD8(0xc0) -/* bits for RT3593*/ +/* bits for RT3593 */ +#define RFCSR50_TX_LO1_EN FIELD8(0x20) #define RFCSR50_TX_LO2_EN FIELD8(0x10) /* RFCSR 51 */ -/* bits for RT3593*/ +/* bits for RT3593 */ +#define RFCSR51_BITS01 FIELD8(0x03) #define RFCSR51_BITS24 FIELD8(0x1c) +#define RFCSR51_BITS57 FIELD8(0xe0) + +#define RFCSR53_TX_POWER FIELD8(0x3f) +#define RFCSR53_UNKNOWN FIELD8(0xc0) + +#define RFCSR54_TX_POWER FIELD8(0x3f) +#define RFCSR54_UNKNOWN FIELD8(0xc0) + +#define RFCSR55_TX_POWER FIELD8(0x3f) +#define RFCSR55_UNKNOWN FIELD8(0xc0) + +#define RFCSR57_DRV_CC FIELD8(0xfc) + /* * RF registers diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 5119bf071936..e6d6c75dc2ce 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2168,6 +2168,303 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); } +static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; + u8 txrx_agc_fc; + u8 txrx_h20m; + u8 rfcsr; + u8 bbp; + const bool txbf_enabled = false; /* TODO */ + + /* TODO: use TX{0,1,2}FinePowerControl values from EEPROM */ + rt2800_bbp_read(rt2x00dev, 109, &bbp); + rt2x00_set_field8(&bbp, BBP109_TX0_POWER, 0); + rt2x00_set_field8(&bbp, BBP109_TX1_POWER, 0); + rt2800_bbp_write(rt2x00dev, 109, bbp); + + rt2800_bbp_read(rt2x00dev, 110, &bbp); + rt2x00_set_field8(&bbp, BBP110_TX2_POWER, 0); + rt2800_bbp_write(rt2x00dev, 110, bbp); + + if (rf->channel <= 14) { + /* Restore BBP 25 & 26 for 2.4 GHz */ + rt2800_bbp_write(rt2x00dev, 25, drv_data->bbp25); + rt2800_bbp_write(rt2x00dev, 26, drv_data->bbp26); + } else { + /* Hard code BBP 25 & 26 for 5GHz */ + + /* Enable IQ Phase correction */ + rt2800_bbp_write(rt2x00dev, 25, 0x09); + /* Setup IQ Phase correction value */ + rt2800_bbp_write(rt2x00dev, 26, 0xff); + } + + rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); + rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3 & 0xf); + + rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR11_R, (rf->rf2 & 0x3)); + rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR11_PLL_IDOH, 1); + if (rf->channel <= 14) + rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 1); + else + rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 2); + rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 53, &rfcsr); + if (rf->channel <= 14) { + rfcsr = 0; + rt2x00_set_field8(&rfcsr, RFCSR53_TX_POWER, + info->default_power1 & 0x1f); + } else { + if (rt2x00_is_usb(rt2x00dev)) + rfcsr = 0x40; + + rt2x00_set_field8(&rfcsr, RFCSR53_TX_POWER, + ((info->default_power1 & 0x18) << 1) | + (info->default_power1 & 7)); + } + rt2800_rfcsr_write(rt2x00dev, 53, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 55, &rfcsr); + if (rf->channel <= 14) { + rfcsr = 0; + rt2x00_set_field8(&rfcsr, RFCSR55_TX_POWER, + info->default_power2 & 0x1f); + } else { + if (rt2x00_is_usb(rt2x00dev)) + rfcsr = 0x40; + + rt2x00_set_field8(&rfcsr, RFCSR55_TX_POWER, + ((info->default_power2 & 0x18) << 1) | + (info->default_power2 & 7)); + } + rt2800_rfcsr_write(rt2x00dev, 55, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 54, &rfcsr); + if (rf->channel <= 14) { + rfcsr = 0; + rt2x00_set_field8(&rfcsr, RFCSR54_TX_POWER, + info->default_power3 & 0x1f); + } else { + if (rt2x00_is_usb(rt2x00dev)) + rfcsr = 0x40; + + rt2x00_set_field8(&rfcsr, RFCSR54_TX_POWER, + ((info->default_power3 & 0x18) << 1) | + (info->default_power3 & 7)); + } + rt2800_rfcsr_write(rt2x00dev, 54, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); + rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); + + switch (rt2x00dev->default_ant.tx_chain_num) { + case 3: + rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); + /* fallthrough */ + case 2: + rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); + /* fallthrough */ + case 1: + rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); + break; + } + + switch (rt2x00dev->default_ant.rx_chain_num) { + case 3: + rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); + /* fallthrough */ + case 2: + rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); + /* fallthrough */ + case 1: + rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); + break; + } + rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); + + /* TODO: frequency calibration? */ + + if (conf_is_ht40(conf)) { + txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw40, + RFCSR24_TX_AGC_FC); + txrx_h20m = rt2x00_get_field8(drv_data->calibration_bw40, + RFCSR24_TX_H20M); + } else { + txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw20, + RFCSR24_TX_AGC_FC); + txrx_h20m = rt2x00_get_field8(drv_data->calibration_bw20, + RFCSR24_TX_H20M); + } + + /* NOTE: the reference driver does not writes the new value + * back to RFCSR 32 + */ + rt2800_rfcsr_read(rt2x00dev, 32, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR32_TX_AGC_FC, txrx_agc_fc); + + if (rf->channel <= 14) + rfcsr = 0xa0; + else + rfcsr = 0x80; + rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, txrx_h20m); + rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, txrx_h20m); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + + /* Band selection */ + rt2800_rfcsr_read(rt2x00dev, 36, &rfcsr); + if (rf->channel <= 14) + rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 1); + else + rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 0); + rt2800_rfcsr_write(rt2x00dev, 36, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 34, &rfcsr); + if (rf->channel <= 14) + rfcsr = 0x3c; + else + rfcsr = 0x20; + rt2800_rfcsr_write(rt2x00dev, 34, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + if (rf->channel <= 14) + rfcsr = 0x1a; + else + rfcsr = 0x12; + rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + if (rf->channel >= 1 && rf->channel <= 14) + rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1); + else if (rf->channel >= 36 && rf->channel <= 64) + rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 2); + else if (rf->channel >= 100 && rf->channel <= 128) + rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 2); + else + rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1); + rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + + rt2800_rfcsr_write(rt2x00dev, 46, 0x60); + + if (rf->channel <= 14) { + rt2800_rfcsr_write(rt2x00dev, 10, 0xd3); + rt2800_rfcsr_write(rt2x00dev, 13, 0x12); + } else { + rt2800_rfcsr_write(rt2x00dev, 10, 0xd8); + rt2800_rfcsr_write(rt2x00dev, 13, 0x23); + } + + rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR51_BITS01, 1); + rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + if (rf->channel <= 14) { + rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, 5); + rt2x00_set_field8(&rfcsr, RFCSR51_BITS57, 3); + } else { + rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, 4); + rt2x00_set_field8(&rfcsr, RFCSR51_BITS57, 2); + } + rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + if (rf->channel <= 14) + rt2x00_set_field8(&rfcsr, RFCSR49_TX_LO1_IC, 3); + else + rt2x00_set_field8(&rfcsr, RFCSR49_TX_LO1_IC, 2); + + if (txbf_enabled) + rt2x00_set_field8(&rfcsr, RFCSR49_TX_DIV, 1); + + rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO1_EN, 0); + rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 57, &rfcsr); + if (rf->channel <= 14) + rt2x00_set_field8(&rfcsr, RFCSR57_DRV_CC, 0x1b); + else + rt2x00_set_field8(&rfcsr, RFCSR57_DRV_CC, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 57, rfcsr); + + if (rf->channel <= 14) { + rt2800_rfcsr_write(rt2x00dev, 44, 0x93); + rt2800_rfcsr_write(rt2x00dev, 52, 0x45); + } else { + rt2800_rfcsr_write(rt2x00dev, 44, 0x9b); + rt2800_rfcsr_write(rt2x00dev, 52, 0x05); + } + + /* Initiate VCO calibration */ + rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + if (rf->channel <= 14) { + rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); + } else { + rt2x00_set_field8(&rfcsr, RFCSR3_BIT1, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_BIT2, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_BIT3, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_BIT4, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_BIT5, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); + } + rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); + + if (rf->channel >= 1 && rf->channel <= 14) { + rfcsr = 0x23; + if (txbf_enabled) + rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1); + rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); + + rt2800_rfcsr_write(rt2x00dev, 45, 0xbb); + } else if (rf->channel >= 36 && rf->channel <= 64) { + rfcsr = 0x36; + if (txbf_enabled) + rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1); + rt2800_rfcsr_write(rt2x00dev, 39, 0x36); + + rt2800_rfcsr_write(rt2x00dev, 45, 0xeb); + } else if (rf->channel >= 100 && rf->channel <= 128) { + rfcsr = 0x32; + if (txbf_enabled) + rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1); + rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); + + rt2800_rfcsr_write(rt2x00dev, 45, 0xb3); + } else { + rfcsr = 0x30; + if (txbf_enabled) + rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1); + rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); + + rt2800_rfcsr_write(rt2x00dev, 45, 0x9b); + } +} + #define POWER_BOUND 0x27 #define POWER_BOUND_5G 0x2b #define FREQ_OFFSET_BOUND 0x5f @@ -2784,6 +3081,9 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, case RF3052: rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info); break; + case RF3053: + rt2800_config_channel_rf3053(rt2x00dev, conf, rf, info); + break; case RF3290: rt2800_config_channel_rf3290(rt2x00dev, conf, rf, info); break; @@ -2829,6 +3129,23 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain); rt2800_bbp_write(rt2x00dev, 27, 0x20); rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain); + } else if (rt2x00_rt(rt2x00dev, RT3593)) { + if (rf->channel > 14) { + /* Disable CCK Packet detection on 5GHz */ + rt2800_bbp_write(rt2x00dev, 70, 0x00); + } else { + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + } + + if (conf_is_ht40(conf)) + rt2800_bbp_write(rt2x00dev, 105, 0x04); + else + rt2800_bbp_write(rt2x00dev, 105, 0x34); + + rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 77, 0x98); } else { rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); @@ -2844,16 +3161,27 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_bbp_write(rt2x00dev, 82, 0x62); rt2800_bbp_write(rt2x00dev, 75, 0x46); } else { - rt2800_bbp_write(rt2x00dev, 82, 0x84); + if (rt2x00_rt(rt2x00dev, RT3593)) + rt2800_bbp_write(rt2x00dev, 82, 0x62); + else + rt2800_bbp_write(rt2x00dev, 82, 0x84); rt2800_bbp_write(rt2x00dev, 75, 0x50); } + if (rt2x00_rt(rt2x00dev, RT3593)) + rt2800_bbp_write(rt2x00dev, 83, 0x8a); } + } else { if (rt2x00_rt(rt2x00dev, RT3572)) rt2800_bbp_write(rt2x00dev, 82, 0x94); + else if (rt2x00_rt(rt2x00dev, RT3593)) + rt2800_bbp_write(rt2x00dev, 82, 0x82); else rt2800_bbp_write(rt2x00dev, 82, 0xf2); + if (rt2x00_rt(rt2x00dev, RT3593)) + rt2800_bbp_write(rt2x00dev, 83, 0x9a); + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) rt2800_bbp_write(rt2x00dev, 75, 0x46); else @@ -2924,6 +3252,41 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, if (rt2x00_rt(rt2x00dev, RT3572)) rt2800_rfcsr_write(rt2x00dev, 8, 0x80); + if (rt2x00_rt(rt2x00dev, RT3593)) { + if (rt2x00_is_usb(rt2x00dev)) { + rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + + /* Band selection. GPIO #8 controls all paths */ + rt2x00_set_field32(®, GPIO_CTRL_DIR8, 0); + if (rf->channel <= 14) + rt2x00_set_field32(®, GPIO_CTRL_VAL8, 1); + else + rt2x00_set_field32(®, GPIO_CTRL_VAL8, 0); + + rt2x00_set_field32(®, GPIO_CTRL_DIR4, 0); + rt2x00_set_field32(®, GPIO_CTRL_DIR7, 0); + + /* LNA PE control. + * GPIO #4 controls PE0 and PE1, + * GPIO #7 controls PE2 + */ + rt2x00_set_field32(®, GPIO_CTRL_VAL4, 1); + rt2x00_set_field32(®, GPIO_CTRL_VAL7, 1); + + rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); + } + + /* AGC init */ + if (rf->channel <= 14) + reg = 0x1c + 2 * rt2x00dev->lna_gain; + else + reg = 0x22 + ((rt2x00dev->lna_gain * 5) / 3); + + rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg); + + usleep_range(1000, 1500); + } + if (rt2x00_rt(rt2x00dev, RT5592)) { rt2800_bbp_write(rt2x00dev, 195, 141); rt2800_bbp_write(rt2x00dev, 196, conf_is_ht40(conf) ? 0x10 : 0x1a); @@ -5883,6 +6246,7 @@ static void rt3593_post_bbp_init(struct rt2x00_dev *rt2x00dev) /* FIXME: BBP 105 owerwrite? */ rt2800_bbp_write(rt2x00dev, 105, 0x04); + } static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) -- cgit v1.2.3 From 1095df07bfc5924e100f1748e6ebc9e5a5881565 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:31 +0200 Subject: rt2x00: rt2800lib: enable VCO recalibration for RF3053 Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index e6d6c75dc2ce..46d5f429987d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4194,6 +4194,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); break; + case RF3053: case RF3290: case RF5360: case RF5370: @@ -7595,6 +7596,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) case RF3022: case RF3320: case RF3052: + case RF3053: case RF3290: case RF5360: case RF5370: -- cgit v1.2.3 From 0f5af26a49c8d6a50ecec2f1b66174069c9f9581 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:32 +0200 Subject: rt2x00: rt2800lib: enable RF3053 support Support for the RF3053 has been implemented in the previous changes, so it is safe to mark it supported in the driver. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 46d5f429987d..9ab587edb28b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -6948,6 +6948,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) case RF3021: case RF3022: case RF3052: + case RF3053: case RF3290: case RF3320: case RF3322: -- cgit v1.2.3 From 2dc2bd2f8aa8eb79184fb3c7e5f530006500897f Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:33 +0200 Subject: rt2x00: rt2800lib: enable RT3593 support Support for the RT3593 has been implemented in the previous changes, so it is safe to mark it supported in the driver. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9ab587edb28b..dedc3d4ae365 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -7636,6 +7636,7 @@ static int rt2800_probe_rt(struct rt2x00_dev *rt2x00dev) case RT3352: case RT3390: case RT3572: + case RT3593: case RT5390: case RT5392: case RT5592: -- cgit v1.2.3 From 65d3c0d5cffb9f1227927544e418a9ac231eae42 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:34 +0200 Subject: rt2x00: rt2800usb: use correct [RT]XWI size for RT3593 The RT3593 chipset requires different [RT]XWI size values. Modify the driver to use the correct values. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 1 + drivers/net/wireless/rt2x00/rt2800usb.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 1ba797b0e147..a3132414ac9f 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2814,6 +2814,7 @@ enum rt2800_eeprom_word { #define TXWI_DESC_SIZE_5WORDS (5 * sizeof(__le32)) #define RXWI_DESC_SIZE_4WORDS (4 * sizeof(__le32)) +#define RXWI_DESC_SIZE_5WORDS (5 * sizeof(__le32)) #define RXWI_DESC_SIZE_6WORDS (6 * sizeof(__le32)) /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 840833b26bfa..c24c1fd91351 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -854,7 +854,10 @@ static void rt2800usb_queue_init(struct data_queue *queue) struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; unsigned short txwi_size, rxwi_size; - if (rt2x00_rt(rt2x00dev, RT5592)) { + if (rt2x00_rt(rt2x00dev, RT3593)) { + txwi_size = TXWI_DESC_SIZE_4WORDS; + rxwi_size = RXWI_DESC_SIZE_5WORDS; + } else if (rt2x00_rt(rt2x00dev, RT5592)) { txwi_size = TXWI_DESC_SIZE_5WORDS; rxwi_size = RXWI_DESC_SIZE_6WORDS; } else { -- cgit v1.2.3 From d02433d15566f542e42e3c469dfade0de332dc7b Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 8 Jul 2013 16:08:35 +0200 Subject: rt2x00: rt2800usb: add USB device ID for Linksys AE3000 The Linksys AE3000 device is based on the RT3573 chipset. The support for this chipset is available already, and the AE3000 device works with the driver. Only managed mode works correctly at the moment, for AP mode additional changes are needed in the driver. Also add a new RT2800USB_RT3573 Kconfig option and only enable support for RT3573 based devices if that is enabled. Signed-off-by: Gabor Juhos Acked-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 6 ++++++ drivers/net/wireless/rt2x00/rt2800usb.c | 4 ++++ 2 files changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 9b915d3a44be..c60d6e83a950 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -166,6 +166,12 @@ config RT2800USB_RT35XX rt2800usb driver. Supported chips: RT3572 +config RT2800USB_RT3573 + bool "rt2800usb - Include support for rt3573 devices (EXPERIMENTAL)" + ---help--- + This enables support for RT3573 chipset based wireless USB devices + in the rt2800usb driver. + config RT2800USB_RT53XX bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)" ---help--- diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index c24c1fd91351..ab609aeb29ae 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1197,6 +1197,10 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Zinwell */ { USB_DEVICE(0x5a57, 0x0284) }, #endif +#ifdef CONFIG_RT2800USB_RT3573 + /* Linksys */ + { USB_DEVICE(0x13b1, 0x003b) }, +#endif #ifdef CONFIG_RT2800USB_RT53XX /* Arcadyan */ { USB_DEVICE(0x043e, 0x7a12) }, -- cgit v1.2.3 From f988b23f7a5045ec5da627ced75de1c2eb080af8 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 11 Jul 2013 18:03:37 +0300 Subject: wil6210: Align WMI header with latest FW FW guys changed header structure; align driver code Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/trace.h | 22 +++++++++++++--------- drivers/net/wireless/ath/wil6210/wil6210.h | 17 ++++++++++++++--- drivers/net/wireless/ath/wil6210/wmi.c | 14 +++++++++----- 3 files changed, 36 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/trace.h b/drivers/net/wireless/ath/wil6210/trace.h index eff1239be53a..e59239d22b94 100644 --- a/drivers/net/wireless/ath/wil6210/trace.h +++ b/drivers/net/wireless/ath/wil6210/trace.h @@ -37,36 +37,40 @@ static inline void trace_ ## name(proto) {} #endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */ DECLARE_EVENT_CLASS(wil6210_wmi, - TP_PROTO(u16 id, void *buf, u16 buf_len), + TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len), - TP_ARGS(id, buf, buf_len), + TP_ARGS(wmi, buf, buf_len), TP_STRUCT__entry( + __field(u8, mid) __field(u16, id) + __field(u32, timestamp) __field(u16, buf_len) __dynamic_array(u8, buf, buf_len) ), TP_fast_assign( - __entry->id = id; + __entry->mid = wmi->mid; + __entry->id = le16_to_cpu(wmi->id); + __entry->timestamp = le32_to_cpu(wmi->timestamp); __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); ), TP_printk( - "id 0x%04x len %d", - __entry->id, __entry->buf_len + "MID %d id 0x%04x len %d timestamp %d", + __entry->mid, __entry->id, __entry->buf_len, __entry->timestamp ) ); DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd, - TP_PROTO(u16 id, void *buf, u16 buf_len), - TP_ARGS(id, buf, buf_len) + TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len), + TP_ARGS(wmi, buf, buf_len) ); DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event, - TP_PROTO(u16 id, void *buf, u16 buf_len), - TP_ARGS(id, buf, buf_len) + TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len), + TP_ARGS(wmi, buf, buf_len) ); #define WIL6210_MSG_MAX (200) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 44fdab51de7e..129c480c8a20 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -156,11 +156,22 @@ struct wil6210_mbox_hdr { /* max. value for wil6210_mbox_hdr.len */ #define MAX_MBOXITEM_SIZE (240) +/** + * struct wil6210_mbox_hdr_wmi - WMI header + * + * @mid: MAC ID + * 00 - default, created by FW + * 01..0f - WiFi ports, driver to create + * 10..fe - debug + * ff - broadcast + * @id: command/event ID + * @timestamp: FW fills for events, free-running msec timer + */ struct wil6210_mbox_hdr_wmi { - u8 reserved0[2]; + u8 mid; + u8 reserved; __le16 id; - __le16 info1; /* bits [0..3] - device_id, rest - unused */ - u8 reserved1[2]; + __le32 timestamp; } __packed; struct pending_wmi_event { diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index dc8059ad4bab..a62511a78ac6 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -172,8 +172,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) .len = cpu_to_le16(sizeof(cmd.wmi) + len), }, .wmi = { + .mid = 0, .id = cpu_to_le16(cmdid), - .info1 = 0, }, }; struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx; @@ -248,7 +248,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) iowrite32(r->head = next_head, wil->csr + HOST_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head)); - trace_wil6210_wmi_cmd(cmdid, buf, len); + trace_wil6210_wmi_cmd(&cmd.wmi, buf, len); /* interrupt to FW */ iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); @@ -640,9 +640,13 @@ void wmi_recv_cmd(struct wil6210_priv *wil) hdr.flags); if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { - u16 id = le16_to_cpu(evt->event.wmi.id); - wil_dbg_wmi(wil, "WMI event 0x%04x\n", id); - trace_wil6210_wmi_event(id, &evt->event.wmi, len); + struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi; + u16 id = le16_to_cpu(wmi->id); + u32 tstamp = le32_to_cpu(wmi->timestamp); + wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n", + id, wmi->mid, tstamp); + trace_wil6210_wmi_event(wmi, &wmi[1], + len - sizeof(*wmi)); } wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1, &evt->event.hdr, sizeof(hdr) + len, true); -- cgit v1.2.3 From 4d1ac0721aae84eec3c8aa54c7574b14f79863bc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 11 Jul 2013 18:03:38 +0300 Subject: wil6210: fix wrong index in wil_vring_free When destroying Rx vring, branch for Rx used wrong Tx descriptor: while SW context was taken for "head", HW descriptor was, by mistake, taken from "tail" Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index d240b24e1ccf..8fde73aa6198 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -133,7 +133,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, } else { /* rx */ struct vring_rx_desc dd, *d = ⅆ volatile struct vring_rx_desc *_d = - &vring->va[vring->swtail].rx; + &vring->va[vring->swhead].rx; *d = *_d; pa = wil_desc_addr(&d->dma.addr); -- cgit v1.2.3 From 03269c658b7a2f6ccfa44d7270da8446881f9552 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 11 Jul 2013 18:03:39 +0300 Subject: wil6210: Optimize Tx completion No need to modify HW descriptor, as it will be re-initialized on Tx. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 8fde73aa6198..dd5f35eb64b4 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -855,10 +855,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) } else { dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); } - d->dma.addr.addr_low = 0; - d->dma.addr.addr_high = 0; - d->dma.length = 0; - d->dma.status = TX_DMA_STATUS_DU; + /* + * There is no need to touch HW descriptor: + * - ststus bit TX_DMA_STATUS_DU is set by design, + * so hardware will not try to process this desc., + * - rest of descriptor will be initialized on Tx. + */ vring->swtail = wil_vring_next_tail(vring); done++; } -- cgit v1.2.3 From f88f113a54f02df62608ec263e8a3ff7e81cfce2 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 11 Jul 2013 18:03:40 +0300 Subject: wil6210: Introduce struct for sw context Enable adding more data to the SW context. For now, add flag "mapped_as_page", to separate decisions on free-ing skb and type of DMA mapping. This allows linking skb itself to any descriptor of fragmented skb. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 4 +-- drivers/net/wireless/ath/wil6210/txrx.c | 58 +++++++++++++++++------------- drivers/net/wireless/ath/wil6210/wil6210.h | 10 +++++- 3 files changed, 44 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index e8308ec30970..971ce46a6b5f 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -51,7 +51,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, if ((i % 64) == 0 && (i != 0)) seq_printf(s, "\n"); seq_printf(s, "%s", (d->dma.status & BIT(0)) ? - "S" : (vring->ctx[i] ? "H" : "h")); + "S" : (vring->ctx[i].skb ? "H" : "h")); } seq_printf(s, "\n"); } @@ -406,7 +406,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) volatile struct vring_tx_desc *d = &(vring->va[dbg_txdesc_index].tx); volatile u32 *u = (volatile u32 *)d; - struct sk_buff *skb = vring->ctx[dbg_txdesc_index]; + struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index dd5f35eb64b4..44cdd2a3dff3 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -70,7 +70,7 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) vring->swhead = 0; vring->swtail = 0; - vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL); + vring->ctx = kcalloc(vring->size, sizeof(vring->ctx[0]), GFP_KERNEL); if (!vring->ctx) { vring->va = NULL; return -ENOMEM; @@ -108,39 +108,39 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, while (!wil_vring_is_empty(vring)) { dma_addr_t pa; - struct sk_buff *skb; u16 dmalen; + struct wil_ctx *ctx; if (tx) { struct vring_tx_desc dd, *d = ⅆ volatile struct vring_tx_desc *_d = &vring->va[vring->swtail].tx; + ctx = &vring->ctx[vring->swtail]; *d = *_d; pa = wil_desc_addr(&d->dma.addr); dmalen = le16_to_cpu(d->dma.length); - skb = vring->ctx[vring->swtail]; - if (skb) { - dma_unmap_single(dev, pa, dmalen, - DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - vring->ctx[vring->swtail] = NULL; - } else { + if (vring->ctx[vring->swtail].mapped_as_page) { dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); + } else { + dma_unmap_single(dev, pa, dmalen, + DMA_TO_DEVICE); } + if (ctx->skb) + dev_kfree_skb_any(ctx->skb); vring->swtail = wil_vring_next_tail(vring); } else { /* rx */ struct vring_rx_desc dd, *d = ⅆ volatile struct vring_rx_desc *_d = &vring->va[vring->swhead].rx; + ctx = &vring->ctx[vring->swhead]; *d = *_d; pa = wil_desc_addr(&d->dma.addr); dmalen = le16_to_cpu(d->dma.length); - skb = vring->ctx[vring->swhead]; dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE); - kfree_skb(skb); + kfree_skb(ctx->skb); wil_vring_advance_head(vring, 1); } } @@ -187,7 +187,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ d->dma.length = cpu_to_le16(sz); *_d = *d; - vring->ctx[i] = skb; + vring->ctx[i].skb = skb; return 0; } @@ -352,11 +352,11 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, return NULL; } - skb = vring->ctx[vring->swhead]; + skb = vring->ctx[vring->swhead].skb; d = wil_skb_rxdesc(skb); *d = *_d; pa = wil_desc_addr(&d->dma.addr); - vring->ctx[vring->swhead] = NULL; + vring->ctx[vring->swhead].skb = NULL; wil_vring_advance_head(vring, 1); dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); @@ -703,7 +703,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, if (unlikely(dma_mapping_error(dev, pa))) goto dma_error; wil_tx_desc_map(d, pa, len, vring_index); - vring->ctx[i] = NULL; + vring->ctx[i].mapped_as_page = 1; *_d = *d; } /* for the last seg only */ @@ -724,7 +724,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * to prevent skb release before accounting * in case of immediate "tx done" */ - vring->ctx[i] = skb_get(skb); + vring->ctx[i].skb = skb_get(skb); return 0; dma_error: @@ -732,6 +732,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /* Note: increment @f to operate with positive index */ for (f++; f > 0; f--) { u16 dmalen; + struct wil_ctx *ctx = &vring->ctx[i]; i = (swhead + f) % vring->size; _d = &(vring->va[i].tx); @@ -739,10 +740,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, _d->dma.status = TX_DMA_STATUS_DU; pa = wil_desc_addr(&d->dma.addr); dmalen = le16_to_cpu(d->dma.length); - if (vring->ctx[i]) - dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); - else + if (ctx->mapped_as_page) dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); + else + dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + + if (ctx->skb) + dev_kfree_skb_any(ctx->skb); + + memset(ctx, 0, sizeof(*ctx)); } return -EINVAL; @@ -821,8 +827,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) &vring->va[vring->swtail].tx; struct vring_tx_desc dd, *d = ⅆ dma_addr_t pa; - struct sk_buff *skb; u16 dmalen; + struct wil_ctx *ctx = &vring->ctx[vring->swtail]; + struct sk_buff *skb = ctx->skb; *d = *_d; @@ -840,7 +847,11 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) (const void *)d, sizeof(*d), false); pa = wil_desc_addr(&d->dma.addr); - skb = vring->ctx[vring->swtail]; + if (ctx->mapped_as_page) + dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); + else + dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + if (skb) { if (d->dma.error == 0) { ndev->stats.tx_packets++; @@ -849,12 +860,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) ndev->stats.tx_errors++; } - dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); dev_kfree_skb_any(skb); - vring->ctx[vring->swtail] = NULL; - } else { - dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); } + memset(ctx, 0, sizeof(*ctx)); /* * There is no need to touch HW descriptor: * - ststus bit TX_DMA_STATUS_DU is set by design, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 129c480c8a20..c4a51638736a 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -183,6 +183,14 @@ struct pending_wmi_event { } __packed event; }; +/** + * struct wil_ctx - software context for Vring descriptor + */ +struct wil_ctx { + struct sk_buff *skb; + u8 mapped_as_page:1; +}; + union vring_desc; struct vring { @@ -192,7 +200,7 @@ struct vring { u32 swtail; u32 swhead; u32 hwtail; /* write here to inform hw */ - void **ctx; /* void *ctx[size] - software context */ + struct wil_ctx *ctx; /* ctx[size] - software context */ }; enum { /* for wil6210_priv.status */ -- cgit v1.2.3 From 6cdadd4dc7621e47739a84548e70713e157fa850 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 11 Jul 2013 18:03:41 +0300 Subject: wil6210: fix subtle race in wil_tx_vring Finish all SW context modifications prior to notifying hardware It used to be race condition: if HW finish Tx and issue Tx completion IRQ very fast, prior to SW context update in wil_tx_vring, Tx completion will mis-handle descriptor, as SW part will have no skb pointer stored. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 44cdd2a3dff3..2a9d56a5fd0c 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -712,6 +712,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); *_d = *d; + /* hold reference to skb + * to prevent skb release before accounting + * in case of immediate "tx done" + */ + vring->ctx[i].skb = skb_get(skb); + wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); @@ -720,11 +726,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); - /* hold reference to skb - * to prevent skb release before accounting - * in case of immediate "tx done" - */ - vring->ctx[i].skb = skb_get(skb); return 0; dma_error: -- cgit v1.2.3 From a76e9ff18b7c4a3f8fc812fb71f55cb2eec74ba8 Mon Sep 17 00:00:00 2001 From: John Greene Date: Mon, 15 Jul 2013 14:33:34 -0400 Subject: brcmsmac: Further reduce log spam from tx phy messages Relegate 2 phy messages to debug status as they create excessive log spam, noted in multiple bugzillas for brcmsmac v3.8 and up. This is a follow on to net-next 99e94940697adec4f84758adb2db71f4a82c7ba5: brcmsmac: Reduce log spam in heavy tx, make err print in debug brcmsmac bcma0:0: phyerr 0x10, rate 0x14 brcmsmac bcma0:0: brcms_c_ampdu_dotxstatus_complete: ampdu tx phy error (0x10) Signed-off-by: John Greene Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/ampdu.c | 6 +++--- drivers/net/wireless/brcm80211/brcmsmac/main.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index bd982856d385..fa391e4eb098 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -928,9 +928,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, } } else if (txs->phyerr) { update_rate = false; - brcms_err(wlc->hw->d11core, - "%s: ampdu tx phy error (0x%x)\n", - __func__, txs->phyerr); + brcms_dbg_ht(wlc->hw->d11core, + "%s: ampdu tx phy error (0x%x)\n", + __func__, txs->phyerr); } } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 9fd6f2fef11b..7ca10bf4a4d3 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -882,8 +882,8 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) mcl = le16_to_cpu(txh->MacTxControlLow); if (txs->phyerr) - brcms_err(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n", - txs->phyerr, txh->MainRates); + brcms_dbg_tx(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n", + txs->phyerr, txh->MainRates); if (txs->frameid != le16_to_cpu(txh->TxFrameID)) { brcms_err(wlc->hw->d11core, "frameid != txh->TxFrameID\n"); -- cgit v1.2.3 From 4b03f16eb56820a1427efeb5372d982a36655315 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 16 Jul 2013 12:03:17 +0530 Subject: ath9k: Move INI overrides to ar9003_hw_override_ini Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 33 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 1f694ab3cc78..57e345a27914 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -632,6 +632,22 @@ static void ar9003_hw_override_ini(struct ath_hw *ah) REG_SET_BIT(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE, + AR_GLB_SWREG_DISCONT_EN_BT_WLAN); + + if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) + ah->enabled_cals |= TX_IQ_CAL; + else + ah->enabled_cals &= ~TX_IQ_CAL; + + if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) + ah->enabled_cals |= TX_CL_CAL; + else + ah->enabled_cals &= ~TX_CL_CAL; + } } static void ar9003_hw_prog_ini(struct ath_hw *ah, @@ -814,29 +830,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, if (chan->channel == 2484) ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE, - AR_GLB_SWREG_DISCONT_EN_BT_WLAN); - ah->modes_index = modesIndex; ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ath9k_hw_apply_txpower(ah, chan, false); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { - if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, - AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) - ah->enabled_cals |= TX_IQ_CAL; - else - ah->enabled_cals &= ~TX_IQ_CAL; - - if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) - ah->enabled_cals |= TX_CL_CAL; - else - ah->enabled_cals &= ~TX_CL_CAL; - } - return 0; } -- cgit v1.2.3 From 81dc75b584fd0f889b56b49b363287a600eaf0d3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 16 Jul 2013 12:03:18 +0530 Subject: ath9k: Add a HW flag for FCC Fast Channel Change across 2G/5G bands is supported only by AR9462 and AR9565. Add a HW capability field to indicate this. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 7 +++++++ drivers/net/wireless/ath/ath9k/hw.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e420c6ba62a7..f353bbd36857 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2610,6 +2610,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; + /* + * Fast channel change across bands is available + * only for AR9462 and AR9565. + */ + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) + pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH; + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index cd74b3afef7d..fd009e593b69 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -247,6 +247,7 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_DFS = BIT(16), ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), ATH9K_HW_CAP_PAPRD = BIT(18), + ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(19), }; /* -- cgit v1.2.3 From b840cffedee3a19b8c90becc4b999e6bf4f28cb0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 16 Jul 2013 12:03:19 +0530 Subject: ath9k: Fix FastChannelChange for AR9462/AR9565 Right now, even though these chips support cross-band FCC, the code is non-functional since we bail out early if the channelFlags differ. Fix this so that cross-band FCC works for cards that support this feature. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 45 ++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f353bbd36857..0208eee91c5b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1496,16 +1496,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_capabilities *pCap = &ah->caps; + bool band_switch = false, mode_diff = false; + u8 ini_reloaded; u32 qnum; int r; - bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); - bool band_switch, mode_diff; - u8 ini_reloaded; - band_switch = (chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ)) != - (ah->curchan->channelFlags & (CHANNEL_2GHZ | - CHANNEL_5GHZ)); - mode_diff = (chan->chanmode != ah->curchan->chanmode); + if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) { + u32 cur = ah->curchan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ); + u32 new = chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ); + band_switch = (cur != new); + mode_diff = (chan->chanmode != ah->curchan->chanmode); + } for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { @@ -1520,7 +1522,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return false; } - if (edma && (band_switch || mode_diff)) { + if (band_switch || mode_diff) { ath9k_hw_mark_phy_inactive(ah); udelay(5); @@ -1548,7 +1550,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ath9k_hw_spur_mitigate_freq(ah, chan); - if (edma && (band_switch || mode_diff)) { + if (band_switch || mode_diff) { ah->ah_flags |= AH_FASTCC; if (band_switch || ini_reloaded) ah->eep_ops->set_board_values(ah, chan); @@ -1778,16 +1780,11 @@ static void ath9k_hw_init_desc(struct ath_hw *ah) /* * Fast channel change: * (Change synthesizer based on channel freq without resetting chip) - * - * Don't do FCC when - * - Flag is not set - * - Chip is just coming out of full sleep - * - Channel to be set is same as current channel - * - Channel flags are different, (eg.,moving from 2GHz to 5GHz channel) */ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_capabilities *pCap = &ah->caps; int ret; if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) @@ -1806,9 +1803,21 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) (CHANNEL_HALF | CHANNEL_QUARTER)) goto fail; - if ((chan->channelFlags & CHANNEL_ALL) != - (ah->curchan->channelFlags & CHANNEL_ALL)) - goto fail; + /* + * If cross-band fcc is not supoprted, bail out if + * either channelFlags or chanmode differ. + * + * chanmode will be different if the HT operating mode + * changes because of CSA. + */ + if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH)) { + if ((chan->channelFlags & CHANNEL_ALL) != + (ah->curchan->channelFlags & CHANNEL_ALL)) + goto fail; + + if (chan->chanmode != ah->curchan->chanmode) + goto fail; + } if (!ath9k_hw_check_alive(ah)) goto fail; -- cgit v1.2.3 From 5f35c0fae9162b867d6cd035490fe4831151301d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 16 Jul 2013 12:03:20 +0530 Subject: ath9k: Use correct channel when switching bands Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0208eee91c5b..04f3a3b1724c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1526,7 +1526,8 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ath9k_hw_mark_phy_inactive(ah); udelay(5); - ath9k_hw_init_pll(ah, NULL); + if (band_switch) + ath9k_hw_init_pll(ah, chan); if (ath9k_hw_fast_chan_change(ah, chan, &ini_reloaded)) { ath_err(common, "Failed to do fast channel change\n"); -- cgit v1.2.3 From 07a9bd205575cee4907089c17e41da2c5cb1af2e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 16 Jul 2013 12:03:21 +0530 Subject: ath9k: Program correct initvals for FCC * CUS217 specific initvals have to be programmed. * iniAdditional is not used for AR9462/AR9565, remove it. * Handle channel 2484 for regulatory compliance. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 57e345a27914..2db4ddf74bc2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1517,6 +1517,18 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + if (AR_SREV_9462_20_OR_LATER(ah)) { + /* + * CUS217 mix LNA mode. + */ + if (ar9003_hw_get_rx_gain_idx(ah) == 2) { + REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_core, + 1, regWrites); + REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_postamble, + modesIndex, regWrites); + } + } + /* * For 5GHz channels requiring Fast Clock, apply * different modal values. @@ -1527,7 +1539,11 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, if (AR_SREV_9565(ah)) REG_WRITE_ARRAY(&ah->iniModesFastClock, 1, regWrites); - REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); + /* + * JAPAN regulatory. + */ + if (chan->channel == 2484) + ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1); ah->modes_index = modesIndex; *ini_reloaded = true; -- cgit v1.2.3 From 70e89a71c83b1937f1662429b255cf21e51aecea Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 16 Jul 2013 12:03:22 +0530 Subject: ath9k: Release the RF bus after setting board values Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 04f3a3b1724c..d55d97c85964 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1498,7 +1498,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_capabilities *pCap = &ah->caps; bool band_switch = false, mode_diff = false; - u8 ini_reloaded; + u8 ini_reloaded = 0; u32 qnum; int r; @@ -1544,22 +1544,21 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, } ath9k_hw_set_clockrate(ah); ath9k_hw_apply_txpower(ah, chan, false); - ath9k_hw_rfbus_done(ah); if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) ath9k_hw_set_delta_slope(ah, chan); ath9k_hw_spur_mitigate_freq(ah, chan); - if (band_switch || mode_diff) { - ah->ah_flags |= AH_FASTCC; - if (band_switch || ini_reloaded) - ah->eep_ops->set_board_values(ah, chan); + if (band_switch || ini_reloaded) + ah->eep_ops->set_board_values(ah, chan); - ath9k_hw_init_bb(ah, chan); + ath9k_hw_init_bb(ah, chan); + ath9k_hw_rfbus_done(ah); - if (band_switch || ini_reloaded) - ath9k_hw_init_cal(ah, chan); + if (band_switch || ini_reloaded) { + ah->ah_flags |= AH_FASTCC; + ath9k_hw_init_cal(ah, chan); ah->ah_flags &= ~AH_FASTCC; } -- cgit v1.2.3 From f291f7deeeef84bd113ff3c309862a888e8f181b Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Sat, 20 Jul 2013 00:02:25 -0400 Subject: cw1200: Fix incorrect endianness annotation in a header field Note that the driver doesn't directly use this field, but it should be correctly defined in any case. Signed-off-by: Solomon Peachy Signed-off-by: John W. Linville --- drivers/net/wireless/cw1200/wsm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/cw1200/wsm.h b/drivers/net/wireless/cw1200/wsm.h index 7afc613c3706..48086e849515 100644 --- a/drivers/net/wireless/cw1200/wsm.h +++ b/drivers/net/wireless/cw1200/wsm.h @@ -832,7 +832,7 @@ struct wsm_tx { /* the MSDU shall be terminated. Overrides the global */ /* dot11MaxTransmitMsduLifeTime setting [optional] */ /* Device will set the default value if this is 0. */ - u32 expire_time; + __le32 expire_time; /* WSM_HT_TX_... */ __le32 ht_tx_parameters; -- cgit v1.2.3 From c2a146f61014543fc4b52acaddcaa31b9f17453d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 21 Jul 2013 11:34:36 +0300 Subject: wil6210: fix error path in wil_tx_vring Release fragments in the order of allocation; including one for skb head Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 2a9d56a5fd0c..e563af13740b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -730,12 +730,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return 0; dma_error: /* unmap what we have mapped */ - /* Note: increment @f to operate with positive index */ - for (f++; f > 0; f--) { + nr_frags = f + 1; /* frags mapped + one for skb head */ + for (f = 0; f < nr_frags; f++) { u16 dmalen; - struct wil_ctx *ctx = &vring->ctx[i]; + struct wil_ctx *ctx; i = (swhead + f) % vring->size; + ctx = &vring->ctx[i]; _d = &(vring->va[i].tx); *d = *_d; _d->dma.status = TX_DMA_STATUS_DU; -- cgit v1.2.3 From 504937d4933fc8f5248b3af63b350ca52fc3b2f7 Mon Sep 17 00:00:00 2001 From: Kirshenbaum Erez Date: Sun, 21 Jul 2013 11:34:37 +0300 Subject: wil6210: Enable TCP/UDP checksum HW offload Add support for TCP and UDP HW checksum offloading. RX chain is allways configured for offload mode. In case of checksum error in RX path the DMA L4 error bit(5) will be set to 1 and driver will drop the packet. TX checksum offloading is configrable (ethtool -K). TX descriptors are configured for checksum offload according to the SKB protocol type (TCP/UDP, IPV4/6), Upon mismatch drop the TX packet (checksum required but not TCP/UDP IPV4/6 type). Signed-off-by: Kirshenbaum Erez Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/netdev.c | 2 + drivers/net/wireless/ath/wil6210/txrx.c | 76 ++++++++++++++++++++++++++++++- drivers/net/wireless/ath/wil6210/txrx.h | 20 +++++++- drivers/net/wireless/ath/wil6210/wmi.c | 6 +++ 4 files changed, 101 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 29dd1e58cb17..717178f09aa8 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -127,6 +127,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ndev->netdev_ops = &wil_netdev_ops; ndev->ieee80211_ptr = wdev; + ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index e563af13740b..ea1abeb18e5b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include "wil6210.h" #include "wmi.h" @@ -407,6 +410,21 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, return NULL; } + /* L4 IDENT is on when HW calculated checksum, check status + * and in case of error drop the packet + * higher stack layers will handle retransmission (if required) + */ + if (d->dma.status & RX_DMA_STATUS_L4_IDENT) { + /* L4 protocol identified, csum calculated */ + if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + wil_err(wil, "Incorrect checksum reported\n"); + kfree_skb(skb); + return NULL; + } + } + ds_bits = wil_rxdesc_ds_bits(d); if (ds_bits == 1) { /* @@ -646,6 +664,53 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, return 0; } +static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, + struct vring_tx_desc *d, + struct sk_buff *skb) +{ + int protocol; + + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + + switch (skb->protocol) { + case cpu_to_be16(ETH_P_IP): + protocol = ip_hdr(skb)->protocol; + break; + case cpu_to_be16(ETH_P_IPV6): + protocol = ipv6_hdr(skb)->nexthdr; + break; + default: + return -EINVAL; + } + + switch (protocol) { + case IPPROTO_TCP: + d->dma.d0 |= (2 << DMA_CFG_DESC_TX_0_L4_TYPE_POS); + /* L4 header len: TCP header length */ + d->dma.d0 |= + (tcp_hdrlen(skb) & DMA_CFG_DESC_TX_0_L4_LENGTH_MSK); + break; + case IPPROTO_UDP: + /* L4 header len: UDP header length */ + d->dma.d0 |= + (sizeof(struct udphdr) & DMA_CFG_DESC_TX_0_L4_LENGTH_MSK); + break; + default: + return -EINVAL; + } + + d->dma.ip_length = skb_network_header_len(skb); + d->dma.b11 = ETH_HLEN; /* MAC header length */ + d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS); + /* Enable TCP/UDP checksum */ + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS); + /* Calculate pseudo-header */ + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS); + + return 0; +} + static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct sk_buff *skb) { @@ -655,7 +720,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, u32 swhead = vring->swhead; int avail = wil_vring_avail_tx(vring); int nr_frags = skb_shinfo(skb)->nr_frags; - uint f; + uint f = 0; int vring_index = vring - wil->vring_tx; uint i = swhead; dma_addr_t pa; @@ -686,13 +751,20 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return -EINVAL; /* 1-st segment */ wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); + /* Process TCP/UDP checksum offloading */ + if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { + wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n", + vring_index); + goto dma_error; + } + d->mac.d[2] |= ((nr_frags + 1) << MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); if (nr_frags) *_d = *d; /* middle segments */ - for (f = 0; f < nr_frags; f++) { + for (; f < nr_frags; f++) { const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[f]; int len = skb_frag_size(frag); diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 859aea68a1fa..b3828279204c 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -235,7 +235,16 @@ struct vring_tx_mac { #define DMA_CFG_DESC_TX_0_L4_TYPE_POS 30 #define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2 -#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 +#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 /* L4 type: 0-UDP, 2-TCP */ + + +#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_POS 0 +#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_LEN 7 +#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_MSK 0x7F /* MAC hdr len */ + +#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS 7 +#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_LEN 1 +#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_MSK 0x80 /* 1-IPv4, 0-IPv6 */ #define TX_DMA_STATUS_DU BIT(0) @@ -334,8 +343,17 @@ struct vring_rx_mac { #define RX_DMA_D0_CMD_DMA_IT BIT(10) +/* Error field, offload bits */ +#define RX_DMA_ERROR_L3_ERR BIT(4) +#define RX_DMA_ERROR_L4_ERR BIT(5) + + +/* Status field */ #define RX_DMA_STATUS_DU BIT(0) #define RX_DMA_STATUS_ERROR BIT(2) + +#define RX_DMA_STATUS_L3_IDENT BIT(4) +#define RX_DMA_STATUS_L4_IDENT BIT(5) #define RX_DMA_STATUS_PHY_INFO BIT(6) struct vring_rx_dma { diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index a62511a78ac6..5220f158b8f5 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -924,6 +924,12 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) cmd.sniffer_cfg.phy_support = cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); + } else { + /* Initialize offload (in non-sniffer mode). + * Linux IP stack always calculates IP checksum + * HW always calculate TCP/UDP checksum + */ + cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS); } /* typical time for secure PCP is 840ms */ rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), -- cgit v1.2.3 From c6c7788fe26fdc91e729f60742815ccdb505fd81 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 22 Jul 2013 12:53:48 +0300 Subject: wil6210: drop -Werror compiler flag In production code, don't use -Werror, as it causes random compilation failures due to compiler version and options used. With every new version of gcc, it becomes stricter and report more warnings. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/Makefile | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index f891d514d881..990dd42ae79e 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -11,9 +11,6 @@ wil6210-y += txrx.o wil6210-y += debug.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o -ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) - subdir-ccflags-y += -Werror -endif # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) -- cgit v1.2.3 From 45fe142cefa864b685615bcb930159f6749c3667 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Jun 2013 08:05:06 -0700 Subject: iwl3945: better skb management in rx path Steinar reported reallocations of skb->head with IPv6, leading to a warning in skb_try_coalesce() It turns out iwl3945 has several problems : 1) skb->truesize is underestimated. We really consume PAGE_SIZE bytes for a fragment, not the frame length. 2) 128 bytes of initial headroom is a bit low and forces reallocations. 3) We can avoid consuming a full page for small enough frames. Reported-by: Steinar H. Gunderson Signed-off-by: Eric Dumazet Cc: Paul Stewart Acked-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/3945.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c index c092033945cc..f09e257759d5 100644 --- a/drivers/net/wireless/iwlegacy/3945.c +++ b/drivers/net/wireless/iwlegacy/3945.c @@ -475,6 +475,8 @@ il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header) } } +#define SMALL_PACKET_SIZE 256 + static void il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb, struct ieee80211_rx_status *stats) @@ -483,14 +485,13 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IL_RX_DATA(pkt); struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt); struct il3945_rx_frame_end *rx_end = IL_RX_END(pkt); - u16 len = le16_to_cpu(rx_hdr->len); + u32 len = le16_to_cpu(rx_hdr->len); struct sk_buff *skb; __le16 fc = hdr->frame_control; + u32 fraglen = PAGE_SIZE << il->hw_params.rx_page_order; /* We received data from the HW, so stop the watchdog */ - if (unlikely - (len + IL39_RX_FRAME_SIZE > - PAGE_SIZE << il->hw_params.rx_page_order)) { + if (unlikely(len + IL39_RX_FRAME_SIZE > fraglen)) { D_DROP("Corruption detected!\n"); return; } @@ -506,26 +507,32 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb, D_INFO("Woke queues - frame received on passive channel\n"); } - skb = dev_alloc_skb(128); + skb = dev_alloc_skb(SMALL_PACKET_SIZE); if (!skb) { IL_ERR("dev_alloc_skb failed\n"); return; } if (!il3945_mod_params.sw_crypto) - il_set_decrypted_flag(il, (struct ieee80211_hdr *)rxb_addr(rxb), + il_set_decrypted_flag(il, (struct ieee80211_hdr *)pkt, le32_to_cpu(rx_end->status), stats); - skb_add_rx_frag(skb, 0, rxb->page, - (void *)rx_hdr->payload - (void *)pkt, len, - len); - + /* If frame is small enough to fit into skb->head, copy it + * and do not consume a full page + */ + if (len <= SMALL_PACKET_SIZE) { + memcpy(skb_put(skb, len), rx_hdr->payload, len); + } else { + skb_add_rx_frag(skb, 0, rxb->page, + (void *)rx_hdr->payload - (void *)pkt, len, + fraglen); + il->alloc_rxb_page--; + rxb->page = NULL; + } il_update_stats(il, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(il->hw, skb); - il->alloc_rxb_page--; - rxb->page = NULL; } #define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) -- cgit v1.2.3 From 0e15370dbc7ab4d4ffd006620024ac3a52cc8c43 Mon Sep 17 00:00:00 2001 From: Huawei Yang Date: Mon, 22 Jul 2013 19:17:38 -0700 Subject: mwifiex: remove stop_net_dev_queue operation in AP forwarding Under uAP mode mwifiex may stop all net tx queues on forwarding packets. This may stop some tx queues and they never have chance to be waked up. There is also no need to check tx_pending and stop queues here. Because local host has such kind of check when transmitting packets and it's not proper to have forwarding affect local transmitting. Signed-off-by: Huawei Yang Reviewed-by: Avinash Patil Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/uap_txrx.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index a018e42d117e..11df2b2f8923 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -95,10 +95,6 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, atomic_inc(&adapter->tx_pending); atomic_inc(&adapter->pending_bridged_pkts); - if ((atomic_read(&adapter->tx_pending) >= MAX_TX_PENDING)) { - mwifiex_set_trans_start(priv->netdev); - mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); - } return; } -- cgit v1.2.3 From f0cb84f8a1925ad1ff0a10c345b83db5f8043428 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jul 2013 19:17:39 -0700 Subject: mwifiex: rename pkt_count to ba_pkt_count in mwifiex_ra_list_tbl struct pkt_count is used to determine if BA can be formed on this RA list by comparing it with randomly generated BA threshold. The pkt_count variable name here is ambiguous and does not reflect its usage correctly. Rename it to ba_pkt_count. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/wmm.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 3da73d36acdf..dff95fede51f 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -207,7 +207,7 @@ struct mwifiex_ra_list_tbl { u32 total_pkts_size; u32 is_11n_enabled; u16 max_amsdu; - u16 pkt_count; + u16 ba_pkt_count; u8 ba_packet_thr; }; diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 944e8846f6fc..9c1eeeee667e 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -188,7 +188,7 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra) ra_list, ra_list->is_11n_enabled); if (ra_list->is_11n_enabled) { - ra_list->pkt_count = 0; + ra_list->ba_pkt_count = 0; ra_list->ba_packet_thr = mwifiex_get_random_ba_threshold(); } @@ -680,7 +680,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, skb_queue_tail(&ra_list->skb_head, skb); ra_list->total_pkts_size += skb->len; - ra_list->pkt_count++; + ra_list->ba_pkt_count++; if (atomic_read(&priv->wmm.highest_queued_prio) < tos_to_tid_inv[tid_down]) @@ -1063,7 +1063,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, skb_queue_tail(&ptr->skb_head, skb); ptr->total_pkts_size += skb->len; - ptr->pkt_count++; + ptr->ba_pkt_count++; tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -1224,7 +1224,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) mwifiex_send_single_packet() */ } else { if (mwifiex_is_ampdu_allowed(priv, tid) && - ptr->pkt_count > ptr->ba_packet_thr) { + ptr->ba_pkt_count > ptr->ba_packet_thr) { if (mwifiex_space_avail_for_new_ba_stream(adapter)) { mwifiex_create_ba_tbl(priv, ptr->ra, tid, BA_SETUP_INPROGRESS); -- cgit v1.2.3 From c7d9ed9ec9b2947a9c5dc5e2c7afce1fd3ad82cc Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jul 2013 19:17:40 -0700 Subject: mwifiex: maintain outstanding packet count for RA list instead of packet size Maintain total outstanding packet count for RA list instead of total outstanding size as packet count metric seems more reasonable for checking threshold etc. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_aggr.c | 4 ++-- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/wmm.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index a78e0651409c..8f9f54231a1c 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -189,7 +189,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_src = skb_dequeue(&pra_list->skb_head); - pra_list->total_pkts_size -= skb_src->len; + pra_list->total_pkt_count--; atomic_dec(&priv->wmm.tx_pkts_queued); @@ -268,7 +268,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_queue_tail(&pra_list->skb_head, skb_aggr); - pra_list->total_pkts_size += skb_aggr->len; + pra_list->total_pkt_count++; atomic_inc(&priv->wmm.tx_pkts_queued); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index dff95fede51f..761e5927eee3 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -204,11 +204,11 @@ struct mwifiex_ra_list_tbl { struct list_head list; struct sk_buff_head skb_head; u8 ra[ETH_ALEN]; - u32 total_pkts_size; u32 is_11n_enabled; u16 max_amsdu; u16 ba_pkt_count; u8 ba_packet_thr; + u16 total_pkt_count; }; struct mwifiex_tid_tbl { diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 9c1eeeee667e..2e8f9cdea54d 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -120,7 +120,7 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) memcpy(ra_list->ra, ra, ETH_ALEN); - ra_list->total_pkts_size = 0; + ra_list->total_pkt_count = 0; dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); @@ -679,8 +679,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, skb_queue_tail(&ra_list->skb_head, skb); - ra_list->total_pkts_size += skb->len; ra_list->ba_pkt_count++; + ra_list->total_pkt_count++; if (atomic_read(&priv->wmm.highest_queued_prio) < tos_to_tid_inv[tid_down]) @@ -1037,7 +1037,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, tx_info = MWIFIEX_SKB_TXCB(skb); dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); - ptr->total_pkts_size -= skb->len; + ptr->total_pkt_count--; if (!skb_queue_empty(&ptr->skb_head)) skb_next = skb_peek(&ptr->skb_head); @@ -1062,7 +1062,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, skb_queue_tail(&ptr->skb_head, skb); - ptr->total_pkts_size += skb->len; + ptr->total_pkt_count++; ptr->ba_pkt_count++; tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, -- cgit v1.2.3 From 61c873045f74b16317c88e2931637329a6844564 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jul 2013 19:17:41 -0700 Subject: mwifiex: delete AP TX queues when bridged packets reach threshold Delete packets from TX queues for this mwifiex_private structure when bridged packet count reaches maximum threshold. Bridged packets from each RA List are deleted till they fall to low threshold of 128. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/decl.h | 3 +- drivers/net/wireless/mwifiex/init.c | 1 + drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/uap_txrx.c | 66 ++++++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 94cc09d48444..a5993475daef 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -75,7 +75,8 @@ #define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) #define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1) -#define MWIFIEX_BRIDGED_PKTS_THRESHOLD 1024 +#define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024 +#define MWIFIEX_BRIDGED_PKTS_THR_LOW 128 enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index caaf4bd56b30..fb86cec1b5cd 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -135,6 +135,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->csa_chan = 0; priv->csa_expire_time = 0; + priv->del_list_idx = 0; return mwifiex_add_bss_prio_tbl(priv); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 761e5927eee3..5db05435d412 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -515,6 +515,7 @@ struct mwifiex_private { bool scan_aborting; u8 csa_chan; unsigned long csa_expire_time; + u8 del_list_idx; }; enum mwifiex_ba_status { diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 11df2b2f8923..1cfe5a738c47 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -24,6 +24,69 @@ #include "11n_aggr.h" #include "11n_rxreorder.h" +/* This function checks if particular RA list has packets more than low bridge + * packet threshold and then deletes packet from this RA list. + * Function deletes packets from such RA list and returns true. If no such list + * is found, false is returned. + */ +static bool +mwifiex_uap_del_tx_pkts_in_ralist(struct mwifiex_private *priv, + struct list_head *ra_list_head) +{ + struct mwifiex_ra_list_tbl *ra_list; + struct sk_buff *skb, *tmp; + bool pkt_deleted = false; + struct mwifiex_txinfo *tx_info; + struct mwifiex_adapter *adapter = priv->adapter; + + list_for_each_entry(ra_list, ra_list_head, list) { + if (skb_queue_empty(&ra_list->skb_head)) + continue; + + skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) { + tx_info = MWIFIEX_SKB_TXCB(skb); + if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) { + __skb_unlink(skb, &ra_list->skb_head); + mwifiex_write_data_complete(adapter, skb, 0, + -1); + atomic_dec(&priv->wmm.tx_pkts_queued); + pkt_deleted = true; + } + if ((atomic_read(&adapter->pending_bridged_pkts) <= + MWIFIEX_BRIDGED_PKTS_THR_LOW)) + break; + } + } + + return pkt_deleted; +} + +/* This function deletes packets from particular RA List. RA list index + * from which packets are deleted is preserved so that packets from next RA + * list are deleted upon subsequent call thus maintaining fairness. + */ +static void mwifiex_uap_cleanup_tx_queues(struct mwifiex_private *priv) +{ + unsigned long flags; + struct list_head *ra_list; + int i; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + for (i = 0; i < MAX_NUM_TID; i++, priv->del_list_idx++) { + if (priv->del_list_idx == MAX_NUM_TID) + priv->del_list_idx = 0; + ra_list = &priv->wmm.tid_tbl_ptr[priv->del_list_idx].ra_list; + if (mwifiex_uap_del_tx_pkts_in_ralist(priv, ra_list)) { + priv->del_list_idx++; + break; + } + } + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + + static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, struct sk_buff *skb) { @@ -40,10 +103,11 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset); if ((atomic_read(&adapter->pending_bridged_pkts) >= - MWIFIEX_BRIDGED_PKTS_THRESHOLD)) { + MWIFIEX_BRIDGED_PKTS_THR_HIGH)) { dev_err(priv->adapter->dev, "Tx: Bridge packet limit reached. Drop packet!\n"); kfree_skb(skb); + mwifiex_uap_cleanup_tx_queues(priv); return; } -- cgit v1.2.3 From 231d83e29e44e39d987ea4c33caf7869cf5ef4c7 Mon Sep 17 00:00:00 2001 From: Huawei Yang Date: Mon, 22 Jul 2013 19:17:42 -0700 Subject: mwifiex: add tx info to skb when forming mgmt frame In function 'mwifiex_write_data_complete' it need tx info to find the mwifiex_private to updates statistics and wake up tx queues. Or we may trigger tx queues timeout when transmitting lots of mgmt frames. Signed-off-by: Huawei Yang Signed-off-by: Stone Piao Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ef5fa890a286..d824feea39ec 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -189,6 +189,7 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct sk_buff *skb; u16 pkt_len; const struct ieee80211_mgmt *mgmt; + struct mwifiex_txinfo *tx_info; struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); if (!buf || !len) { @@ -216,6 +217,10 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, return -ENOMEM; } + tx_info = MWIFIEX_SKB_TXCB(skb); + tx_info->bss_num = priv->bss_num; + tx_info->bss_type = priv->bss_type; + mwifiex_form_mgmt_frame(skb, buf, len); mwifiex_queue_tx_pkt(priv, skb); -- cgit v1.2.3 From eaf49dbc4b7ef7e9fe420713730e403c9ba0bef1 Mon Sep 17 00:00:00 2001 From: Stone Piao Date: Mon, 22 Jul 2013 19:17:43 -0700 Subject: mwifiex: discard deauth and disassoc event during WPS session Some GO will send deauth or disassoc packet at the end of WPS handshake, which causes P2P connecion failure due to the race condition between event path and data path. Signed-off-by: Stone Piao Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_event.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index ea265ec0e522..8b057524b252 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -201,6 +201,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_DEAUTHENTICATED: dev_dbg(adapter->dev, "event: Deauthenticated\n"); + if (priv->wps.session_enable) { + dev_dbg(adapter->dev, + "info: receive deauth event in wps session\n"); + break; + } adapter->dbg.num_event_deauth++; if (priv->media_connected) { reason_code = @@ -211,6 +216,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_DISASSOCIATED: dev_dbg(adapter->dev, "event: Disassociated\n"); + if (priv->wps.session_enable) { + dev_dbg(adapter->dev, + "info: receive disassoc event in wps session\n"); + break; + } adapter->dbg.num_event_disassoc++; if (priv->media_connected) { reason_code = -- cgit v1.2.3 From 4481b2dba0930015d7c15acd0b69a3a89cae3591 Mon Sep 17 00:00:00 2001 From: Stone Piao Date: Mon, 22 Jul 2013 19:17:44 -0700 Subject: mwifiex: skip registering mgmt frame that has already registered Before sending command to firmware, we need to check the frame type. We skip registering the mgmt frame that has already been registered. Signed-off-by: Stone Piao Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index d824feea39ec..dbdd3b2a5eb5 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -240,16 +240,20 @@ mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy, u16 frame_type, bool reg) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); + u32 mask; if (reg) - priv->mgmt_frame_mask |= BIT(frame_type >> 4); + mask = priv->mgmt_frame_mask | BIT(frame_type >> 4); else - priv->mgmt_frame_mask &= ~BIT(frame_type >> 4); + mask = priv->mgmt_frame_mask & ~BIT(frame_type >> 4); - mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG, - HostCmd_ACT_GEN_SET, 0, &priv->mgmt_frame_mask); - - wiphy_dbg(wiphy, "info: mgmt frame registered\n"); + if (mask != priv->mgmt_frame_mask) { + priv->mgmt_frame_mask = mask; + mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG, + HostCmd_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask); + wiphy_dbg(wiphy, "info: mgmt frame registered\n"); + } } /* -- cgit v1.2.3 From 5e4c07987f4db22cbc3e1dadb021baab0a34a57f Mon Sep 17 00:00:00 2001 From: Stone Piao Date: Mon, 22 Jul 2013 19:17:45 -0700 Subject: mwifiex: support to send deauth for P2P client During P2P handshake, P2P client needs to send deauth after EAPOL FAILURE to GO. We need add bss mode for P2P client when handle deauth request. Without this change, deauth can not be sent out from P2P client side. Signed-off-by: Stone Piao Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/join.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 1c8a771e8e81..ba043ca2a34a 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1425,6 +1425,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) switch (priv->bss_mode) { case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: return mwifiex_deauthenticate_infra(priv, mac); case NL80211_IFTYPE_ADHOC: return mwifiex_send_cmd_sync(priv, -- cgit v1.2.3 From 8795ca61e4ff3db70f2d072a28aaefc29f1a2301 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jul 2013 19:17:46 -0700 Subject: mwifiex: correct max IE length check for WPS IE This patch is bug fix for an invalid boundry check for WPS IE. We should check max IE length against defined macro; instead we were checking it against size of pointer. Fix it. Also move IE length check before allocation of memory. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_ioctl.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 206c3e038072..c071ce91c8b2 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -797,15 +797,16 @@ static int mwifiex_set_wps_ie(struct mwifiex_private *priv, u8 *ie_data_ptr, u16 ie_len) { if (ie_len) { - priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL); - if (!priv->wps_ie) - return -ENOMEM; - if (ie_len > sizeof(priv->wps_ie)) { + if (ie_len > MWIFIEX_MAX_VSIE_LEN) { dev_dbg(priv->adapter->dev, "info: failed to copy WPS IE, too big\n"); - kfree(priv->wps_ie); return -1; } + + priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL); + if (!priv->wps_ie) + return -ENOMEM; + memcpy(priv->wps_ie, ie_data_ptr, ie_len); priv->wps_ie_len = ie_len; dev_dbg(priv->adapter->dev, "cmd: Set wps_ie_len=%d IE=%#x\n", -- cgit v1.2.3 From 43ba6b9f2f5e8090f16e8efe19d17cc8ce291d22 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:47 -0700 Subject: mwifiex: add PCIe shutdown handler to avoid system hang on reboot If reboot command is issued when device is in connected state, system hangs while booting. This issue is fixed by doing cleanup in shutdown handler. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 4a57eb45f9a8..dce648682694 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -235,6 +235,14 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) kfree(card); } +static void mwifiex_pcie_shutdown(struct pci_dev *pdev) +{ + user_rmmod = 1; + mwifiex_pcie_remove(pdev); + + return; +} + static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = { { PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P, @@ -268,6 +276,7 @@ static struct pci_driver __refdata mwifiex_pcie = { .pm = &mwifiex_pcie_pm_ops, }, #endif + .shutdown = mwifiex_pcie_shutdown, }; /* -- cgit v1.2.3 From 003d87cbece50c2a558c954b7ce915dcc70acba7 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:48 -0700 Subject: mwifiex: move del_timer_sync(scan_delay_timer) call to fix memleak Currently it is in mwifiex_adapter_cleanup() which doesn't get called if driver initialization is failed causing memory leak. scan_delay_timer is initialized in mwifiex_register(), so it should be deleted in mwifiex_unregister(). Hence it has been moved to appropriate place. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/init.c | 7 ------- drivers/net/wireless/mwifiex/main.c | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index fb86cec1b5cd..f23520f47717 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -378,18 +378,11 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) static void mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) { - int i; - if (!adapter) { pr_err("%s: adapter is NULL\n", __func__); return; } - for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) - del_timer_sync(&adapter->priv[i]->scan_delay_timer); - } - mwifiex_cancel_all_pending_cmd(adapter); /* Free lock variables */ diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index e15ab72fb03d..ef151c58ac14 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -197,6 +197,7 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { mwifiex_free_curr_bcn(adapter->priv[i]); + del_timer_sync(&adapter->priv[i]->scan_delay_timer); kfree(adapter->priv[i]); } } -- cgit v1.2.3 From f3340e6cfd0100d70653fe8a300049420e464deb Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:49 -0700 Subject: mwifiex: remove unnecessary del_timer(cmd_timer) It is already there in mwifiex_unregister(). So unnecessary call in mwifiex_adapter_cleanup() is removed in this patch. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/init.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index f23520f47717..2a430c9cbd0e 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -392,8 +392,6 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) dev_dbg(adapter->dev, "info: free cmd buffer\n"); mwifiex_free_cmd_buffer(adapter); - del_timer(&adapter->cmd_timer); - dev_dbg(adapter->dev, "info: free scan table\n"); if (adapter->if_ops.cleanup_if) -- cgit v1.2.3 From 4cfda67d8f37cc422ad9f181c173a241c913055b Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:50 -0700 Subject: mwifiex: move if_ops.cleanup_if() call As if_ops.init_if() is called in mwifiex_register(), corresponding cleanup routine should be called in mwifiex_unregister(). Currently it's there in mwifiex_adapter_cleanup(), hence interface specific cleanup is not performed if driver initialization is failed. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/init.c | 3 --- drivers/net/wireless/mwifiex/main.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 2a430c9cbd0e..2ef450e99c75 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -394,9 +394,6 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) dev_dbg(adapter->dev, "info: free scan table\n"); - if (adapter->if_ops.cleanup_if) - adapter->if_ops.cleanup_if(adapter); - if (adapter->sleep_cfm) dev_kfree_skb_any(adapter->sleep_cfm); } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index ef151c58ac14..f26beb7ed022 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -191,6 +191,9 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) { s32 i; + if (adapter->if_ops.cleanup_if) + adapter->if_ops.cleanup_if(adapter); + del_timer(&adapter->cmd_timer); /* Free private structures */ -- cgit v1.2.3 From 2739a95d708c67ff541826f79ef0b2d19320306f Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:51 -0700 Subject: mwifiex: add unregister_dev handler for usb interface Clear the data pointer stored in USB interface structure in this handler. This helps to return from mwifiex_usb_disconnect() if driver deinitialization is already performed while handling an error path for mwifiex_usb_probe(). USB8797 card gets enumerated twice. First enumeration is for firmware download and second enumeration expects firmware initialization. mwifiex_usb_probe() always takes care of deinitialization for first enumeration after firmware download. Also, this change matches our handling for SDIO and PCIe interfaces. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/usb.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index f90fe21e5bfd..fca98b5d7de4 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -786,6 +786,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) return 0; } +static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + + usb_set_intfdata(card->intf, NULL); +} + static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *fw) { @@ -978,6 +985,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) static struct mwifiex_if_ops usb_ops = { .register_dev = mwifiex_register_dev, + .unregister_dev = mwifiex_unregister_dev, .wakeup = mwifiex_pm_wakeup_card, .wakeup_complete = mwifiex_pm_wakeup_card_complete, -- cgit v1.2.3 From d00062e318b1e4a4bec8a8e343efe8bc92d3b109 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:52 -0700 Subject: mwifiex: reduce firmware poll retries After downloading the firmware, firmware status is checked by reading a register. Polling interval is 100 msecs. Therefore 100 retries means the status is checked for 10 secs which is more than sufficient for firmware to get ready. This patch removes 1000 retries macro usage, because 100secs time is not practical. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/fw.h | 3 --- drivers/net/wireless/mwifiex/init.c | 1 - 2 files changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 1b45aa533300..99c27296cbef 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -85,9 +85,6 @@ enum KEY_TYPE_ID { #define WAPI_KEY_LEN 50 #define MAX_POLL_TRIES 100 - -#define MAX_MULTI_INTERFACE_POLL_TRIES 1000 - #define MAX_FIRMWARE_POLL_TRIES 100 #define FIRMWARE_READY_SDIO 0xfedc diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 2ef450e99c75..e4c5ae34c6a8 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -691,7 +691,6 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, if (!adapter->winner) { dev_notice(adapter->dev, "FW already running! Skip FW dnld\n"); - poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; goto poll_fw; } } -- cgit v1.2.3 From a76b20e5ca8a9ec0b45a4150b4ad19e27dd19699 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:53 -0700 Subject: mwifiex: replace mdelay with msleep It is observed that when wrong firmware is downloaded for PCIe card, system hangs for 10 seconds. The reason is mdelay() is used when firmware status is polled. Replace mdelay with msleep(non-blocking API) to fix the issue. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 2 +- drivers/net/wireless/mwifiex/sdio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index dce648682694..098153f14e18 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1942,7 +1942,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) ret = 0; break; } else { - mdelay(100); + msleep(100); ret = -1; } } diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 5ee5ed02eccd..14ac51fd7d3c 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -927,7 +927,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, ret = 0; break; } else { - mdelay(100); + msleep(100); ret = -1; } } -- cgit v1.2.3 From bedb361b5092ee9aa77ba9d0114bf75e8520825e Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:54 -0700 Subject: mwifiex: correction in mwifiex_check_fw_status() return status For PCIe cards, when wrong firmware is downloaded, firmware is failed to be ready in 10 seconds. We should return an error at this point. But currently we are sending first command to firmware. As expected firmware doesn't respond to this command and command timeout occurs. This patch fixes the problem by removing unnecessary 'ret' variable modifications in "if (ret) {" block. The block is just supposed to update "adapter->winner" flag. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 098153f14e18..52da8ee7599a 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1954,12 +1954,10 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) else if (!winner_status) { dev_err(adapter->dev, "PCI-E is the winner\n"); adapter->winner = 1; - ret = -1; } else { dev_err(adapter->dev, "PCI-E is not the winner <%#x,%d>, exit dnld\n", ret, adapter->winner); - ret = 0; } } -- cgit v1.2.3 From 6b21a69fbc5c60c44634963f3fe3e6f1d9140d3a Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:57 -0700 Subject: mwifiex: remove duplicate structure host_cmd_tlv We already have 'struct mwifiex_ie_types_header' with same definition. Hence host_cmd_tlv is removed in this patch. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/fw.h | 41 +++++------ drivers/net/wireless/mwifiex/ie.c | 2 +- drivers/net/wireless/mwifiex/sta_cmd.c | 5 +- drivers/net/wireless/mwifiex/uap_cmd.c | 130 +++++++++++++++++---------------- 4 files changed, 91 insertions(+), 87 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 99c27296cbef..c0dfc4dea75a 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -1366,11 +1366,6 @@ struct host_cmd_ds_802_11_eeprom_access { u8 value; } __packed; -struct host_cmd_tlv { - __le16 type; - __le16 len; -} __packed; - struct mwifiex_assoc_event { u8 sta_addr[ETH_ALEN]; __le16 type; @@ -1396,99 +1391,99 @@ struct host_cmd_11ac_vht_cfg { } __packed; struct host_cmd_tlv_akmp { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; __le16 key_mgmt; __le16 key_mgmt_operation; } __packed; struct host_cmd_tlv_pwk_cipher { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; __le16 proto; u8 cipher; u8 reserved; } __packed; struct host_cmd_tlv_gwk_cipher { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 cipher; u8 reserved; } __packed; struct host_cmd_tlv_passphrase { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 passphrase[0]; } __packed; struct host_cmd_tlv_wep_key { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 key_index; u8 is_default; u8 key[1]; }; struct host_cmd_tlv_auth_type { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 auth_type; } __packed; struct host_cmd_tlv_encrypt_protocol { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; __le16 proto; } __packed; struct host_cmd_tlv_ssid { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 ssid[0]; } __packed; struct host_cmd_tlv_rates { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 rates[0]; } __packed; struct host_cmd_tlv_bcast_ssid { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 bcast_ctl; } __packed; struct host_cmd_tlv_beacon_period { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; __le16 period; } __packed; struct host_cmd_tlv_dtim_period { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 period; } __packed; struct host_cmd_tlv_frag_threshold { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; __le16 frag_thr; } __packed; struct host_cmd_tlv_rts_threshold { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; __le16 rts_thr; } __packed; struct host_cmd_tlv_retry_limit { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 limit; } __packed; struct host_cmd_tlv_mac_addr { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 mac_addr[ETH_ALEN]; } __packed; struct host_cmd_tlv_channel_band { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; u8 band_config; u8 channel; } __packed; struct host_cmd_tlv_ageout_timer { - struct host_cmd_tlv tlv; + struct mwifiex_ie_types_header header; __le32 sta_ao_timer; } __packed; diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index e38342f86c51..220af4fe0fc6 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -87,7 +87,7 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv, u8 *tmp; input_len = le16_to_cpu(ie_list->len); - travel_len = sizeof(struct host_cmd_tlv); + travel_len = sizeof(struct mwifiex_ie_types_header); ie_list->len = 0; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 8ece48580642..9b75ed8563b6 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -707,8 +707,9 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) { tlv_mac = (void *)((u8 *)&key_material->key_param_set + key_param_len); - tlv_mac->tlv.type = cpu_to_le16(TLV_TYPE_STA_MAC_ADDR); - tlv_mac->tlv.len = cpu_to_le16(ETH_ALEN); + tlv_mac->header.type = + cpu_to_le16(TLV_TYPE_STA_MAC_ADDR); + tlv_mac->header.len = cpu_to_le16(ETH_ALEN); memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN); cmd_size = key_param_len + S_DS_GEN + sizeof(key_material->action) + diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 2de882dead0f..64424c81b44f 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -293,9 +293,9 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) u8 *tlv = *tlv_buf; tlv_akmp = (struct host_cmd_tlv_akmp *)tlv; - tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP); - tlv_akmp->tlv.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) - - sizeof(struct host_cmd_tlv)); + tlv_akmp->header.type = cpu_to_le16(TLV_TYPE_UAP_AKMP); + tlv_akmp->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) - + sizeof(struct mwifiex_ie_types_header)); tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation); tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt); cmd_size += sizeof(struct host_cmd_tlv_akmp); @@ -303,10 +303,10 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) { pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; - pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); - pwk_cipher->tlv.len = + pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); + pwk_cipher->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA); pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa; cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); @@ -315,10 +315,10 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) { pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; - pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); - pwk_cipher->tlv.len = + pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); + pwk_cipher->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2); pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2; cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); @@ -327,10 +327,10 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) { gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv; - gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER); - gwk_cipher->tlv.len = + gwk_cipher->header.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER); + gwk_cipher->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher; cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher); tlv += sizeof(struct host_cmd_tlv_gwk_cipher); @@ -338,13 +338,15 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) if (bss_cfg->wpa_cfg.length) { passphrase = (struct host_cmd_tlv_passphrase *)tlv; - passphrase->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE); - passphrase->tlv.len = cpu_to_le16(bss_cfg->wpa_cfg.length); + passphrase->header.type = + cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE); + passphrase->header.len = cpu_to_le16(bss_cfg->wpa_cfg.length); memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase, bss_cfg->wpa_cfg.length); - cmd_size += sizeof(struct host_cmd_tlv) + + cmd_size += sizeof(struct mwifiex_ie_types_header) + bss_cfg->wpa_cfg.length; - tlv += sizeof(struct host_cmd_tlv) + bss_cfg->wpa_cfg.length; + tlv += sizeof(struct mwifiex_ie_types_header) + + bss_cfg->wpa_cfg.length; } *param_size = cmd_size; @@ -403,16 +405,17 @@ mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size) (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 || bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) { wep_key = (struct host_cmd_tlv_wep_key *)tlv; - wep_key->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WEP_KEY); - wep_key->tlv.len = + wep_key->header.type = + cpu_to_le16(TLV_TYPE_UAP_WEP_KEY); + wep_key->header.len = cpu_to_le16(bss_cfg->wep_cfg[i].length + 2); wep_key->key_index = bss_cfg->wep_cfg[i].key_index; wep_key->is_default = bss_cfg->wep_cfg[i].is_default; memcpy(wep_key->key, bss_cfg->wep_cfg[i].key, bss_cfg->wep_cfg[i].length); - cmd_size += sizeof(struct host_cmd_tlv) + 2 + + cmd_size += sizeof(struct mwifiex_ie_types_header) + 2 + bss_cfg->wep_cfg[i].length; - tlv += sizeof(struct host_cmd_tlv) + 2 + + tlv += sizeof(struct mwifiex_ie_types_header) + 2 + bss_cfg->wep_cfg[i].length; } } @@ -449,16 +452,17 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) if (bss_cfg->ssid.ssid_len) { ssid = (struct host_cmd_tlv_ssid *)tlv; - ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID); - ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len); + ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_SSID); + ssid->header.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len); memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len); - cmd_size += sizeof(struct host_cmd_tlv) + + cmd_size += sizeof(struct mwifiex_ie_types_header) + bss_cfg->ssid.ssid_len; - tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len; + tlv += sizeof(struct mwifiex_ie_types_header) + + bss_cfg->ssid.ssid_len; bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv; - bcast_ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID); - bcast_ssid->tlv.len = + bcast_ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID); + bcast_ssid->header.len = cpu_to_le16(sizeof(bcast_ssid->bcast_ctl)); bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl; cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid); @@ -466,13 +470,13 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) } if (bss_cfg->rates[0]) { tlv_rates = (struct host_cmd_tlv_rates *)tlv; - tlv_rates->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RATES); + tlv_rates->header.type = cpu_to_le16(TLV_TYPE_UAP_RATES); for (i = 0; i < MWIFIEX_SUPPORTED_RATES && bss_cfg->rates[i]; i++) tlv_rates->rates[i] = bss_cfg->rates[i]; - tlv_rates->tlv.len = cpu_to_le16(i); + tlv_rates->header.len = cpu_to_le16(i); cmd_size += sizeof(struct host_cmd_tlv_rates) + i; tlv += sizeof(struct host_cmd_tlv_rates) + i; } @@ -482,10 +486,10 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) (bss_cfg->band_cfg == BAND_CONFIG_A && bss_cfg->channel <= MAX_CHANNEL_BAND_A))) { chan_band = (struct host_cmd_tlv_channel_band *)tlv; - chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST); - chan_band->tlv.len = + chan_band->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST); + chan_band->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); chan_band->band_config = bss_cfg->band_cfg; chan_band->channel = bss_cfg->channel; cmd_size += sizeof(struct host_cmd_tlv_channel_band); @@ -494,11 +498,11 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD && bss_cfg->beacon_period <= MAX_BEACON_PERIOD) { beacon_period = (struct host_cmd_tlv_beacon_period *)tlv; - beacon_period->tlv.type = + beacon_period->header.type = cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD); - beacon_period->tlv.len = + beacon_period->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); beacon_period->period = cpu_to_le16(bss_cfg->beacon_period); cmd_size += sizeof(struct host_cmd_tlv_beacon_period); tlv += sizeof(struct host_cmd_tlv_beacon_period); @@ -506,21 +510,22 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD && bss_cfg->dtim_period <= MAX_DTIM_PERIOD) { dtim_period = (struct host_cmd_tlv_dtim_period *)tlv; - dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD); - dtim_period->tlv.len = + dtim_period->header.type = + cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD); + dtim_period->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); dtim_period->period = bss_cfg->dtim_period; cmd_size += sizeof(struct host_cmd_tlv_dtim_period); tlv += sizeof(struct host_cmd_tlv_dtim_period); } if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) { rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv; - rts_threshold->tlv.type = + rts_threshold->header.type = cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD); - rts_threshold->tlv.len = + rts_threshold->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold); cmd_size += sizeof(struct host_cmd_tlv_frag_threshold); tlv += sizeof(struct host_cmd_tlv_frag_threshold); @@ -528,21 +533,22 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) && (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) { frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv; - frag_threshold->tlv.type = + frag_threshold->header.type = cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD); - frag_threshold->tlv.len = + frag_threshold->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold); cmd_size += sizeof(struct host_cmd_tlv_frag_threshold); tlv += sizeof(struct host_cmd_tlv_frag_threshold); } if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) { retry_limit = (struct host_cmd_tlv_retry_limit *)tlv; - retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT); - retry_limit->tlv.len = + retry_limit->header.type = + cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT); + retry_limit->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); retry_limit->limit = (u8)bss_cfg->retry_limit; cmd_size += sizeof(struct host_cmd_tlv_retry_limit); tlv += sizeof(struct host_cmd_tlv_retry_limit); @@ -557,21 +563,21 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) || (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) { auth_type = (struct host_cmd_tlv_auth_type *)tlv; - auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); - auth_type->tlv.len = + auth_type->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth_type->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) - - sizeof(struct host_cmd_tlv)); + sizeof(struct mwifiex_ie_types_header)); auth_type->auth_type = (u8)bss_cfg->auth_mode; cmd_size += sizeof(struct host_cmd_tlv_auth_type); tlv += sizeof(struct host_cmd_tlv_auth_type); } if (bss_cfg->protocol) { encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv; - encrypt_protocol->tlv.type = + encrypt_protocol->header.type = cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL); - encrypt_protocol->tlv.len = + encrypt_protocol->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol) - - sizeof(struct host_cmd_tlv)); + - sizeof(struct mwifiex_ie_types_header)); encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol); cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol); tlv += sizeof(struct host_cmd_tlv_encrypt_protocol); @@ -608,9 +614,9 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) if (bss_cfg->sta_ao_timer) { ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv; - ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER); - ao_timer->tlv.len = cpu_to_le16(sizeof(*ao_timer) - - sizeof(struct host_cmd_tlv)); + ao_timer->header.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER); + ao_timer->header.len = cpu_to_le16(sizeof(*ao_timer) - + sizeof(struct mwifiex_ie_types_header)); ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->sta_ao_timer); cmd_size += sizeof(*ao_timer); tlv += sizeof(*ao_timer); @@ -618,9 +624,10 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) if (bss_cfg->ps_sta_ao_timer) { ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv; - ps_ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER); - ps_ao_timer->tlv.len = cpu_to_le16(sizeof(*ps_ao_timer) - - sizeof(struct host_cmd_tlv)); + ps_ao_timer->header.type = + cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER); + ps_ao_timer->header.len = cpu_to_le16(sizeof(*ps_ao_timer) - + sizeof(struct mwifiex_ie_types_header)); ps_ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->ps_sta_ao_timer); cmd_size += sizeof(*ps_ao_timer); @@ -636,16 +643,17 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size) { struct mwifiex_ie_list *ap_ie = cmd_buf; - struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv; + struct mwifiex_ie_types_header *tlv_ie = (void *)tlv; if (!ap_ie || !ap_ie->len || !ap_ie->ie_list) return -1; - *ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv); + *ie_size += le16_to_cpu(ap_ie->len) + + sizeof(struct mwifiex_ie_types_header); tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE); tlv_ie->len = ap_ie->len; - tlv += sizeof(struct host_cmd_tlv); + tlv += sizeof(struct mwifiex_ie_types_header); memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len)); -- cgit v1.2.3 From a4df8f56e92104c5e7be82cc2c471e600ea3f9ef Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jul 2013 19:17:58 -0700 Subject: mwifiex: modify mwifiex_ap_sta_limits to advertise support for P2P We support maximum simultaneous 2 non-AP station interfaces and they can assume role of Station/P2P client/P2P GO. Advertise this support to cfg80211 so that concurrent P2P/STA operation is possible. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index dbdd3b2a5eb5..cc334d529dbe 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -25,7 +25,9 @@ module_param(reg_alpha2, charp, 0); static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { { - .max = 2, .types = BIT(NL80211_IFTYPE_STATION), + .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT), }, { .max = 1, .types = BIT(NL80211_IFTYPE_AP), -- cgit v1.2.3 From c2b8359d7878f75584ed68b7a2b930bd9bea814d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 23 Jul 2013 16:25:17 +0530 Subject: ath9k: Fix diversity combining for AR9285 When antenna diversity combining is enabled in the EEPROM, the initial values for the MAIN/ALT config have to be programmed correctly. This patch adds it for AR9285. Since the diversity combining macros are common to all chip families, remove the redundant AR9285 macros and move the definitions to phy.h. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_phy.h | 4 ---- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 4 ++-- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 4 ++-- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 5 ----- drivers/net/wireless/ath/ath9k/ath9k.h | 7 ------- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 19 +++++++++++++++++++ drivers/net/wireless/ath/ath9k/phy.h | 7 +++++++ 7 files changed, 30 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h index f9eb2c357169..d3f09287d1d0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -317,10 +317,6 @@ #define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29 #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000 #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30 -#define AR_PHY_9285_ANT_DIV_LNA1 2 -#define AR_PHY_9285_ANT_DIV_LNA2 1 -#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3 -#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0 #define AR_PHY_9285_ANT_DIV_GAINTB_0 0 #define AR_PHY_9285_ANT_DIV_GAINTB_1 1 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index d105e43d22e1..a98e6a3dd8a1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3673,9 +3673,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) AR_PHY_ANT_DIV_ALT_GAINTB | AR_PHY_ANT_DIV_MAIN_GAINTB)); /* by default use LNA1 for the main antenna */ - regval |= (AR_PHY_ANT_DIV_LNA1 << + regval |= (ATH_ANT_DIV_COMB_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S); - regval |= (AR_PHY_ANT_DIV_LNA2 << + regval |= (ATH_ANT_DIV_COMB_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 2db4ddf74bc2..3ec33ce7be66 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1465,8 +1465,8 @@ static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, AR_PHY_ANT_DIV_ALT_LNACONF | AR_PHY_ANT_DIV_MAIN_GAINTB | AR_PHY_ANT_DIV_ALT_GAINTB); - regval |= (AR_PHY_ANT_DIV_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S); - regval |= (AR_PHY_ANT_DIV_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S); + regval |= (ATH_ANT_DIV_COMB_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S); + regval |= (ATH_ANT_DIV_COMB_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index d4d39f305a0b..23c019d0d9aa 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -296,11 +296,6 @@ #define AR_PHY_ANT_DIV_MAIN_GAINTB 0x40000000 #define AR_PHY_ANT_DIV_MAIN_GAINTB_S 30 -#define AR_PHY_ANT_DIV_LNA1_MINUS_LNA2 0x0 -#define AR_PHY_ANT_DIV_LNA2 0x1 -#define AR_PHY_ANT_DIV_LNA1 0x2 -#define AR_PHY_ANT_DIV_LNA1_PLUS_LNA2 0x3 - #define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c) #define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30) #define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index c1224b5a257b..76e38d3540c0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -591,13 +591,6 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) #define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2 #define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2 -enum ath9k_ant_div_comb_lna_conf { - ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2, - ATH_ANT_DIV_COMB_LNA2, - ATH_ANT_DIV_COMB_LNA1, - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2, -}; - struct ath_ant_comb { u16 count; u16 total_pkt_count; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index c2bfd748eed8..9ea8e4b779c9 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -812,6 +812,7 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { + struct ath9k_hw_capabilities *pCap = &ah->caps; struct modal_eep_4k_header *pModal; struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; struct base_eep_header_4k *pBase = &eep->baseEepHeader; @@ -858,6 +859,24 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); regVal = REG_READ(ah, AR_PHY_CCK_DETECT); + + if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { + /* + * If diversity combining is enabled, + * set MAIN to LNA1 and ALT to LNA2 initially. + */ + regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); + regVal &= (~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF | + AR_PHY_9285_ANT_DIV_ALT_LNACONF)); + + regVal |= (ATH_ANT_DIV_COMB_LNA1 << + AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S); + regVal |= (ATH_ANT_DIV_COMB_LNA2 << + AR_PHY_9285_ANT_DIV_ALT_LNACONF_S); + regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS)); + regVal |= (0 << AR_PHY_9285_FAST_DIV_BIAS_S); + REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); + } } if (pModal->version >= 2) { diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 8b380305b0fc..4a1b99238ec2 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -48,4 +48,11 @@ #define AR_PHY_PLL_CONTROL 0x16180 #define AR_PHY_PLL_MODE 0x16184 +enum ath9k_ant_div_comb_lna_conf { + ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2, + ATH_ANT_DIV_COMB_LNA2, + ATH_ANT_DIV_COMB_LNA1, + ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2, +}; + #endif -- cgit v1.2.3 From 637065267eab4817c0b06cbf3c7fc80842acab99 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Tue, 23 Jul 2013 14:55:15 +0200 Subject: wireless: rt2x00: rt2800usb: add RT3573 devices taken from Ralink linux and windows drivers: 0x1b75, 0x7733 AirLive 450Mbps Wireless-N Dual Band USB Adapter 0x0b05, 0x17bc ASUS USB-N66 450Mbps Dual Band USB Adapter 0x0b05, 0x17ad ASUS USB-N66 Dual Band N Network Adapter 0x050d, 0x1103 Belkin Wireless Adapter 0x148f, 0xf301 Cameo Ralink3573 3x3 single band USB dongle 0x7392, 0x7733 Edimax 0x0e66, 0x0020 Hawking HD45U Dual Band USB Wireless-N Adapter 0x0e66, 0x0021 Hawking HD45U Dual Band Wls-450N Adapter 0x04bb, 0x094e I-O DATA WN-AG450U Wireless LAN Adapter 0x0789, 0x016b Logitec LAN-W450AN/U2 0x0846, 0x9012 NETGEAR WNDA4100 N900 Wireless Dual Band USB Adapter 0x0846, 0x9019 NETGEAR WNDA4200D Wireless Dual Band USB Adapter 0x2019, 0xed19 Planex GW-USDual450 0x148f, 0x3573 Ralink 802.11n USB Wireless LAN Card 0x0df6, 0x0067 Sitecom Wireless Dualband Network Adapter N750 X6 0x0df6, 0x006a Sitecom Wireless Dualband Network Adapter N900 X7 0x0586, 0x3421 ZyXEL Dual-Band Wireless N450 USB Adapter Cc: Ivo van Doorn Cc: Gertjan van Wingerde Cc: Helmut Schaa Cc: John W. Linville Cc: users@rt2x00.serialmonkey.com Cc: linux-wireless@vger.kernel.org Signed-off-by: Xose Vazquez Perez Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index ab609aeb29ae..fc9efdfca8f2 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1198,8 +1198,38 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x5a57, 0x0284) }, #endif #ifdef CONFIG_RT2800USB_RT3573 + /* AirLive */ + { USB_DEVICE(0x1b75, 0x7733) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x17bc) }, + { USB_DEVICE(0x0b05, 0x17ad) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x1103) }, + /* Cameo */ + { USB_DEVICE(0x148f, 0xf301) }, + /* Edimax */ + { USB_DEVICE(0x7392, 0x7733) }, + /* Hawking */ + { USB_DEVICE(0x0e66, 0x0020) }, + { USB_DEVICE(0x0e66, 0x0021) }, + /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x094e) }, /* Linksys */ { USB_DEVICE(0x13b1, 0x003b) }, + /* Logitec */ + { USB_DEVICE(0x0789, 0x016b) }, + /* NETGEAR */ + { USB_DEVICE(0x0846, 0x9012) }, + { USB_DEVICE(0x0846, 0x9019) }, + /* Planex */ + { USB_DEVICE(0x2019, 0xed19) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x3573) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x0067) }, + { USB_DEVICE(0x0df6, 0x006a) }, + /* ZyXEL */ + { USB_DEVICE(0x0586, 0x3421) }, #endif #ifdef CONFIG_RT2800USB_RT53XX /* Arcadyan */ -- cgit v1.2.3 From da4f87f088b3ddfc9153aa3559834a3922da4395 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Jul 2013 13:48:56 +0200 Subject: iwlwifi: dvm: remove P2P support We're not planning to support P2P on older devices, so remove the Kconfig option and associated code for it. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/Kconfig | 17 --- drivers/net/wireless/iwlwifi/dvm/agn.h | 6 - drivers/net/wireless/iwlwifi/dvm/dev.h | 7 -- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 172 +--------------------------- drivers/net/wireless/iwlwifi/dvm/main.c | 62 ---------- drivers/net/wireless/iwlwifi/dvm/rxon.c | 6 +- drivers/net/wireless/iwlwifi/dvm/scan.c | 105 +---------------- drivers/net/wireless/iwlwifi/dvm/tx.c | 19 --- 8 files changed, 3 insertions(+), 391 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index cbaa5c2c410f..e5c133ee7901 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -127,20 +127,3 @@ config IWLWIFI_DEVICE_TRACING If unsure, say Y so we can help you better when problems occur. endmenu - -config IWLWIFI_P2P - def_bool y - bool "iwlwifi experimental P2P support" - depends on IWLWIFI - help - This option enables experimental P2P support for some devices - based on microcode support. Since P2P support is still under - development, this option may even enable it for some devices - now that turn out to not support it in the future due to - microcode restrictions. - - To determine if your microcode supports the experimental P2P - offered by this option, check if the driver advertises AP - support when it is loaded. - - Say Y only if you want to experiment with P2P. diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 18355110deff..f2a86ffc3b4c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -106,7 +106,6 @@ extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg; #define STATUS_CHANNEL_SWITCH_PENDING 11 #define STATUS_SCAN_COMPLETE 12 #define STATUS_POWER_PMI 13 -#define STATUS_SCAN_ROC_EXPIRED 14 struct iwl_ucode_capabilities; @@ -250,7 +249,6 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid); /* scan */ void iwlagn_post_scan(struct iwl_priv *priv); -void iwlagn_disable_roc(struct iwl_priv *priv); int iwl_force_rf_reset(struct iwl_priv *priv, bool external); void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); @@ -265,10 +263,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, enum iwl_scan_type scan_type, enum ieee80211_band band); -void iwl_scan_roc_expired(struct iwl_priv *priv); -void iwl_scan_offchannel_skb(struct iwl_priv *priv); -void iwl_scan_offchannel_skb_status(struct iwl_priv *priv); - /* For faster active scanning, scan will move to the next channel if fewer than * PLCP_QUIET_THRESH packets are heard on this channel within * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 60a4e0d15715..a79fdd137f95 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -540,7 +540,6 @@ struct iwl_rxon_context { enum iwl_scan_type { IWL_SCAN_NORMAL, IWL_SCAN_RADIO_RESET, - IWL_SCAN_ROC, }; /** @@ -825,12 +824,6 @@ struct iwl_priv { struct reply_tx_error_statistics reply_tx_stats; struct reply_agg_tx_error_statistics reply_agg_tx_stats; - /* remain-on-channel offload support */ - struct ieee80211_channel *hw_roc_channel; - struct delayed_work hw_roc_disable_work; - int hw_roc_duration; - bool hw_roc_setup, hw_roc_start_notified; - /* bt coex */ u8 bt_enable_flag; u8 bt_status; diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 822f1a00efbb..f0a2c957d503 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -76,29 +76,6 @@ static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = { }, }; -static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_STATION), - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_AP), - }, -}; - -static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = { - { - .max = 2, - .types = BIT(NL80211_IFTYPE_STATION), - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_CLIENT), - }, -}; - static const struct ieee80211_iface_combination iwlagn_iface_combinations_dualmode[] = { { .num_different_channels = 1, @@ -114,21 +91,6 @@ iwlagn_iface_combinations_dualmode[] = { }, }; -static const struct ieee80211_iface_combination -iwlagn_iface_combinations_p2p[] = { - { .num_different_channels = 1, - .max_interfaces = 2, - .beacon_int_infra_match = true, - .limits = iwlagn_p2p_sta_go_limits, - .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits), - }, - { .num_different_channels = 1, - .max_interfaces = 2, - .limits = iwlagn_p2p_2sta_limits, - .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits), - }, -}; - /* * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. @@ -186,19 +148,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); - if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) { - hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p; - hw->wiphy->n_iface_combinations = - ARRAY_SIZE(iwlagn_iface_combinations_p2p); - } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { + if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { hw->wiphy->iface_combinations = iwlagn_iface_combinations_dualmode; hw->wiphy->n_iface_combinations = ARRAY_SIZE(iwlagn_iface_combinations_dualmode); } - hw->wiphy->max_remain_on_channel_duration = 500; - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_IBSS_RSN; @@ -1156,126 +1112,6 @@ done: IWL_DEBUG_MAC80211(priv, "leave\n"); } -static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel *channel, - int duration, - enum ieee80211_roc_type type) -{ - struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; - int err = 0; - - if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) - return -EOPNOTSUPP; - - if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT))) - return -EOPNOTSUPP; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->mutex); - - if (test_bit(STATUS_SCAN_HW, &priv->status)) { - /* mac80211 should not scan while ROC or ROC while scanning */ - if (WARN_ON_ONCE(priv->scan_type != IWL_SCAN_RADIO_RESET)) { - err = -EBUSY; - goto out; - } - - iwl_scan_cancel_timeout(priv, 100); - - if (test_bit(STATUS_SCAN_HW, &priv->status)) { - err = -EBUSY; - goto out; - } - } - - priv->hw_roc_channel = channel; - /* convert from ms to TU */ - priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024); - priv->hw_roc_start_notified = false; - cancel_delayed_work(&priv->hw_roc_disable_work); - - if (!ctx->is_active) { - static const struct iwl_qos_info default_qos_data = { - .def_qos_parm = { - .ac[0] = { - .cw_min = cpu_to_le16(3), - .cw_max = cpu_to_le16(7), - .aifsn = 2, - .edca_txop = cpu_to_le16(1504), - }, - .ac[1] = { - .cw_min = cpu_to_le16(7), - .cw_max = cpu_to_le16(15), - .aifsn = 2, - .edca_txop = cpu_to_le16(3008), - }, - .ac[2] = { - .cw_min = cpu_to_le16(15), - .cw_max = cpu_to_le16(1023), - .aifsn = 3, - }, - .ac[3] = { - .cw_min = cpu_to_le16(15), - .cw_max = cpu_to_le16(1023), - .aifsn = 7, - }, - }, - }; - - ctx->is_active = true; - ctx->qos_data = default_qos_data; - ctx->staging.dev_type = RXON_DEV_TYPE_P2P; - memcpy(ctx->staging.node_addr, - priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, - ETH_ALEN); - memcpy(ctx->staging.bssid_addr, - priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, - ETH_ALEN); - err = iwlagn_commit_rxon(priv, ctx); - if (err) - goto out; - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK | - RXON_FILTER_PROMISC_MSK | - RXON_FILTER_CTL2HOST_MSK; - - err = iwlagn_commit_rxon(priv, ctx); - if (err) { - iwlagn_disable_roc(priv); - goto out; - } - priv->hw_roc_setup = true; - } - - err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band); - if (err) - iwlagn_disable_roc(priv); - - out: - mutex_unlock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return err; -} - -static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - - if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) - return -EOPNOTSUPP; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->mutex); - iwl_scan_cancel_timeout(priv, priv->hw_roc_duration); - iwlagn_disable_roc(priv); - mutex_unlock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return 0; -} - static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_rssi_event rssi_event) @@ -1431,12 +1267,8 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", viftype, vif->addr); - cancel_delayed_work_sync(&priv->hw_roc_disable_work); - mutex_lock(&priv->mutex); - iwlagn_disable_roc(priv); - if (!iwl_is_ready_rf(priv)) { IWL_WARN(priv, "Try to add interface when device not ready\n"); err = -EINVAL; @@ -1763,8 +1595,6 @@ struct ieee80211_ops iwlagn_hw_ops = { .channel_switch = iwlagn_mac_channel_switch, .flush = iwlagn_mac_flush, .tx_last_beacon = iwlagn_mac_tx_last_beacon, - .remain_on_channel = iwlagn_mac_remain_on_channel, - .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel, .rssi_callback = iwlagn_mac_rssi_callback, .set_tim = iwlagn_mac_set_tim, }; diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 3952ddf2ddb2..f78a3d35ad71 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -587,11 +587,6 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) priv->contexts[IWL_RXON_CTX_PAN].interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); - if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P) - priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); - priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; @@ -854,14 +849,6 @@ void iwl_down(struct iwl_priv *priv) iwl_scan_cancel_timeout(priv, 200); - /* - * If active, scanning won't cancel it, so say it expired. - * No race since we hold the mutex here and a new one - * can't come in at this time. - */ - if (priv->ucode_loaded && priv->cur_ucode != IWL_UCODE_INIT) - ieee80211_remain_on_channel_expired(priv->hw); - exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); @@ -1002,41 +989,6 @@ static void iwl_bg_restart(struct work_struct *data) } } - - - -void iwlagn_disable_roc(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; - - lockdep_assert_held(&priv->mutex); - - if (!priv->hw_roc_setup) - return; - - ctx->staging.dev_type = RXON_DEV_TYPE_P2P; - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - - priv->hw_roc_channel = NULL; - - memset(ctx->staging.node_addr, 0, ETH_ALEN); - - iwlagn_commit_rxon(priv, ctx); - - ctx->is_active = false; - priv->hw_roc_setup = false; -} - -static void iwlagn_disable_roc_work(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, - hw_roc_disable_work.work); - - mutex_lock(&priv->mutex); - iwlagn_disable_roc(priv); - mutex_unlock(&priv->mutex); -} - /***************************************************************************** * * driver setup and teardown @@ -1053,8 +1005,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); - INIT_DELAYED_WORK(&priv->hw_roc_disable_work, - iwlagn_disable_roc_work); iwl_setup_scan_deferred_work(priv); @@ -1082,7 +1032,6 @@ void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->bt_full_concurrency); cancel_work_sync(&priv->bt_runtime_config); - cancel_delayed_work_sync(&priv->hw_roc_disable_work); del_timer_sync(&priv->statistics_periodic); del_timer_sync(&priv->ucode_trace); @@ -1169,12 +1118,6 @@ static void iwl_option_config(struct iwl_priv *priv) #else IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n"); #endif - -#ifdef CONFIG_IWLWIFI_P2P - IWL_INFO(priv, "CONFIG_IWLWIFI_P2P enabled\n"); -#else - IWL_INFO(priv, "CONFIG_IWLWIFI_P2P disabled\n"); -#endif } static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) @@ -1315,10 +1258,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, ucode_flags = fw->ucode_capa.flags; -#ifndef CONFIG_IWLWIFI_P2P - ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; -#endif - if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; @@ -1413,7 +1352,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, * if not PAN, then don't support P2P -- might be a uCode * packaging bug or due to the eeprom check above */ - ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; priv->sta_key_max_num = STA_KEY_MAX_NUM; trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index cd1ad0019185..d7ce2f12a907 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -564,11 +564,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) cmd.slots[0].type = 0; /* BSS */ cmd.slots[1].type = 1; /* PAN */ - if (priv->hw_roc_setup) { - /* both contexts must be used for this to happen */ - slot1 = IWL_MIN_SLOT_TIME; - slot0 = 3000; - } else if (ctx_bss->vif && ctx_pan->vif) { + if (ctx_bss->vif && ctx_pan->vif) { int bcnint = ctx_pan->beacon_int; int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1; diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 8c686a5b90ac..35e0ee8b4e5b 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -100,9 +100,6 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) ieee80211_scan_completed(priv->hw, aborted); } - if (priv->scan_type == IWL_SCAN_ROC) - iwl_scan_roc_expired(priv); - priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; @@ -130,9 +127,6 @@ static void iwl_process_scan_complete(struct iwl_priv *priv) goto out_settings; } - if (priv->scan_type == IWL_SCAN_ROC) - iwl_scan_roc_expired(priv); - if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { int err; @@ -284,12 +278,6 @@ static int iwl_rx_scan_start_notif(struct iwl_priv *priv, le32_to_cpu(notif->tsf_low), notif->status, notif->beacon_timer); - if (priv->scan_type == IWL_SCAN_ROC && - !priv->hw_roc_start_notified) { - ieee80211_ready_on_channel(priv->hw); - priv->hw_roc_start_notified = true; - } - return 0; } @@ -697,8 +685,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; scan->quiet_time = IWL_ACTIVE_QUIET_TIME; - if (priv->scan_type != IWL_SCAN_ROC && - iwl_is_any_associated(priv)) { + if (iwl_is_any_associated(priv)) { u16 interval = 0; u32 extra; u32 suspend_time = 100; @@ -706,9 +693,6 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); switch (priv->scan_type) { - case IWL_SCAN_ROC: - WARN_ON(1); - break; case IWL_SCAN_RADIO_RESET: interval = 0; break; @@ -728,11 +712,6 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) scan->suspend_time = cpu_to_le32(scan_suspend_time); IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", scan_suspend_time, interval); - } else if (priv->scan_type == IWL_SCAN_ROC) { - scan->suspend_time = 0; - scan->max_out_time = 0; - scan->quiet_time = 0; - scan->quiet_plcp_th = 0; } switch (priv->scan_type) { @@ -774,9 +753,6 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) } else IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); break; - case IWL_SCAN_ROC: - IWL_DEBUG_SCAN(priv, "Start ROC scan.\n"); - break; } scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; @@ -898,7 +874,6 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) scan_cmd_size - sizeof(*scan)); break; case IWL_SCAN_RADIO_RESET: - case IWL_SCAN_ROC: /* use bcast addr, will not be transmitted but must be valid */ cmd_len = iwl_fill_probe_req( (struct ieee80211_mgmt *)scan->data, @@ -926,46 +901,6 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) is_active, n_probes, (void *)&scan->data[cmd_len]); break; - case IWL_SCAN_ROC: { - struct iwl_scan_channel *scan_ch; - int n_chan, i; - u16 dwell; - - dwell = iwl_limit_dwell(priv, priv->hw_roc_duration); - n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell); - - scan->channel_count = n_chan; - - scan_ch = (void *)&scan->data[cmd_len]; - - for (i = 0; i < n_chan; i++) { - scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; - scan_ch->channel = - cpu_to_le16(priv->hw_roc_channel->hw_value); - - if (i == n_chan - 1) - dwell = priv->hw_roc_duration - i * dwell; - - scan_ch->active_dwell = - scan_ch->passive_dwell = cpu_to_le16(dwell); - - /* Set txpower levels to defaults */ - scan_ch->dsp_atten = 110; - - /* NOTE: if we were doing 6Mb OFDM for scans we'd use - * power level: - * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; - */ - if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ) - scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; - else - scan_ch->tx_gain = ((1 << 5) | (5 << 3)); - - scan_ch++; - } - } - - break; } if (scan->channel_count == 0) { @@ -1035,7 +970,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", scan_type == IWL_SCAN_NORMAL ? "" : - scan_type == IWL_SCAN_ROC ? "remain-on-channel " : "internal short "); set_bit(STATUS_SCANNING, &priv->status); @@ -1149,40 +1083,3 @@ void iwl_cancel_scan_deferred_work(struct iwl_priv *priv) mutex_unlock(&priv->mutex); } } - -void iwl_scan_roc_expired(struct iwl_priv *priv) -{ - /* - * The status bit should be set here, to prevent a race - * where the atomic_read returns 1, but before the execution continues - * iwl_scan_offchannel_skb_status() checks if the status bit is set - */ - set_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status); - - if (atomic_read(&priv->num_aux_in_flight) == 0) { - ieee80211_remain_on_channel_expired(priv->hw); - priv->hw_roc_channel = NULL; - schedule_delayed_work(&priv->hw_roc_disable_work, - 10 * HZ); - - clear_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status); - } else { - IWL_DEBUG_SCAN(priv, "ROC done with %d frames in aux\n", - atomic_read(&priv->num_aux_in_flight)); - } -} - -void iwl_scan_offchannel_skb(struct iwl_priv *priv) -{ - WARN_ON(!priv->hw_roc_start_notified); - atomic_inc(&priv->num_aux_in_flight); -} - -void iwl_scan_offchannel_skb_status(struct iwl_priv *priv) -{ - if (atomic_dec_return(&priv->num_aux_in_flight) == 0 && - test_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status)) { - IWL_DEBUG_SCAN(priv, "0 aux frames. Calling ROC expired\n"); - iwl_scan_roc_expired(priv); - } -} diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 5ee983faa679..3db0bbb1d123 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -478,9 +478,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, if (sta_priv && sta_priv->client && !is_agg) atomic_inc(&sta_priv->pending_frames); - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) - iwl_scan_offchannel_skb(priv); - return 0; drop_unlock_sta: @@ -1158,7 +1155,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, struct sk_buff *skb; struct iwl_rxon_context *ctx; bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); - bool is_offchannel_skb; tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> IWLAGN_TX_RES_TID_POS; @@ -1178,8 +1174,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, __skb_queue_head_init(&skbs); - is_offchannel_skb = false; - if (tx_resp->frame_count == 1) { u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl); next_reclaimed = IEEE80211_SEQ_TO_SN(next_reclaimed + 0x10); @@ -1256,8 +1250,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, if (!is_agg) iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); - is_offchannel_skb = - (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); freed++; } @@ -1271,14 +1263,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, if (!is_agg && freed != 1) IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed); - /* - * An offchannel frame can be send only on the AUX queue, where - * there is no aggregation (and reordering) so it only is single - * skb is expected to be processed. - */ - if (is_offchannel_skb && freed != 1) - IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed); - IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id, iwl_get_tx_fail_reason(status), status); @@ -1298,9 +1282,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, ieee80211_tx_status_ni(priv->hw, skb); } - if (is_offchannel_skb) - iwl_scan_offchannel_skb_status(priv); - return 0; } -- cgit v1.2.3 From 26e05cc32d4dab8ad939fd1318bc470d737a20ca Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Mon, 8 Jul 2013 13:12:29 +0300 Subject: iwlwifi: mvm: enable pre-scan passive to active Enable passive to active scan feature, on channels that was active in the past hour. Signed-off-by: David Spinadel Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 5 ++++- drivers/net/wireless/iwlwifi/mvm/scan.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index b60d14151721..c33ff8e61f4f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -138,6 +138,8 @@ struct iwl_ssid_ie { *@SCAN_FLAGS_DELAYED_SCAN_LOWBAND: *@SCAN_FLAGS_DELAYED_SCAN_HIGHBAND: *@SCAN_FLAGS_FRAGMENTED_SCAN: + *@SCAN_FLAGS_PASSIVE2ACTIVE: use active scan on channels that was active + * in the past hour, even if they are marked as passive. */ enum iwl_scan_flags { SCAN_FLAGS_PERIODIC_SCAN = BIT(0), @@ -145,6 +147,7 @@ enum iwl_scan_flags { SCAN_FLAGS_DELAYED_SCAN_LOWBAND = BIT(2), SCAN_FLAGS_DELAYED_SCAN_HIGHBAND = BIT(3), SCAN_FLAGS_FRAGMENTED_SCAN = BIT(4), + SCAN_FLAGS_PASSIVE2ACTIVE = BIT(5), }; /** @@ -179,7 +182,7 @@ enum iwl_scan_type { * @quiet_time: in msecs, dwell this time for active scan on quiet channels * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than * this number of packets were received (typically 1) - * @passive2active: is auto switching from passive to active allowed (0 or 1) + * @passive2active: is auto switching from passive to active during scan allowed * @rxchain_sel_flags: RXON_RX_CHAIN_* * @max_out_time: in usecs, max out of serving channel time * @suspend_time: how long to pause scan when returning to service channel: diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 2157b0f8ced5..dc635798b2e5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -306,10 +306,12 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, */ if (req->n_ssids > 0) { cmd->passive2active = cpu_to_le16(1); + cmd->scan_flags |= SCAN_FLAGS_PASSIVE2ACTIVE; ssid = req->ssids[0].ssid; ssid_len = req->ssids[0].ssid_len; } else { cmd->passive2active = 0; + cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE; } iwl_mvm_scan_fill_ssids(cmd, req); -- cgit v1.2.3 From 6b41f941d7cdfb88b0222f5532af5032e4008bb6 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:55 -0700 Subject: mwifiex: handle driver initialization error paths mwifiex_fw_dpc() asynchronously takes care of firmware download and initialization. Currently the error paths in mwifiex_fw_dpc() are not handled. So if wrong firmware is downloaded, required cleanup work is not performed. memory is leaked and workqueue remains unterminated in this case. mwifiex_terminate_workqueue() is moved to avoid forward declaration. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.c | 83 ++++++++++++++++++++++++------------- drivers/net/wireless/mwifiex/main.h | 1 + 2 files changed, 56 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index e64c369f3024..5644c7f86fcb 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -389,6 +389,17 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) pr_debug("info: %s: free adapter\n", __func__); } +/* + * This function cancels all works in the queue and destroys + * the main workqueue. + */ +static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) +{ + flush_workqueue(adapter->workqueue); + destroy_workqueue(adapter->workqueue); + adapter->workqueue = NULL; +} + /* * This function gets firmware and initializes it. * @@ -398,7 +409,7 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) */ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) { - int ret; + int ret, i; char fmt[64]; struct mwifiex_private *priv; struct mwifiex_adapter *adapter = context; @@ -407,7 +418,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) if (!firmware) { dev_err(adapter->dev, "Failed to get firmware %s\n", adapter->fw_name); - goto done; + goto err_dnld_fw; } memset(&fw, 0, sizeof(struct mwifiex_fw_image)); @@ -420,7 +431,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) else ret = mwifiex_dnld_fw(adapter, &fw); if (ret == -1) - goto done; + goto err_dnld_fw; dev_notice(adapter->dev, "WLAN FW is active\n"); @@ -432,13 +443,15 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) } /* enable host interrupt after fw dnld is successful */ - if (adapter->if_ops.enable_int) - adapter->if_ops.enable_int(adapter); + if (adapter->if_ops.enable_int) { + if (adapter->if_ops.enable_int(adapter)) + goto err_dnld_fw; + } adapter->init_wait_q_woken = false; ret = mwifiex_init_fw(adapter); if (ret == -1) { - goto done; + goto err_init_fw; } else if (!ret) { adapter->hw_status = MWIFIEX_HW_STATUS_READY; goto done; @@ -447,12 +460,12 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) wait_event_interruptible(adapter->init_wait_q, adapter->init_wait_q_woken); if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) - goto done; + goto err_init_fw; priv = adapter->priv[MWIFIEX_BSS_ROLE_STA]; if (mwifiex_register_cfg80211(adapter)) { dev_err(adapter->dev, "cannot register with cfg80211\n"); - goto err_init_fw; + goto err_register_cfg80211; } rtnl_lock(); @@ -483,13 +496,39 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: - mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + + if (!priv) + continue; + + if (priv->wdev && priv->netdev) + mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); + } rtnl_unlock(); +err_register_cfg80211: + wiphy_unregister(adapter->wiphy); + wiphy_free(adapter->wiphy); err_init_fw: if (adapter->if_ops.disable_int) adapter->if_ops.disable_int(adapter); +err_dnld_fw: pr_debug("info: %s: unregister device\n", __func__); - adapter->if_ops.unregister_dev(adapter); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); + + if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || + (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + pr_debug("info: %s: shutdown mwifiex\n", __func__); + adapter->init_wait_q_woken = false; + + if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + } + adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); + mwifiex_free_adapter(adapter); done: if (adapter->cal_data) { release_firmware(adapter->cal_data); @@ -497,6 +536,7 @@ done: } release_firmware(adapter->firmware); complete(&adapter->fw_load); + up(adapter->card_sem); return; } @@ -806,18 +846,6 @@ static void mwifiex_main_work_queue(struct work_struct *work) mwifiex_main_process(adapter); } -/* - * This function cancels all works in the queue and destroys - * the main workqueue. - */ -static void -mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) -{ - flush_workqueue(adapter->workqueue); - destroy_workqueue(adapter->workqueue); - adapter->workqueue = NULL; -} - /* * This function adds the card. * @@ -846,6 +874,7 @@ mwifiex_add_card(void *card, struct semaphore *sem, } adapter->iface_type = iface_type; + adapter->card_sem = sem; adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; adapter->surprise_removed = false; @@ -876,17 +905,12 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_init_fw; } - up(sem); return 0; err_init_fw: pr_debug("info: %s: unregister device\n", __func__); if (adapter->if_ops.unregister_dev) adapter->if_ops.unregister_dev(adapter); -err_registerdev: - adapter->surprise_removed = true; - mwifiex_terminate_workqueue(adapter); -err_kmalloc: if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { pr_debug("info: %s: shutdown mwifiex\n", __func__); @@ -896,7 +920,10 @@ err_kmalloc: wait_event_interruptible(adapter->init_wait_q, adapter->init_wait_q_woken); } - +err_registerdev: + adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); +err_kmalloc: mwifiex_free_adapter(adapter); err_init_sw: diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index bb28d3dc0164..9ee3b1b7c365 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -749,6 +749,7 @@ struct mwifiex_adapter { atomic_t is_tx_received; atomic_t pending_bridged_pkts; + struct semaphore *card_sem; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); -- cgit v1.2.3 From 2cdf359a521bb72286b6714478dfdbcd2691f3fe Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 22 Jul 2013 19:17:56 -0700 Subject: mwifiex: code rearrangement in sdio.c Some function definitions are moved to appropriate place to avoid forward declarations. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sdio.c | 211 ++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 107 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index c32a735ca3aa..1eb5efa1bce2 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -50,9 +50,6 @@ static struct mwifiex_if_ops sdio_ops; static struct semaphore add_remove_card_sem; -static int mwifiex_sdio_resume(struct device *dev); -static void mwifiex_sdio_interrupt(struct sdio_func *func); - /* * SDIO probe. * @@ -112,6 +109,51 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) return ret; } +/* + * SDIO resume. + * + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not resumed, this function turns on the traffic and + * sends a host sleep cancel request to the firmware. + */ +static int mwifiex_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct mwifiex_adapter *adapter; + mmc_pm_flag_t pm_flag = 0; + + if (func) { + pm_flag = sdio_get_host_pm_caps(func); + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_err("resume: invalid card or adapter\n"); + return 0; + } + } else { + pr_err("resume: sdio_func is not specified\n"); + return 0; + } + + adapter = card->adapter; + + if (!adapter->is_suspended) { + dev_warn(adapter->dev, "device already resumed\n"); + return 0; + } + + adapter->is_suspended = false; + + /* Disable Host Sleep */ + mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), + MWIFIEX_ASYNC_CMD); + + return 0; +} + /* * SDIO remove. * @@ -212,51 +254,6 @@ static int mwifiex_sdio_suspend(struct device *dev) return ret; } -/* - * SDIO resume. - * - * Kernel needs to suspend all functions separately. Therefore all - * registered functions must have drivers with suspend and resume - * methods. Failing that the kernel simply removes the whole card. - * - * If already not resumed, this function turns on the traffic and - * sends a host sleep cancel request to the firmware. - */ -static int mwifiex_sdio_resume(struct device *dev) -{ - struct sdio_func *func = dev_to_sdio_func(dev); - struct sdio_mmc_card *card; - struct mwifiex_adapter *adapter; - mmc_pm_flag_t pm_flag = 0; - - if (func) { - pm_flag = sdio_get_host_pm_caps(func); - card = sdio_get_drvdata(func); - if (!card || !card->adapter) { - pr_err("resume: invalid card or adapter\n"); - return 0; - } - } else { - pr_err("resume: sdio_func is not specified\n"); - return 0; - } - - adapter = card->adapter; - - if (!adapter->is_suspended) { - dev_warn(adapter->dev, "device already resumed\n"); - return 0; - } - - adapter->is_suspended = false; - - /* Disable Host Sleep */ - mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), - MWIFIEX_ASYNC_CMD); - - return 0; -} - /* Device ID for SD8786 */ #define SDIO_DEVICE_ID_MARVELL_8786 (0x9116) /* Device ID for SD8787 */ @@ -706,6 +703,65 @@ static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) sdio_release_host(func); } +/* + * This function reads the interrupt status from card. + */ +static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + u8 sdio_ireg; + unsigned long flags; + + if (mwifiex_read_data_sync(adapter, card->mp_regs, + card->reg->max_mp_regs, + REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) { + dev_err(adapter->dev, "read mp_regs failed\n"); + return; + } + + sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG]; + if (sdio_ireg) { + /* + * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS + * For SDIO new mode CMD port interrupts + * DN_LD_CMD_PORT_HOST_INT_STATUS and/or + * UP_LD_CMD_PORT_HOST_INT_STATUS + * Clear the interrupt status register + */ + dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status |= sdio_ireg; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } +} + +/* + * SDIO interrupt handler. + * + * This function reads the interrupt status from firmware and handles + * the interrupt in current thread (ksdioirqd) right away. + */ +static void +mwifiex_sdio_interrupt(struct sdio_func *func) +{ + struct mwifiex_adapter *adapter; + struct sdio_mmc_card *card; + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_debug("int: func=%p card=%p adapter=%p\n", + func, card, card ? card->adapter : NULL); + return; + } + adapter = card->adapter; + + if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) + adapter->ps_state = PS_STATE_AWAKE; + + mwifiex_interrupt_status(adapter); + mwifiex_main_process(adapter); +} + /* * This function enables the host interrupt. * @@ -962,65 +1018,6 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, return ret; } -/* - * This function reads the interrupt status from card. - */ -static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) -{ - struct sdio_mmc_card *card = adapter->card; - u8 sdio_ireg; - unsigned long flags; - - if (mwifiex_read_data_sync(adapter, card->mp_regs, - card->reg->max_mp_regs, - REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) { - dev_err(adapter->dev, "read mp_regs failed\n"); - return; - } - - sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG]; - if (sdio_ireg) { - /* - * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS - * For SDIO new mode CMD port interrupts - * DN_LD_CMD_PORT_HOST_INT_STATUS and/or - * UP_LD_CMD_PORT_HOST_INT_STATUS - * Clear the interrupt status register - */ - dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); - spin_lock_irqsave(&adapter->int_lock, flags); - adapter->int_status |= sdio_ireg; - spin_unlock_irqrestore(&adapter->int_lock, flags); - } -} - -/* - * SDIO interrupt handler. - * - * This function reads the interrupt status from firmware and handles - * the interrupt in current thread (ksdioirqd) right away. - */ -static void -mwifiex_sdio_interrupt(struct sdio_func *func) -{ - struct mwifiex_adapter *adapter; - struct sdio_mmc_card *card; - - card = sdio_get_drvdata(func); - if (!card || !card->adapter) { - pr_debug("int: func=%p card=%p adapter=%p\n", - func, card, card ? card->adapter : NULL); - return; - } - adapter = card->adapter; - - if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) - adapter->ps_state = PS_STATE_AWAKE; - - mwifiex_interrupt_status(adapter); - mwifiex_main_process(adapter); -} - /* * This function decodes a received packet. * -- cgit v1.2.3 From a783c77076d9d06558a6d4bb07f0c1e0819c8c89 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:02 +0300 Subject: ath10k: fix teardown ordering This should fix memory corruption if HIF is tried to be restarted. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 33af4672c909..92f35f2c4f6e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1263,7 +1263,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_process_ce(ar); ath10k_pci_cleanup_ce(ar); ath10k_pci_buffer_cleanup(ar); - ath10k_pci_ce_deinit(ar); } static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, @@ -2333,6 +2332,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) tasklet_kill(&ar_pci->msi_fw_err); ath10k_core_unregister(ar); + ath10k_pci_ce_deinit(ar); ath10k_pci_stop_intr(ar); pci_set_drvdata(pdev, NULL); -- cgit v1.2.3 From 80c78c67e6660db46f0a6e60941386ce22863e24 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:03 +0300 Subject: ath10k: fix possible deadlock It was possible to have a deadlock due to inverted locking of local->iflist_mtx and ath10k->conf_mutex. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index da5c333d0d4b..608e240cb56b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2581,8 +2581,9 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) ar_iter.ar = ar; mutex_lock(&ar->conf_mutex); - ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, - ath10k_set_rts_iter, &ar_iter); + ieee80211_iterate_active_interfaces_atomic( + hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath10k_set_rts_iter, &ar_iter); mutex_unlock(&ar->conf_mutex); return ar_iter.ret; @@ -2622,8 +2623,9 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) ar_iter.ar = ar; mutex_lock(&ar->conf_mutex); - ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, - ath10k_set_frag_iter, &ar_iter); + ieee80211_iterate_active_interfaces_atomic( + hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath10k_set_frag_iter, &ar_iter); mutex_unlock(&ar->conf_mutex); return ar_iter.ret; -- cgit v1.2.3 From 679c54a67141fb12fd579c6097ebfab4cecf0043 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:04 +0300 Subject: ath10k: setup rts/frag thresholds upon vdev creation mac80211 configures rts/frag thresholds per-hw not per-vif. ath10k FW expects those values to be set per-vdev (i.e. per-vif). ath10k should now respect rts/frag thresholds set before a given interface was brought up. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 608e240cb56b..2bfb8fd9b28d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1756,7 +1756,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); enum wmi_sta_powersave_param param; int ret = 0; - u32 value; + u32 value, rts, frag; int bit; mutex_lock(&ar->conf_mutex); @@ -1859,6 +1859,24 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ath10k_warn("Failed to set PSPOLL count: %d\n", ret); } + rts = min_t(u32, ar->hw->wiphy->rts_threshold, ATH10K_RTS_MAX); + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, + WMI_VDEV_PARAM_RTS_THRESHOLD, + rts); + if (ret) + ath10k_warn("failed to set rts threshold for vdev %d (%d)\n", + arvif->vdev_id, ret); + + frag = clamp_t(u32, ar->hw->wiphy->frag_threshold, + ATH10K_FRAGMT_THRESHOLD_MIN, + ATH10K_FRAGMT_THRESHOLD_MAX); + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + frag); + if (ret) + ath10k_warn("failed to set frag threshold for vdev %d (%d)\n", + arvif->vdev_id, ret); + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) ar->monitor_present = true; -- cgit v1.2.3 From 671b96db55c3ef372a5b01dfeb6b445b5c7cc3d1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:05 +0300 Subject: ath10k: do not setup rts/frag thresholds for suspended interfaces mac80211 calls for rts/frag threshold hooks before any interface is brought back up again when resuming. We would set vdev parameters before given vdev is created lading to a FW crash. rts/frag thresholds will be re-set accordingly in add_interface() hook anyway. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2bfb8fd9b28d..87fa3c2d9382 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2600,7 +2600,7 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&ar->conf_mutex); ieee80211_iterate_active_interfaces_atomic( - hw, IEEE80211_IFACE_ITER_RESUME_ALL, + hw, IEEE80211_IFACE_ITER_NORMAL, ath10k_set_rts_iter, &ar_iter); mutex_unlock(&ar->conf_mutex); @@ -2642,7 +2642,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&ar->conf_mutex); ieee80211_iterate_active_interfaces_atomic( - hw, IEEE80211_IFACE_ITER_RESUME_ALL, + hw, IEEE80211_IFACE_ITER_NORMAL, ath10k_set_frag_iter, &ar_iter); mutex_unlock(&ar->conf_mutex); -- cgit v1.2.3 From 3a0861fffd2238438101b830dc06b13233d1cf92 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:06 +0300 Subject: ath10k: remove ath10k_bus It serves no purpose. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 -- drivers/net/wireless/ath/ath10k/core.h | 6 ------ drivers/net/wireless/ath/ath10k/pci.c | 3 +-- 3 files changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 2b3426b1ff3f..aabe16634c1a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -441,7 +441,6 @@ static int ath10k_init_hw_params(struct ath10k *ar) } struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, - enum ath10k_bus bus, const struct ath10k_hif_ops *hif_ops) { struct ath10k *ar; @@ -458,7 +457,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ar->hif.priv = hif_priv; ar->hif.ops = hif_ops; - ar->hif.bus = bus; ar->free_vdev_map = 0xFF; /* 8 vdevs */ diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 539336d1be4b..748977037603 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -43,10 +43,6 @@ struct ath10k; -enum ath10k_bus { - ATH10K_BUS_PCI, -}; - struct ath10k_skb_cb { dma_addr_t paddr; bool is_mapped; @@ -274,7 +270,6 @@ struct ath10k { struct { void *priv; - enum ath10k_bus bus; const struct ath10k_hif_ops *ops; } hif; @@ -356,7 +351,6 @@ struct ath10k { }; struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, - enum ath10k_bus bus, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 92f35f2c4f6e..926a7ebae226 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2157,8 +2157,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ath10k_pci_dump_features(ar_pci); - ar = ath10k_core_create(ar_pci, ar_pci->dev, ATH10K_BUS_PCI, - &ath10k_pci_hif_ops); + ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops); if (!ar) { ath10k_err("ath10k_core_create failed!\n"); ret = -EINVAL; -- cgit v1.2.3 From cba4ca7553deb8273d393645a1be8b01d3761543 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:07 +0300 Subject: ath10k: fix typo in define name Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 6 +++--- drivers/net/wireless/ath/ath10k/pci.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 61a8ac70d3ca..b40792900bd5 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -79,7 +79,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); void __iomem *indicator_addr; - if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) { + if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) { ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); return; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 926a7ebae226..fe43b4105d7a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2117,7 +2117,7 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci) case ATH10K_PCI_FEATURE_MSI_X: ath10k_dbg(ATH10K_DBG_PCI, "device supports MSI-X\n"); break; - case ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND: + case ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND: ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n"); break; } @@ -2144,7 +2144,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, switch (pci_dev->device) { case QCA988X_1_0_DEVICE_ID: - set_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features); + set_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features); break; case QCA988X_2_0_DEVICE_ID: set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features); @@ -2165,7 +2165,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, } /* Enable QCA988X_1.0 HW workarounds */ - if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) + if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) spin_lock_init(&ar_pci->hw_v1_workaround_lock); ar_pci->ar = ar; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index d2a055a07dc6..d3a2e6cc9179 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -152,7 +152,7 @@ struct service_to_pipe { enum ath10k_pci_features { ATH10K_PCI_FEATURE_MSI_X = 0, - ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND = 1, + ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND = 1, /* keep last */ ATH10K_PCI_FEATURE_COUNT @@ -311,7 +311,7 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); void __iomem *addr = ar_pci->mem; - if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) { + if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) { unsigned long irq_flags; spin_lock_irqsave(&ar_pci->hw_v1_workaround_lock, irq_flags); -- cgit v1.2.3 From 09af8f85c6a1fbe9c1ffc6253a4c0e8a0d8a9033 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:08 +0300 Subject: ath10k: silent warning in IBSS mode There is no TIM IE generated in IBSS beacons by mac80211. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7d4b7987422d..1b5312d1f0ce 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -501,8 +501,8 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies, (u8 *)skb_tail_pointer(bcn) - ies); if (!ie) { - /* highly unlikely for mac80211 */ - ath10k_warn("no tim ie found;\n"); + if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS) + ath10k_warn("no tim ie found;\n"); return; } -- cgit v1.2.3 From 342004bea753434fb8e0d486afa8fc72b2be4bd7 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:09 +0300 Subject: ath10k: lower print level for a message Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 74363c949392..7b5c33445dc0 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -751,8 +751,9 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, tx_alloc = ath10k_htc_get_credit_allocation(htc, conn_req->service_id); if (!tx_alloc) - ath10k_warn("HTC Service %s does not allocate target credits\n", - htc_service_name(conn_req->service_id)); + ath10k_dbg(ATH10K_DBG_HTC, + "HTC Service %s does not allocate target credits\n", + htc_service_name(conn_req->service_id)); skb = ath10k_htc_build_tx_ctrl_skb(htc->ar); if (!skb) { -- cgit v1.2.3 From ed48b35644a08da5ee3c54570241a023abf3ea40 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:10 +0300 Subject: ath10k: provide errno if bmi read/write fails Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index 1a2ef51b69d9..aeae02979d46 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -105,7 +105,8 @@ int ath10k_bmi_read_memory(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &rxlen); if (ret) { - ath10k_warn("unable to read from the device\n"); + ath10k_warn("unable to read from the device (%d)\n", + ret); return ret; } @@ -149,7 +150,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen, NULL, NULL); if (ret) { - ath10k_warn("unable to write to the device\n"); + ath10k_warn("unable to write to the device (%d)\n", + ret); return ret; } -- cgit v1.2.3 From 7a5fe3f87c39565e4c5eb7e39638fc979c8fd98b Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:11 +0300 Subject: ath10k: change function to take struct ath10k as arg This aligns it to the argument list of other similar functions. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index fe43b4105d7a..445ec78d4982 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2058,9 +2058,9 @@ static int ath10k_pci_reset_target(struct ath10k *ar) return 0; } -static void ath10k_pci_device_reset(struct ath10k_pci *ar_pci) +static void ath10k_pci_device_reset(struct ath10k *ar) { - struct ath10k *ar = ar_pci->ar; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); void __iomem *mem = ar_pci->mem; int i; u32 val; @@ -2255,7 +2255,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, * is in an unexpected state. We try to catch that here in order to * reset the Target and retry the probe. */ - ath10k_pci_device_reset(ar_pci); + ath10k_pci_device_reset(ar); ret = ath10k_pci_reset_target(ar); if (ret) -- cgit v1.2.3 From e799bbffdd6e67305b057e3c13c0eed23523bdad Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:12 +0300 Subject: ath10k: rename hif callback The `set_callbacks` is a more appopriate name for the function. Let's leave `init` for something else. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hif.h | 10 +++++----- drivers/net/wireless/ath/ath10k/htc.c | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 73a24d44d1b4..010e26528f35 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -66,8 +66,8 @@ struct ath10k_hif_ops { */ void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force); - void (*init)(struct ath10k *ar, - struct ath10k_hif_cb *callbacks); + void (*set_callbacks)(struct ath10k *ar, + struct ath10k_hif_cb *callbacks); u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); }; @@ -122,10 +122,10 @@ static inline void ath10k_hif_send_complete_check(struct ath10k *ar, ar->hif.ops->send_complete_check(ar, pipe_id, force); } -static inline void ath10k_hif_init(struct ath10k *ar, - struct ath10k_hif_cb *callbacks) +static inline void ath10k_hif_set_callbacks(struct ath10k *ar, + struct ath10k_hif_cb *callbacks) { - ar->hif.ops->init(ar, callbacks); + ar->hif.ops->set_callbacks(ar, callbacks); } static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 7b5c33445dc0..f37a6e18c0ca 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -987,7 +987,7 @@ struct ath10k_htc *ath10k_htc_create(struct ath10k *ar, /* Get HIF default pipe for HTC message exchange */ ep = &htc->endpoint[ATH10K_HTC_EP_0]; - ath10k_hif_init(ar, &htc_callbacks); + ath10k_hif_set_callbacks(ar, &htc_callbacks); ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id); init_completion(&htc->ctl_resp); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 445ec78d4982..7da09832b9d1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -744,8 +744,8 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, ath10k_ce_per_engine_service(ar, pipe); } -static void ath10k_pci_hif_post_init(struct ath10k *ar, - struct ath10k_hif_cb *callbacks) +static void ath10k_pci_hif_set_callbacks(struct ath10k *ar, + struct ath10k_hif_cb *callbacks) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1742,7 +1742,7 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe, .get_default_pipe = ath10k_pci_hif_get_default_pipe, .send_complete_check = ath10k_pci_hif_send_complete_check, - .init = ath10k_pci_hif_post_init, + .set_callbacks = ath10k_pci_hif_set_callbacks, .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, }; -- cgit v1.2.3 From cd003fad17d9258efdc5dd658666731377cfebd1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:13 +0300 Subject: ath10k: embed HTC struct inside ath10k This reduces number of allocations and simplifies memory managemnt. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 28 ++++++++++++---------------- drivers/net/wireless/ath/ath10k/core.h | 2 +- drivers/net/wireless/ath/ath10k/htc.c | 23 +++++------------------ drivers/net/wireless/ath/ath10k/htc.h | 4 +--- drivers/net/wireless/ath/ath10k/htt.c | 2 +- drivers/net/wireless/ath/ath10k/htt_tx.c | 10 +++++----- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++-- 7 files changed, 27 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index aabe16634c1a..4199560b4693 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -100,7 +100,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) goto conn_fail; /* Start HTC */ - status = ath10k_htc_start(ar->htc); + status = ath10k_htc_start(&ar->htc); if (status) goto conn_fail; @@ -116,7 +116,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) return 0; timeout: - ath10k_htc_stop(ar->htc); + ath10k_htc_stop(&ar->htc); conn_fail: return status; } @@ -505,7 +505,6 @@ EXPORT_SYMBOL(ath10k_core_destroy); int ath10k_core_register(struct ath10k *ar) { - struct ath10k_htc_ops htc_ops; struct bmi_target_info target_info; int status; @@ -534,26 +533,26 @@ int ath10k_core_register(struct ath10k *ar) if (status) goto err; - htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; + ar->htc.htc_ops.target_send_suspend_complete = + ath10k_send_suspend_complete; - ar->htc = ath10k_htc_create(ar, &htc_ops); - if (IS_ERR(ar->htc)) { - status = PTR_ERR(ar->htc); - ath10k_err("could not create HTC (%d)\n", status); + status = ath10k_htc_init(ar); + if (status) { + ath10k_err("could not init HTC (%d)\n", status); goto err; } status = ath10k_bmi_done(ar); if (status) - goto err_htc_destroy; + goto err; status = ath10k_wmi_attach(ar); if (status) { ath10k_err("WMI attach failed: %d\n", status); - goto err_htc_destroy; + goto err; } - status = ath10k_htc_wait_target(ar->htc); + status = ath10k_htc_wait_target(&ar->htc); if (status) goto err_wmi_detach; @@ -605,13 +604,11 @@ int ath10k_core_register(struct ath10k *ar) err_unregister_mac: ath10k_mac_unregister(ar); err_disconnect_htc: - ath10k_htc_stop(ar->htc); + ath10k_htc_stop(&ar->htc); err_htt_detach: ath10k_htt_detach(ar->htt); err_wmi_detach: ath10k_wmi_detach(ar); -err_htc_destroy: - ath10k_htc_destroy(ar->htc); err: return status; } @@ -623,10 +620,9 @@ void ath10k_core_unregister(struct ath10k *ar) * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); - ath10k_htc_stop(ar->htc); + ath10k_htc_stop(&ar->htc); ath10k_htt_detach(ar->htt); ath10k_wmi_detach(ar); - ath10k_htc_destroy(ar->htc); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 748977037603..dfd4fe1e82fb 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -279,8 +279,8 @@ struct ath10k { bool is_target_paused; struct ath10k_bmi bmi; + struct ath10k_htc htc; - struct ath10k_htc *htc; struct ath10k_htt *htt; struct ath10k_hw_params { diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index f37a6e18c0ca..7d5a36616b71 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -265,7 +265,7 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb, unsigned int eid) { - struct ath10k_htc *htc = ar->htc; + struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_ep *ep = &htc->endpoint[eid]; bool stopping; @@ -414,7 +414,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, u8 pipe_id) { int status = 0; - struct ath10k_htc *htc = ar->htc; + struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_hdr *hdr; struct ath10k_htc_ep *ep; u16 payload_len; @@ -961,22 +961,14 @@ void ath10k_htc_stop(struct ath10k_htc *htc) } /* registered target arrival callback from the HIF layer */ -struct ath10k_htc *ath10k_htc_create(struct ath10k *ar, - struct ath10k_htc_ops *htc_ops) +int ath10k_htc_init(struct ath10k *ar) { struct ath10k_hif_cb htc_callbacks; struct ath10k_htc_ep *ep = NULL; - struct ath10k_htc *htc = NULL; - - /* FIXME: use struct ath10k instead */ - htc = kzalloc(sizeof(struct ath10k_htc), GFP_KERNEL); - if (!htc) - return ERR_PTR(-ENOMEM); + struct ath10k_htc *htc = &ar->htc; spin_lock_init(&htc->tx_lock); - memcpy(&htc->htc_ops, htc_ops, sizeof(struct ath10k_htc_ops)); - ath10k_htc_reset_endpoint_states(htc); /* setup HIF layer callbacks */ @@ -992,10 +984,5 @@ struct ath10k_htc *ath10k_htc_create(struct ath10k *ar, init_completion(&htc->ctl_resp); - return htc; -} - -void ath10k_htc_destroy(struct ath10k_htc *htc) -{ - kfree(htc); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index fa45844b59fb..1606c9f9dff3 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -352,8 +352,7 @@ struct ath10k_htc { bool stopping; }; -struct ath10k_htc *ath10k_htc_create(struct ath10k *ar, - struct ath10k_htc_ops *htc_ops); +int ath10k_htc_init(struct ath10k *ar); int ath10k_htc_wait_target(struct ath10k_htc *htc); int ath10k_htc_start(struct ath10k_htc *htc); int ath10k_htc_connect_service(struct ath10k_htc *htc, @@ -362,7 +361,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, struct sk_buff *packet); void ath10k_htc_stop(struct ath10k_htc *htc); -void ath10k_htc_destroy(struct ath10k_htc *htc); struct sk_buff *ath10k_htc_alloc_skb(int size); #endif diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 185a5468a2f2..2bfb9b488e09 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -36,7 +36,7 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt) /* connect to control service */ conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG; - status = ath10k_htc_connect_service(htt->ar->htc, &conn_req, + status = ath10k_htc_connect_service(&htt->ar->htc, &conn_req, &conn_resp); if (status) diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index ef79106db247..fa568f10e9dd 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -92,7 +92,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt) /* At the beginning free queue number should hint us the maximum * queue length */ - pipe = htt->ar->htc->endpoint[htt->eid].ul_pipe_id; + pipe = htt->ar->htc.endpoint[htt->eid].ul_pipe_id; htt->max_num_pending_tx = ath10k_hif_get_free_queue_number(htt->ar, pipe); @@ -194,7 +194,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) ATH10K_SKB_CB(skb)->htt.is_conf = true; - ret = ath10k_htc_send(htt->ar->htc, htt->eid, skb); + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); if (ret) { dev_kfree_skb_any(skb); return ret; @@ -281,7 +281,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) ATH10K_SKB_CB(skb)->htt.is_conf = true; - ret = ath10k_htc_send(htt->ar->htc, htt->eid, skb); + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); if (ret) { dev_kfree_skb_any(skb); return ret; @@ -346,7 +346,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->htt.refcount = 2; skb_cb->htt.msdu = msdu; - res = ath10k_htc_send(htt->ar->htc, htt->eid, txdesc); + res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); if (res) goto err; @@ -486,7 +486,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->htt.txfrag = txfrag; skb_cb->htt.msdu = msdu; - res = ath10k_htc_send(htt->ar->htc, htt->eid, txdesc); + res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); if (res) goto err; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1b5312d1f0ce..681e941073c6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -111,7 +111,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len); - status = ath10k_htc_send(ar->htc, ar->wmi.eid, skb); + status = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb); if (status) { dev_kfree_skb_any(skb); atomic_dec(&ar->wmi.pending_tx_count); @@ -1114,7 +1114,7 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar) /* connect to control service */ conn_req.service_id = ATH10K_HTC_SVC_ID_WMI_CONTROL; - status = ath10k_htc_connect_service(ar->htc, &conn_req, &conn_resp); + status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp); if (status) { ath10k_warn("failed to connect to WMI CONTROL service status: %d\n", status); -- cgit v1.2.3 From edb8236df4d0429d973e093062a4806471f5efa2 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:14 +0300 Subject: ath10k: embed HTT struct inside ath10k This reduces number of allocations and simplifies memory managemnt. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 12 ++++++------ drivers/net/wireless/ath/ath10k/core.h | 7 +++---- drivers/net/wireless/ath/ath10k/htt.c | 25 +++++++++++++------------ drivers/net/wireless/ath/ath10k/htt.h | 3 +-- drivers/net/wireless/ath/ath10k/htt_rx.c | 3 ++- drivers/net/wireless/ath/ath10k/htt_tx.c | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 16 ++++++++-------- 7 files changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 4199560b4693..f1312fae8056 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -556,9 +556,9 @@ int ath10k_core_register(struct ath10k *ar) if (status) goto err_wmi_detach; - ar->htt = ath10k_htt_attach(ar); - if (!ar->htt) { - status = -ENOMEM; + status = ath10k_htt_attach(ar); + if (status) { + ath10k_err("could not attach htt (%d)\n", status); goto err_wmi_detach; } @@ -585,7 +585,7 @@ int ath10k_core_register(struct ath10k *ar) goto err_disconnect_htc; } - status = ath10k_htt_attach_target(ar->htt); + status = ath10k_htt_attach_target(&ar->htt); if (status) goto err_disconnect_htc; @@ -606,7 +606,7 @@ err_unregister_mac: err_disconnect_htc: ath10k_htc_stop(&ar->htc); err_htt_detach: - ath10k_htt_detach(ar->htt); + ath10k_htt_detach(&ar->htt); err_wmi_detach: ath10k_wmi_detach(ar); err: @@ -621,7 +621,7 @@ void ath10k_core_unregister(struct ath10k *ar) * unhappy about callback failures. */ ath10k_mac_unregister(ar); ath10k_htc_stop(&ar->htc); - ath10k_htt_detach(ar->htt); + ath10k_htt_detach(&ar->htt); ath10k_wmi_detach(ar); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index dfd4fe1e82fb..2f7065c48f57 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -23,6 +23,7 @@ #include #include +#include "htt.h" #include "htc.h" #include "hw.h" #include "targaddrs.h" @@ -273,15 +274,13 @@ struct ath10k { const struct ath10k_hif_ops *ops; } hif; - struct ath10k_wmi wmi; - wait_queue_head_t event_queue; bool is_target_paused; struct ath10k_bmi bmi; + struct ath10k_wmi wmi; struct ath10k_htc htc; - - struct ath10k_htt *htt; + struct ath10k_htt htt; struct ath10k_hw_params { u32 id; diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 2bfb9b488e09..39342c5cfcb2 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -16,6 +16,7 @@ */ #include +#include #include "htt.h" #include "core.h" @@ -47,15 +48,11 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt) return 0; } -struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) +int ath10k_htt_attach(struct ath10k *ar) { - struct ath10k_htt *htt; + struct ath10k_htt *htt = &ar->htt; int ret; - htt = kzalloc(sizeof(*htt), GFP_KERNEL); - if (!htt) - return NULL; - htt->ar = ar; htt->max_throughput_mbps = 800; @@ -65,8 +62,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) * since ath10k_htt_rx_attach involves sending a rx ring configure * message to the target. */ - if (ath10k_htt_htc_attach(htt)) + ret = ath10k_htt_htc_attach(htt); + if (ret) { + ath10k_err("could not attach htt htc (%d)\n", ret); goto err_htc_attach; + } ret = ath10k_htt_tx_attach(htt); if (ret) { @@ -74,8 +74,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) goto err_htc_attach; } - if (ath10k_htt_rx_attach(htt)) + ret = ath10k_htt_rx_attach(htt); + if (ret) { + ath10k_err("could not attach htt rx (%d)\n", ret); goto err_rx_attach; + } /* * Prefetch enough data to satisfy target @@ -89,13 +92,12 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) 8 + /* llc snap */ 2; /* ip4 dscp or ip6 priority */ - return htt; + return 0; err_rx_attach: ath10k_htt_tx_detach(htt); err_htc_attach: - kfree(htt); - return NULL; + return ret; } #define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ) @@ -148,5 +150,4 @@ void ath10k_htt_detach(struct ath10k_htt *htt) { ath10k_htt_rx_detach(htt); ath10k_htt_tx_detach(htt); - kfree(htt); } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index a7a7aa040536..318be4629cde 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -20,7 +20,6 @@ #include -#include "core.h" #include "htc.h" #include "rx_desc.h" @@ -1317,7 +1316,7 @@ struct htt_rx_desc { #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) -struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar); +int ath10k_htt_attach(struct ath10k *ar); int ath10k_htt_attach_target(struct ath10k_htt *htt); void ath10k_htt_detach(struct ath10k_htt *htt); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index de058d7adca8..04f08d946479 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -15,6 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "core.h" #include "htc.h" #include "htt.h" #include "txrx.h" @@ -1036,7 +1037,7 @@ end: void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) { - struct ath10k_htt *htt = ar->htt; + struct ath10k_htt *htt = &ar->htt; struct htt_resp *resp = (struct htt_resp *)skb->data; /* confirm alignment */ diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index fa568f10e9dd..dc3f3e8de32b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -153,7 +153,7 @@ void ath10k_htt_tx_detach(struct ath10k_htt *htt) void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); - struct ath10k_htt *htt = ar->htt; + struct ath10k_htt *htt = &ar->htt; if (skb_cb->htt.is_conf) { dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 87fa3c2d9382..f91701c6963c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1397,15 +1397,15 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) int ret; if (ieee80211_is_mgmt(hdr->frame_control)) - ret = ath10k_htt_mgmt_tx(ar->htt, skb); + ret = ath10k_htt_mgmt_tx(&ar->htt, skb); else if (ieee80211_is_nullfunc(hdr->frame_control)) /* FW does not report tx status properly for NullFunc frames * unless they are sent through mgmt tx path. mac80211 sends * those frames when it detects link/beacon loss and depends on * the tx status to be correct. */ - ret = ath10k_htt_mgmt_tx(ar->htt, skb); + ret = ath10k_htt_mgmt_tx(&ar->htt, skb); else - ret = ath10k_htt_tx(ar->htt, skb); + ret = ath10k_htt_tx(&ar->htt, skb); if (ret) { ath10k_warn("tx failed (%d). dropping packet.\n", ret); @@ -2659,12 +2659,12 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) if (drop) return; - ret = wait_event_timeout(ar->htt->empty_tx_wq, ({ + ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ bool empty; - spin_lock_bh(&ar->htt->tx_lock); - empty = bitmap_empty(ar->htt->used_msdu_ids, - ar->htt->max_num_pending_tx); - spin_unlock_bh(&ar->htt->tx_lock); + spin_lock_bh(&ar->htt.tx_lock); + empty = bitmap_empty(ar->htt.used_msdu_ids, + ar->htt.max_num_pending_tx); + spin_unlock_bh(&ar->htt.tx_lock); (empty); }), ATH10K_FLUSH_TIMEOUT_HZ); if (ret <= 0) -- cgit v1.2.3 From 548db54cc1890b161e87d4ca1028cf77f51fd16c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:15 +0300 Subject: ath10k: improve locking Add more lockdep asserts and a few conf_mutex locks. It's better to be on the safe side. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 57 +++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index f91701c6963c..278c9689ce7a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -43,6 +43,8 @@ static int ath10k_send_key(struct ath10k_vif *arvif, .macaddr = macaddr, }; + lockdep_assert_held(&arvif->ar->conf_mutex); + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) arg.key_flags = WMI_KEY_PAIRWISE; else @@ -87,6 +89,8 @@ static int ath10k_install_key(struct ath10k_vif *arvif, struct ath10k *ar = arvif->ar; int ret; + lockdep_assert_held(&ar->conf_mutex); + INIT_COMPLETION(ar->install_key_done); ret = ath10k_send_key(arvif, key, cmd, macaddr); @@ -372,6 +376,8 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) { int ret; + lockdep_assert_held(&ar->conf_mutex); + ret = wait_for_completion_timeout(&ar->vdev_setup_done, ATH10K_VDEV_SETUP_TIMEOUT_HZ); if (ret == 0) @@ -605,6 +611,8 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, { int ret = 0; + lockdep_assert_held(&arvif->ar->conf_mutex); + if (!info->enable_beacon) { ath10k_vdev_stop(arvif); return; @@ -631,6 +639,8 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, { int ret = 0; + lockdep_assert_held(&arvif->ar->conf_mutex); + if (!info->ibss_joined) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer); if (ret) @@ -680,6 +690,8 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) enum wmi_sta_ps_mode psmode; int ret; + lockdep_assert_held(&arvif->ar->conf_mutex); + if (vif->type != NL80211_IFTYPE_STATION) return; @@ -722,6 +734,8 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar, struct ieee80211_bss_conf *bss_conf, struct wmi_peer_assoc_complete_arg *arg) { + lockdep_assert_held(&ar->conf_mutex); + memcpy(arg->addr, sta->addr, ETH_ALEN); arg->vdev_id = arvif->vdev_id; arg->peer_aid = sta->aid; @@ -764,6 +778,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, const u8 *rsnie = NULL; const u8 *wpaie = NULL; + lockdep_assert_held(&ar->conf_mutex); + bss = cfg80211_get_bss(ar->hw->wiphy, ar->hw->conf.chandef.chan, info->bssid, NULL, 0, 0, 0); if (bss) { @@ -804,6 +820,8 @@ static void ath10k_peer_assoc_h_rates(struct ath10k *ar, u32 ratemask; int i; + lockdep_assert_held(&ar->conf_mutex); + sband = ar->hw->wiphy->bands[ar->hw->conf.chandef.chan->band]; ratemask = sta->supp_rates[ar->hw->conf.chandef.chan->band]; rates = sband->bitrates; @@ -827,6 +845,8 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, int smps; int i, n; + lockdep_assert_held(&ar->conf_mutex); + if (!ht_cap->ht_supported) return; @@ -905,6 +925,8 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, u32 uapsd = 0; u32 max_sp = 0; + lockdep_assert_held(&ar->conf_mutex); + if (sta->wme) arg->peer_flags |= WMI_PEER_QOS; @@ -1056,6 +1078,8 @@ static int ath10k_peer_assoc(struct ath10k *ar, { struct wmi_peer_assoc_complete_arg arg; + lockdep_assert_held(&ar->conf_mutex); + memset(&arg, 0, sizeof(struct wmi_peer_assoc_complete_arg)); ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, &arg); @@ -1079,6 +1103,8 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_sta *ap_sta; int ret; + lockdep_assert_held(&ar->conf_mutex); + rcu_read_lock(); ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); @@ -1119,6 +1145,8 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); int ret; + lockdep_assert_held(&ar->conf_mutex); + /* * For some reason, calling VDEV-DOWN before VDEV-STOP * makes the FW to send frames via HTT after disassociation. @@ -1152,6 +1180,8 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, { int ret = 0; + lockdep_assert_held(&ar->conf_mutex); + ret = ath10k_peer_assoc(ar, arvif, sta, NULL); if (ret) { ath10k_warn("WMI peer assoc failed for %pM\n", sta->addr); @@ -1172,6 +1202,8 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif, { int ret = 0; + lockdep_assert_held(&ar->conf_mutex); + ret = ath10k_clear_peer_keys(arvif, sta->addr); if (ret) { ath10k_warn("could not clear all peer wep keys (%d)\n", ret); @@ -1198,6 +1230,8 @@ static int ath10k_update_channel_list(struct ath10k *ar) int ret; int i; + lockdep_assert_held(&ar->conf_mutex); + bands = hw->wiphy->bands; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!bands[band]) @@ -1284,6 +1318,8 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, struct ath10k *ar = hw->priv; int ret; + mutex_lock(&ar->conf_mutex); + ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); ret = ath10k_update_channel_list(ar); @@ -1301,6 +1337,8 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, regpair->reg_5ghz_ctl); if (ret) ath10k_warn("could not set pdev regdomain (%d)\n", ret); + + mutex_unlock(&ar->conf_mutex); } /***************/ @@ -1678,6 +1716,8 @@ static int ath10k_start(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; int ret; + mutex_lock(&ar->conf_mutex); + ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1); if (ret) ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", @@ -1688,6 +1728,7 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ret); + mutex_unlock(&ar->conf_mutex); return 0; } @@ -1695,9 +1736,11 @@ static void ath10k_stop(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; - /* avoid leaks in case FW never confirms scan for offchannel */ - cancel_work_sync(&ar->offchan_tx_work); + mutex_lock(&ar->conf_mutex); ath10k_offchan_tx_purge(ar); + mutex_unlock(&ar->conf_mutex); + + cancel_work_sync(&ar->offchan_tx_work); } static int ath10k_config(struct ieee80211_hw *hw, u32 changed) @@ -2381,6 +2424,8 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, u32 value = 0; int ret = 0; + lockdep_assert_held(&ar->conf_mutex); + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) return 0; @@ -2576,6 +2621,8 @@ static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif) struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); u32 rts = ar_iter->ar->hw->wiphy->rts_threshold; + lockdep_assert_held(&arvif->ar->conf_mutex); + rts = min_t(u32, rts, ATH10K_RTS_MAX); ar_iter->ret = ath10k_wmi_vdev_set_param(ar_iter->ar, arvif->vdev_id, @@ -2614,6 +2661,8 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif) u32 frag = ar_iter->ar->hw->wiphy->frag_threshold; int ret; + lockdep_assert_held(&arvif->ar->conf_mutex); + frag = clamp_t(u32, frag, ATH10K_FRAGMT_THRESHOLD_MIN, ATH10K_FRAGMT_THRESHOLD_MAX); @@ -2659,6 +2708,8 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) if (drop) return; + mutex_lock(&ar->conf_mutex); + ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ bool empty; spin_lock_bh(&ar->htt.tx_lock); @@ -2669,6 +2720,8 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) }), ATH10K_FLUSH_TIMEOUT_HZ); if (ret <= 0) ath10k_warn("tx not flushed\n"); + + mutex_unlock(&ar->conf_mutex); } /* TODO: Implement this function properly -- cgit v1.2.3 From adb8c9b77cd182b1b3f2b145b8db4043623e3745 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:16 +0300 Subject: ath10k: abort scan properly if wmi_scan_stop fails Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 278c9689ce7a..50825030bb17 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1590,6 +1590,10 @@ static int ath10k_abort_scan(struct ath10k *ar) ret = ath10k_wmi_stop_scan(ar, &arg); if (ret) { ath10k_warn("could not submit wmi stop scan (%d)\n", ret); + spin_lock_bh(&ar->data_lock); + ar->scan.in_progress = false; + ath10k_offchan_tx_purge(ar); + spin_unlock_bh(&ar->data_lock); return -EIO; } -- cgit v1.2.3 From e0c508ab099bda4629768107d14bbe9afa5c6705 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 5 Jul 2013 16:15:17 +0300 Subject: ath10k: add missing debug prints Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 681e941073c6..b7e7e456b5de 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1748,6 +1748,9 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar, if (arg->key_data) memcpy(cmd->key_data, arg->key_data, arg->key_len); + ath10k_dbg(ATH10K_DBG_WMI, + "wmi vdev install key idx %d cipher %d len %d\n", + arg->key_idx, arg->key_cipher, arg->key_len); return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_INSTALL_KEY_CMDID); } @@ -2011,6 +2014,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, cmd->peer_vht_rates.tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); + ath10k_dbg(ATH10K_DBG_WMI, + "wmi peer assoc vdev %d addr %pM\n", + arg->vdev_id, arg->addr); return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID); } -- cgit v1.2.3 From 8c5c53682f0da87b91ff87d060a5d92df524c13d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:50 +0200 Subject: ath10k: decouple pci start/stop logic Split logic that prepares the device for BMI phase/cleans up related resources. This is necessary for ath10k to be able to restart hw on the fly without reloading the module. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hif.h | 20 +++++++ drivers/net/wireless/ath/ath10k/pci.c | 110 ++++++++++++++++++++++------------ 2 files changed, 91 insertions(+), 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 010e26528f35..00d29402fa1d 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -46,8 +46,11 @@ struct ath10k_hif_ops { void *request, u32 request_len, void *response, u32 *response_len); + /* Post BMI phase, after FW is loaded. Starts regular operation */ int (*start)(struct ath10k *ar); + /* Clean up what start() did. This does not revert to BMI phase. If + * desired so, call power_down() and power_up() */ void (*stop)(struct ath10k *ar); int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id, @@ -70,6 +73,13 @@ struct ath10k_hif_ops { struct ath10k_hif_cb *callbacks); u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); + + /* Power up the device and enter BMI transfer mode for FW download */ + int (*power_up)(struct ath10k *ar); + + /* Power down the device and free up resources. stop() must be called + * before this if start() was called earlier */ + void (*power_down)(struct ath10k *ar); }; @@ -134,4 +144,14 @@ static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar, return ar->hif.ops->get_free_queue_number(ar, pipe_id); } +static inline int ath10k_hif_power_up(struct ath10k *ar) +{ + return ar->hif.ops->power_up(ar); +} + +static inline void ath10k_hif_power_down(struct ath10k *ar) +{ + ar->hif.ops->power_down(ar); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 7da09832b9d1..c15b0c58cc87 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -54,6 +54,8 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info, int num); static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info); static void ath10k_pci_stop_ce(struct ath10k *ar); +static void ath10k_pci_device_reset(struct ath10k *ar); +static int ath10k_pci_reset_target(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* host->target HTC control and raw streams */ @@ -1734,6 +1736,66 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_pci_sleep(ar); } +static int ath10k_pci_hif_power_up(struct ath10k *ar) +{ + int ret; + + /* + * Bring the target up cleanly. + * + * The target may be in an undefined state with an AUX-powered Target + * and a Host in WoW mode. If the Host crashes, loses power, or is + * restarted (without unloading the driver) then the Target is left + * (aux) powered and running. On a subsequent driver load, the Target + * is in an unexpected state. We try to catch that here in order to + * reset the Target and retry the probe. + */ + ath10k_pci_device_reset(ar); + + ret = ath10k_pci_reset_target(ar); + if (ret) + goto err; + + if (ath10k_target_ps) { + ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n"); + } else { + /* Force AWAKE forever */ + ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save disabled\n"); + ath10k_do_pci_wake(ar); + } + + ret = ath10k_pci_ce_init(ar); + if (ret) + goto err_ps; + + ret = ath10k_pci_init_config(ar); + if (ret) + goto err_ce; + + ret = ath10k_pci_wake_target_cpu(ar); + if (ret) { + ath10k_err("could not wake up target CPU (%d)\n", ret); + goto err_ce; + } + + return 0; + +err_ce: + ath10k_pci_ce_deinit(ar); +err_ps: + if (!ath10k_target_ps) + ath10k_do_pci_sleep(ar); +err: + return ret; +} + +static void ath10k_pci_hif_power_down(struct ath10k *ar) +{ + ath10k_pci_ce_deinit(ar); + if (!ath10k_target_ps) + ath10k_do_pci_sleep(ar); +} + static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .send_head = ath10k_pci_hif_send_head, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, @@ -1744,6 +1806,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .send_complete_check = ath10k_pci_hif_send_complete_check, .set_callbacks = ath10k_pci_hif_set_callbacks, .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, + .power_up = ath10k_pci_hif_power_up, + .power_down = ath10k_pci_hif_power_down, }; static void ath10k_pci_ce_tasklet(unsigned long ptr) @@ -2245,54 +2309,22 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_iomap; } - /* - * Bring the target up cleanly. - * - * The target may be in an undefined state with an AUX-powered Target - * and a Host in WoW mode. If the Host crashes, loses power, or is - * restarted (without unloading the driver) then the Target is left - * (aux) powered and running. On a subsequent driver load, the Target - * is in an unexpected state. We try to catch that here in order to - * reset the Target and retry the probe. - */ - ath10k_pci_device_reset(ar); - - ret = ath10k_pci_reset_target(ar); - if (ret) - goto err_intr; - - if (ath10k_target_ps) { - ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n"); - } else { - /* Force AWAKE forever */ - ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save disabled\n"); - ath10k_do_pci_wake(ar); - } - - ret = ath10k_pci_ce_init(ar); - if (ret) - goto err_intr; - - ret = ath10k_pci_init_config(ar); - if (ret) - goto err_ce; - - ret = ath10k_pci_wake_target_cpu(ar); + ret = ath10k_pci_hif_power_up(ar); if (ret) { - ath10k_err("could not wake up target CPU (%d)\n", ret); - goto err_ce; + ath10k_err("could not start pci hif (%d)\n", ret); + goto err_intr; } ret = ath10k_core_register(ar); if (ret) { ath10k_err("could not register driver core (%d)\n", ret); - goto err_ce; + goto err_hif; } return 0; -err_ce: - ath10k_pci_ce_deinit(ar); +err_hif: + ath10k_pci_hif_power_down(ar); err_intr: ath10k_pci_stop_intr(ar); err_iomap: @@ -2331,7 +2363,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) tasklet_kill(&ar_pci->msi_fw_err); ath10k_core_unregister(ar); - ath10k_pci_ce_deinit(ar); + ath10k_pci_hif_power_down(ar); ath10k_pci_stop_intr(ar); pci_set_drvdata(pdev, NULL); -- cgit v1.2.3 From dd30a36e11a1315751c668832cbaa2c42f9e9002 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:51 +0200 Subject: ath10k: decouple core start/stop logic Enables code reuse for proper hw reconfiguration that is in turn required for proper suspend/hibernation/wowlan support. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 44 ++++++++++++++++++++++++---------- drivers/net/wireless/ath/ath10k/core.h | 2 ++ 2 files changed, 34 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f1312fae8056..dcddae4d5d90 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -502,8 +502,7 @@ void ath10k_core_destroy(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_core_destroy); - -int ath10k_core_register(struct ath10k *ar) +int ath10k_core_start(struct ath10k *ar) { struct bmi_target_info target_info; int status; @@ -589,9 +588,36 @@ int ath10k_core_register(struct ath10k *ar) if (status) goto err_disconnect_htc; + return 0; + +err_disconnect_htc: + ath10k_htc_stop(&ar->htc); +err_htt_detach: + ath10k_htt_detach(&ar->htt); +err_wmi_detach: + ath10k_wmi_detach(ar); +err: + return status; +} + +void ath10k_core_stop(struct ath10k *ar) +{ + ath10k_htc_stop(&ar->htc); + ath10k_htt_detach(&ar->htt); + ath10k_wmi_detach(ar); +} + +int ath10k_core_register(struct ath10k *ar) +{ + int status; + + status = ath10k_core_start(ar); + if (status) + goto err; + status = ath10k_mac_register(ar); if (status) - goto err_disconnect_htc; + goto err_core_stop; status = ath10k_debug_create(ar); if (status) { @@ -603,12 +629,8 @@ int ath10k_core_register(struct ath10k *ar) err_unregister_mac: ath10k_mac_unregister(ar); -err_disconnect_htc: - ath10k_htc_stop(&ar->htc); -err_htt_detach: - ath10k_htt_detach(&ar->htt); -err_wmi_detach: - ath10k_wmi_detach(ar); +err_core_stop: + ath10k_core_stop(ar); err: return status; } @@ -620,9 +642,7 @@ void ath10k_core_unregister(struct ath10k *ar) * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); - ath10k_htc_stop(&ar->htc); - ath10k_htt_detach(&ar->htt); - ath10k_wmi_detach(ar); + ath10k_core_stop(ar); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2f7065c48f57..5a0b2cef7d90 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -353,6 +353,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); +int ath10k_core_start(struct ath10k *ar); +void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar); -- cgit v1.2.3 From f7843d7f1ac57fb388d5814cdcbd309fa18214be Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:52 +0200 Subject: ath10k: allow deferred regd update Regulatory domain notification hook can be called regardless of the hw state (i.e. before start mac80211 callback). Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 7 +++++++ drivers/net/wireless/ath/ath10k/mac.c | 26 +++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5a0b2cef7d90..d5b2533d33a1 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -247,6 +247,11 @@ struct ath10k_debug { struct completion event_stats_compl; }; +enum ath10k_state { + ATH10K_STATE_OFF = 0, + ATH10K_STATE_ON, +}; + struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; @@ -344,6 +349,8 @@ struct ath10k { struct completion offchan_tx_completed; struct sk_buff *offchan_tx_skb; + enum ath10k_state state; + #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 50825030bb17..4627c16d2d05 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1310,23 +1310,19 @@ static int ath10k_update_channel_list(struct ath10k *ar) return ret; } -static void ath10k_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +static void ath10k_regd_update(struct ath10k *ar) { - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct reg_dmn_pair_mapping *regpair; - struct ath10k *ar = hw->priv; int ret; - mutex_lock(&ar->conf_mutex); - - ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); + lockdep_assert_held(&ar->conf_mutex); ret = ath10k_update_channel_list(ar); if (ret) ath10k_warn("could not update channel list (%d)\n", ret); regpair = ar->ath_common.regulatory.regpair; + /* Target allows setting up per-band regdomain but ath_common provides * a combined one only */ ret = ath10k_wmi_pdev_set_regdomain(ar, @@ -1337,7 +1333,19 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, regpair->reg_5ghz_ctl); if (ret) ath10k_warn("could not set pdev regdomain (%d)\n", ret); +} +static void ath10k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath10k *ar = hw->priv; + + ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); + + mutex_lock(&ar->conf_mutex); + if (ar->state == ATH10K_STATE_ON) + ath10k_regd_update(ar); mutex_unlock(&ar->conf_mutex); } @@ -1732,6 +1740,9 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ret); + ar->state = ATH10K_STATE_ON; + ath10k_regd_update(ar); + mutex_unlock(&ar->conf_mutex); return 0; } @@ -1742,6 +1753,7 @@ static void ath10k_stop(struct ieee80211_hw *hw) mutex_lock(&ar->conf_mutex); ath10k_offchan_tx_purge(ar); + ar->state = ATH10K_STATE_OFF; mutex_unlock(&ar->conf_mutex); cancel_work_sync(&ar->offchan_tx_work); -- cgit v1.2.3 From 64d151d47030d0d73d82bb6fa7bfe1e29385ed43 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:53 +0200 Subject: ath10k: reset BMI state upon init This is necessary if we want to be able to restart hw on-the-fly. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.c | 6 ++++++ drivers/net/wireless/ath/ath10k/bmi.h | 1 + drivers/net/wireless/ath/ath10k/core.c | 2 ++ 3 files changed, 9 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index aeae02979d46..744da6d1c405 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -20,6 +20,12 @@ #include "debug.h" #include "htc.h" +void ath10k_bmi_start(struct ath10k *ar) +{ + ath10k_dbg(ATH10K_DBG_CORE, "BMI started\n"); + ar->bmi.done_sent = false; +} + int ath10k_bmi_done(struct ath10k *ar) { struct bmi_cmd cmd; diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 32c56aa33a5e..8d81ce1cec21 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -184,6 +184,7 @@ struct bmi_target_info { #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 +void ath10k_bmi_start(struct ath10k *ar); int ath10k_bmi_done(struct ath10k *ar); int ath10k_bmi_get_target_info(struct ath10k *ar, struct bmi_target_info *target_info); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index dcddae4d5d90..3d75c6a74fc6 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -507,6 +507,8 @@ int ath10k_core_start(struct ath10k *ar) struct bmi_target_info target_info; int status; + ath10k_bmi_start(ar); + memset(&target_info, 0, sizeof(target_info)); status = ath10k_bmi_get_target_info(ar, &target_info); if (status) -- cgit v1.2.3 From 8cd13cad1caf94ba66f626a94887b795fe23f939 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:54 +0200 Subject: ath10k: decouple suspend code Split up fw-related and hw-related suspension code. Although we don't advertise WoW support to mac80211 yet it's useful to keep the code in suspend/resume hooks. At this point there's no need to keep pci pm ops. In case of WoW mac80211 calls ath10k_suspend() which should take care of entering low-power mode. In case WoW is not available mac80211 will go through regular interface teradown and use start/stop. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 28 ------ drivers/net/wireless/ath/ath10k/core.h | 3 - drivers/net/wireless/ath/ath10k/hif.h | 19 ++++ drivers/net/wireless/ath/ath10k/mac.c | 66 +++++++++++++ drivers/net/wireless/ath/ath10k/pci.c | 176 ++++++++++----------------------- 5 files changed, 138 insertions(+), 154 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3d75c6a74fc6..01c1d82f674f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -648,34 +648,6 @@ void ath10k_core_unregister(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_core_unregister); -int ath10k_core_target_suspend(struct ath10k *ar) -{ - int ret; - - ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); - - ret = ath10k_wmi_pdev_suspend_target(ar); - if (ret) - ath10k_warn("could not suspend target (%d)\n", ret); - - return ret; -} -EXPORT_SYMBOL(ath10k_core_target_suspend); - -int ath10k_core_target_resume(struct ath10k *ar) -{ - int ret; - - ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); - - ret = ath10k_wmi_pdev_resume_target(ar); - if (ret) - ath10k_warn("could not resume target (%d)\n", ret); - - return ret; -} -EXPORT_SYMBOL(ath10k_core_target_resume); - MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index d5b2533d33a1..5c94ea06eb71 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -365,7 +365,4 @@ void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar); -int ath10k_core_target_suspend(struct ath10k *ar); -int ath10k_core_target_resume(struct ath10k *ar); - #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 00d29402fa1d..dcdea68bcc0a 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -80,6 +80,9 @@ struct ath10k_hif_ops { /* Power down the device and free up resources. stop() must be called * before this if start() was called earlier */ void (*power_down)(struct ath10k *ar); + + int (*suspend)(struct ath10k *ar); + int (*resume)(struct ath10k *ar); }; @@ -154,4 +157,20 @@ static inline void ath10k_hif_power_down(struct ath10k *ar) ar->hif.ops->power_down(ar); } +static inline int ath10k_hif_suspend(struct ath10k *ar) +{ + if (!ar->hif.ops->suspend) + return -EOPNOTSUPP; + + return ar->hif.ops->suspend(ar); +} + +static inline int ath10k_hif_resume(struct ath10k *ar) +{ + if (!ar->hif.ops->resume) + return -EOPNOTSUPP; + + return ar->hif.ops->resume(ar); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4627c16d2d05..febba7d8ca42 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -20,6 +20,7 @@ #include #include +#include "hif.h" #include "core.h" #include "debug.h" #include "wmi.h" @@ -2749,6 +2750,67 @@ static int ath10k_tx_last_beacon(struct ieee80211_hw *hw) return 1; } +#ifdef CONFIG_PM +static int ath10k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct ath10k *ar = hw->priv; + int ret; + + ar->is_target_paused = false; + + ret = ath10k_wmi_pdev_suspend_target(ar); + if (ret) { + ath10k_warn("could not suspend target (%d)\n", ret); + return 1; + } + + ret = wait_event_interruptible_timeout(ar->event_queue, + ar->is_target_paused == true, + 1 * HZ); + if (ret < 0) { + ath10k_warn("suspend interrupted (%d)\n", ret); + goto resume; + } else if (ret == 0) { + ath10k_warn("suspend timed out - target pause event never came\n"); + goto resume; + } + + ret = ath10k_hif_suspend(ar); + if (ret) { + ath10k_warn("could not suspend hif (%d)\n", ret); + goto resume; + } + + return 0; +resume: + ret = ath10k_wmi_pdev_resume_target(ar); + if (ret) + ath10k_warn("could not resume target (%d)\n", ret); + return 1; +} + +static int ath10k_resume(struct ieee80211_hw *hw) +{ + struct ath10k *ar = hw->priv; + int ret; + + ret = ath10k_hif_resume(ar); + if (ret) { + ath10k_warn("could not resume hif (%d)\n", ret); + return 1; + } + + ret = ath10k_wmi_pdev_resume_target(ar); + if (ret) { + ath10k_warn("could not resume target (%d)\n", ret); + return 1; + } + + return 0; +} +#endif + static const struct ieee80211_ops ath10k_ops = { .tx = ath10k_tx, .start = ath10k_start, @@ -2769,6 +2831,10 @@ static const struct ieee80211_ops ath10k_ops = { .set_frag_threshold = ath10k_set_frag_threshold, .flush = ath10k_flush, .tx_last_beacon = ath10k_tx_last_beacon, +#ifdef CONFIG_PM + .suspend = ath10k_suspend, + .resume = ath10k_resume, +#endif }; #define RATETAB_ENT(_rate, _rateid, _flags) { \ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c15b0c58cc87..75f5427bb416 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1796,6 +1796,55 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) ath10k_do_pci_sleep(ar); } +#ifdef CONFIG_PM + +#define ATH10K_PCI_PM_CONTROL 0x44 + +static int ath10k_pci_hif_suspend(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct pci_dev *pdev = ar_pci->pdev; + u32 val; + + pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val); + + if ((val & 0x000000ff) != 0x3) { + pci_save_state(pdev); + pci_disable_device(pdev); + pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL, + (val & 0xffffff00) | 0x03); + } + + return 0; +} + +static int ath10k_pci_hif_resume(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct pci_dev *pdev = ar_pci->pdev; + u32 val; + + pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val); + + if ((val & 0x000000ff) != 0) { + pci_restore_state(pdev); + pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL, + val & 0xffffff00); + /* + * Suspend/Resume resets the PCI configuration space, + * so we have to re-disable the RETRY_TIMEOUT register (0x41) + * to keep PCI Tx retries from interfering with C3 CPU state + */ + pci_read_config_dword(pdev, 0x40, &val); + + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + } + + return 0; +} +#endif + static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .send_head = ath10k_pci_hif_send_head, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, @@ -1808,6 +1857,10 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, .power_up = ath10k_pci_hif_power_up, .power_down = ath10k_pci_hif_power_down, +#ifdef CONFIG_PM + .suspend = ath10k_pci_hif_suspend, + .resume = ath10k_pci_hif_resume, +#endif }; static void ath10k_pci_ce_tasklet(unsigned long ptr) @@ -2376,128 +2429,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev) kfree(ar_pci); } -#if defined(CONFIG_PM_SLEEP) - -#define ATH10K_PCI_PM_CONTROL 0x44 - -static int ath10k_pci_suspend(struct device *device) -{ - struct pci_dev *pdev = to_pci_dev(device); - struct ath10k *ar = pci_get_drvdata(pdev); - struct ath10k_pci *ar_pci; - u32 val; - int ret, retval; - - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); - - if (!ar) - return -ENODEV; - - ar_pci = ath10k_pci_priv(ar); - if (!ar_pci) - return -ENODEV; - - if (ath10k_core_target_suspend(ar)) - return -EBUSY; - - ret = wait_event_interruptible_timeout(ar->event_queue, - ar->is_target_paused == true, - 1 * HZ); - if (ret < 0) { - ath10k_warn("suspend interrupted (%d)\n", ret); - retval = ret; - goto resume; - } else if (ret == 0) { - ath10k_warn("suspend timed out - target pause event never came\n"); - retval = EIO; - goto resume; - } - - /* - * reset is_target_paused and host can check that in next time, - * or it will always be TRUE and host just skip the waiting - * condition, it causes target assert due to host already - * suspend - */ - ar->is_target_paused = false; - - pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val); - - if ((val & 0x000000ff) != 0x3) { - pci_save_state(pdev); - pci_disable_device(pdev); - pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL, - (val & 0xffffff00) | 0x03); - } - - return 0; -resume: - ret = ath10k_core_target_resume(ar); - if (ret) - ath10k_warn("could not resume (%d)\n", ret); - - return retval; -} - -static int ath10k_pci_resume(struct device *device) -{ - struct pci_dev *pdev = to_pci_dev(device); - struct ath10k *ar = pci_get_drvdata(pdev); - struct ath10k_pci *ar_pci; - int ret; - u32 val; - - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); - - if (!ar) - return -ENODEV; - ar_pci = ath10k_pci_priv(ar); - - if (!ar_pci) - return -ENODEV; - - ret = pci_enable_device(pdev); - if (ret) { - ath10k_warn("cannot enable PCI device: %d\n", ret); - return ret; - } - - pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val); - - if ((val & 0x000000ff) != 0) { - pci_restore_state(pdev); - pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL, - val & 0xffffff00); - /* - * Suspend/Resume resets the PCI configuration space, - * so we have to re-disable the RETRY_TIMEOUT register (0x41) - * to keep PCI Tx retries from interfering with C3 CPU state - */ - pci_read_config_dword(pdev, 0x40, &val); - - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - } - - ret = ath10k_core_target_resume(ar); - if (ret) - ath10k_warn("target resume failed: %d\n", ret); - - return ret; -} - -static SIMPLE_DEV_PM_OPS(ath10k_dev_pm_ops, - ath10k_pci_suspend, - ath10k_pci_resume); - -#define ATH10K_PCI_PM_OPS (&ath10k_dev_pm_ops) - -#else - -#define ATH10K_PCI_PM_OPS NULL - -#endif /* CONFIG_PM_SLEEP */ - MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table); static struct pci_driver ath10k_pci_driver = { @@ -2505,7 +2436,6 @@ static struct pci_driver ath10k_pci_driver = { .id_table = ath10k_pci_id_table, .probe = ath10k_pci_probe, .remove = ath10k_pci_remove, - .driver.pm = ATH10K_PCI_PM_OPS, }; static int __init ath10k_pci_init(void) -- cgit v1.2.3 From 1a1b8a889d1fad1a0b48c07c26b894085fcc692c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:55 +0200 Subject: ath10k: move free_vdev_map initialization This is necessary for hw reconfiguration to work. Since mac80211 is not calling remove_interface() is such case we must reset free_vdev_map. Also use a define instead of a hardcoded value for vdev map initialization. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 01c1d82f674f..0e4a704516f7 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -458,8 +458,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ar->hif.priv = hif_priv; ar->hif.ops = hif_ops; - ar->free_vdev_map = 0xFF; /* 8 vdevs */ - init_completion(&ar->scan.started); init_completion(&ar->scan.completed); init_completion(&ar->scan.on_channel); @@ -590,6 +588,8 @@ int ath10k_core_start(struct ath10k *ar) if (status) goto err_disconnect_htc; + ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; + return 0; err_disconnect_htc: -- cgit v1.2.3 From a96d7745592274077e517173ec2cdac2a22d5b79 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:56 +0200 Subject: ath10k: make sure all resources are freed upon ath10k_stop() This is necessary for proper hw reconfiguration and to avoid memory leaks. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index febba7d8ca42..b9663e94dba5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -369,6 +369,20 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) spin_unlock_bh(&ar->data_lock); } +static void ath10k_peer_cleanup_all(struct ath10k *ar) +{ + struct ath10k_peer *peer, *tmp; + + lockdep_assert_held(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + list_for_each_entry_safe(peer, tmp, &ar->peers, list) { + list_del(&peer->list); + kfree(peer); + } + spin_unlock_bh(&ar->data_lock); +} + /************************/ /* Interface management */ /************************/ @@ -1753,7 +1767,18 @@ static void ath10k_stop(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); + del_timer_sync(&ar->scan.timeout); ath10k_offchan_tx_purge(ar); + ath10k_peer_cleanup_all(ar); + + spin_lock_bh(&ar->data_lock); + if (ar->scan.in_progress) { + del_timer(&ar->scan.timeout); + ar->scan.in_progress = false; + ieee80211_scan_completed(ar->hw, true); + } + spin_unlock_bh(&ar->data_lock); + ar->state = ATH10K_STATE_OFF; mutex_unlock(&ar->conf_mutex); -- cgit v1.2.3 From 818bdd16b229919cfd07447d261154a1343871e1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:57 +0200 Subject: ath10k: defer hw setup to start/stop mac80211 hooks This fixes suspend-to-disk. The hardware is now re-initialized upon freeze/thaw properly. This also makes suspend/resume re-initialize the hardware as WoWLAN support is not done yet. With some little work it should be possible to support hw reconfiguration for hw/fw recovery. HW must be initialized once before registering to mac80211 because FW determinates what hw capabilities can be advertised. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 46 ++++++++++++++++++++++------ drivers/net/wireless/ath/ath10k/mac.c | 56 ++++++++++++++++++++++++++-------- drivers/net/wireless/ath/ath10k/pci.c | 11 +------ 3 files changed, 81 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 0e4a704516f7..1d4c24583f1d 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -601,6 +601,7 @@ err_wmi_detach: err: return status; } +EXPORT_SYMBOL(ath10k_core_start); void ath10k_core_stop(struct ath10k *ar) { @@ -608,18 +609,49 @@ void ath10k_core_stop(struct ath10k *ar) ath10k_htt_detach(&ar->htt); ath10k_wmi_detach(ar); } +EXPORT_SYMBOL(ath10k_core_stop); + +/* mac80211 manages fw/hw initialization through start/stop hooks. However in + * order to know what hw capabilities should be advertised to mac80211 it is + * necessary to load the firmware (and tear it down immediately since start + * hook will try to init it again) before registering */ +static int ath10k_core_probe_fw(struct ath10k *ar) +{ + int ret; + + ret = ath10k_hif_power_up(ar); + if (ret) { + ath10k_err("could not start pci hif (%d)\n", ret); + return ret; + } + + ret = ath10k_core_start(ar); + if (ret) { + ath10k_err("could not init core (%d)\n", ret); + ath10k_hif_power_down(ar); + return ret; + } + + ath10k_core_stop(ar); + ath10k_hif_power_down(ar); + return 0; +} int ath10k_core_register(struct ath10k *ar) { int status; - status = ath10k_core_start(ar); - if (status) - goto err; + status = ath10k_core_probe_fw(ar); + if (status) { + ath10k_err("could not probe fw (%d)\n", status); + return status; + } status = ath10k_mac_register(ar); - if (status) - goto err_core_stop; + if (status) { + ath10k_err("could not register to mac80211 (%d)\n", status); + return status; + } status = ath10k_debug_create(ar); if (status) { @@ -631,9 +663,6 @@ int ath10k_core_register(struct ath10k *ar) err_unregister_mac: ath10k_mac_unregister(ar); -err_core_stop: - ath10k_core_stop(ar); -err: return status; } EXPORT_SYMBOL(ath10k_core_register); @@ -644,7 +673,6 @@ void ath10k_core_unregister(struct ath10k *ar) * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); - ath10k_core_stop(ar); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b9663e94dba5..2dfd446251b1 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1738,13 +1738,52 @@ static void ath10k_tx(struct ieee80211_hw *hw, /* * Initialize various parameters with default vaules. */ +static void ath10k_halt(struct ath10k *ar) +{ + lockdep_assert_held(&ar->conf_mutex); + + del_timer_sync(&ar->scan.timeout); + ath10k_offchan_tx_purge(ar); + ath10k_peer_cleanup_all(ar); + ath10k_core_stop(ar); + ath10k_hif_power_down(ar); + + spin_lock_bh(&ar->data_lock); + if (ar->scan.in_progress) { + del_timer(&ar->scan.timeout); + ar->scan.in_progress = false; + ieee80211_scan_completed(ar->hw, true); + } + spin_unlock_bh(&ar->data_lock); +} + static int ath10k_start(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; - int ret; + int ret = 0; mutex_lock(&ar->conf_mutex); + if (ar->state != ATH10K_STATE_OFF) { + ret = -EINVAL; + goto exit; + } + + ret = ath10k_hif_power_up(ar); + if (ret) { + ath10k_err("could not init hif (%d)\n", ret); + ar->state = ATH10K_STATE_OFF; + goto exit; + } + + ret = ath10k_core_start(ar); + if (ret) { + ath10k_err("could not init core (%d)\n", ret); + ath10k_hif_power_down(ar); + ar->state = ATH10K_STATE_OFF; + goto exit; + } + ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1); if (ret) ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", @@ -1755,9 +1794,9 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ret); - ar->state = ATH10K_STATE_ON; ath10k_regd_update(ar); +exit: mutex_unlock(&ar->conf_mutex); return 0; } @@ -1767,17 +1806,8 @@ static void ath10k_stop(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); - del_timer_sync(&ar->scan.timeout); - ath10k_offchan_tx_purge(ar); - ath10k_peer_cleanup_all(ar); - - spin_lock_bh(&ar->data_lock); - if (ar->scan.in_progress) { - del_timer(&ar->scan.timeout); - ar->scan.in_progress = false; - ieee80211_scan_completed(ar->hw, true); - } - spin_unlock_bh(&ar->data_lock); + if (ar->state == ATH10K_STATE_ON) + ath10k_halt(ar); ar->state = ATH10K_STATE_OFF; mutex_unlock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 75f5427bb416..bfe856166bb0 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2362,22 +2362,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_iomap; } - ret = ath10k_pci_hif_power_up(ar); - if (ret) { - ath10k_err("could not start pci hif (%d)\n", ret); - goto err_intr; - } - ret = ath10k_core_register(ar); if (ret) { ath10k_err("could not register driver core (%d)\n", ret); - goto err_hif; + goto err_intr; } return 0; -err_hif: - ath10k_pci_hif_power_down(ar); err_intr: ath10k_pci_stop_intr(ar); err_iomap: @@ -2416,7 +2408,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev) tasklet_kill(&ar_pci->msi_fw_err); ath10k_core_unregister(ar); - ath10k_pci_hif_power_down(ar); ath10k_pci_stop_intr(ar); pci_set_drvdata(pdev, NULL); -- cgit v1.2.3 From 293850575d0cba068913bcb22fc082286650516c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:58 +0200 Subject: ath10k: store firmware files in memory Different FW versions may provide different functions thus mean different hw capabilities advertised to mac80211. It is safe to swap firmware files on disk during driver/device runtime without worries. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 157 ++++++++++++++++++++++----------- drivers/net/wireless/ath/ath10k/core.h | 4 + 2 files changed, 109 insertions(+), 52 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 1d4c24583f1d..c37f79f6f8ce 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -247,19 +247,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, static int ath10k_download_board_data(struct ath10k *ar) { + const struct firmware *fw = ar->board_data; u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 address; - const struct firmware *fw; int ret; - fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.board); - if (IS_ERR(fw)) { - ath10k_err("could not fetch board data fw file (%ld)\n", - PTR_ERR(fw)); - return PTR_ERR(fw); - } - ret = ath10k_push_board_ext_data(ar, fw); if (ret) { ath10k_err("could not push board ext data (%d)\n", ret); @@ -286,32 +278,20 @@ static int ath10k_download_board_data(struct ath10k *ar) } exit: - release_firmware(fw); return ret; } static int ath10k_download_and_run_otp(struct ath10k *ar) { - const struct firmware *fw; - u32 address; + const struct firmware *fw = ar->otp; + u32 address = ar->hw_params.patch_load_addr; u32 exec_param; int ret; /* OTP is optional */ - if (ar->hw_params.fw.otp == NULL) { - ath10k_info("otp file not defined\n"); - return 0; - } - - address = ar->hw_params.patch_load_addr; - - fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.otp); - if (IS_ERR(fw)) { - ath10k_warn("could not fetch otp (%ld)\n", PTR_ERR(fw)); + if (!ar->otp) return 0; - } ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { @@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) } exit: - release_firmware(fw); return ret; } static int ath10k_download_fw(struct ath10k *ar) { - const struct firmware *fw; + const struct firmware *fw = ar->firmware; u32 address; int ret; - if (ar->hw_params.fw.fw == NULL) - return -EINVAL; - address = ar->hw_params.patch_load_addr; - fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.fw); - if (IS_ERR(fw)) { - ath10k_err("could not fetch fw (%ld)\n", PTR_ERR(fw)); - return PTR_ERR(fw); - } - ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { ath10k_err("could not write fw (%d)\n", ret); @@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar) } exit: - release_firmware(fw); + return ret; +} + +static void ath10k_core_free_firmware_files(struct ath10k *ar) +{ + if (ar->board_data && !IS_ERR(ar->board_data)) + release_firmware(ar->board_data); + + if (ar->otp && !IS_ERR(ar->otp)) + release_firmware(ar->otp); + + if (ar->firmware && !IS_ERR(ar->firmware)) + release_firmware(ar->firmware); + + ar->board_data = NULL; + ar->otp = NULL; + ar->firmware = NULL; +} + +static int ath10k_core_fetch_firmware_files(struct ath10k *ar) +{ + int ret = 0; + + if (ar->hw_params.fw.fw == NULL) { + ath10k_err("firmware file not defined\n"); + return -EINVAL; + } + + if (ar->hw_params.fw.board == NULL) { + ath10k_err("board data file not defined"); + return -EINVAL; + } + + ar->board_data = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.board); + if (IS_ERR(ar->board_data)) { + ret = PTR_ERR(ar->board_data); + ath10k_err("could not fetch board data (%d)\n", ret); + goto err; + } + + ar->firmware = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.fw); + if (IS_ERR(ar->firmware)) { + ret = PTR_ERR(ar->firmware); + ath10k_err("could not fetch firmware (%d)\n", ret); + goto err; + } + + /* OTP may be undefined. If so, don't fetch it at all */ + if (ar->hw_params.fw.otp == NULL) + return 0; + + ar->otp = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.otp); + if (IS_ERR(ar->otp)) { + ret = PTR_ERR(ar->otp); + ath10k_err("could not fetch otp (%d)\n", ret); + goto err; + } + + return 0; + +err: + ath10k_core_free_firmware_files(ar); return ret; } @@ -502,23 +538,10 @@ EXPORT_SYMBOL(ath10k_core_destroy); int ath10k_core_start(struct ath10k *ar) { - struct bmi_target_info target_info; int status; ath10k_bmi_start(ar); - memset(&target_info, 0, sizeof(target_info)); - status = ath10k_bmi_get_target_info(ar, &target_info); - if (status) - goto err; - - ar->target_version = target_info.version; - ar->hw->wiphy->hw_version = target_info.version; - - status = ath10k_init_hw_params(ar); - if (status) - goto err; - if (ath10k_init_configure_target(ar)) { status = -EINVAL; goto err; @@ -617,7 +640,8 @@ EXPORT_SYMBOL(ath10k_core_stop); * hook will try to init it again) before registering */ static int ath10k_core_probe_fw(struct ath10k *ar) { - int ret; + struct bmi_target_info target_info; + int ret = 0; ret = ath10k_hif_power_up(ar); if (ret) { @@ -625,9 +649,35 @@ static int ath10k_core_probe_fw(struct ath10k *ar) return ret; } + memset(&target_info, 0, sizeof(target_info)); + ret = ath10k_bmi_get_target_info(ar, &target_info); + if (ret) { + ath10k_err("could not get target info (%d)\n", ret); + ath10k_hif_power_down(ar); + return ret; + } + + ar->target_version = target_info.version; + ar->hw->wiphy->hw_version = target_info.version; + + ret = ath10k_init_hw_params(ar); + if (ret) { + ath10k_err("could not get hw params (%d)\n", ret); + ath10k_hif_power_down(ar); + return ret; + } + + ret = ath10k_core_fetch_firmware_files(ar); + if (ret) { + ath10k_err("could not fetch firmware files (%d)\n", ret); + ath10k_hif_power_down(ar); + return ret; + } + ret = ath10k_core_start(ar); if (ret) { ath10k_err("could not init core (%d)\n", ret); + ath10k_core_free_firmware_files(ar); ath10k_hif_power_down(ar); return ret; } @@ -650,7 +700,7 @@ int ath10k_core_register(struct ath10k *ar) status = ath10k_mac_register(ar); if (status) { ath10k_err("could not register to mac80211 (%d)\n", status); - return status; + goto err_release_fw; } status = ath10k_debug_create(ar); @@ -663,6 +713,8 @@ int ath10k_core_register(struct ath10k *ar) err_unregister_mac: ath10k_mac_unregister(ar); +err_release_fw: + ath10k_core_free_firmware_files(ar); return status; } EXPORT_SYMBOL(ath10k_core_register); @@ -673,6 +725,7 @@ void ath10k_core_unregister(struct ath10k *ar) * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); + ath10k_core_free_firmware_files(ar); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5c94ea06eb71..413f1c5a8119 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -300,6 +300,10 @@ struct ath10k { } fw; } hw_params; + const struct firmware *board_data; + const struct firmware *otp; + const struct firmware *firmware; + struct { struct completion started; struct completion completed; -- cgit v1.2.3 From 87571bf0b8b27d4a97848ce48de34fa6d3b12db8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:38:59 +0200 Subject: ath10k: skip fw stats debugfs interface if device is down If the device is not running then there may be no FW at all to send the query to. If the FW is already there it might still trigger a crash if the command is sent before the device is fully initialized. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 499034b873d1..65279f5347c8 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, struct wmi_pdev_stats *ps; int i; - mutex_lock(&ar->conf_mutex); + spin_lock_bh(&ar->data_lock); stats = &ar->debug.target_stats; @@ -259,6 +259,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, } } + spin_unlock_bh(&ar->data_lock); mutex_unlock(&ar->conf_mutex); complete(&ar->debug.event_stats_compl); } @@ -268,35 +269,35 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, { struct ath10k *ar = file->private_data; struct ath10k_target_stats *fw_stats; - char *buf; + char *buf = NULL; unsigned int len = 0, buf_len = 2500; - ssize_t ret_cnt; + ssize_t ret_cnt = 0; long left; int i; int ret; fw_stats = &ar->debug.target_stats; + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON) + goto exit; + buf = kzalloc(buf_len, GFP_KERNEL); if (!buf) - return -ENOMEM; + goto exit; ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); if (ret) { ath10k_warn("could not request stats (%d)\n", ret); - kfree(buf); - return -EIO; + goto exit; } left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ); + if (left <= 0) + goto exit; - if (left <= 0) { - kfree(buf); - return -ETIMEDOUT; - } - - mutex_lock(&ar->conf_mutex); - + spin_lock_bh(&ar->data_lock); len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s\n", "ath10k PDEV stats"); @@ -424,14 +425,15 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, fw_stats->peer_stat[i].peer_tx_rate); len += scnprintf(buf + len, buf_len - len, "\n"); } + spin_unlock_bh(&ar->data_lock); if (len > buf_len) len = buf_len; ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); +exit: mutex_unlock(&ar->conf_mutex); - kfree(buf); return ret_cnt; } -- cgit v1.2.3 From affd321733eebc92b12cd329505f63e94ae80c93 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:54:35 +0200 Subject: ath10k: implement device recovery Restart the hardware if FW crashes. If FW crashes during recovery we leave the hardware in a "wedged" state to avoid recursive recoveries. When in "wedged" state userspace may bring interfaces down (to issue stop()) and then bring one interface (to issue start()) to reload hardware manually. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 30 ++++++++++ drivers/net/wireless/ath/ath10k/core.h | 19 +++++++ drivers/net/wireless/ath/ath10k/htc.c | 3 + drivers/net/wireless/ath/ath10k/mac.c | 101 ++++++++++++++++++++++++++------- drivers/net/wireless/ath/ath10k/mac.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 2 + drivers/net/wireless/ath/ath10k/wmi.c | 7 +++ 7 files changed, 144 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c37f79f6f8ce..7226c23b9569 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -476,6 +476,34 @@ static int ath10k_init_hw_params(struct ath10k *ar) return 0; } +static void ath10k_core_restart(struct work_struct *work) +{ + struct ath10k *ar = container_of(work, struct ath10k, restart_work); + + mutex_lock(&ar->conf_mutex); + + switch (ar->state) { + case ATH10K_STATE_ON: + ath10k_halt(ar); + ar->state = ATH10K_STATE_RESTARTING; + ieee80211_restart_hw(ar->hw); + break; + case ATH10K_STATE_OFF: + /* this can happen if driver is being unloaded */ + ath10k_warn("cannot restart a device that hasn't been started\n"); + break; + case ATH10K_STATE_RESTARTING: + case ATH10K_STATE_RESTARTED: + ar->state = ATH10K_STATE_WEDGED; + /* fall through */ + case ATH10K_STATE_WEDGED: + ath10k_warn("device is wedged, will not restart\n"); + break; + } + + mutex_unlock(&ar->conf_mutex); +} + struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, const struct ath10k_hif_ops *hif_ops) { @@ -519,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, init_waitqueue_head(&ar->event_queue); + INIT_WORK(&ar->restart_work, ath10k_core_restart); + return ar; err_wq: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 413f1c5a8119..9f21ecb239d7 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -250,6 +250,23 @@ struct ath10k_debug { enum ath10k_state { ATH10K_STATE_OFF = 0, ATH10K_STATE_ON, + + /* When doing firmware recovery the device is first powered down. + * mac80211 is supposed to call in to start() hook later on. It is + * however possible that driver unloading and firmware crash overlap. + * mac80211 can wait on conf_mutex in stop() while the device is + * stopped in ath10k_core_restart() work holding conf_mutex. The state + * RESTARTED means that the device is up and mac80211 has started hw + * reconfiguration. Once mac80211 is done with the reconfiguration we + * set the state to STATE_ON in restart_complete(). */ + ATH10K_STATE_RESTARTING, + ATH10K_STATE_RESTARTED, + + /* The device has crashed while restarting hw. This state is like ON + * but commands are blocked in HTC and -ECOMM response is given. This + * prevents completion timeouts and makes the driver more responsive to + * userspace commands. This is also prevents recursive recovery. */ + ATH10K_STATE_WEDGED, }; struct ath10k { @@ -355,6 +372,8 @@ struct ath10k { enum ath10k_state state; + struct work_struct restart_work; + #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 7d5a36616b71..72e072c97588 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -246,6 +246,9 @@ int ath10k_htc_send(struct ath10k_htc *htc, { struct ath10k_htc_ep *ep = &htc->endpoint[eid]; + if (htc->ar->state == ATH10K_STATE_WEDGED) + return -ECOMM; + if (eid >= ATH10K_HTC_EP_COUNT) { ath10k_warn("Invalid endpoint id: %d\n", eid); return -ENOENT; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2dfd446251b1..b1bb318d153f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1738,7 +1738,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, /* * Initialize various parameters with default vaules. */ -static void ath10k_halt(struct ath10k *ar) +void ath10k_halt(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); @@ -1764,7 +1764,8 @@ static int ath10k_start(struct ieee80211_hw *hw) mutex_lock(&ar->conf_mutex); - if (ar->state != ATH10K_STATE_OFF) { + if (ar->state != ATH10K_STATE_OFF && + ar->state != ATH10K_STATE_RESTARTING) { ret = -EINVAL; goto exit; } @@ -1784,6 +1785,11 @@ static int ath10k_start(struct ieee80211_hw *hw) goto exit; } + if (ar->state == ATH10K_STATE_OFF) + ar->state = ATH10K_STATE_ON; + else if (ar->state == ATH10K_STATE_RESTARTING) + ar->state = ATH10K_STATE_RESTARTED; + ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1); if (ret) ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", @@ -1806,22 +1812,47 @@ static void ath10k_stop(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); - if (ar->state == ATH10K_STATE_ON) + if (ar->state == ATH10K_STATE_ON || + ar->state == ATH10K_STATE_RESTARTED || + ar->state == ATH10K_STATE_WEDGED) ath10k_halt(ar); ar->state = ATH10K_STATE_OFF; mutex_unlock(&ar->conf_mutex); cancel_work_sync(&ar->offchan_tx_work); + cancel_work_sync(&ar->restart_work); } -static int ath10k_config(struct ieee80211_hw *hw, u32 changed) +static void ath10k_config_ps(struct ath10k *ar) { struct ath10k_generic_iter ar_iter; + + lockdep_assert_held(&ar->conf_mutex); + + /* During HW reconfiguration mac80211 reports all interfaces that were + * running until reconfiguration was started. Since FW doesn't have any + * vdevs at this point we must not iterate over this interface list. + * This setting will be updated upon add_interface(). */ + if (ar->state == ATH10K_STATE_RESTARTED) + return; + + memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); + ar_iter.ar = ar; + + ieee80211_iterate_active_interfaces_atomic( + ar->hw, IEEE80211_IFACE_ITER_NORMAL, + ath10k_ps_iter, &ar_iter); + + if (ar_iter.ret) + ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret); +} + +static int ath10k_config(struct ieee80211_hw *hw, u32 changed) +{ struct ath10k *ar = hw->priv; struct ieee80211_conf *conf = &hw->conf; int ret = 0; - u32 flags; mutex_lock(&ar->conf_mutex); @@ -1833,18 +1864,8 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&ar->data_lock); } - if (changed & IEEE80211_CONF_CHANGE_PS) { - memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); - ar_iter.ar = ar; - flags = IEEE80211_IFACE_ITER_RESUME_ALL; - - ieee80211_iterate_active_interfaces_atomic(hw, - flags, - ath10k_ps_iter, - &ar_iter); - - ret = ar_iter.ret; - } + if (changed & IEEE80211_CONF_CHANGE_PS) + ath10k_config_ps(ar); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (conf->flags & IEEE80211_CONF_MONITOR) @@ -1853,6 +1874,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ret = ath10k_monitor_destroy(ar); } + ath10k_wmi_flush_tx(ar); mutex_unlock(&ar->conf_mutex); return ret; } @@ -2695,6 +2717,13 @@ static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif) lockdep_assert_held(&arvif->ar->conf_mutex); + /* During HW reconfiguration mac80211 reports all interfaces that were + * running until reconfiguration was started. Since FW doesn't have any + * vdevs at this point we must not iterate over this interface list. + * This setting will be updated upon add_interface(). */ + if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) + return; + rts = min_t(u32, rts, ATH10K_RTS_MAX); ar_iter->ret = ath10k_wmi_vdev_set_param(ar_iter->ar, arvif->vdev_id, @@ -2735,6 +2764,13 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif) lockdep_assert_held(&arvif->ar->conf_mutex); + /* During HW reconfiguration mac80211 reports all interfaces that were + * running until reconfiguration was started. Since FW doesn't have any + * vdevs at this point we must not iterate over this interface list. + * This setting will be updated upon add_interface(). */ + if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) + return; + frag = clamp_t(u32, frag, ATH10K_FRAGMT_THRESHOLD_MIN, ATH10K_FRAGMT_THRESHOLD_MAX); @@ -2773,6 +2809,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) { struct ath10k *ar = hw->priv; + bool skip; int ret; /* mac80211 doesn't care if we really xmit queued frames or not @@ -2782,17 +2819,26 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) mutex_lock(&ar->conf_mutex); + if (ar->state == ATH10K_STATE_WEDGED) + goto skip; + ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ bool empty; + spin_lock_bh(&ar->htt.tx_lock); empty = bitmap_empty(ar->htt.used_msdu_ids, ar->htt.max_num_pending_tx); spin_unlock_bh(&ar->htt.tx_lock); - (empty); + + skip = (ar->state == ATH10K_STATE_WEDGED); + + (empty || skip); }), ATH10K_FLUSH_TIMEOUT_HZ); - if (ret <= 0) + + if (ret <= 0 || skip) ath10k_warn("tx not flushed\n"); +skip: mutex_unlock(&ar->conf_mutex); } @@ -2866,6 +2912,22 @@ static int ath10k_resume(struct ieee80211_hw *hw) } #endif +static void ath10k_restart_complete(struct ieee80211_hw *hw) +{ + struct ath10k *ar = hw->priv; + + mutex_lock(&ar->conf_mutex); + + /* If device failed to restart it will be in a different state, e.g. + * ATH10K_STATE_WEDGED */ + if (ar->state == ATH10K_STATE_RESTARTED) { + ath10k_info("device successfully recovered\n"); + ar->state = ATH10K_STATE_ON; + } + + mutex_unlock(&ar->conf_mutex); +} + static const struct ieee80211_ops ath10k_ops = { .tx = ath10k_tx, .start = ath10k_start, @@ -2886,6 +2948,7 @@ static const struct ieee80211_ops ath10k_ops = { .set_frag_threshold = ath10k_set_frag_threshold, .flush = ath10k_flush, .tx_last_beacon = ath10k_tx_last_beacon, + .restart_complete = ath10k_restart_complete, #ifdef CONFIG_PM .suspend = ath10k_suspend, .resume = ath10k_resume, diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 27fc92e58829..6fce9bfb19a5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -34,6 +34,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id); void ath10k_reset_scan(unsigned long ptr); void ath10k_offchan_tx_purge(struct ath10k *ar); void ath10k_offchan_tx_work(struct work_struct *work); +void ath10k_halt(struct ath10k *ar); static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index bfe856166bb0..c71b488eba9f 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -720,6 +720,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) reg_dump_values[i + 1], reg_dump_values[i + 2], reg_dump_values[i + 3]); + + ieee80211_queue_work(ar->hw, &ar->restart_work); } static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b7e7e456b5de..0d25cd733afd 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -27,6 +27,13 @@ void ath10k_wmi_flush_tx(struct ath10k *ar) { int ret; + lockdep_assert_held(&ar->conf_mutex); + + if (ar->state == ATH10K_STATE_WEDGED) { + ath10k_warn("wmi flush skipped - device is wedged anyway\n"); + return; + } + ret = wait_event_timeout(ar->wmi.wq, atomic_read(&ar->wmi.pending_tx_count) == 0, 5*HZ); -- cgit v1.2.3 From 9cfbce75c806e151b11a5d2c04b3aea3e920b3c1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 09:54:36 +0200 Subject: ath10k: implement fw crash simulation command This can be useful to test FW crash handling. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 19 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0d25cd733afd..5e4246015cdc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2092,3 +2092,22 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); return ath10k_wmi_cmd_send(ar, skb, WMI_REQUEST_STATS_CMDID); } + +int ath10k_wmi_force_fw_hang(struct ath10k *ar, + enum wmi_force_fw_hang_type type, u32 delay_ms) +{ + struct wmi_force_fw_hang_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_force_fw_hang_cmd *)skb->data; + cmd->type = __cpu_to_le32(type); + cmd->delay_ms = __cpu_to_le32(delay_ms); + + ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n", + type, delay_ms); + return ath10k_wmi_cmd_send(ar, skb, WMI_FORCE_FW_HANG_CMDID); +} diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9555f5a0e041..da3b2bc4c88a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -416,6 +416,7 @@ enum wmi_cmd_id { WMI_PDEV_FTM_INTG_CMDID, WMI_VDEV_SET_KEEPALIVE_CMDID, WMI_VDEV_GET_KEEPALIVE_CMDID, + WMI_FORCE_FW_HANG_CMDID, /* GPIO Configuration */ WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP(WMI_GRP_GPIO), @@ -2972,6 +2973,22 @@ struct wmi_sta_keepalive_cmd { struct wmi_sta_keepalive_arp_resp arp_resp; } __packed; +enum wmi_force_fw_hang_type { + WMI_FORCE_FW_HANG_ASSERT = 1, + WMI_FORCE_FW_HANG_NO_DETECT, + WMI_FORCE_FW_HANG_CTRL_EP_FULL, + WMI_FORCE_FW_HANG_EMPTY_POINT, + WMI_FORCE_FW_HANG_STACK_OVERFLOW, + WMI_FORCE_FW_HANG_INFINITE_LOOP, +}; + +#define WMI_FORCE_FW_HANG_RANDOM_TIME 0xFFFFFFFF + +struct wmi_force_fw_hang_cmd { + __le32 type; + __le32 delay_ms; +} __packed; + #define ATH10K_RTS_MAX 2347 #define ATH10K_FRAGMT_THRESHOLD_MIN 540 #define ATH10K_FRAGMT_THRESHOLD_MAX 2346 @@ -3048,5 +3065,7 @@ int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg); int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, const struct wmi_pdev_set_wmm_params_arg *arg); int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); +int ath10k_wmi_force_fw_hang(struct ath10k *ar, + enum wmi_force_fw_hang_type type, u32 delay_ms); #endif /* _WMI_H_ */ -- cgit v1.2.3 From cf84bd4defe22c7359bd3e4d6978bd88af1f8f90 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 16 Jul 2013 11:04:54 +0200 Subject: ath10k: fix NULL dereference for injected packets Tx processing functions dereference vif and caused NULL to be dereferenced for injected frames. Don't call these functions at all for injected frames. It doesn't make much sense to do so anyway. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b1bb318d153f..07e5f7d40466 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1710,10 +1710,14 @@ static void ath10k_tx(struct ieee80211_hw *hw, tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; } - ath10k_tx_h_qos_workaround(hw, control, skb); - ath10k_tx_h_update_wep_key(skb); - ath10k_tx_h_add_p2p_noa_ie(ar, skb); - ath10k_tx_h_seq_no(skb); + /* it makes no sense to process injected frames like that */ + if (info->control.vif && + info->control.vif->type != NL80211_IFTYPE_MONITOR) { + ath10k_tx_h_qos_workaround(hw, control, skb); + ath10k_tx_h_update_wep_key(skb); + ath10k_tx_h_add_p2p_noa_ie(ar, skb); + ath10k_tx_h_seq_no(skb); + } memset(ATH10K_SKB_CB(skb), 0, sizeof(*ATH10K_SKB_CB(skb))); ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id; -- cgit v1.2.3 From 278c4a85e6267979ab164c0a8b57447005cf388c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 22 Jul 2013 14:08:51 +0200 Subject: ath10k: create debugfs interface to trigger fw crash This can be useful for testing. To perform a forced firmware crash write 'crash' to 'simulate_fw_crash' debugfs file. E.g. echo crash > /sys/kernel/debug/ieee80211/phy1/ath10k/simulate_fw_crash Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 65279f5347c8..3d65594fa098 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -445,6 +445,60 @@ static const struct file_operations fops_fw_stats = { .llseek = default_llseek, }; +static ssize_t ath10k_read_simulate_fw_crash(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + const char buf[] = "To simulate firmware crash write the keyword" + " `crash` to this file.\nThis will force firmware" + " to report a crash to the host system.\n"; + return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); +} + +static ssize_t ath10k_write_simulate_fw_crash(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + char buf[32] = {}; + int ret; + + mutex_lock(&ar->conf_mutex); + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) { + ret = -EINVAL; + goto exit; + } + + if (ar->state != ATH10K_STATE_ON && + ar->state != ATH10K_STATE_RESTARTED) { + ret = -ENETDOWN; + goto exit; + } + + ath10k_info("simulating firmware crash\n"); + + ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); + if (ret) + ath10k_warn("failed to force fw hang (%d)\n", ret); + + if (ret == 0) + ret = count; + +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_simulate_fw_crash = { + .read = ath10k_read_simulate_fw_crash, + .write = ath10k_write_simulate_fw_crash, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath10k_debug_create(struct ath10k *ar) { ar->debug.debugfs_phy = debugfs_create_dir("ath10k", @@ -461,6 +515,9 @@ int ath10k_debug_create(struct ath10k *ar) debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_wmi_services); + debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy, + ar, &fops_simulate_fw_crash); + return 0; } #endif /* CONFIG_ATH10K_DEBUGFS */ -- cgit v1.2.3 From 08fe9b40d055d4ace995a5e1e93c7c17573f17a5 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 22 Jul 2013 14:13:28 +0200 Subject: ath10k: prevent HTC from being used after stopping It was possible to submit new HTC commands after/while HTC stopped. This led to memory corruption in some rare cases. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 27 +++++++++++++-------------- drivers/net/wireless/ath/ath10k/htc.h | 4 ++-- 2 files changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 72e072c97588..47b7752656f7 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -254,10 +254,14 @@ int ath10k_htc_send(struct ath10k_htc *htc, return -ENOENT; } - skb_push(skb, sizeof(struct ath10k_htc_hdr)); - spin_lock_bh(&htc->tx_lock); + if (htc->stopped) { + spin_unlock_bh(&htc->tx_lock); + return -ESHUTDOWN; + } + __skb_queue_tail(&ep->tx_queue, skb); + skb_push(skb, sizeof(struct ath10k_htc_hdr)); spin_unlock_bh(&htc->tx_lock); queue_work(htc->ar->workqueue, &ep->send_work); @@ -270,23 +274,17 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar, { struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_ep *ep = &htc->endpoint[eid]; - bool stopping; ath10k_htc_notify_tx_completion(ep, skb); /* the skb now belongs to the completion handler */ + /* note: when using TX credit flow, the re-checking of queues happens + * when credits flow back from the target. in the non-TX credit case, + * we recheck after the packet completes */ spin_lock_bh(&htc->tx_lock); - stopping = htc->stopping; - spin_unlock_bh(&htc->tx_lock); - - if (!ep->tx_credit_flow_enabled && !stopping) - /* - * note: when using TX credit flow, the re-checking of - * queues happens when credits flow back from the target. - * in the non-TX credit case, we recheck after the packet - * completes - */ + if (!ep->tx_credit_flow_enabled && !htc->stopped) queue_work(ar->workqueue, &ep->send_work); + spin_unlock_bh(&htc->tx_lock); return 0; } @@ -951,7 +949,7 @@ void ath10k_htc_stop(struct ath10k_htc *htc) struct ath10k_htc_ep *ep; spin_lock_bh(&htc->tx_lock); - htc->stopping = true; + htc->stopped = true; spin_unlock_bh(&htc->tx_lock); for (i = ATH10K_HTC_EP_0; i < ATH10K_HTC_EP_COUNT; i++) { @@ -972,6 +970,7 @@ int ath10k_htc_init(struct ath10k *ar) spin_lock_init(&htc->tx_lock); + htc->stopped = false; ath10k_htc_reset_endpoint_states(htc); /* setup HIF layer callbacks */ diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 1606c9f9dff3..e1dd8c761853 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -335,7 +335,7 @@ struct ath10k_htc { struct ath10k *ar; struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT]; - /* protects endpoint and stopping fields */ + /* protects endpoint and stopped fields */ spinlock_t tx_lock; struct ath10k_htc_ops htc_ops; @@ -349,7 +349,7 @@ struct ath10k_htc { struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT]; int target_credit_size; - bool stopping; + bool stopped; }; int ath10k_htc_init(struct ath10k *ar); -- cgit v1.2.3 From 21bf9112b596cb91e4f63de859ea514f081031fd Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 22 Jul 2013 14:13:29 +0200 Subject: ath10k: don't reset HTC endpoints unnecessarily Endpoints are re-initialized upon HTC start anyway so there's no need to do that twice in case of restarting HTC (i.e. in case of hardware recovery). Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 47b7752656f7..ef3329ef52f3 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -958,7 +958,6 @@ void ath10k_htc_stop(struct ath10k_htc *htc) } ath10k_hif_stop(htc->ar); - ath10k_htc_reset_endpoint_states(htc); } /* registered target arrival callback from the HIF layer */ -- cgit v1.2.3 From d6015b27f7dd6e167cd90b590dc9ed5dfbc68086 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 22 Jul 2013 14:13:30 +0200 Subject: ath10k: fix memleak in mac setup In some cases channel arrays were never freed. The patch also unifies error handling in the mac setup function. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 07e5f7d40466..6144b3bf3da5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3225,8 +3225,10 @@ int ath10k_mac_register(struct ath10k *ar) channels = kmemdup(ath10k_2ghz_channels, sizeof(ath10k_2ghz_channels), GFP_KERNEL); - if (!channels) - return -ENOMEM; + if (!channels) { + ret = -ENOMEM; + goto err_free; + } band = &ar->mac.sbands[IEEE80211_BAND_2GHZ]; band->n_channels = ARRAY_SIZE(ath10k_2ghz_channels); @@ -3245,11 +3247,8 @@ int ath10k_mac_register(struct ath10k *ar) sizeof(ath10k_5ghz_channels), GFP_KERNEL); if (!channels) { - if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) { - band = &ar->mac.sbands[IEEE80211_BAND_2GHZ]; - kfree(band->channels); - } - return -ENOMEM; + ret = -ENOMEM; + goto err_free; } band = &ar->mac.sbands[IEEE80211_BAND_5GHZ]; @@ -3313,25 +3312,30 @@ int ath10k_mac_register(struct ath10k *ar) ath10k_reg_notifier); if (ret) { ath10k_err("Regulatory initialization failed\n"); - return ret; + goto err_free; } ret = ieee80211_register_hw(ar->hw); if (ret) { ath10k_err("ieee80211 registration failed: %d\n", ret); - return ret; + goto err_free; } if (!ath_is_world_regd(&ar->ath_common.regulatory)) { ret = regulatory_hint(ar->hw->wiphy, ar->ath_common.regulatory.alpha2); if (ret) - goto exit; + goto err_unregister; } return 0; -exit: + +err_unregister: ieee80211_unregister_hw(ar->hw); +err_free: + kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); + kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); + return ret; } -- cgit v1.2.3 From 424121c365aed6ec93bbc8b515548df79c5af61c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 22 Jul 2013 14:13:31 +0200 Subject: ath10k: fix rts/fragmentation threshold setup If RTS and fragmentation threshold values are 0xFFFFFFFF they should be considered disabled and no min/max limits must be applied. This fixes some issues with throughput issues, especially with VHT. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 54 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 6144b3bf3da5..d0a776124f13 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -332,6 +332,29 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) return 0; } +static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) +{ + if (value != 0xFFFFFFFF) + value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold, + ATH10K_RTS_MAX); + + return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, + WMI_VDEV_PARAM_RTS_THRESHOLD, + value); +} + +static int ath10k_mac_set_frag(struct ath10k_vif *arvif, u32 value) +{ + if (value != 0xFFFFFFFF) + value = clamp_t(u32, arvif->ar->hw->wiphy->frag_threshold, + ATH10K_FRAGMT_THRESHOLD_MIN, + ATH10K_FRAGMT_THRESHOLD_MAX); + + return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + value); +} + static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) { int ret; @@ -1897,7 +1920,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); enum wmi_sta_powersave_param param; int ret = 0; - u32 value, rts, frag; + u32 value; int bit; mutex_lock(&ar->conf_mutex); @@ -2000,20 +2023,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ath10k_warn("Failed to set PSPOLL count: %d\n", ret); } - rts = min_t(u32, ar->hw->wiphy->rts_threshold, ATH10K_RTS_MAX); - ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, - WMI_VDEV_PARAM_RTS_THRESHOLD, - rts); + ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); if (ret) ath10k_warn("failed to set rts threshold for vdev %d (%d)\n", arvif->vdev_id, ret); - frag = clamp_t(u32, ar->hw->wiphy->frag_threshold, - ATH10K_FRAGMT_THRESHOLD_MIN, - ATH10K_FRAGMT_THRESHOLD_MAX); - ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, - WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, - frag); + ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); if (ret) ath10k_warn("failed to set frag threshold for vdev %d (%d)\n", arvif->vdev_id, ret); @@ -2728,11 +2743,7 @@ static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif) if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) return; - rts = min_t(u32, rts, ATH10K_RTS_MAX); - - ar_iter->ret = ath10k_wmi_vdev_set_param(ar_iter->ar, arvif->vdev_id, - WMI_VDEV_PARAM_RTS_THRESHOLD, - rts); + ar_iter->ret = ath10k_mac_set_rts(arvif, rts); if (ar_iter->ret) ath10k_warn("Failed to set RTS threshold for VDEV: %d\n", arvif->vdev_id); @@ -2764,7 +2775,6 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif) struct ath10k_generic_iter *ar_iter = data; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); u32 frag = ar_iter->ar->hw->wiphy->frag_threshold; - int ret; lockdep_assert_held(&arvif->ar->conf_mutex); @@ -2775,15 +2785,7 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif) if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) return; - frag = clamp_t(u32, frag, - ATH10K_FRAGMT_THRESHOLD_MIN, - ATH10K_FRAGMT_THRESHOLD_MAX); - - ret = ath10k_wmi_vdev_set_param(ar_iter->ar, arvif->vdev_id, - WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, - frag); - - ar_iter->ret = ret; + ar_iter->ret = ath10k_mac_set_frag(arvif, frag); if (ar_iter->ret) ath10k_warn("Failed to set frag threshold for VDEV: %d\n", arvif->vdev_id); -- cgit v1.2.3 From ba0ccd7affd777cb90ad7279de4143663ae4d485 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 22 Jul 2013 14:25:28 +0200 Subject: ath10k: improve tx throughput on slow machines It is more efficient to move just the 802.11 header instead of the whole payload in most cases. This has no measurable effect on modern hardware. It should improve performance by a few percent on hardware such as an Access Point that have a slow CPU compared to a typical desktop CPU. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index d0a776124f13..6e01ef6e376b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1406,9 +1406,9 @@ static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw, return; qos_ctl = ieee80211_get_qos_ctl(hdr); - memmove(qos_ctl, qos_ctl + IEEE80211_QOS_CTL_LEN, - skb->len - ieee80211_hdrlen(hdr->frame_control)); - skb_trim(skb, skb->len - IEEE80211_QOS_CTL_LEN); + memmove(skb->data + IEEE80211_QOS_CTL_LEN, + skb->data, (void *)qos_ctl - (void *)skb->data); + skb_pull(skb, IEEE80211_QOS_CTL_LEN); } static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) -- cgit v1.2.3 From 8865bee4835441d9b3220d779d254d5856a68af0 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 24 Jul 2013 12:36:46 +0200 Subject: ath10k: detect the number of spatial streams supported by hw Until now ath10k assumed 3 spatial streams. However some devices support only 2 spatial streams. This patch improves performance on devices that don't support 3 spatial streams. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 19 +++++++++---------- drivers/net/wireless/ath/ath10k/wmi.c | 12 ++++++++++-- 3 files changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 9f21ecb239d7..ff42bb744d9e 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -285,6 +285,7 @@ struct ath10k { u32 hw_max_tx_power; u32 ht_cap_info; u32 vht_cap_info; + u32 num_rf_chains; struct targetdef *targetdef; struct hostdef *hostdef; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 6e01ef6e376b..344ad2772de8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3093,19 +3093,18 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) { struct ieee80211_sta_vht_cap vht_cap = {0}; u16 mcs_map; + int i; vht_cap.vht_supported = 1; vht_cap.cap = ar->vht_cap_info; - /* FIXME: check dynamically how many streams board supports */ - mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | - IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | - IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; + mcs_map = 0; + for (i = 0; i < 8; i++) { + if (i < ar->num_rf_chains) + mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i*2); + else + mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2); + } vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); @@ -3168,7 +3167,7 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar) if (ar->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_MASK) ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; - for (i = 0; i < WMI_MAX_SPATIAL_STREAM; i++) + for (i = 0; i < ar->num_rf_chains; i++) ht_cap.mcs.rx_mask[i] = 0xFF; ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 5e4246015cdc..1cbcb2ea12f7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -868,6 +868,13 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16; ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff); ar->phy_capability = __le32_to_cpu(ev->phy_capability); + ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); + + if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { + ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", + ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); + ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; + } ar->ath_common.regulatory.current_rd = __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); @@ -892,7 +899,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, } ath10k_dbg(ATH10K_DBG_WMI, - "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u\n", + "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", __le32_to_cpu(ev->sw_version), __le32_to_cpu(ev->sw_version_1), __le32_to_cpu(ev->abi_version), @@ -901,7 +908,8 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, __le32_to_cpu(ev->vht_cap_info), __le32_to_cpu(ev->vht_supp_mcs), __le32_to_cpu(ev->sys_cap_info), - __le32_to_cpu(ev->num_mem_reqs)); + __le32_to_cpu(ev->num_mem_reqs), + __le32_to_cpu(ev->num_rf_chains)); complete(&ar->wmi.service_ready); } -- cgit v1.2.3 From a2d7b870d0c99abefe7c302a92f62f0a9aced3b3 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Tue, 9 Jul 2013 01:42:17 +0300 Subject: iwlwifi: mvm: new api to get signal strength A new API that replaces the rx signal strength calculation via agc & rssi. The energy is now calculated outside the driver and transferred by the fw. Signed-off-by: Avri Altman Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-fw.h | 14 ++++++----- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 8 ++++++ drivers/net/wireless/iwlwifi/mvm/rx.c | 41 ++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index f26f12689969..46dc38a32115 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -75,14 +75,16 @@ * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD + * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api */ enum iwl_ucode_tlv_flag { - IWL_UCODE_TLV_FLAGS_PAN = BIT(0), - IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), - IWL_UCODE_TLV_FLAGS_MFP = BIT(2), - IWL_UCODE_TLV_FLAGS_P2P = BIT(3), - IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), - IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), + IWL_UCODE_TLV_FLAGS_PAN = BIT(0), + IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), + IWL_UCODE_TLV_FLAGS_MFP = BIT(2), + IWL_UCODE_TLV_FLAGS_P2P = BIT(3), + IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), + IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), + IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), }; /* The default calibrate table size if not specified by firmware file */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 44614f5e4485..28cab821c9f4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -768,6 +768,14 @@ struct iwl_phy_context_cmd { } __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ #define IWL_RX_INFO_PHY_CNT 8 +#define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1 +#define IWL_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff +#define IWL_RX_INFO_ENERGY_ANT_B_MSK 0x0000ff00 +#define IWL_RX_INFO_ENERGY_ANT_C_MSK 0x00ff0000 +#define IWL_RX_INFO_ENERGY_ANT_A_POS 0 +#define IWL_RX_INFO_ENERGY_ANT_B_POS 8 +#define IWL_RX_INFO_ENERGY_ANT_C_POS 16 + #define IWL_RX_INFO_AGC_IDX 1 #define IWL_RX_INFO_RSSI_AB_IDX 2 #define IWL_OFDM_AGC_A_MSK 0x0000007f diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index e4930d5027d2..c8e4af23d04c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -124,10 +124,6 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, ieee80211_rx_ni(mvm->hw, skb); } -/* - * iwl_mvm_calc_rssi - calculate the rssi in dBm - * @phy_info: the phy information for the coming packet - */ static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, struct iwl_rx_phy_info *phy_info) { @@ -136,12 +132,6 @@ static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, u32 agc_a, agc_b, max_agc; u32 val; - /* Find max rssi among 2 possible receivers. - * These values are measured by the Digital Signal Processor (DSP). - * They should stay fairly constant even as the signal strength varies, - * if the radio's Automatic Gain Control (AGC) is working right. - * AGC value (see below) will provide the "interesting" info. - */ val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; @@ -169,6 +159,32 @@ static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, return max_rssi_dbm; } +/* + * iwl_mvm_get_signal_strength - use new rx PHY INFO API + */ +static int iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, + struct iwl_rx_phy_info *phy_info) +{ + int energy_a, energy_b, energy_c, max_energy; + u32 val; + + val = + le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_ENERGY_ANT_ABC_IDX]); + energy_a = -((val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >> + IWL_RX_INFO_ENERGY_ANT_A_POS); + energy_b = -((val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >> + IWL_RX_INFO_ENERGY_ANT_B_POS); + energy_c = -((val & IWL_RX_INFO_ENERGY_ANT_C_MSK) >> + IWL_RX_INFO_ENERGY_ANT_C_POS); + max_energy = max(energy_a, energy_b); + max_energy = max(max_energy, energy_c); + + IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n", + energy_a, energy_b, energy_c, max_energy); + + return max_energy; +} + /* * iwl_mvm_set_mac80211_rx_flag - translate fw status to mac80211 format * @mvm: the mvm object @@ -290,7 +306,10 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.signal = iwl_mvm_calc_rssi(mvm, phy_info); + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_RX_ENERGY_API) + rx_status.signal = iwl_mvm_get_signal_strength(mvm, phy_info); + else + rx_status.signal = iwl_mvm_calc_rssi(mvm, phy_info); IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, (unsigned long long)rx_status.mactime); -- cgit v1.2.3 From 58fa2aad295579a0fcab699eb76bff79eb8df3a8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 25 Jun 2013 23:01:28 +0300 Subject: iwlwifi: mvm: remove the default calibration values for 7000 The fw is now able to run TX_IQ_SKEW and RX_IQ_SKEW by itself. No need for default values any more. Signed-off-by: Emmanuel Grumbach Reviewed-by: Dor Shaish Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/fw.c | 55 ----------------------------------- 1 file changed, 55 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index cd7c0032cc58..c76299a3a1e0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -78,22 +78,6 @@ #define UCODE_VALID_OK cpu_to_le32(0x1) -/* Default calibration values for WkP - set to INIT image w/o running */ -static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 }; -static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; - -struct iwl_calib_default_data { - u16 size; - void *data; -}; - -#define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf} - -static const struct iwl_calib_default_data wkp_calib_default_data[12] = { - [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), - [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew), -}; - struct iwl_mvm_alive_data { bool valid; u32 scd_base_addr; @@ -248,40 +232,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) sizeof(phy_cfg_cmd), &phy_cfg_cmd); } -static int iwl_set_default_calibrations(struct iwl_mvm *mvm) -{ - u8 cmd_raw[16]; /* holds the variable size commands */ - struct iwl_set_calib_default_cmd *cmd = - (struct iwl_set_calib_default_cmd *)cmd_raw; - int ret, i; - - /* Setting default values for calibrations we don't run */ - for (i = 0; i < ARRAY_SIZE(wkp_calib_default_data); i++) { - u16 cmd_len; - - if (wkp_calib_default_data[i].size == 0) - continue; - - memset(cmd_raw, 0, sizeof(cmd_raw)); - cmd_len = wkp_calib_default_data[i].size + sizeof(cmd); - cmd->calib_index = cpu_to_le16(i); - cmd->length = cpu_to_le16(wkp_calib_default_data[i].size); - if (WARN_ONCE(cmd_len > sizeof(cmd_raw), - "Need to enlarge cmd_raw to %d\n", cmd_len)) - break; - memcpy(cmd->data, wkp_calib_default_data[i].data, - wkp_calib_default_data[i].size); - ret = iwl_mvm_send_cmd_pdu(mvm, SET_CALIB_DEFAULT_CMD, 0, - sizeof(*cmd) + - wkp_calib_default_data[i].size, - cmd); - if (ret) - return ret; - } - - return 0; -} - int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) { struct iwl_notification_wait calib_wait; @@ -342,11 +292,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) if (ret) goto error; - /* need to set default values */ - ret = iwl_set_default_calibrations(mvm); - if (ret) - goto error; - /* * Send phy configurations command to init uCode * to start the 16.0 uCode init image internal calibrations. -- cgit v1.2.3 From ac1ed4163b5a523728fa0e8c27c1ff4d182f40fd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 Jul 2013 15:25:25 +0200 Subject: iwlwifi: mvm: reprobe device on firmware error during restart If we get a firmware error during restart, we currently abandon any hope and simply fail, getting stuck until the driver is reloaded. Unfortunately, there isn't really much else we can do since restart will likely continue to fail, and asking mac80211 for disconnection just causes more error. To allow the user to at least set up the device again completely from scratch, reprobe the device and in doing so completely destroy any mac80211/driver state. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/ops.c | 40 +++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index fa1e1ce9f2be..5d5dedddd2dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -644,6 +644,22 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) ieee80211_free_txskb(mvm->hw, skb); } +struct iwl_mvm_reprobe { + struct device *dev; + struct work_struct work; +}; + +static void iwl_mvm_reprobe_wk(struct work_struct *wk) +{ + struct iwl_mvm_reprobe *reprobe; + + reprobe = container_of(wk, struct iwl_mvm_reprobe, work); + if (device_reprobe(reprobe->dev)) + dev_err(reprobe->dev, "reprobe failed!\n"); + kfree(reprobe); + module_put(THIS_MODULE); +} + static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) { iwl_abort_notification_waits(&mvm->notif_wait); @@ -655,7 +671,29 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) * can't recover this since we're already half suspended. */ if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n"); + struct iwl_mvm_reprobe *reprobe; + + IWL_ERR(mvm, + "Firmware error during reconfiguration - reprobe!\n"); + + /* + * get a module reference to avoid doing this while unloading + * anyway and to avoid scheduling a work with code that's + * being removed. + */ + if (!try_module_get(THIS_MODULE)) { + IWL_ERR(mvm, "Module is being unloaded - abort\n"); + return; + } + + reprobe = kzalloc(sizeof(*reprobe), GFP_ATOMIC); + if (!reprobe) { + module_put(THIS_MODULE); + return; + } + reprobe->dev = mvm->trans->dev; + INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); + schedule_work(&reprobe->work); } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && iwlwifi_mod_params.restart_fw) { /* -- cgit v1.2.3 From 88f2fd7300da1b671255ef26469627206fe20a8e Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Tue, 9 Jul 2013 15:25:46 +0300 Subject: iwlwifi: mvm: Enable user set TX power Support Tx power limitations. These limitations can come from mac80211 for various reasons. Signed-off-by: Matti Gottlieb Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 8 ++++++-- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 14 ++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 +++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 4 files changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index acd2665afb8c..b76a9a8fc0b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -118,6 +118,7 @@ static const u8 iwl_nvm_channels[] = { #define LAST_2GHZ_HT_PLUS 9 #define LAST_5GHZ_HT 161 +#define DEFAULT_MAX_TX_POWER 16 /* rate data (static) */ static struct ieee80211_rate iwl_cfg80211_rates[] = { @@ -232,8 +233,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, /* Initialize regulatory-based run-time data */ - /* TODO: read the real value from the NVM */ - channel->max_power = 0; + /* + * Default value - highest tx power value. max_power + * is not used in mvm, and is used for backwards compatibility + */ + channel->max_power = DEFAULT_MAX_TX_POWER; is_5ghz = channel->band == IEEE80211_BAND_5GHZ; IWL_DEBUG_EEPROM(dev, "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 28cab821c9f4..55854a309f94 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -159,6 +159,7 @@ enum { TX_ANT_CONFIGURATION_CMD = 0x98, BT_CONFIG = 0x9b, STATISTICS_NOTIFICATION = 0x9d, + REDUCE_TX_POWER_CMD = 0x9f, /* RF-KILL commands and notifications */ CARD_STATE_CMD = 0xa0, @@ -226,6 +227,19 @@ struct iwl_tx_ant_cfg_cmd { __le32 valid; } __packed; +/** + * struct iwl_reduce_tx_power_cmd - TX power reduction command + * REDUCE_TX_POWER_CMD = 0x9f + * @flags: (reserved for future implementation) + * @mac_context_id: id of the mac ctx for which we are reducing TX power. + * @pwr_restriction: TX power restriction in dBms. + */ +struct iwl_reduce_tx_power_cmd { + u8 flags; + u8 mac_context_id; + __le16 pwr_restriction; +} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ + /* * Calibration control struct. * Sent as part of the phy configuration command. diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 30319e069f45..fbb8c2dc66e0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -714,6 +714,20 @@ out_release: mutex_unlock(&mvm->mutex); } +static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + s8 tx_power) +{ + /* FW is in charge of regulatory enforcement */ + struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = { + .mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id, + .pwr_restriction = cpu_to_le16(tx_power), + }; + + return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, CMD_SYNC, + sizeof(reduce_txpwr_cmd), + &reduce_txpwr_cmd); +} + static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) { return 0; @@ -794,6 +808,11 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to update power mode\n"); } + if (changes & BSS_CHANGED_TXPOWER) { + IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", + bss_conf->txpower); + iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); + } } static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 5d5dedddd2dc..70ac726c0265 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -275,6 +275,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(BEACON_NOTIFICATION), CMD(BEACON_TEMPLATE_CMD), CMD(STATISTICS_NOTIFICATION), + CMD(REDUCE_TX_POWER_CMD), CMD(TX_ANT_CONFIGURATION_CMD), CMD(D3_CONFIG_CMD), CMD(PROT_OFFLOAD_CONFIG_CMD), -- cgit v1.2.3 From 5369d6c167317a99caf2c4c87957f07cd77a1888 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 8 Jul 2013 11:17:06 +0200 Subject: iwlwifi: mvm: support six IPv6 addresses in D3 Newer firmware supports offloading more IPv6 addresses for NDP, adjust the code to send the correct command depending on the firmware capability. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-fw.h | 3 ++ drivers/net/wireless/iwlwifi/mvm/d3.c | 66 +++++++++++++++++++++------- drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | 49 ++++++++++++++++----- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- 4 files changed, 92 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 46dc38a32115..b766ee9bb05a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -76,6 +76,8 @@ * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api + * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six + * (rather than two) IPv6 addresses */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), @@ -85,6 +87,7 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), + IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), }; /* The default calibrate table size if not specified by firmware file */ diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 7e5e5c2f9f87..ebf7f9468926 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -105,7 +105,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, list_for_each_entry(ifa, &idev->addr_list, if_list) { mvmvif->target_ipv6_addrs[idx] = ifa->addr; idx++; - if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) + if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX) break; } read_unlock_bh(&idev->lock); @@ -373,36 +373,68 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - struct iwl_proto_offload_cmd cmd = {}; + union { + struct iwl_proto_offload_cmd_v1 v1; + struct iwl_proto_offload_cmd_v2 v2; + } cmd = {}; + struct iwl_proto_offload_cmd_common *common; + u32 enabled = 0, size; #if IS_ENABLED(CONFIG_IPV6) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int i; - if (mvmvif->num_target_ipv6_addrs) { - cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS); - memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN); - } + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { + if (mvmvif->num_target_ipv6_addrs) { + enabled |= IWL_D3_PROTO_OFFLOAD_NS; + memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); + } + + BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != + sizeof(mvmvif->target_ipv6_addrs[0])); + + for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, + IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) + memcpy(cmd.v2.target_ipv6_addr[i], + &mvmvif->target_ipv6_addrs[i], + sizeof(cmd.v2.target_ipv6_addr[i])); + } else { + if (mvmvif->num_target_ipv6_addrs) { + enabled |= IWL_D3_PROTO_OFFLOAD_NS; + memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); + } - BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) != - sizeof(mvmvif->target_ipv6_addrs[i])); + BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != + sizeof(mvmvif->target_ipv6_addrs[0])); - for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++) - memcpy(cmd.target_ipv6_addr[i], - &mvmvif->target_ipv6_addrs[i], - sizeof(cmd.target_ipv6_addr[i])); + for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, + IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) + memcpy(cmd.v1.target_ipv6_addr[i], + &mvmvif->target_ipv6_addrs[i], + sizeof(cmd.v1.target_ipv6_addr[i])); + } #endif + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { + common = &cmd.v2.common; + size = sizeof(cmd.v2); + } else { + common = &cmd.v1.common; + size = sizeof(cmd.v1); + } + if (vif->bss_conf.arp_addr_cnt) { - cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP); - cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; - memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN); + enabled |= IWL_D3_PROTO_OFFLOAD_ARP; + common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; + memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); } - if (!cmd.enabled) + if (!enabled) return 0; + common->enabled = cpu_to_le32(enabled); + return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, - sizeof(cmd), &cmd); + size, &cmd); } enum iwl_mvm_tcp_packet_type { diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 6f8b2c16ae17..df72fcdf8170 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -98,34 +98,63 @@ enum iwl_proto_offloads { IWL_D3_PROTO_OFFLOAD_NS = BIT(1), }; -#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS 2 +#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 +#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6 +#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 6 /** - * struct iwl_proto_offload_cmd - ARP/NS offload configuration + * struct iwl_proto_offload_cmd_common - ARP/NS offload common part * @enabled: enable flags * @remote_ipv4_addr: remote address to answer to (or zero if all) * @host_ipv4_addr: our IPv4 address to respond to queries for * @arp_mac_addr: our MAC address for ARP responses - * @remote_ipv6_addr: remote address to answer to (or zero if all) - * @solicited_node_ipv6_addr: broken -- solicited node address exists - * for each target address - * @target_ipv6_addr: our target addresses - * @ndp_mac_addr: neighbor soliciation response MAC address + * @reserved: unused */ -struct iwl_proto_offload_cmd { +struct iwl_proto_offload_cmd_common { __le32 enabled; __be32 remote_ipv4_addr; __be32 host_ipv4_addr; u8 arp_mac_addr[ETH_ALEN]; - __le16 reserved1; + __le16 reserved; +} __packed; +/** + * struct iwl_proto_offload_cmd_v1 - ARP/NS offload configuration + * @common: common/IPv4 configuration + * @remote_ipv6_addr: remote address to answer to (or zero if all) + * @solicited_node_ipv6_addr: broken -- solicited node address exists + * for each target address + * @target_ipv6_addr: our target addresses + * @ndp_mac_addr: neighbor soliciation response MAC address + */ +struct iwl_proto_offload_cmd_v1 { + struct iwl_proto_offload_cmd_common common; u8 remote_ipv6_addr[16]; u8 solicited_node_ipv6_addr[16]; - u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS][16]; + u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1][16]; u8 ndp_mac_addr[ETH_ALEN]; __le16 reserved2; } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */ +/** + * struct iwl_proto_offload_cmd_v2 - ARP/NS offload configuration + * @common: common/IPv4 configuration + * @remote_ipv6_addr: remote address to answer to (or zero if all) + * @solicited_node_ipv6_addr: broken -- solicited node address exists + * for each target address + * @target_ipv6_addr: our target addresses + * @ndp_mac_addr: neighbor soliciation response MAC address + */ +struct iwl_proto_offload_cmd_v2 { + struct iwl_proto_offload_cmd_common common; + u8 remote_ipv6_addr[16]; + u8 solicited_node_ipv6_addr[16]; + u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2][16]; + u8 ndp_mac_addr[ETH_ALEN]; + u8 numValidIPv6Addresses; + u8 reserved2[3]; +} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */ + /* * WOWLAN_PATTERNS diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index caa6a1758172..879fb01da40c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -282,7 +282,7 @@ struct iwl_mvm_vif { #if IS_ENABLED(CONFIG_IPV6) /* IPv6 addresses for WoWLAN */ - struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS]; + struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; int num_target_ipv6_addrs; #endif #endif -- cgit v1.2.3 From 0f2ed58e6e185bb7f22a534d12b755b7459177ef Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Tue, 2 Jul 2013 19:51:09 +0300 Subject: iwlwifi: mvm: Change AM->PSM timeout for EAPOL frames Currently after sending EAPOL frame FW transition to power saving mode within 10 or 100 msec (as specified by power table command). According to new requirement this timeout for a specific EAPOL frame must be controlled by the driver by setting tx_pm_timeout field of TX_CMD to 2 (PM_FRAME_ENUM_MGMT). This value corresponds to 32 msec timeout. Signed-off-by: Alexander Bondar Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index f0e96a927407..7694b8fa4c37 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -123,6 +123,8 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, * it */ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); + } else if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { + tx_cmd->pm_frame_timeout = cpu_to_le16(2); } else { tx_cmd->pm_frame_timeout = 0; } -- cgit v1.2.3 From fd11bd05552e8639abbdc2f1d478f70dfb9b5e3e Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 16 Jun 2013 12:18:11 +0300 Subject: iwlwifi: mvm: Return on inconsistency in add interface Return in case that HW restart is in progress but the added interface is not found during the iteration over all the interfaces. Signed-off-by: Ilan Peer Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 94aae9c8562c..5fe23a5ea9b6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -264,7 +264,8 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, return 0; /* Therefore, in recovery, we can't get here */ - WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); + if (WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) + return -EBUSY; mvmvif->id = find_first_bit(data.available_mac_ids, NUM_MAC_INDEX_DRIVER); -- cgit v1.2.3 From 7b8359cf2bda0103688f9cc623ce6c221a6004c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Jul 2013 12:59:38 +0200 Subject: iwlwifi: mvm: assign quota per virtual interface Instead of assigning quota per used binding (channel) assign the same amount of quota for each virtual interface so that when there are more than two interfaces using more than one channel, we'll stay on the channels proportionally to the number of virtual interfaces using the channels. Reviewed-by: Emmanuel Grumbach Reviewed-by: Ilan Peer Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/quota.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 29d49cf0fdb2..18973874b77a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -132,7 +132,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) { struct iwl_time_quota_cmd cmd; - int i, idx, ret, num_active_bindings, quota, quota_rem; + int i, idx, ret, num_active_macs, quota, quota_rem; struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, .colors = { -1, -1, -1, -1 }, @@ -162,18 +162,17 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) * IWL_MVM_MAX_QUOTA fragments. Divide these fragments * equally between all the bindings that require quota */ - num_active_bindings = 0; + num_active_macs = 0; for (i = 0; i < MAX_BINDINGS; i++) { cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); - if (data.n_interfaces[i] > 0) - num_active_bindings++; + num_active_macs += data.n_interfaces[i]; } quota = 0; quota_rem = 0; - if (num_active_bindings) { - quota = IWL_MVM_MAX_QUOTA / num_active_bindings; - quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings; + if (num_active_macs) { + quota = IWL_MVM_MAX_QUOTA / num_active_macs; + quota_rem = IWL_MVM_MAX_QUOTA % num_active_macs; } for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { @@ -187,7 +186,8 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) cmd.quotas[idx].quota = cpu_to_le32(0); cmd.quotas[idx].max_duration = cpu_to_le32(0); } else { - cmd.quotas[idx].quota = cpu_to_le32(quota); + cmd.quotas[idx].quota = + cpu_to_le32(quota * data.n_interfaces[i]); cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA); } -- cgit v1.2.3 From 99545924a10c2c8ee2cc04a0d1be38a4c5b3ef66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Jun 2013 13:36:21 +0200 Subject: iwlwifi: mvm: split constants into separate file To make maintaining some constant default values in the driver easier, declare them in a separate file. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/constants.h | 71 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/power.c | 12 +++-- 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/mvm/constants.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h new file mode 100644 index 000000000000..64656e0c8f91 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -0,0 +1,71 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __MVM_CONSTANTS_H +#define __MVM_CONSTANTS_H + +#define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) +#define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) +#define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) +#define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) + +#endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 879fb01da40c..8891c815871b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -76,6 +76,7 @@ #include "iwl-trans.h" #include "sta.h" #include "fw-api.h" +#include "constants.h" #define IWL_INVALID_MAC80211_QUEUE 0xff #define IWL_MVM_MAX_ADDRESSES 5 diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 644bf476921a..8ed04038345d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -217,11 +217,15 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, } if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { - cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); - cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); + cmd->rx_data_timeout = + cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT); + cmd->tx_data_timeout = + cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT); } else { - cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); - cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); + cmd->rx_data_timeout = + cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT); + cmd->tx_data_timeout = + cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); } #ifdef CONFIG_IWLWIFI_DEBUGFS -- cgit v1.2.3 From 77740cb433fd5c4394cad4bb948e5c550b027837 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 26 Jun 2013 23:51:41 +0300 Subject: iwlwifi: mvm: register vif debugfs for AP mode too The current registered the per-vif debugfs handler for STA mode only. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index fbb8c2dc66e0..13cc7722fbcf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -526,6 +526,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_release; } + iwl_mvm_vif_dbgfs_register(mvm, vif); goto out_unlock; } -- cgit v1.2.3 From 5dca7c241e92a5c619260ad969b53b2c4849c340 Mon Sep 17 00:00:00 2001 From: Hila Gonen Date: Tue, 16 Jul 2013 11:15:35 +0300 Subject: iwlwifi: mvm: Change beacon filtering command Change beacon filtering command due to a change in the API. In case the FW supports the old API, we do not send the BF HCMD and assume that since the corresponding struct in the FW is zeroed by default then we don't need to disable it in the FW actively. Signed-off-by: Hila Gonen Signed-off-by: Dor Shaish Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-fw.h | 2 + drivers/net/wireless/iwlwifi/mvm/debugfs.c | 74 ++++++++++++++++--------- drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 65 ++++++++++++++-------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 30 +++++----- drivers/net/wireless/iwlwifi/mvm/power.c | 55 +++++++++++------- 6 files changed, 145 insertions(+), 84 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index b766ee9bb05a..bd335f0c40d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -78,6 +78,7 @@ * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six * (rather than two) IPv6 addresses + * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), @@ -88,6 +89,7 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), + IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11), }; /* The default calibrate table size if not specified by firmware file */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 5d669da09afe..347aa1cb29d5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -632,8 +632,14 @@ static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, case MVM_DEBUGFS_BF_ROAMING_STATE: dbgfs_bf->bf_roaming_state = value; break; - case MVM_DEBUGFS_BF_TEMPERATURE_DELTA: - dbgfs_bf->bf_temperature_delta = value; + case MVM_DEBUGFS_BF_TEMP_THRESHOLD: + dbgfs_bf->bf_temp_threshold = value; + break; + case MVM_DEBUGFS_BF_TEMP_FAST_FILTER: + dbgfs_bf->bf_temp_fast_filter = value; + break; + case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER: + dbgfs_bf->bf_temp_slow_filter = value; break; case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER: dbgfs_bf->bf_enable_beacon_filter = value; @@ -692,13 +698,27 @@ static ssize_t iwl_dbgfs_bf_params_write(struct file *file, value > IWL_BF_ROAMING_STATE_MAX) return -EINVAL; param = MVM_DEBUGFS_BF_ROAMING_STATE; - } else if (!strncmp("bf_temperature_delta=", buf, 21)) { - if (sscanf(buf+21, "%d", &value) != 1) + } else if (!strncmp("bf_temp_threshold=", buf, 18)) { + if (sscanf(buf+18, "%d", &value) != 1) + return -EINVAL; + if (value < IWL_BF_TEMP_THRESHOLD_MIN || + value > IWL_BF_TEMP_THRESHOLD_MAX) + return -EINVAL; + param = MVM_DEBUGFS_BF_TEMP_THRESHOLD; + } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) { + if (sscanf(buf+20, "%d", &value) != 1) + return -EINVAL; + if (value < IWL_BF_TEMP_FAST_FILTER_MIN || + value > IWL_BF_TEMP_FAST_FILTER_MAX) + return -EINVAL; + param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER; + } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) { + if (sscanf(buf+20, "%d", &value) != 1) return -EINVAL; - if (value < IWL_BF_TEMPERATURE_DELTA_MIN || - value > IWL_BF_TEMPERATURE_DELTA_MAX) + if (value < IWL_BF_TEMP_SLOW_FILTER_MIN || + value > IWL_BF_TEMP_SLOW_FILTER_MAX) return -EINVAL; - param = MVM_DEBUGFS_BF_TEMPERATURE_DELTA; + param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER; } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { if (sscanf(buf+24, "%d", &value) != 1) return -EINVAL; @@ -760,41 +780,41 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, int pos = 0; const size_t bufsz = sizeof(buf); struct iwl_beacon_filter_cmd cmd = { - .bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT, - .bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT, - .bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT, - .bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT, - .bf_enable_beacon_filter = IWL_BF_ENABLE_BEACON_FILTER_DEFAULT, - .bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT, - .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), - .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT), - .ba_enable_beacon_abort = IWL_BA_ENABLE_BEACON_ABORT_DEFAULT, + IWL_BF_CMD_CONFIG_DEFAULTS, + .bf_enable_beacon_filter = + cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT), + .ba_enable_beacon_abort = + cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT), }; iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); if (mvmvif->bf_enabled) - cmd.bf_enable_beacon_filter = 1; + cmd.bf_enable_beacon_filter = cpu_to_le32(1); else cmd.bf_enable_beacon_filter = 0; pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n", - cmd.bf_energy_delta); + le32_to_cpu(cmd.bf_energy_delta)); pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n", - cmd.bf_roaming_energy_delta); + le32_to_cpu(cmd.bf_roaming_energy_delta)); pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n", - cmd.bf_roaming_state); - pos += scnprintf(buf+pos, bufsz-pos, "bf_temperature_delta = %d\n", - cmd.bf_temperature_delta); + le32_to_cpu(cmd.bf_roaming_state)); + pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n", + le32_to_cpu(cmd.bf_temp_threshold)); + pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n", + le32_to_cpu(cmd.bf_temp_fast_filter)); + pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n", + le32_to_cpu(cmd.bf_temp_slow_filter)); pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n", - cmd.bf_enable_beacon_filter); + le32_to_cpu(cmd.bf_enable_beacon_filter)); pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n", - cmd.bf_debug_flag); + le32_to_cpu(cmd.bf_debug_flag)); pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n", - cmd.bf_escape_timer); + le32_to_cpu(cmd.bf_escape_timer)); pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n", - cmd.ba_escape_timer); + le32_to_cpu(cmd.ba_escape_timer)); pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n", - cmd.ba_enable_beacon_abort); + le32_to_cpu(cmd.ba_enable_beacon_abort)); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 300211d79f2a..149347d45d26 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -216,11 +216,21 @@ struct iwl_mac_power_cmd { * calculated for current beacon is less than the threshold, use * Roaming Energy Delta Threshold, otherwise use normal Energy Delta * Threshold. Typical energy threshold is -72dBm. - * @bf_temperature_delta: Send Beacon to driver if delta in temperature values - * calculated for this and the last passed beacon is greater than this - * threshold. Zero value means that the temperature changeis ignored for + * @bf_temp_threshold: This threshold determines the type of temperature + * filtering (Slow or Fast) that is selected (Units are in Celsuis): + * If the current temperature is above this threshold - Fast filter + * will be used, If the current temperature is below this threshold - + * Slow filter will be used. + * @bf_temp_fast_filter: Send Beacon to driver if delta in temperature values + * calculated for this and the last passed beacon is greater than this + * threshold. Zero value means that the temperature change is ignored for * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temerature has been changed. + * @bf_temp_slow_filter: Send Beacon to driver if delta in temperature values + * calculated for this and the last passed beacon is greater than this + * threshold. Zero value means that the temperature change is ignored for + * beacon filtering; beacons will not be forced to be sent to driver + * regardless of whether its temerature has been changed. * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. * @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed * for a specific period of time. Units: Beacons. @@ -229,17 +239,17 @@ struct iwl_mac_power_cmd { * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled. */ struct iwl_beacon_filter_cmd { - u8 bf_energy_delta; - u8 bf_roaming_energy_delta; - u8 bf_roaming_state; - u8 bf_temperature_delta; - u8 bf_enable_beacon_filter; - u8 bf_debug_flag; - __le16 reserved1; + __le32 bf_energy_delta; + __le32 bf_roaming_energy_delta; + __le32 bf_roaming_state; + __le32 bf_temp_threshold; + __le32 bf_temp_fast_filter; + __le32 bf_temp_slow_filter; + __le32 bf_enable_beacon_filter; + __le32 bf_debug_flag; __le32 bf_escape_timer; __le32 ba_escape_timer; - u8 ba_enable_beacon_abort; - u8 reserved2[3]; + __le32 ba_enable_beacon_abort; } __packed; /* Beacon filtering and beacon abort */ @@ -255,9 +265,17 @@ struct iwl_beacon_filter_cmd { #define IWL_BF_ROAMING_STATE_MAX 255 #define IWL_BF_ROAMING_STATE_MIN 0 -#define IWL_BF_TEMPERATURE_DELTA_DEFAULT 5 -#define IWL_BF_TEMPERATURE_DELTA_MAX 255 -#define IWL_BF_TEMPERATURE_DELTA_MIN 0 +#define IWL_BF_TEMP_THRESHOLD_DEFAULT 112 +#define IWL_BF_TEMP_THRESHOLD_MAX 255 +#define IWL_BF_TEMP_THRESHOLD_MIN 0 + +#define IWL_BF_TEMP_FAST_FILTER_DEFAULT 1 +#define IWL_BF_TEMP_FAST_FILTER_MAX 255 +#define IWL_BF_TEMP_FAST_FILTER_MIN 0 + +#define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5 +#define IWL_BF_TEMP_SLOW_FILTER_MAX 255 +#define IWL_BF_TEMP_SLOW_FILTER_MIN 0 #define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1 @@ -273,13 +291,16 @@ struct iwl_beacon_filter_cmd { #define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1 -#define IWL_BF_CMD_CONFIG_DEFAULTS \ - .bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT, \ - .bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT, \ - .bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT, \ - .bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT, \ - .bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT, \ - .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \ +#define IWL_BF_CMD_CONFIG_DEFAULTS \ + .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA_DEFAULT), \ + .bf_roaming_energy_delta = \ + cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT), \ + .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE_DEFAULT), \ + .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD_DEFAULT), \ + .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER_DEFAULT), \ + .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER_DEFAULT), \ + .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG_DEFAULT), \ + .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \ .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT) #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 13cc7722fbcf..8e4e79a83d14 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -563,7 +563,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, /* beacon filtering */ if (!mvm->bf_allowed_vif && - vif->type == NL80211_IFTYPE_STATION && !vif->p2p){ + vif->type == NL80211_IFTYPE_STATION && !vif->p2p && + mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){ mvm->bf_allowed_vif = mvmvif; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 8891c815871b..dda0cd012330 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -195,24 +195,28 @@ enum iwl_dbgfs_bf_mask { MVM_DEBUGFS_BF_ENERGY_DELTA = BIT(0), MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA = BIT(1), MVM_DEBUGFS_BF_ROAMING_STATE = BIT(2), - MVM_DEBUGFS_BF_TEMPERATURE_DELTA = BIT(3), - MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER = BIT(4), - MVM_DEBUGFS_BF_DEBUG_FLAG = BIT(5), - MVM_DEBUGFS_BF_ESCAPE_TIMER = BIT(6), - MVM_DEBUGFS_BA_ESCAPE_TIMER = BIT(7), - MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT = BIT(8), + MVM_DEBUGFS_BF_TEMP_THRESHOLD = BIT(3), + MVM_DEBUGFS_BF_TEMP_FAST_FILTER = BIT(4), + MVM_DEBUGFS_BF_TEMP_SLOW_FILTER = BIT(5), + MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER = BIT(6), + MVM_DEBUGFS_BF_DEBUG_FLAG = BIT(7), + MVM_DEBUGFS_BF_ESCAPE_TIMER = BIT(8), + MVM_DEBUGFS_BA_ESCAPE_TIMER = BIT(9), + MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT = BIT(10), }; struct iwl_dbgfs_bf { - u8 bf_energy_delta; - u8 bf_roaming_energy_delta; - u8 bf_roaming_state; - u8 bf_temperature_delta; - u8 bf_enable_beacon_filter; - u8 bf_debug_flag; + u32 bf_energy_delta; + u32 bf_roaming_energy_delta; + u32 bf_roaming_state; + u32 bf_temp_threshold; + u32 bf_temp_fast_filter; + u32 bf_temp_slow_filter; + u32 bf_enable_beacon_filter; + u32 bf_debug_flag; u32 bf_escape_timer; u32 ba_escape_timer; - u8 ba_enable_beacon_abort; + u32 ba_enable_beacon_abort; int mask; }; #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 8ed04038345d..30306a9b0c48 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -85,23 +85,27 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, if (!ret) { IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", - cmd->ba_enable_beacon_abort); + le32_to_cpu(cmd->ba_enable_beacon_abort)); IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", - cmd->ba_escape_timer); + le32_to_cpu(cmd->ba_escape_timer)); IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", - cmd->bf_debug_flag); + le32_to_cpu(cmd->bf_debug_flag)); IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", - cmd->bf_enable_beacon_filter); + le32_to_cpu(cmd->bf_enable_beacon_filter)); IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", - cmd->bf_energy_delta); + le32_to_cpu(cmd->bf_energy_delta)); IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", - cmd->bf_escape_timer); + le32_to_cpu(cmd->bf_escape_timer)); IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", - cmd->bf_roaming_energy_delta); + le32_to_cpu(cmd->bf_roaming_energy_delta)); IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", - cmd->bf_roaming_state); - IWL_DEBUG_POWER(mvm, "bf_temperature_delta is: %d\n", - cmd->bf_temperature_delta); + le32_to_cpu(cmd->bf_roaming_state)); + IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", + le32_to_cpu(cmd->bf_temp_threshold)); + IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", + le32_to_cpu(cmd->bf_temp_fast_filter)); + IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", + le32_to_cpu(cmd->bf_temp_slow_filter)); } return ret; } @@ -112,8 +116,8 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_beacon_filter_cmd cmd = { IWL_BF_CMD_CONFIG_DEFAULTS, - .bf_enable_beacon_filter = 1, - .ba_enable_beacon_abort = enable, + .bf_enable_beacon_filter = cpu_to_le32(1), + .ba_enable_beacon_abort = cpu_to_le32(enable), }; if (!mvmvif->bf_enabled) @@ -369,22 +373,30 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA) - cmd->bf_energy_delta = dbgfs_bf->bf_energy_delta; + cmd->bf_energy_delta = cpu_to_le32(dbgfs_bf->bf_energy_delta); if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA) cmd->bf_roaming_energy_delta = - dbgfs_bf->bf_roaming_energy_delta; + cpu_to_le32(dbgfs_bf->bf_roaming_energy_delta); if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE) - cmd->bf_roaming_state = dbgfs_bf->bf_roaming_state; - if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMPERATURE_DELTA) - cmd->bf_temperature_delta = dbgfs_bf->bf_temperature_delta; + cmd->bf_roaming_state = cpu_to_le32(dbgfs_bf->bf_roaming_state); + if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_THRESHOLD) + cmd->bf_temp_threshold = + cpu_to_le32(dbgfs_bf->bf_temp_threshold); + if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_FAST_FILTER) + cmd->bf_temp_fast_filter = + cpu_to_le32(dbgfs_bf->bf_temp_fast_filter); + if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_SLOW_FILTER) + cmd->bf_temp_slow_filter = + cpu_to_le32(dbgfs_bf->bf_temp_slow_filter); if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG) - cmd->bf_debug_flag = dbgfs_bf->bf_debug_flag; + cmd->bf_debug_flag = cpu_to_le32(dbgfs_bf->bf_debug_flag); if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER) cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer); if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER) cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer); if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT) - cmd->ba_enable_beacon_abort = dbgfs_bf->ba_enable_beacon_abort; + cmd->ba_enable_beacon_abort = + cpu_to_le32(dbgfs_bf->ba_enable_beacon_abort); } #endif @@ -394,7 +406,7 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_beacon_filter_cmd cmd = { IWL_BF_CMD_CONFIG_DEFAULTS, - .bf_enable_beacon_filter = 1, + .bf_enable_beacon_filter = cpu_to_le32(1), }; int ret; @@ -418,7 +430,8 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED) || + vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); -- cgit v1.2.3 From 291aa7c4a4c01ef925b366174fc05ff2a757fad0 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Wed, 3 Jul 2013 11:00:06 +0300 Subject: iwlwifi: mvm: fix debugfs restart if fw_restart is disabled If fw_restart is disabled, using the fw_restart debugfs file will enable fw_restart and then send the failing command, but this still frequently fails restart because it resets fw_restart afterwards and is thus racy. Fix this by tracking fw_restart separately and allowing "always restart", "never restart" and "restart N times". Signed-off-by: Eran Harary Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 9 ++++----- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/ops.c | 9 ++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 347aa1cb29d5..15d52bad2d2a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -597,20 +597,19 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - bool restart_fw = iwlwifi_mod_params.restart_fw; int ret; - iwlwifi_mod_params.restart_fw = true; - mutex_lock(&mvm->mutex); + /* allow one more restart that we're provoking here */ + if (mvm->restart_fw >= 0) + mvm->restart_fw++; + /* take the return value to make compiler happy - it will fail anyway */ ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL); mutex_unlock(&mvm->mutex); - iwlwifi_mod_params.restart_fw = restart_fw; - return count; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index dda0cd012330..5dc5dfde916e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -477,6 +477,9 @@ struct iwl_mvm { */ u8 vif_count; + /* -1 for always, 0 for never, >0 for that many times */ + s8 restart_fw; + struct led_classdev led; struct ieee80211_vif *p2p_device_vif; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 70ac726c0265..65e5fb86291f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -342,6 +342,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->fw = fw; mvm->hw = hw; + mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; + mutex_init(&mvm->mutex); spin_lock_init(&mvm->async_handlers_lock); INIT_LIST_HEAD(&mvm->time_event_list); @@ -695,8 +697,7 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) reprobe->dev = mvm->trans->dev; INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); - } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && - iwlwifi_mod_params.restart_fw) { + } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) { /* * This is a bit racy, but worst case we tell mac80211 about * a stopped/aborted (sched) scan when that was already done @@ -714,6 +715,8 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) break; } + if (mvm->restart_fw > 0) + mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); } } @@ -723,7 +726,7 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); iwl_mvm_dump_nic_error_log(mvm); - if (!iwlwifi_mod_params.restart_fw) + if (!mvm->restart_fw) iwl_mvm_dump_sram(mvm); iwl_mvm_nic_restart(mvm); -- cgit v1.2.3 From 226eb8cd22b6cddccd6e109a8400427ea6fed080 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jul 2013 11:55:17 +0200 Subject: iwlwifi: mvm: report per-chain signal to mac80211 Instead of reporting the maximum signal strength and the antenna bitmap in the antenna field (which is really just for radiotap and defined differently), report the signal strength values per chain and set the chain bitmap. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rx.c | 47 ++++++++++++++++------------------- 1 file changed, 21 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index c8e4af23d04c..6fd7fae30c0a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -124,8 +124,9 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, ieee80211_rx_ni(mvm->hw, skb); } -static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, - struct iwl_rx_phy_info *phy_info) +static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm, + struct iwl_rx_phy_info *phy_info, + struct ieee80211_rx_status *rx_status) { int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; int rssi_all_band_a, rssi_all_band_b; @@ -156,14 +157,20 @@ static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); - return max_rssi_dbm; + rx_status->signal = max_rssi_dbm; + rx_status->chains = (le16_to_cpu(phy_info->phy_flags) & + RX_RES_PHY_FLAGS_ANTENNA) + >> RX_RES_PHY_FLAGS_ANTENNA_POS; + rx_status->chain_signal[0] = rssi_a_dbm; + rx_status->chain_signal[1] = rssi_b_dbm; } /* * iwl_mvm_get_signal_strength - use new rx PHY INFO API */ -static int iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, - struct iwl_rx_phy_info *phy_info) +static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, + struct iwl_rx_phy_info *phy_info, + struct ieee80211_rx_status *rx_status) { int energy_a, energy_b, energy_c, max_energy; u32 val; @@ -182,7 +189,13 @@ static int iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n", energy_a, energy_b, energy_c, max_energy); - return max_energy; + rx_status->signal = max_energy; + rx_status->chains = (le16_to_cpu(phy_info->phy_flags) & + RX_RES_PHY_FLAGS_ANTENNA) + >> RX_RES_PHY_FLAGS_ANTENNA_POS; + rx_status->chain_signal[0] = energy_a; + rx_status->chain_signal[1] = energy_b; + rx_status->chain_signal[2] = energy_c; } /* @@ -305,32 +318,14 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, */ /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ - /* Find max signal strength (dBm) among 3 antenna/receiver chains */ if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_RX_ENERGY_API) - rx_status.signal = iwl_mvm_get_signal_strength(mvm, phy_info); + iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status); else - rx_status.signal = iwl_mvm_calc_rssi(mvm, phy_info); + iwl_mvm_calc_rssi(mvm, phy_info, &rx_status); IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, (unsigned long long)rx_status.mactime); - /* - * "antenna number" - * - * It seems that the antenna field in the phy flags value - * is actually a bit field. This is undefined by radiotap, - * it wants an actual antenna number but I always get "7" - * for most legacy frames I receive indicating that the - * same frame was received on all three RX chains. - * - * I think this field should be removed in favor of a - * new 802.11n radiotap field "RX chains" that is defined - * as a bitmask. - */ - rx_status.antenna = (le16_to_cpu(phy_info->phy_flags) & - RX_RES_PHY_FLAGS_ANTENNA) - >> RX_RES_PHY_FLAGS_ANTENNA_POS; - /* set the preamble flag if appropriate */ if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) rx_status.flag |= RX_FLAG_SHORTPRE; -- cgit v1.2.3 From 913e25640ca10a82894378cab21a846f722e260c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 21 Jul 2013 08:04:28 +0300 Subject: iwlwifi: mvm: remove obsolete flag in TX command API This API isn't valid any more. It wasn't used anyway. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 700cce731770..d606197bde8f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -91,7 +91,6 @@ * @TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW * @TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration * @TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation - * @TX_CMD_FLG_CTS_ONLY: send CTS only, no data after that * @TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id * @TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped * @TX_CMD_FLG_EXEC_PAPD: execute PAPD @@ -120,7 +119,6 @@ enum iwl_tx_flags { TX_CMD_FLG_RESP_TO_DRV = BIT(21), TX_CMD_FLG_CCMP_AGG = BIT(22), TX_CMD_FLG_TKIP_MIC_DONE = BIT(23), - TX_CMD_FLG_CTS_ONLY = BIT(24), TX_CMD_FLG_DUR = BIT(25), TX_CMD_FLG_FW_DROP = BIT(26), TX_CMD_FLG_EXEC_PAPD = BIT(27), -- cgit v1.2.3 From 2f2ad0d0722d4319f16161022da6e013a075f65b Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 15 Jul 2013 14:57:28 +0300 Subject: iwlwifi: remove duplicate rate scale init code The rate scale windows are cleared twice as part of the init. Cleanup this duplication in both mvm and dvm. Signed-off-by: Eyal Shapira Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/rs.c | 3 --- drivers/net/wireless/iwlwifi/mvm/rs.c | 3 --- 2 files changed, 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 1b693944123b..339538700ab6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -2826,9 +2826,6 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; - for (j = 0; j < LQ_SIZE; j++) - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init for station %d ***\n", sta_id); diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 3856c285c69a..e4a7b3872d33 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2688,9 +2688,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; - for (j = 0; j < LQ_SIZE; j++) - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); IWL_DEBUG_RATE(mvm, "LQ: *** rate scale station global init for station %d ***\n", -- cgit v1.2.3 From 8434925f20fbcac3c2699f33f069c8071bad1214 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Mon, 22 Jul 2013 15:39:26 +0300 Subject: iwlwifi: mvm: Change beacon abort escape time value Set beacon abort escape timer values - 6 beacons in D0 state, 9 beacons in D3 and D0i3. Signed-off-by: Alexander Bondar Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 3 ++- drivers/net/wireless/iwlwifi/mvm/power.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 149347d45d26..060e630b3d82 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -285,7 +285,8 @@ struct iwl_beacon_filter_cmd { #define IWL_BF_ESCAPE_TIMER_MAX 1024 #define IWL_BF_ESCAPE_TIMER_MIN 0 -#define IWL_BA_ESCAPE_TIMER_DEFAULT 3 +#define IWL_BA_ESCAPE_TIMER_DEFAULT 6 +#define IWL_BA_ESCAPE_TIMER_D3 6 #define IWL_BA_ESCAPE_TIMER_MAX 1024 #define IWL_BA_ESCAPE_TIMER_MIN 0 diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 30306a9b0c48..4e7c9f245846 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -123,6 +123,9 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, if (!mvmvif->bf_enabled) return 0; + if (mvm->cur_ucode == IWL_UCODE_WOWLAN) + cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); + iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); } -- cgit v1.2.3 From 6be497f29e207dcfb5d00a692c4e1d4e0fdcac3c Mon Sep 17 00:00:00 2001 From: Eytan Lifshitz Date: Wed, 24 Jul 2013 14:49:18 +0300 Subject: iwlwifi: mvm: add high temperature SKU thermal throttling parameters When the NIC is expected to operate in high temperature, it is advisable to put more aggresive thermal throttling parameters, in order to prevent CT-kill. Signed-off-by: eytan lifshitz Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-7000.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-config.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/tt.c | 29 ++++++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/pcie/drv.c | 6 +++--- 4 files changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 7f61674685c9..76e14c046d94 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -127,6 +127,16 @@ const struct iwl_cfg iwl7260_2ac_cfg = { .nvm_calib_ver = IWL7260_TX_POWER_VERSION, }; +const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { + .name = "Intel(R) Dual Band Wireless AC 7260", + .fw_name_pre = IWL7260_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL7260_NVM_VERSION, + .nvm_calib_ver = IWL7260_TX_POWER_VERSION, + .high_temp = true, +}; + const struct iwl_cfg iwl7260_2n_cfg = { .name = "Intel(R) Dual Band Wireless N 7260", .fw_name_pre = IWL7260_FW_PRE, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 87fe955e2a91..e4d370bff306 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -206,6 +206,7 @@ struct iwl_eeprom_params { * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) * @rx_with_siso_diversity: 1x1 device with rx antenna diversity * @internal_wimax_coex: internal wifi/wimax combo device + * @high_temp: Is this NIC is designated to be in high temperature. * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -234,6 +235,7 @@ struct iwl_cfg { enum iwl_led_mode led_mode; const bool rx_with_siso_diversity; const bool internal_wimax_coex; + bool high_temp; }; /* @@ -284,6 +286,7 @@ extern const struct iwl_cfg iwl135_bgn_cfg; #endif /* CONFIG_IWLDVM */ #if IS_ENABLED(CONFIG_IWLMVM) extern const struct iwl_cfg iwl7260_2ac_cfg; +extern const struct iwl_cfg iwl7260_2ac_cfg_high_temp; extern const struct iwl_cfg iwl7260_2n_cfg; extern const struct iwl_cfg iwl7260_n_cfg; extern const struct iwl_cfg iwl3160_2ac_cfg; diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index f5ba185f09b1..1f3282dff513 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -512,12 +512,39 @@ static const struct iwl_tt_params iwl7000_tt_params = { .support_tx_backoff = true, }; +static const struct iwl_tt_params iwl7000_high_temp_tt_params = { + .ct_kill_entry = 118, + .ct_kill_exit = 96, + .ct_kill_duration = 5, + .dynamic_smps_entry = 114, + .dynamic_smps_exit = 110, + .tx_protection_entry = 114, + .tx_protection_exit = 108, + .tx_backoff = { + {.temperature = 112, .backoff = 300}, + {.temperature = 113, .backoff = 800}, + {.temperature = 114, .backoff = 1500}, + {.temperature = 115, .backoff = 3000}, + {.temperature = 116, .backoff = 5000}, + {.temperature = 117, .backoff = 10000}, + }, + .support_ct_kill = true, + .support_dynamic_smps = true, + .support_tx_protection = true, + .support_tx_backoff = true, +}; + void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) { struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n"); - tt->params = &iwl7000_tt_params; + + if (mvm->cfg->high_temp) + tt->params = &iwl7000_high_temp_tt_params; + else + tt->params = &iwl7000_tt_params; + tt->throttle = false; INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); } diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 81f3ea5b09a4..db6be2491d7c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -272,9 +272,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x08B1, 0x4462, iwl7260_n_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x4870, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x486E, iwl7260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x08B1, 0x4A70, iwl7260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x08B1, 0x4A6E, iwl7260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x08B1, 0x4A6C, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0x4A70, iwl7260_2ac_cfg_high_temp)}, + {IWL_PCI_DEVICE(0x08B1, 0x4A6E, iwl7260_2ac_cfg_high_temp)}, + {IWL_PCI_DEVICE(0x08B1, 0x4A6C, iwl7260_2ac_cfg_high_temp)}, {IWL_PCI_DEVICE(0x08B1, 0x4020, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B2, 0x4220, iwl7260_2n_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0x4420, iwl7260_2n_cfg)}, -- cgit v1.2.3 From 147fc9be81d10e6e863323c0b54e140b42fd1ed6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 28 Jul 2013 11:00:52 +0300 Subject: iwlwifi: mvm: advertise support for DYNAMIC / STATIC SMPS This feature is fully supported by iwlwmvm, so advertise it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 8e4e79a83d14..76cdba65b321 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -153,7 +153,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IEEE80211_HW_SUPPORTS_DYNAMIC_PS | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TIMING_BEACON_ONLY | - IEEE80211_HW_CONNECTION_MONITOR; + IEEE80211_HW_CONNECTION_MONITOR | + IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | + IEEE80211_HW_SUPPORTS_STATIC_SMPS; hw->queues = IWL_MVM_FIRST_AGG_QUEUE; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; -- cgit v1.2.3 From c3afd99fb5adfb31925f0b493a0d4152cd6447cc Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 30 Jul 2013 17:18:15 -0700 Subject: mwifiex: fix adapter pointer dereference issue It has introduced by recent commit 6b41f941d7cd: "mwifiex: handle driver initialization error paths" which adds error path handling for mwifiex_fw_dpc(). release_firmware(adapter->*) is called for success as well as failure paths. In failure paths, adapter is already freed at this point. The issue is fixed by moving mwifiex_free_adapter() call. Reported-by: Dan Carpenter Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 5644c7f86fcb..3402bffdd016 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -414,6 +414,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) struct mwifiex_private *priv; struct mwifiex_adapter *adapter = context; struct mwifiex_fw_image fw; + struct semaphore *sem = adapter->card_sem; + bool init_failed = false; if (!firmware) { dev_err(adapter->dev, @@ -528,15 +530,20 @@ err_dnld_fw: } adapter->surprise_removed = true; mwifiex_terminate_workqueue(adapter); - mwifiex_free_adapter(adapter); + init_failed = true; done: if (adapter->cal_data) { release_firmware(adapter->cal_data); adapter->cal_data = NULL; } - release_firmware(adapter->firmware); + if (adapter->firmware) { + release_firmware(adapter->firmware); + adapter->firmware = NULL; + } complete(&adapter->fw_load); - up(adapter->card_sem); + if (init_failed) + mwifiex_free_adapter(adapter); + up(sem); return; } -- cgit v1.2.3 From 78dfca62f1a0a8d00b155e48197a565da18aebd9 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Tue, 30 Jul 2013 17:18:56 -0700 Subject: mwifiex: populate rates in probe request using cfg80211_scan_request Whenever available, use cfg80211_scan_request to populates rates in outgoing probe request. This will help to advertise band specific rates and fix an issue where 11b rates were advertised in probe request going out on 11a band. This will also ensure that we do not advertise 11b rates while P2P scan is going on. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfp.c | 42 ++++++++++++++++++++++--- drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/scan.c | 63 +++++++++++++++++++++++++++---------- 3 files changed, 85 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 988552dece75..913bb63fd0ad 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -404,11 +404,43 @@ mwifiex_is_rate_auto(struct mwifiex_private *priv) return false; } -/* - * This function gets the supported data rates. - * - * The function works in both Ad-Hoc and infra mode by printing the - * band and returning the data rates. +/* This function gets the supported data rates from bitmask inside + * cfg80211_scan_request. + */ +u32 mwifiex_get_rates_from_cfg80211(struct mwifiex_private *priv, + u8 *rates, u8 radio_type) +{ + struct wiphy *wiphy = priv->adapter->wiphy; + struct cfg80211_scan_request *request = priv->scan_request; + u32 num_rates, rate_mask; + struct ieee80211_supported_band *sband; + int i; + + if (radio_type) { + sband = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (WARN_ON_ONCE(!sband)) + return 0; + rate_mask = request->rates[IEEE80211_BAND_5GHZ]; + } else { + sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + if (WARN_ON_ONCE(!sband)) + return 0; + rate_mask = request->rates[IEEE80211_BAND_2GHZ]; + } + + num_rates = 0; + for (i = 0; i < sband->n_bitrates; i++) { + if ((BIT(i) & rate_mask) == 0) + continue; /* skip rate */ + rates[num_rates++] = (u8)(sband->bitrates[i].bitrate / 5); + } + + return num_rates; +} + +/* This function gets the supported data rates. The function works in + * both Ad-Hoc and infra mode by printing the band and returning the + * data rates. */ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) { diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 9ee3b1b7c365..d2e5ccd891da 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -902,6 +902,8 @@ int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates); u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates); +u32 mwifiex_get_rates_from_cfg80211(struct mwifiex_private *priv, + u8 *rates, u8 radio_type); u8 mwifiex_is_rate_auto(struct mwifiex_private *priv); extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE]; void mwifiex_save_curr_bcn(struct mwifiex_private *priv); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index c447d9bd1aa9..8cf7d50a7603 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -543,6 +543,37 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, return chan_idx; } +/* This function appends rate TLV to scan config command. */ +static int +mwifiex_append_rate_tlv(struct mwifiex_private *priv, + struct mwifiex_scan_cmd_config *scan_cfg_out, + u8 radio) +{ + struct mwifiex_ie_types_rates_param_set *rates_tlv; + u8 rates[MWIFIEX_SUPPORTED_RATES], *tlv_pos; + u32 rates_size; + + memset(rates, 0, sizeof(rates)); + + tlv_pos = (u8 *)scan_cfg_out->tlv_buf + scan_cfg_out->tlv_buf_len; + + if (priv->scan_request) + rates_size = mwifiex_get_rates_from_cfg80211(priv, rates, + radio); + else + rates_size = mwifiex_get_supported_rates(priv, rates); + + dev_dbg(priv->adapter->dev, "info: SCAN_CMD: Rates size = %d\n", + rates_size); + rates_tlv = (struct mwifiex_ie_types_rates_param_set *)tlv_pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16) rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + scan_cfg_out->tlv_buf_len += sizeof(rates_tlv->header) + rates_size; + + return rates_size; +} + /* * This function constructs and sends multiple scan config commands to * the firmware. @@ -564,9 +595,10 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, struct mwifiex_chan_scan_param_set *tmp_chan_list; struct mwifiex_chan_scan_param_set *start_chan; - u32 tlv_idx; + u32 tlv_idx, rates_size; u32 total_scan_time; u32 done_early; + u8 radio_type; if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) { dev_dbg(priv->adapter->dev, @@ -591,6 +623,7 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, tlv_idx = 0; total_scan_time = 0; + radio_type = 0; chan_tlv_out->header.len = 0; start_chan = tmp_chan_list; done_early = false; @@ -612,6 +645,7 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, continue; } + radio_type = tmp_chan_list->radio_type; dev_dbg(priv->adapter->dev, "info: Scan: Chan(%3d), Radio(%d)," " Mode(%d, %d), Dur(%d)\n", @@ -692,6 +726,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, break; } + rates_size = mwifiex_append_rate_tlv(priv, scan_cfg_out, + radio_type); + priv->adapter->scan_channels = start_chan; /* Send the scan command to the firmware with the specified @@ -699,6 +736,14 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN, HostCmd_ACT_GEN_SET, 0, scan_cfg_out); + + /* rate IE is updated per scan command but same starting + * pointer is used each time so that rate IE from earlier + * scan_cfg_out->buf is overwritten with new one. + */ + scan_cfg_out->tlv_buf_len -= + sizeof(struct mwifiex_ie_types_header) + rates_size; + if (ret) break; } @@ -741,7 +786,6 @@ mwifiex_config_scan(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_ie_types_num_probes *num_probes_tlv; struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; - struct mwifiex_ie_types_rates_param_set *rates_tlv; u8 *tlv_pos; u32 num_probes; u32 ssid_len; @@ -753,8 +797,6 @@ mwifiex_config_scan(struct mwifiex_private *priv, u8 radio_type; int i; u8 ssid_filter; - u8 rates[MWIFIEX_SUPPORTED_RATES]; - u32 rates_size; struct mwifiex_ie_types_htcap *ht_cap; /* The tlv_buf_len is calculated for each scan command. The TLVs added @@ -889,19 +931,6 @@ mwifiex_config_scan(struct mwifiex_private *priv, } - /* Append rates tlv */ - memset(rates, 0, sizeof(rates)); - - rates_size = mwifiex_get_supported_rates(priv, rates); - - rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos; - rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); - rates_tlv->header.len = cpu_to_le16((u16) rates_size); - memcpy(rates_tlv->rates, rates, rates_size); - tlv_pos += sizeof(rates_tlv->header) + rates_size; - - dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size); - if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && (priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN)) { -- cgit v1.2.3 From d28e5e5d96cde070d794553d16702ca6879bb7a2 Mon Sep 17 00:00:00 2001 From: Mark Schulte Date: Wed, 31 Jul 2013 19:30:14 -0700 Subject: rtlwifi: rtl8192cu: fix function declaration header Move rtl92cu_update_hal_rate_tbl declaration to hw.h to correspond with function definition in hw.c. Fixes sparse warning in hw.c warning: symbol 'rtl92cu_update_hal_rate_tbl' was not declared. Signed-off-by: Mark Schulte Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192cu/hw.h | 3 +++ drivers/net/wireless/rtlwifi/rtl8192cu/sw.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h index 8e3ec1e25644..0f7812e0c8aa 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h @@ -109,5 +109,8 @@ void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw); +void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h index 262e1e4c6e5b..a1310abd0d54 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h @@ -49,8 +49,5 @@ bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); -void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, - u8 rssi_level); #endif -- cgit v1.2.3 From c1de4a9557d9e25e41fc4ba034b9659152205539 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 1 Jul 2013 14:19:30 +0200 Subject: iwl4965: better skb management in rx path 4965 version of Eric patch "iwl3945: better skb management in rx path". It fixes several problems : 1) skb->truesize is underestimated. We really consume PAGE_SIZE bytes for a fragment, not the frame length. 2) 128 bytes of initial headroom is a bit low and forces reallocations. 3) We can avoid consuming a full page for small enough frames. Signed-off-by: Stanislaw Gruszka Acked-by: Eric Dumazet Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/4965-mac.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index b9b2bb51e605..c4b22e190a54 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -574,9 +574,11 @@ il4965_translate_rx_status(struct il_priv *il, u32 decrypt_in) return decrypt_out; } +#define SMALL_PACKET_SIZE 256 + static void il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr, - u16 len, u32 ampdu_status, struct il_rx_buf *rxb, + u32 len, u32 ampdu_status, struct il_rx_buf *rxb, struct ieee80211_rx_status *stats) { struct sk_buff *skb; @@ -598,21 +600,25 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr, il_set_decrypted_flag(il, hdr, ampdu_status, stats)) return; - skb = dev_alloc_skb(128); + skb = dev_alloc_skb(SMALL_PACKET_SIZE); if (!skb) { IL_ERR("dev_alloc_skb failed\n"); return; } - skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len, - len); + if (len <= SMALL_PACKET_SIZE) { + memcpy(skb_put(skb, len), hdr, len); + } else { + skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), + len, PAGE_SIZE << il->hw_params.rx_page_order); + il->alloc_rxb_page--; + rxb->page = NULL; + } il_update_stats(il, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(il->hw, skb); - il->alloc_rxb_page--; - rxb->page = NULL; } /* Called for N_RX (legacy ABG frames), or -- cgit v1.2.3 From 4eba10cc8086e3dde09f00e44b43ff4f8624d527 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 29 Jul 2013 16:04:49 +0530 Subject: ath9k: Add a debugfs file for antenna diversity Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 87454f6c7b4f..d8764ae3371e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -321,6 +321,68 @@ static const struct file_operations fops_ant_diversity = { .llseek = default_llseek, }; +static ssize_t read_file_antenna_diversity(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN]; + struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; + unsigned int len = 0, size = 1024; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) { + len += snprintf(buf + len, size - len, "%s\n", + "Antenna Diversity Combining is disabled"); + goto exit; + } + + len += snprintf(buf + len, size - len, "%30s%15s\n", + "MAIN", "ALT"); + len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + "RECV CNT", + as_main->recv_cnt, + as_alt->recv_cnt); + len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + "LNA1", + as_main->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1], + as_alt->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1]); + len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + "LNA2", + as_main->lna_config_cnt[ATH_ANT_DIV_COMB_LNA2], + as_alt->lna_config_cnt[ATH_ANT_DIV_COMB_LNA2]); + len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + "LNA1 + LNA2", + as_main->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], + as_alt->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); + len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + "LNA1 - LNA2", + as_main->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], + as_alt->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); +exit: + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_antenna_diversity = { + .read = read_file_antenna_diversity, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1816,6 +1878,8 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); debugfs_create_file("diversity", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_ant_diversity); + debugfs_create_file("antenna_diversity", S_IRUSR, + sc->debug.debugfs_phy, sc, &fops_antenna_diversity); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_btcoex); -- cgit v1.2.3 From 3fbaf4c55b2bf123085ab3adf5da97bc9a555060 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 1 Aug 2013 11:53:17 +0530 Subject: ath9k: Do a quick scan only when scan_not_start is true Right now, it is being done for all cases. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 20 ++++++++++++-------- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/debug.h | 13 +++++++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 664844c5d3d5..f2cd96063a00 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -561,10 +561,16 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) antcomb->total_pkt_count++; antcomb->main_total_rssi += main_rssi; antcomb->alt_total_rssi += alt_rssi; - if (main_ant_conf == rx_ant_conf) + + if (main_ant_conf == rx_ant_conf) { antcomb->main_recv_cnt++; - else + ANT_STAT_INC(ANT_MAIN, recv_cnt); + ANT_LNA_INC(ANT_MAIN, rx_ant_conf); + } else { antcomb->alt_recv_cnt++; + ANT_STAT_INC(ANT_ALT, recv_cnt); + ANT_LNA_INC(ANT_ALT, rx_ant_conf); + } } /* Short scan check */ @@ -753,14 +759,12 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } goto div_comb_done; } + ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, + main_rssi_avg, alt_rssi_avg, + alt_ratio); + antcomb->quick_scan_cnt++; } - ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, - main_rssi_avg, alt_rssi_avg, - alt_ratio); - - antcomb->quick_scan_cnt++; - div_comb_done: ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio); ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 76e38d3540c0..ed8f8efb6ecf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -609,7 +609,7 @@ struct ath_ant_comb { int rssi_third; bool alt_good; int quick_scan_cnt; - int main_conf; + enum ath9k_ant_div_comb_lna_conf main_conf; enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf; enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf; bool first_ratio; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index fc679198a0f3..a879e451dc46 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -28,9 +28,13 @@ struct fft_sample_tlv; #ifdef CONFIG_ATH9K_DEBUGFS #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ #define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++ +#define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++ +#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_config_cnt[c]++; #else #define TX_STAT_INC(q, c) do { } while (0) #define RESET_STAT_INC(sc, type) do { } while (0) +#define ANT_STAT_INC(i, c) do { } while (0) +#define ANT_LNA_INC(i, c) do { } while (0) #endif enum ath_reset_type { @@ -243,11 +247,20 @@ struct ath_rx_stats { u32 rx_spectral; }; +#define ANT_MAIN 0 +#define ANT_ALT 1 + +struct ath_antenna_stats { + u32 recv_cnt; + u32 lna_config_cnt[4]; +}; + struct ath_stats { struct ath_interrupt_stats istats; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_rx_stats rxstats; struct ath_dfs_stats dfs_stats; + struct ath_antenna_stats ant_stats[2]; u32 reset[__RESET_TYPE_MAX]; }; -- cgit v1.2.3 From 9383be420460908df0118d54894ef65317821f3a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 1 Aug 2013 11:53:18 +0530 Subject: ath9k: Use a subroutine to check for short scan Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 37 ++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index f2cd96063a00..69674d4ee496 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -540,6 +540,27 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, } } +static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb) +{ + int alt_ratio; + + if (!antcomb->scan || !antcomb->alt_good) + return false; + + if (time_after(jiffies, antcomb->scan_start_time + + msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) + return true; + + if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { + alt_ratio = ((antcomb->alt_recv_cnt * 100) / + antcomb->total_pkt_count); + if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) + return true; + } + + return false; +} + void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) { struct ath_hw_antcomb_conf div_ant_conf; @@ -574,22 +595,10 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } /* Short scan check */ - if (antcomb->scan && antcomb->alt_good) { - if (time_after(jiffies, antcomb->scan_start_time + - msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) - short_scan = true; - else - if (antcomb->total_pkt_count == - ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { - alt_ratio = ((antcomb->alt_recv_cnt * 100) / - antcomb->total_pkt_count); - if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) - short_scan = true; - } - } + short_scan = ath_ant_short_scan_check(antcomb); if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || - rs->rs_moreaggr) && !short_scan) + rs->rs_moreaggr) && !short_scan) return; if (antcomb->total_pkt_count) { -- cgit v1.2.3 From 552bde40dd4c5d5b3e48e950e6bf2bfb0de6ab1f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 1 Aug 2013 11:53:19 +0530 Subject: ath9k: Add ALT check for cards with GROUP-3 config Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 50 +++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 69674d4ee496..cfb43ccc0852 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -25,28 +25,45 @@ static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); } -static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio, - int curr_main_set, int curr_alt_set, - int alt_rssi_avg, int main_rssi_avg) +static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf conf, + int alt_ratio, int alt_rssi_avg, + int main_rssi_avg) { - bool result = false; - switch (div_group) { + bool result, set1, set2; + + result = set1 = set2 = false; + + if (conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2 && + conf.alt_lna_conf == ATH_ANT_DIV_COMB_LNA1) + set1 = true; + + if (conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1 && + conf.alt_lna_conf == ATH_ANT_DIV_COMB_LNA2) + set2 = true; + + switch (conf.div_group) { case 0: if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) result = true; break; case 1: case 2: - if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) && - (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) && - (alt_rssi_avg >= (main_rssi_avg - 5))) || - ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) && - (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) && - (alt_rssi_avg >= (main_rssi_avg - 2)))) && - (alt_rssi_avg >= 4)) + if (alt_rssi_avg < 4) + break; + + if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) || + (set2 && (alt_rssi_avg >= (main_rssi_avg - 2)))) result = true; - else - result = false; + + break; + case 3: + if (alt_rssi_avg < 4) + break; + + if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) || + (set2 && (alt_rssi_avg >= (main_rssi_avg + 3)))) + result = true; + break; } @@ -632,9 +649,8 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if (!antcomb->scan) { - if (ath_ant_div_comb_alt_check(div_ant_conf.div_group, - alt_ratio, curr_main_set, curr_alt_set, - alt_rssi_avg, main_rssi_avg)) { + if (ath_ant_div_comb_alt_check(div_ant_conf, alt_ratio, + alt_rssi_avg, main_rssi_avg)) { if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { /* Switch main and alt LNA */ div_ant_conf.main_lna_conf = -- cgit v1.2.3 From ef999114ee1e39236fac49903c661e9c019b03ee Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 1 Aug 2013 11:53:20 +0530 Subject: ath9k: Use a subroutine to try LNA switch Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 92 ++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index cfb43ccc0852..ee5f9befefa1 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -25,7 +25,7 @@ static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); } -static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf conf, +static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf, int alt_ratio, int alt_rssi_avg, int main_rssi_avg) { @@ -33,15 +33,15 @@ static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf conf, result = set1 = set2 = false; - if (conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2 && - conf.alt_lna_conf == ATH_ANT_DIV_COMB_LNA1) + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 && + conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1) set1 = true; - if (conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1 && - conf.alt_lna_conf == ATH_ANT_DIV_COMB_LNA2) + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 && + conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2) set2 = true; - switch (conf.div_group) { + switch (conf->div_group) { case 0: if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) result = true; @@ -557,6 +557,43 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, } } +static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf, + int alt_ratio, int alt_rssi_avg, + int main_rssi_avg, int curr_main_set, + int curr_alt_set) +{ + bool ret = false; + + if (ath_ant_div_comb_alt_check(div_ant_conf, alt_ratio, + alt_rssi_avg, main_rssi_avg)) { + if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { + /* + * Switch main and alt LNA. + */ + div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) { + div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + } + + ret = true; + } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) && + (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) { + /* + Set alt to another LNA. + */ + if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) + div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) + div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + + ret = true; + } + + return ret; +} + static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb) { int alt_ratio; @@ -587,7 +624,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) int main_rssi = rs->rs_rssi_ctl0; int alt_rssi = rs->rs_rssi_ctl1; int rx_ant_conf, main_ant_conf; - bool short_scan = false; + bool short_scan = false, ret; rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) & ATH_ANT_RX_MASK; @@ -627,11 +664,9 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) antcomb->total_pkt_count); } - ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf); curr_alt_set = div_ant_conf.alt_lna_conf; curr_main_set = div_ant_conf.main_lna_conf; - antcomb->count++; if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { @@ -649,40 +684,17 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if (!antcomb->scan) { - if (ath_ant_div_comb_alt_check(div_ant_conf, alt_ratio, - alt_rssi_avg, main_rssi_avg)) { - if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { - /* Switch main and alt LNA */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) { - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - } - - goto div_comb_done; - } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) && - (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) { - /* Set alt to another LNA */ - if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - - goto div_comb_done; - } - - if ((alt_rssi_avg < (main_rssi_avg + - div_ant_conf.lna1_lna2_delta))) + ret = ath_ant_try_switch(&div_ant_conf, alt_ratio, + alt_rssi_avg, main_rssi_avg, + curr_main_set, curr_alt_set); + if (ret) goto div_comb_done; } + if (!antcomb->scan && + (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta))) + goto div_comb_done; + if (!antcomb->scan_not_start) { switch (curr_alt_set) { case ATH_ANT_DIV_COMB_LNA2: -- cgit v1.2.3 From 5f800ffbbb29c51fbcd886080dc3b0a6ab20b9b9 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 1 Aug 2013 11:53:21 +0530 Subject: ath9k: Use a helper function for checking LNA options Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 166 +++++++++++++++---------------- 1 file changed, 79 insertions(+), 87 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index ee5f9befefa1..0b157ad91255 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -557,6 +557,79 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, } } +static void ath_ant_try_scan(struct ath_ant_comb *antcomb, + struct ath_hw_antcomb_conf *conf, + int curr_alt_set, int alt_rssi_avg, + int main_rssi_avg) +{ + switch (curr_alt_set) { + case ATH_ANT_DIV_COMB_LNA2: + antcomb->rssi_lna2 = alt_rssi_avg; + antcomb->rssi_lna1 = main_rssi_avg; + antcomb->scan = true; + /* set to A+B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; + break; + case ATH_ANT_DIV_COMB_LNA1: + antcomb->rssi_lna1 = alt_rssi_avg; + antcomb->rssi_lna2 = main_rssi_avg; + antcomb->scan = true; + /* set to A+B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; + break; + case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: + antcomb->rssi_add = alt_rssi_avg; + antcomb->scan = true; + /* set to A-B */ + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; + break; + case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2: + antcomb->rssi_sub = alt_rssi_avg; + antcomb->scan = false; + if (antcomb->rssi_lna2 > + (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { + /* use LNA2 as main LNA */ + if ((antcomb->rssi_add > antcomb->rssi_lna1) && + (antcomb->rssi_add > antcomb->rssi_sub)) { + /* set to A+B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; + } else if (antcomb->rssi_sub > + antcomb->rssi_lna1) { + /* set to A-B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; + } else { + /* set to LNA1 */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + } + } else { + /* use LNA1 as main LNA */ + if ((antcomb->rssi_add > antcomb->rssi_lna2) && + (antcomb->rssi_add > antcomb->rssi_sub)) { + /* set to A+B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; + } else if (antcomb->rssi_sub > + antcomb->rssi_lna1) { + /* set to A-B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; + } else { + /* set to LNA2 */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + } + } + break; + default: + break; + } +} + static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf, int alt_ratio, int alt_rssi_avg, int main_rssi_avg, int curr_main_set, @@ -696,103 +769,22 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) goto div_comb_done; if (!antcomb->scan_not_start) { - switch (curr_alt_set) { - case ATH_ANT_DIV_COMB_LNA2: - antcomb->rssi_lna2 = alt_rssi_avg; - antcomb->rssi_lna1 = main_rssi_avg; - antcomb->scan = true; - /* set to A+B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; - break; - case ATH_ANT_DIV_COMB_LNA1: - antcomb->rssi_lna1 = alt_rssi_avg; - antcomb->rssi_lna2 = main_rssi_avg; - antcomb->scan = true; - /* set to A+B */ - div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; - break; - case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: - antcomb->rssi_add = alt_rssi_avg; - antcomb->scan = true; - /* set to A-B */ - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; - break; - case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2: - antcomb->rssi_sub = alt_rssi_avg; - antcomb->scan = false; - if (antcomb->rssi_lna2 > - (antcomb->rssi_lna1 + - ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { - /* use LNA2 as main LNA */ - if ((antcomb->rssi_add > antcomb->rssi_lna1) && - (antcomb->rssi_add > antcomb->rssi_sub)) { - /* set to A+B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; - } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { - /* set to A-B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; - } else { - /* set to LNA1 */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - } - } else { - /* use LNA1 as main LNA */ - if ((antcomb->rssi_add > antcomb->rssi_lna2) && - (antcomb->rssi_add > antcomb->rssi_sub)) { - /* set to A+B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; - } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { - /* set to A-B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; - } else { - /* set to LNA2 */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - } - } - break; - default: - break; - } + ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set, + alt_rssi_avg, main_rssi_avg); } else { if (!antcomb->alt_good) { antcomb->scan_not_start = false; /* Set alt to another LNA */ if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) { div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; + ATH_ANT_DIV_COMB_LNA2; div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; + ATH_ANT_DIV_COMB_LNA1; } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) { div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; + ATH_ANT_DIV_COMB_LNA1; div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; + ATH_ANT_DIV_COMB_LNA2; } goto div_comb_done; } -- cgit v1.2.3 From 9ddf03017917970c53da577b263e1686ef5c9652 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 1 Aug 2013 11:53:22 +0530 Subject: ath9k: Simplify checks in quick_scan There is a function to do a ratio comparison for ALT, so make use of it. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 0b157ad91255..6495fc620b40 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -164,11 +164,11 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->first_ratio = false; } else { - if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || - (alt_rssi_avg > main_rssi_avg)) && - (antcomb->total_pkt_count > 50)) + if (ath_is_alt_ant_ratio_better(alt_ratio, + ATH_ANT_DIV_COMB_LNA1_DELTA_HI, + 0, + main_rssi_avg, alt_rssi_avg, + antcomb->total_pkt_count)) antcomb->first_ratio = true; else antcomb->first_ratio = false; @@ -219,11 +219,11 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->second_ratio = false; } else { - if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || - (alt_rssi_avg > main_rssi_avg)) && - (antcomb->total_pkt_count > 50)) + if (ath_is_alt_ant_ratio_better(alt_ratio, + ATH_ANT_DIV_COMB_LNA1_DELTA_HI, + 0, + main_rssi_avg, alt_rssi_avg, + antcomb->total_pkt_count)) antcomb->second_ratio = true; else antcomb->second_ratio = false; -- cgit v1.2.3 From 37133002f5263153e71a509191fbb8951c1de3e0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 1 Aug 2013 11:53:23 +0530 Subject: ath9k: Use a subroutine to calculate ALT ratio Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 173 ++++++++++++++----------------- 1 file changed, 79 insertions(+), 94 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 6495fc620b40..ea4ee08cddf2 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -125,6 +125,74 @@ static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb, } } +static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb, + struct ath_hw_antcomb_conf *conf) +{ + /* set alt to the conf with maximun ratio */ + if (antcomb->first_ratio && antcomb->second_ratio) { + if (antcomb->rssi_second > antcomb->rssi_third) { + /* first alt*/ + if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2*/ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = + antcomb->first_quick_scan_conf; + } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) { + /* Set alt LNA1 or LNA2 */ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + } else { + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = antcomb->second_quick_scan_conf; + } + } else if (antcomb->first_ratio) { + /* first alt */ + if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = antcomb->first_quick_scan_conf; + } else if (antcomb->second_ratio) { + /* second alt */ + if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = antcomb->second_quick_scan_conf; + } else { + /* main is largest */ + if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = antcomb->main_conf; + } +} + static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, struct ath_hw_antcomb_conf *div_ant_conf, int main_rssi_avg, int alt_rssi_avg, @@ -181,17 +249,21 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, antcomb->rssi_first = main_rssi_avg; antcomb->rssi_third = alt_rssi_avg; - if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) + switch(antcomb->second_quick_scan_conf) { + case ATH_ANT_DIV_COMB_LNA1: antcomb->rssi_lna1 = alt_rssi_avg; - else if (antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2) + break; + case ATH_ANT_DIV_COMB_LNA2: antcomb->rssi_lna2 = alt_rssi_avg; - else if (antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) { + break; + case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) antcomb->rssi_lna2 = main_rssi_avg; else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) antcomb->rssi_lna1 = main_rssi_avg; + break; + default: + break; } if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + @@ -229,95 +301,8 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, antcomb->second_ratio = false; } - /* set alt to the conf with maximun ratio */ - if (antcomb->first_ratio && antcomb->second_ratio) { - if (antcomb->rssi_second > antcomb->rssi_third) { - /* first alt*/ - if ((antcomb->first_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1) || - (antcomb->first_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2*/ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->first_quick_scan_conf; - } else if ((antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1) || - (antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2)) { - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - } else { - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->second_quick_scan_conf; - } - } else if (antcomb->first_ratio) { - /* first alt */ - if ((antcomb->first_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1) || - (antcomb->first_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->first_quick_scan_conf; - } else if (antcomb->second_ratio) { - /* second alt */ - if ((antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1) || - (antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->second_quick_scan_conf; - } else { - /* main is largest */ - if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) || - (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = antcomb->main_conf; - } + ath_ant_set_alt_ratio(antcomb, div_ant_conf); + break; default: break; -- cgit v1.2.3 From e3d5291436ff9efeeb968459724af5332305dded Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 1 Aug 2013 20:57:06 +0530 Subject: ath9k: Add statistics for antenna diversity Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 18 ++++--- drivers/net/wireless/ath/ath9k/debug.c | 85 ++++++++++++++++++++++++++------ drivers/net/wireless/ath/ath9k/debug.h | 20 +++++--- 3 files changed, 95 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index ea4ee08cddf2..291ca019d37b 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -695,15 +695,18 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) antcomb->main_total_rssi += main_rssi; antcomb->alt_total_rssi += alt_rssi; - if (main_ant_conf == rx_ant_conf) { + if (main_ant_conf == rx_ant_conf) antcomb->main_recv_cnt++; - ANT_STAT_INC(ANT_MAIN, recv_cnt); - ANT_LNA_INC(ANT_MAIN, rx_ant_conf); - } else { + else antcomb->alt_recv_cnt++; - ANT_STAT_INC(ANT_ALT, recv_cnt); - ANT_LNA_INC(ANT_ALT, rx_ant_conf); - } + } + + if (main_ant_conf == rx_ant_conf) { + ANT_STAT_INC(ANT_MAIN, recv_cnt); + ANT_LNA_INC(ANT_MAIN, rx_ant_conf); + } else { + ANT_STAT_INC(ANT_ALT, recv_cnt); + ANT_LNA_INC(ANT_ALT, rx_ant_conf); } /* Short scan check */ @@ -782,6 +785,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) div_comb_done: ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio); ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf); + ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg); antcomb->scan_start_time = jiffies; antcomb->total_pkt_count = 0; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index d8764ae3371e..e744d9747697 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -321,6 +321,20 @@ static const struct file_operations fops_ant_diversity = { .llseek = default_llseek, }; +void ath9k_debug_stat_ant(struct ath_softc *sc, + struct ath_hw_antcomb_conf *div_ant_conf, + int main_rssi_avg, int alt_rssi_avg) +{ + struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN]; + struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; + + as_main->lna_attempt_cnt[div_ant_conf->main_lna_conf]++; + as_alt->lna_attempt_cnt[div_ant_conf->alt_lna_conf]++; + + as_main->rssi_avg = main_rssi_avg; + as_alt->rssi_avg = alt_rssi_avg; +} + static ssize_t read_file_antenna_diversity(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -330,9 +344,14 @@ static ssize_t read_file_antenna_diversity(struct file *file, struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN]; struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; + struct ath_hw_antcomb_conf div_ant_conf; unsigned int len = 0, size = 1024; ssize_t retval = 0; char *buf; + char *lna_conf_str[4] = {"LNA1_MINUS_LNA2", + "LNA2", + "LNA1", + "LNA1_PLUS_LNA2"}; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -344,28 +363,66 @@ static ssize_t read_file_antenna_diversity(struct file *file, goto exit; } + ath9k_ps_wakeup(sc); + ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); + len += snprintf(buf + len, size - len, "Current MAIN config : %s\n", + lna_conf_str[div_ant_conf.main_lna_conf]); + len += snprintf(buf + len, size - len, "Current ALT config : %s\n", + lna_conf_str[div_ant_conf.alt_lna_conf]); + len += snprintf(buf + len, size - len, "Average MAIN RSSI : %d\n", + as_main->rssi_avg); + len += snprintf(buf + len, size - len, "Average ALT RSSI : %d\n\n", + as_alt->rssi_avg); + ath9k_ps_restore(sc); + + len += snprintf(buf + len, size - len, "Packet Receive Cnt:\n"); + len += snprintf(buf + len, size - len, "-------------------\n"); + len += snprintf(buf + len, size - len, "%30s%15s\n", "MAIN", "ALT"); - len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", - "RECV CNT", + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "TOTAL COUNT", as_main->recv_cnt, as_alt->recv_cnt); - len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1", + as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1], + as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]); + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA2", + as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2], + as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]); + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1 + LNA2", + as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], + as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1 - LNA2", + as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], + as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); + + len += snprintf(buf + len, size - len, "\nLNA Config Attempts:\n"); + len += snprintf(buf + len, size - len, "--------------------\n"); + + len += snprintf(buf + len, size - len, "%30s%15s\n", + "MAIN", "ALT"); + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", "LNA1", - as_main->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1], - as_alt->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1]); - len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1], + as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]); + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", "LNA2", - as_main->lna_config_cnt[ATH_ANT_DIV_COMB_LNA2], - as_alt->lna_config_cnt[ATH_ANT_DIV_COMB_LNA2]); - len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2], + as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]); + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", "LNA1 + LNA2", - as_main->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], - as_alt->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); - len += snprintf(buf + len, size - len, "%-15s%15d%15d\n", + as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], + as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); + len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", "LNA1 - LNA2", - as_main->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], - as_alt->lna_config_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); + as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], + as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); + exit: if (len > size) len = size; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index a879e451dc46..01c5c6a22e1b 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -29,7 +29,7 @@ struct fft_sample_tlv; #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ #define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++ #define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++ -#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_config_cnt[c]++; +#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_recv_cnt[c]++; #else #define TX_STAT_INC(q, c) do { } while (0) #define RESET_STAT_INC(sc, type) do { } while (0) @@ -252,7 +252,9 @@ struct ath_rx_stats { struct ath_antenna_stats { u32 recv_cnt; - u32 lna_config_cnt[4]; + u32 rssi_avg; + u32 lna_recv_cnt[4]; + u32 lna_attempt_cnt[4]; }; struct ath_stats { @@ -294,10 +296,11 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); - void ath_debug_send_fft_sample(struct ath_softc *sc, struct fft_sample_tlv *fft_sample); - +void ath9k_debug_stat_ant(struct ath_softc *sc, + struct ath_hw_antcomb_conf *div_ant_conf, + int main_rssi_avg, int alt_rssi_avg); #else #define RX_STAT_INC(c) /* NOP */ @@ -310,12 +313,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah) 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) { } - static inline void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, @@ -323,10 +324,15 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc, unsigned int flags) { } - static inline void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { +} +static inline void ath9k_debug_stat_ant(struct ath_softc *sc, + struct ath_hw_antcomb_conf *div_ant_conf, + int main_rssi_avg, int alt_rssi_avg) +{ + } #endif /* CONFIG_ATH9K_DEBUGFS */ -- cgit v1.2.3 From 605f81aae7cfe4f61d0a5ee5f588f4956413858c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 31 Jul 2013 10:47:56 +0200 Subject: ath10k: implement rx checksum offloading HW supports L3/L4 rx checksum offloading. This should reduce CPU load and improve performance on slow host machines. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 04f08d946479..e784c40b904b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -804,6 +804,37 @@ static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb) return false; } +static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) +{ + struct htt_rx_desc *rxd; + u32 flags, info; + bool is_ip4, is_ip6; + bool is_tcp, is_udp; + bool ip_csum_ok, tcpudp_csum_ok; + + rxd = (void *)skb->data - sizeof(*rxd); + flags = __le32_to_cpu(rxd->attention.flags); + info = __le32_to_cpu(rxd->msdu_start.info1); + + is_ip4 = !!(info & RX_MSDU_START_INFO1_IPV4_PROTO); + is_ip6 = !!(info & RX_MSDU_START_INFO1_IPV6_PROTO); + is_tcp = !!(info & RX_MSDU_START_INFO1_TCP_PROTO); + is_udp = !!(info & RX_MSDU_START_INFO1_UDP_PROTO); + ip_csum_ok = !(flags & RX_ATTENTION_FLAGS_IP_CHKSUM_FAIL); + tcpudp_csum_ok = !(flags & RX_ATTENTION_FLAGS_TCP_UDP_CHKSUM_FAIL); + + if (!is_ip4 && !is_ip6) + return CHECKSUM_NONE; + if (!is_tcp && !is_udp) + return CHECKSUM_NONE; + if (!ip_csum_ok) + return CHECKSUM_NONE; + if (!tcpudp_csum_ok) + return CHECKSUM_NONE; + + return CHECKSUM_UNNECESSARY; +} + static void ath10k_htt_rx_handler(struct ath10k_htt *htt, struct htt_rx_indication *rx) { @@ -815,6 +846,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, u8 *fw_desc; int i, j; int ret; + int ip_summed; memset(&info, 0, sizeof(info)); @@ -889,6 +921,11 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, continue; } + /* The skb is not yet processed and it may be + * reallocated. Since the offload is in the original + * skb extract the checksum now and assign it later */ + ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); + info.skb = msdu_head; info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head); info.signal = ATH10K_DEFAULT_NOISE_FLOOR; @@ -914,6 +951,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, if (ath10k_htt_rx_hdr_is_amsdu((void *)info.skb->data)) ath10k_dbg(ATH10K_DBG_HTT, "htt mpdu is amsdu\n"); + info.skb->ip_summed = ip_summed; + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt mpdu: ", info.skb->data, info.skb->len); ath10k_process_rx(htt->ar, &info); @@ -980,6 +1019,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, info.status = HTT_RX_IND_MPDU_STATUS_OK; info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0), RX_MPDU_START_INFO0_ENCRYPT_TYPE); + info.skb->ip_summed = ath10k_htt_rx_get_csum_state(info.skb); if (tkip_mic_err) { ath10k_warn("tkip mic error\n"); -- cgit v1.2.3 From 7c199997ded6c90fd45a50f49e9ac63adaacb95e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 31 Jul 2013 10:47:57 +0200 Subject: ath10k: implement tx checksum offloading HW supports L3/L4 tx checksum offloading. This should reduce CPU load and improve performance on slow host machines. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 2 ++ drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index dc3f3e8de32b..656c2546b294 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -465,6 +465,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) flags1 = 0; flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); + flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; + flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; frags_paddr = ATH10K_SKB_CB(txfrag)->paddr; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 344ad2772de8..57843377fa0b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3309,6 +3309,8 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->iface_combinations = &ath10k_if_comb; ar->hw->wiphy->n_iface_combinations = 1; + ar->hw->netdev_features = NETIF_F_HW_CSUM; + ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ath10k_reg_notifier); if (ret) { -- cgit v1.2.3 From 2e1dea40512d7e99a7e91ac88a6f434a5d7c6fde Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 31 Jul 2013 10:32:40 +0200 Subject: ath10k: implement get_survey() This implements a limited subset of what can be reported in the survey dump. This can be used for assessing approximate channel load, e.g. for automatic channel selection. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 7 ++++ drivers/net/wireless/ath/ath10k/mac.c | 36 ++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 75 +++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/wmi.h | 5 +++ 4 files changed, 122 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ff42bb744d9e..e4bba563ed42 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -38,6 +38,7 @@ #define ATH10K_SCAN_ID 0 #define WMI_READY_TIMEOUT (5 * HZ) #define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ) +#define ATH10K_NUM_CHANS 38 /* Antenna noise floor */ #define ATH10K_DEFAULT_NOISE_FLOOR -95 @@ -375,6 +376,12 @@ struct ath10k { struct work_struct restart_work; + /* cycle count is reported twice for each visited channel during scan. + * access protected by data_lock */ + u32 survey_last_rx_clear_count; + u32 survey_last_cycle_count; + struct survey_info survey[ATH10K_NUM_CHANS]; + #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 57843377fa0b..9ea31f89b748 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2934,6 +2934,41 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw) mutex_unlock(&ar->conf_mutex); } +static int ath10k_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct ath10k *ar = hw->priv; + struct ieee80211_supported_band *sband; + struct survey_info *ar_survey = &ar->survey[idx]; + int ret = 0; + + mutex_lock(&ar->conf_mutex); + + sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; + if (sband && idx >= sband->n_channels) { + idx -= sband->n_channels; + sband = NULL; + } + + if (!sband) + sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; + + if (!sband || idx >= sband->n_channels) { + ret = -ENOENT; + goto exit; + } + + spin_lock_bh(&ar->data_lock); + memcpy(survey, ar_survey, sizeof(*survey)); + spin_unlock_bh(&ar->data_lock); + + survey->channel = &sband->channels[idx]; + +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + static const struct ieee80211_ops ath10k_ops = { .tx = ath10k_tx, .start = ath10k_start, @@ -2955,6 +2990,7 @@ static const struct ieee80211_ops ath10k_ops = { .flush = ath10k_flush, .tx_last_beacon = ath10k_tx_last_beacon, .restart_complete = ath10k_restart_complete, + .get_survey = ath10k_get_survey, #ifdef CONFIG_PM .suspend = ath10k_suspend, .resume = ath10k_resume, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1cbcb2ea12f7..55f90c761868 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -390,9 +390,82 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) return 0; } +static int freq_to_idx(struct ath10k *ar, int freq) +{ + struct ieee80211_supported_band *sband; + int band, ch, idx = 0; + + for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { + sband = ar->hw->wiphy->bands[band]; + if (!sband) + continue; + + for (ch = 0; ch < sband->n_channels; ch++, idx++) + if (sband->channels[ch].center_freq == freq) + goto exit; + } + +exit: + return idx; +} + static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_CHAN_INFO_EVENTID\n"); + struct wmi_chan_info_event *ev; + struct survey_info *survey; + u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count; + int idx; + + ev = (struct wmi_chan_info_event *)skb->data; + + err_code = __le32_to_cpu(ev->err_code); + freq = __le32_to_cpu(ev->freq); + cmd_flags = __le32_to_cpu(ev->cmd_flags); + noise_floor = __le32_to_cpu(ev->noise_floor); + rx_clear_count = __le32_to_cpu(ev->rx_clear_count); + cycle_count = __le32_to_cpu(ev->cycle_count); + + ath10k_dbg(ATH10K_DBG_WMI, + "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n", + err_code, freq, cmd_flags, noise_floor, rx_clear_count, + cycle_count); + + spin_lock_bh(&ar->data_lock); + + if (!ar->scan.in_progress) { + ath10k_warn("chan info event without a scan request?\n"); + goto exit; + } + + idx = freq_to_idx(ar, freq); + if (idx >= ARRAY_SIZE(ar->survey)) { + ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n", + freq, idx); + goto exit; + } + + if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) { + /* During scanning chan info is reported twice for each + * visited channel. The reported cycle count is global + * and per-channel cycle count must be calculated */ + + cycle_count -= ar->survey_last_cycle_count; + rx_clear_count -= ar->survey_last_rx_clear_count; + + survey = &ar->survey[idx]; + survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count); + survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count); + survey->noise = noise_floor; + survey->filled = SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_RX | + SURVEY_INFO_NOISE_DBM; + } + + ar->survey_last_rx_clear_count = rx_clear_count; + ar->survey_last_cycle_count = cycle_count; + +exit: + spin_unlock_bh(&ar->data_lock); } static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index da3b2bc4c88a..2c5a4f8daf2e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2931,6 +2931,11 @@ struct wmi_chan_info_event { __le32 cycle_count; } __packed; +#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) + +/* FIXME: empirically extrapolated */ +#define WMI_CHAN_INFO_MSEC(x) ((x) / 76595) + /* Beacon filter wmi command info */ #define BCN_FLT_MAX_SUPPORTED_IES 256 #define BCN_FLT_MAX_ELEMS_IE_LIST (BCN_FLT_MAX_SUPPORTED_IES / 32) -- cgit v1.2.3 From 432358ed1d18c19dbf89008325ff6ba662d0996e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 31 Jul 2013 10:55:11 +0200 Subject: ath10k: prevent using invalid ringbuffer indexes If the device is removed and hotplug fails ioread32() will return 0xFFFFFFFF. In that case reading ringbuffer during device bringup led to out-of-bounds addressing of a ringbuffer array that in turn led to a paging failure. This could be reproduced by the following: * boot without acpi/prevent hotplug from working * insert and manually detect (pci rescan) the device * remove the device physically * load ath10k driver * kernel crashed Ringbuffer index reading is now protected by using an appropriate mask to prevent addressing an invalid array index. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index b40792900bd5..f8b969f518f8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -637,6 +637,7 @@ static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state, ath10k_pci_wake(ar); src_ring->hw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); + src_ring->hw_index &= nentries_mask; ath10k_pci_sleep(ar); } read_index = src_ring->hw_index; @@ -950,10 +951,12 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, ath10k_pci_wake(ar); src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); + src_ring->sw_index &= src_ring->nentries_mask; src_ring->hw_index = src_ring->sw_index; src_ring->write_index = ath10k_ce_src_ring_write_index_get(ar, ctrl_addr); + src_ring->write_index &= src_ring->nentries_mask; ath10k_pci_sleep(ar); src_ring->per_transfer_context = (void **)ptr; @@ -1035,8 +1038,10 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, ath10k_pci_wake(ar); dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); + dest_ring->sw_index &= dest_ring->nentries_mask; dest_ring->write_index = ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); + dest_ring->write_index &= dest_ring->nentries_mask; ath10k_pci_sleep(ar); dest_ring->per_transfer_context = (void **)ptr; -- cgit v1.2.3 From dcd4a561215b46d2d7c57b855a7da6a3e6e80c0e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 31 Jul 2013 10:55:12 +0200 Subject: ath10k: make sure to use passive scan when n_ssids is 0 Normally user specifies broadcast ssid for scanning. If the user wants to do a passive scan it does not pass any ssids. The patch makes sure we ath10k tells firmware to not send anything at all in case it decides no ssids equals broadcast ssid. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9ea31f89b748..6b9f85009288 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2338,6 +2338,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.ssids[i].len = req->ssids[i].ssid_len; arg.ssids[i].ssid = req->ssids[i].ssid; } + } else { + arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; } if (req->n_channels) { -- cgit v1.2.3 From d531cb85d538d4a445e3bb3c669af794ea32e558 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 31 Jul 2013 10:55:13 +0200 Subject: ath10k: advertise more conservative intf combinations Apparently the available firmware has a limit of handling 7 APs, 3 GOs or 8 STAs. This is based on empirical tests and it is still possible some combinations may crash the firmware. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 6b9f85009288..47c11632e15d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3114,9 +3114,15 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = { .max = 8, .types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) - | BIT(NL80211_IFTYPE_P2P_GO) - | BIT(NL80211_IFTYPE_AP) - } + }, + { + .max = 3, + .types = BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 7, + .types = BIT(NL80211_IFTYPE_AP) + }, }; static const struct ieee80211_iface_combination ath10k_if_comb = { -- cgit v1.2.3 From 0dbd09e6284dc7c3de1470e2f1a3c83e0a0fc591 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 31 Jul 2013 10:55:14 +0200 Subject: ath10k: zero arvif memory on add_interface() The private memory area in vif provided by mac80211 isn't guaranteed to be zeroed. This patch should fix issues when switching between STA and AP interface types. The tim_bitmap could become polluted by STA bssid field (since it's a union), wep_keys array could also become polluted with invalid pointers and probably much more. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 47c11632e15d..cf2ba4d850c9 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1925,6 +1925,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); + memset(arvif, 0, sizeof(*arvif)); + arvif->ar = ar; arvif->vif = vif; -- cgit v1.2.3 From 591ecdb8f276925251bb5f5fad7eb064979ecee1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 31 Jul 2013 10:55:15 +0200 Subject: ath10k: fix failpath in MSI-X setup pci_disable_msi() must be called if the initial request_irq() fails. Also add a warning message so it's possible to distinguish request_irq() failure and pci_enable_msi() failure. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c71b488eba9f..d95439b8dd33 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1990,8 +1990,13 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num) ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ath10k_pci_msi_fw_handler, IRQF_SHARED, "ath10k_pci", ar); - if (ret) + if (ret) { + ath10k_warn("request_irq(%d) failed %d\n", + ar_pci->pdev->irq + MSI_ASSIGN_FW, ret); + + pci_disable_msi(ar_pci->pdev); return ret; + } for (i = MSI_ASSIGN_CE_INITIAL; i <= MSI_ASSIGN_CE_MAX; i++) { ret = request_irq(ar_pci->pdev->irq + i, -- cgit v1.2.3 From 32270b61b3fcdce3495c7b746576d49f70587150 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 2 Aug 2013 09:15:47 +0200 Subject: ath10k: fix device teardown This fixes interrupt-related issue when no interfaces were running thus the device was considered powered down. The power_down() function isn't really powering down the device. It simply assumed it won't interrupt. This wasn't true in some cases and could lead to paging failures upon FW indication interrupt (i.e. FW crash) because some structures aren't allocated in that device state. One reason for that was that ar_pci->started wasn't reset. The other is interrupts should've been masked when teardown starts. The patch reorganized interrupt setup and makes sure ar_pci->started is reset accordingly. Reported-by: Ben Greear Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 41 +++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index d95439b8dd33..503e380e4cc0 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -56,6 +56,8 @@ static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info); static void ath10k_pci_stop_ce(struct ath10k *ar); static void ath10k_pci_device_reset(struct ath10k *ar); static int ath10k_pci_reset_target(struct ath10k *ar); +static int ath10k_pci_start_intr(struct ath10k *ar); +static void ath10k_pci_stop_intr(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* host->target HTC control and raw streams */ @@ -1254,10 +1256,25 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar) } } +static void ath10k_pci_disable_irqs(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int i; + + for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) + disable_irq(ar_pci->pdev->irq + i); +} + static void ath10k_pci_hif_stop(struct ath10k *ar) { + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + /* Irqs are never explicitly re-enabled. They are implicitly re-enabled + * by ath10k_pci_start_intr(). */ + ath10k_pci_disable_irqs(ar); + ath10k_pci_stop_ce(ar); /* At this point, asynchronous threads are stopped, the target should @@ -1267,6 +1284,8 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_process_ce(ar); ath10k_pci_cleanup_ce(ar); ath10k_pci_buffer_cleanup(ar); + + ar_pci->started = 0; } static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, @@ -1742,6 +1761,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) { int ret; + ret = ath10k_pci_start_intr(ar); + if (ret) { + ath10k_err("could not start interrupt handling (%d)\n", ret); + goto err; + } + /* * Bring the target up cleanly. * @@ -1756,7 +1781,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ret = ath10k_pci_reset_target(ar); if (ret) - goto err; + goto err_irq; if (ath10k_target_ps) { ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n"); @@ -1787,12 +1812,15 @@ err_ce: err_ps: if (!ath10k_target_ps) ath10k_do_pci_sleep(ar); +err_irq: + ath10k_pci_stop_intr(ar); err: return ret; } static void ath10k_pci_hif_power_down(struct ath10k *ar) { + ath10k_pci_stop_intr(ar); ath10k_pci_ce_deinit(ar); if (!ath10k_target_ps) ath10k_do_pci_sleep(ar); @@ -2363,22 +2391,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar_pci->cacheline_sz = dma_get_cache_alignment(); - ret = ath10k_pci_start_intr(ar); - if (ret) { - ath10k_err("could not start interrupt handling (%d)\n", ret); - goto err_iomap; - } - ret = ath10k_core_register(ar); if (ret) { ath10k_err("could not register driver core (%d)\n", ret); - goto err_intr; + goto err_iomap; } return 0; -err_intr: - ath10k_pci_stop_intr(ar); err_iomap: pci_iounmap(pdev, mem); err_master: @@ -2415,7 +2435,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev) tasklet_kill(&ar_pci->msi_fw_err); ath10k_core_unregister(ar); - ath10k_pci_stop_intr(ar); pci_set_drvdata(pdev, NULL); pci_iounmap(pdev, ar_pci->mem); -- cgit v1.2.3 From fd7f838731a8b5f7567305dfc4c032c9ea135127 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:21:52 +0530 Subject: ath9k: Add information about antenna diversity Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 291ca019d37b..4cd2bcead1e5 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -16,6 +16,58 @@ #include "ath9k.h" +/* + * AR9285 + * ====== + * + * EEPROM has 2 4-bit fields containing the card configuration. + * + * antdiv_ctl1: + * ------------ + * bb_enable_ant_div_lnadiv : 1 + * bb_ant_div_alt_gaintb : 1 + * bb_ant_div_main_gaintb : 1 + * bb_enable_ant_fast_div : 1 + * + * antdiv_ctl2: + * ----------- + * bb_ant_div_alt_lnaconf : 2 + * bb_ant_div_main_lnaconf : 2 + * + * The EEPROM bits are used as follows: + * ------------------------------------ + * + * bb_enable_ant_div_lnadiv - Enable LNA path rx antenna diversity/combining. + * Set in AR_PHY_MULTICHAIN_GAIN_CTL. + * + * bb_ant_div_[alt/main]_gaintb - 0 -> Antenna config Alt/Main uses gaintable 0 + * 1 -> Antenna config Alt/Main uses gaintable 1 + * Set in AR_PHY_MULTICHAIN_GAIN_CTL. + * + * bb_enable_ant_fast_div - Enable fast antenna diversity. + * Set in AR_PHY_CCK_DETECT. + * + * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config. + * Set in AR_PHY_MULTICHAIN_GAIN_CTL. + * 10=LNA1 + * 01=LNA2 + * 11=LNA1+LNA2 + * 00=LNA1-LNA2 + * + * AR9485 / AR9565 / AR9331 + * ======================== + * + * The same bits are present in the EEPROM, but the location in the + * EEPROM is different (ant_div_control in ar9300_BaseExtension_1). + * + * ant_div_alt_lnaconf ==> bit 0~1 + * ant_div_main_lnaconf ==> bit 2~3 + * ant_div_alt_gaintb ==> bit 4 + * ant_div_main_gaintb ==> bit 5 + * enable_ant_div_lnadiv ==> bit 6 + * enable_ant_fast_div ==> bit 7 + */ + static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta, int main_rssi_avg, int alt_rssi_avg, int pkt_count) -- cgit v1.2.3 From f85c3371aee070a65d837afdd5377e9dc66fbd52 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:21:53 +0530 Subject: ath9k: Print LNA combining mode during init Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d55d97c85964..8bd602cba7f1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2559,34 +2559,28 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah)) pCap->hw_caps |= ATH9K_HW_CAP_SGI_20; - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah)) { if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) { ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); - if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1)) + if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1)) { pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; + ath_info(common, "Enable LNA combining\n"); + } } + } + if (AR_SREV_9300_20_OR_LATER(ah)) { if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE)) pCap->hw_caps |= ATH9K_HW_CAP_APM; } - if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) { ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); - /* - * enable the diversity-combining algorithm only when - * both enable_lna_div and enable_fast_div are set - * Table for Diversity - * ant_div_alt_lnaconf bit 0-1 - * ant_div_main_lnaconf bit 2-3 - * ant_div_alt_gaintb bit 4 - * ant_div_main_gaintb bit 5 - * enable_ant_div_lnadiv bit 6 - * enable_ant_fast_div bit 7 - */ - if ((ant_div_ctl1 >> 0x6) == 0x3) + if ((ant_div_ctl1 >> 0x6) == 0x3) { pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; + ath_info(common, "Enable LNA combining\n"); + } } if (ath9k_hw_dfs_tested(ah)) -- cgit v1.2.3 From 3afa6b4f54181e88814680e71b2f12fae64057f4 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:21:54 +0530 Subject: ath9k: Fix antenna diversity for CUS198 CUS198/CUS230 need a few tweaks in the antenna diversity algorithm to accomodate RSSI variation. Add a couple of knobs to control low RSSI threshold and fast antenna diversity bias values. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 73 ++++++++++++++++++++------------ drivers/net/wireless/ath/ath9k/ath9k.h | 10 +++++ drivers/net/wireless/ath/ath9k/init.c | 2 + 3 files changed, 59 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 4cd2bcead1e5..8de314cd4aed 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -68,16 +68,27 @@ * enable_ant_fast_div ==> bit 7 */ -static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, +static inline bool ath_is_alt_ant_ratio_better(struct ath_ant_comb *antcomb, + int alt_ratio, int maxdelta, int mindelta, int main_rssi_avg, int alt_rssi_avg, int pkt_count) { - return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + maxdelta)) || - (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); + if (pkt_count <= 50) + return false; + + if (alt_rssi_avg > main_rssi_avg + mindelta) + return true; + + if (alt_ratio >= antcomb->ant_ratio2 && + alt_rssi_avg >= antcomb->low_rssi_thresh && + (alt_rssi_avg > main_rssi_avg + maxdelta)) + return true; + + return false; } static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf, + struct ath_ant_comb *antcomb, int alt_ratio, int alt_rssi_avg, int main_rssi_avg) { @@ -100,20 +111,22 @@ static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf, break; case 1: case 2: - if (alt_rssi_avg < 4) + if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh) break; if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) || - (set2 && (alt_rssi_avg >= (main_rssi_avg - 2)))) + (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))) || + (alt_ratio > antcomb->ant_ratio)) result = true; break; case 3: - if (alt_rssi_avg < 4) + if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh) break; if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) || - (set2 && (alt_rssi_avg >= (main_rssi_avg + 3)))) + (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))) || + (alt_ratio > antcomb->ant_ratio)) result = true; break; @@ -266,7 +279,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { /* main is LNA1 */ - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_HI, ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, main_rssi_avg, alt_rssi_avg, @@ -275,7 +288,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->first_ratio = false; } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) { - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_MID, ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, main_rssi_avg, alt_rssi_avg, @@ -284,7 +297,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->first_ratio = false; } else { - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_HI, 0, main_rssi_avg, alt_rssi_avg, @@ -325,7 +338,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_HI, ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, main_rssi_avg, alt_rssi_avg, @@ -334,7 +347,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->second_ratio = false; } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) { - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_MID, ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, main_rssi_avg, alt_rssi_avg, @@ -343,7 +356,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->second_ratio = false; } else { - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_HI, 0, main_rssi_avg, alt_rssi_avg, @@ -484,8 +497,7 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; break; case 0x10: /* LNA2 A-B */ - if (!(antcomb->scan) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; @@ -494,15 +506,13 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; break; case 0x13: /* LNA2 A+B */ - if (!(antcomb->scan) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; break; case 0x20: /* LNA1 A-B */ - if (!(antcomb->scan) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; @@ -511,8 +521,7 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; break; case 0x23: /* LNA1 A+B */ - if (!(antcomb->scan) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; @@ -529,6 +538,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, default: break; } + + if (antcomb->fast_div_bias) + ant_conf->fast_div_bias = antcomb->fast_div_bias; } else if (ant_conf->div_group == 3) { switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { @@ -668,13 +680,14 @@ static void ath_ant_try_scan(struct ath_ant_comb *antcomb, } static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf, + struct ath_ant_comb *antcomb, int alt_ratio, int alt_rssi_avg, int main_rssi_avg, int curr_main_set, int curr_alt_set) { bool ret = false; - if (ath_ant_div_comb_alt_check(div_ant_conf, alt_ratio, + if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio, alt_rssi_avg, main_rssi_avg)) { if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { /* @@ -718,7 +731,7 @@ static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb) if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { alt_ratio = ((antcomb->alt_recv_cnt * 100) / antcomb->total_pkt_count); - if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) + if (alt_ratio < antcomb->ant_ratio) return true; } @@ -741,6 +754,14 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) & ATH_ANT_RX_MASK; + if (alt_rssi >= antcomb->low_rssi_thresh) { + antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO; + antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2; + } else { + antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI; + antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI; + } + /* Record packet only when both main_rssi and alt_rssi is positive */ if (main_rssi > 0 && alt_rssi > 0) { antcomb->total_pkt_count++; @@ -783,7 +804,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) antcomb->count++; if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { - if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { + if (alt_ratio > antcomb->ant_ratio) { ath_lnaconf_alt_good_scan(antcomb, div_ant_conf, main_rssi_avg); antcomb->alt_good = true; @@ -797,7 +818,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if (!antcomb->scan) { - ret = ath_ant_try_switch(&div_ant_conf, alt_ratio, + ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio, alt_rssi_avg, main_rssi_avg, curr_main_set, curr_alt_set); if (ret) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ed8f8efb6ecf..74009f1238a0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -585,6 +585,8 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) #define ATH_ANT_DIV_COMB_MAX_COUNT 100 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20 +#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI 50 +#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI 50 #define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1 #define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4 @@ -607,6 +609,8 @@ struct ath_ant_comb { int rssi_first; int rssi_second; int rssi_third; + int ant_ratio; + int ant_ratio2; bool alt_good; int quick_scan_cnt; enum ath9k_ant_div_comb_lna_conf main_conf; @@ -615,6 +619,12 @@ struct ath_ant_comb { bool first_ratio; bool second_ratio; unsigned long scan_start_time; + + /* + * Card-specific config values. + */ + int low_rssi_thresh; + int fast_div_bias; }; void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 16f8b201642b..7ded9d607db0 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -525,6 +525,8 @@ static void ath9k_init_platform(struct ath_softc *sc) ATH9K_PCI_CUS230)) { ah->config.xlna_gpio = 9; ah->config.xatten_margin_cfg = true; + sc->ant_comb.low_rssi_thresh = 20; + sc->ant_comb.fast_div_bias = 3; ath_info(common, "Set parameters for %s\n", (sc->driver_data & ATH9K_PCI_CUS198) ? -- cgit v1.2.3 From 6308130542e2ad913b678436c8f7b833e1420d65 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:21:55 +0530 Subject: ath9k: Cleanup WLAN/BT RX diversity For single-chain WLAN+BT cards, the BT antenna can be used for WLAN RX when the BT interface is disabled. Rename the modparam "antenna_diversity" to "bt_ant_diversity" to clarify this. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 2 +- drivers/net/wireless/ath/ath9k/antenna.c | 2 +- drivers/net/wireless/ath/ath9k/debug.c | 38 +++++++++++++++----------------- drivers/net/wireless/ath/ath9k/init.c | 12 +++++----- 4 files changed, 26 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index daeafeff186b..e0ba7cd14252 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -159,7 +159,7 @@ struct ath_common { bool btcoex_enabled; bool disable_ani; - bool antenna_diversity; + bool bt_ant_diversity; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 8de314cd4aed..354dc668205e 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -887,6 +887,6 @@ void ath_ant_comb_update(struct ath_softc *sc) ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); - if (common->antenna_diversity) + if (common->bt_ant_diversity) ath9k_hw_antctrl_shared_chain_lnadiv(ah, true); } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index e744d9747697..881ca6cb47db 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -270,25 +270,26 @@ static const struct file_operations fops_ani = { .llseek = default_llseek, }; -static ssize_t read_file_ant_diversity(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t read_file_bt_ant_diversity(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); char buf[32]; unsigned int len; - len = sprintf(buf, "%d\n", common->antenna_diversity); + len = sprintf(buf, "%d\n", common->bt_ant_diversity); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static ssize_t write_file_ant_diversity(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t write_file_bt_ant_diversity(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - unsigned long antenna_diversity; + unsigned long bt_ant_diversity; char buf[32]; ssize_t len; @@ -296,26 +297,23 @@ static ssize_t write_file_ant_diversity(struct file *file, if (copy_from_user(buf, user_buf, len)) return -EFAULT; - if (!AR_SREV_9565(sc->sc_ah)) - goto exit; - buf[len] = '\0'; - if (kstrtoul(buf, 0, &antenna_diversity)) + if (kstrtoul(buf, 0, &bt_ant_diversity)) return -EINVAL; - common->antenna_diversity = !!antenna_diversity; + common->bt_ant_diversity = !!bt_ant_diversity; ath9k_ps_wakeup(sc); ath_ant_comb_update(sc); - ath_dbg(common, CONFIG, "Antenna diversity: %d\n", - common->antenna_diversity); + ath_dbg(common, CONFIG, "Enable WLAN/BT RX Antenna diversity: %d\n", + common->bt_ant_diversity); ath9k_ps_restore(sc); -exit: + return count; } -static const struct file_operations fops_ant_diversity = { - .read = read_file_ant_diversity, - .write = write_file_ant_diversity, +static const struct file_operations fops_bt_ant_diversity = { + .read = read_file_bt_ant_diversity, + .write = write_file_bt_ant_diversity, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, @@ -1933,8 +1931,8 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); - debugfs_create_file("diversity", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_ant_diversity); + debugfs_create_file("bt_ant_diversity", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_bt_ant_diversity); debugfs_create_file("antenna_diversity", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_antenna_diversity); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 7ded9d607db0..5e81b2c24342 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -53,9 +53,9 @@ static int ath9k_btcoex_enable; module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); -static int ath9k_enable_diversity; -module_param_named(enable_diversity, ath9k_enable_diversity, int, 0444); -MODULE_PARM_DESC(enable_diversity, "Enable Antenna diversity for AR9565"); +static int ath9k_bt_ant_diversity; +module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444); +MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity"); bool is_ath9k_unloaded; /* We use the hw_value as an index into our private channel structure */ @@ -633,11 +633,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath9k_init_platform(sc); /* - * Enable Antenna diversity only when BTCOEX is disabled + * Enable WLAN/BT RX Antenna diversity only when BTCOEX is enabled * and the user manually requests the feature. */ - if (!common->btcoex_enabled && ath9k_enable_diversity) - common->antenna_diversity = 1; + if (common->btcoex_enabled && ath9k_bt_ant_diversity) + common->bt_ant_diversity = 1; spin_lock_init(&common->cc_lock); -- cgit v1.2.3 From 3f2da95517029d88365a074ef81a928a99871964 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:21:56 +0530 Subject: ath9k: Add a HW capability for WLAN/BT RX diversity Make use of this capability to restrict the usage of the debugfs file and modparam using which this feature can be enabled. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 9 +++++---- drivers/net/wireless/ath/ath9k/debug.c | 6 +++++- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 21 +++++++++++++++++---- 4 files changed, 28 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 74009f1238a0..18898abeef84 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -634,10 +634,11 @@ void ath_ant_comb_update(struct ath_softc *sc); /* Main driver core */ /********************/ -#define ATH9K_PCI_CUS198 0x0001 -#define ATH9K_PCI_CUS230 0x0002 -#define ATH9K_PCI_CUS217 0x0004 -#define ATH9K_PCI_WOW 0x0008 +#define ATH9K_PCI_CUS198 0x0001 +#define ATH9K_PCI_CUS230 0x0002 +#define ATH9K_PCI_CUS217 0x0004 +#define ATH9K_PCI_WOW 0x0008 +#define ATH9K_PCI_BT_ANT_DIV 0x0010 /* * Default cache line size, in bytes. diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 881ca6cb47db..daa316bf47b3 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -289,6 +289,7 @@ static ssize_t write_file_bt_ant_diversity(struct file *file, { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath9k_hw_capabilities *pCap = &sc->sc_ah->caps; unsigned long bt_ant_diversity; char buf[32]; ssize_t len; @@ -297,6 +298,9 @@ static ssize_t write_file_bt_ant_diversity(struct file *file, if (copy_from_user(buf, user_buf, len)) return -EFAULT; + if (!(pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV)) + goto exit; + buf[len] = '\0'; if (kstrtoul(buf, 0, &bt_ant_diversity)) return -EINVAL; @@ -307,7 +311,7 @@ static ssize_t write_file_bt_ant_diversity(struct file *file, ath_dbg(common, CONFIG, "Enable WLAN/BT RX Antenna diversity: %d\n", common->bt_ant_diversity); ath9k_ps_restore(sc); - +exit: return count; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index fd009e593b69..4ab8f58c7287 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -248,6 +248,7 @@ enum ath9k_hw_caps { ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), ATH9K_HW_CAP_PAPRD = BIT(18), ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(19), + ATH9K_HW_CAP_BT_ANT_DIV = BIT(20), }; /* diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 5e81b2c24342..b678add8b3ee 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -516,6 +516,7 @@ static void ath9k_init_misc(struct ath_softc *sc) static void ath9k_init_platform(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); if (common->bus_ops->ath_bus_type != ATH_PCI) @@ -531,8 +532,14 @@ static void ath9k_init_platform(struct ath_softc *sc) ath_info(common, "Set parameters for %s\n", (sc->driver_data & ATH9K_PCI_CUS198) ? "CUS198" : "CUS230"); - } else if (sc->driver_data & ATH9K_PCI_CUS217) { + } + + if (sc->driver_data & ATH9K_PCI_CUS217) ath_info(common, "CUS217 card detected\n"); + + if (sc->driver_data & ATH9K_PCI_BT_ANT_DIV) { + pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV; + ath_info(common, "Set BT/WLAN RX diversity capability\n"); } } @@ -586,6 +593,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, { struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath_hw *ah = NULL; + struct ath9k_hw_capabilities *pCap; struct ath_common *common; int ret = 0, i; int csz = 0; @@ -602,6 +610,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ah->reg_ops.rmw = ath9k_reg_rmw; atomic_set(&ah->intr_ref_cnt, -1); sc->sc_ah = ah; + pCap = &ah->caps; sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET); @@ -633,10 +642,14 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath9k_init_platform(sc); /* - * Enable WLAN/BT RX Antenna diversity only when BTCOEX is enabled - * and the user manually requests the feature. + * Enable WLAN/BT RX Antenna diversity only when: + * + * - BTCOEX is enabled + * - the user manually requests the feature. + * - the HW cap is set using the platform data. */ - if (common->btcoex_enabled && ath9k_bt_ant_diversity) + if (common->btcoex_enabled && ath9k_bt_ant_diversity && + (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV)) common->bt_ant_diversity = 1; spin_lock_init(&common->cc_lock); -- cgit v1.2.3 From d8d7744b72b56587b39fb4ecc2cbfb3d8cb734a4 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:21:57 +0530 Subject: ath9k: Rename ath9k_hw_antctrl_shared_chain_lnadiv Use "ath9k_hw_set_bt_ant_diversity" instead. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 2 +- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 5 ++--- drivers/net/wireless/ath/ath9k/hw-ops.h | 7 +++---- drivers/net/wireless/ath/ath9k/hw.h | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 354dc668205e..85391e690931 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -888,5 +888,5 @@ void ath_ant_comb_update(struct ath_softc *sc) ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); if (common->bt_ant_diversity) - ath9k_hw_antctrl_shared_chain_lnadiv(ah, true); + ath9k_hw_set_bt_ant_diversity(ah, true); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 3ec33ce7be66..f9fe9c81268f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1412,8 +1412,7 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } -static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, - bool enable) +static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) { u8 ant_div_ctl1; u32 regval; @@ -1646,7 +1645,7 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; - ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv; + ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity; ops->spectral_scan_config = ar9003_hw_spectral_scan_config; ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger; ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait; diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 14b701140b49..a78d48c3ad21 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -78,11 +78,10 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); } -static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, - bool enable) +static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) { - if (ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv) - ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv(ah, enable); + if (ath9k_hw_ops(ah)->set_bt_ant_diversity) + ath9k_hw_ops(ah)->set_bt_ant_diversity(ah, enable); } /* Private hardware call ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4ab8f58c7287..c037718cf6e3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -718,7 +718,7 @@ struct ath_hw_ops { struct ath_hw_antcomb_conf *antconf); void (*antdiv_comb_conf_set)(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf); - void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable); + void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable); void (*spectral_scan_config)(struct ath_hw *ah, struct ath_spec_scan *param); void (*spectral_scan_trigger)(struct ath_hw *ah); -- cgit v1.2.3 From a5354ccaaf54ac61c6d1b350e8d3e4234dd28849 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:21:58 +0530 Subject: ath9k: Enable WLAN/BT Ant Diversity for WB225/WB195 A custom solution for Asus is WB195 based and supports WLAN/BT Rx diversity. Identify this card and set the capability. CUS198/CUS230, which are based on WB225 also support WLAN/BT Rx diversity. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index c585c9b35973..30652b4d076e 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -29,6 +29,14 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ + + /* AR9285 card for Asus */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002B, + PCI_VENDOR_ID_AZWAVE, + 0x2C37), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ @@ -40,29 +48,29 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { 0x0032, PCI_VENDOR_ID_AZWAVE, 0x2086), - .driver_data = ATH9K_PCI_CUS198 }, + .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_AZWAVE, 0x1237), - .driver_data = ATH9K_PCI_CUS198 }, + .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_AZWAVE, 0x2126), - .driver_data = ATH9K_PCI_CUS198 }, + .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, /* PCI-E CUS230 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_AZWAVE, 0x2152), - .driver_data = ATH9K_PCI_CUS230 }, + .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_FOXCONN, 0xE075), - .driver_data = ATH9K_PCI_CUS230 }, + .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV }, { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */ -- cgit v1.2.3 From d7150908248bc76eff48c16045802c7f0b1cfd74 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:21:59 +0530 Subject: ath9k: Program HW for WB195 diversity The MC_GAIN_CTL/CCK_DETECT registers have to be programmed with the correct configuration values if WLAN/BT RX diversity is enabled. Add this and also take care of the BTCOEX mode when fast diversity is enabled/disabled. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_phy.c | 60 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9002_phy.h | 6 +++ 2 files changed, 66 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index f4003512d8d5..456d8b917396 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -555,6 +555,65 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); } +static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) +{ + struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; + u8 antdiv_ctrl1, antdiv_ctrl2; + u32 regval; + + if (enable) { + antdiv_ctrl1 = ATH_BT_COEX_ANTDIV_CONTROL1_ENABLE; + antdiv_ctrl2 = ATH_BT_COEX_ANTDIV_CONTROL2_ENABLE; + + /* + * Don't disable BT ant to allow BB to control SWCOM. + */ + btcoex->bt_coex_mode2 &= (~(AR_BT_DISABLE_BT_ANT)); + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2); + + REG_WRITE(ah, AR_PHY_SWITCH_COM, ATH_BT_COEX_ANT_DIV_SWITCH_COM); + REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000); + } else { + /* + * Disable antenna diversity, use LNA1 only. + */ + antdiv_ctrl1 = ATH_BT_COEX_ANTDIV_CONTROL1_FIXED_A; + antdiv_ctrl2 = ATH_BT_COEX_ANTDIV_CONTROL2_FIXED_A; + + /* + * Disable BT Ant. to allow concurrent BT and WLAN receive. + */ + btcoex->bt_coex_mode2 |= AR_BT_DISABLE_BT_ANT; + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2); + + /* + * Program SWCOM table to make sure RF switch always parks + * at BT side. + */ + REG_WRITE(ah, AR_PHY_SWITCH_COM, 0); + REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000); + } + + regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); + regval &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); + /* + * Clear ant_fast_div_bias [14:9] since for WB195, + * the main LNA is always LNA1. + */ + regval &= (~(AR_PHY_9285_FAST_DIV_BIAS)); + regval |= SM(antdiv_ctrl1, AR_PHY_9285_ANT_DIV_CTL); + regval |= SM(antdiv_ctrl2, AR_PHY_9285_ANT_DIV_ALT_LNACONF); + regval |= SM((antdiv_ctrl2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF); + regval |= SM((antdiv_ctrl1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB); + regval |= SM((antdiv_ctrl1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB); + REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); + + regval = REG_READ(ah, AR_PHY_CCK_DETECT); + regval &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + regval |= SM((antdiv_ctrl1 >> 3), AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); +} + static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, struct ath_spec_scan *param) { @@ -630,6 +689,7 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah) ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set; + ops->set_bt_ant_diversity = ar9002_hw_set_bt_ant_diversity; ops->spectral_scan_config = ar9002_hw_spectral_scan_config; ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger; ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h index d3f09287d1d0..6314ae2e93e3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -320,6 +320,12 @@ #define AR_PHY_9285_ANT_DIV_GAINTB_0 0 #define AR_PHY_9285_ANT_DIV_GAINTB_1 1 +#define ATH_BT_COEX_ANTDIV_CONTROL1_ENABLE 0x0b +#define ATH_BT_COEX_ANTDIV_CONTROL2_ENABLE 0x09 +#define ATH_BT_COEX_ANTDIV_CONTROL1_FIXED_A 0x04 +#define ATH_BT_COEX_ANTDIV_CONTROL2_FIXED_A 0x09 +#define ATH_BT_COEX_ANT_DIV_SWITCH_COM 0x66666666 + #define AR_PHY_EXT_CCA0 0x99b8 #define AR_PHY_EXT_CCA0_THRESH62 0x000000FF #define AR_PHY_EXT_CCA0_THRESH62_S 0 -- cgit v1.2.3 From 7bdea96a1bbae75e7922584e3ae37fb9ad6cb79a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:22:00 +0530 Subject: ath9k: Remove "shared_chain_lnadiv" This variable is redundant since we can use common->bt_ant_diversity to determine if diversity has to be enabled/disabled. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 3 ++- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 1 - drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index a98e6a3dd8a1..c2f1f18e364b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3561,6 +3561,7 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, int chain, static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) { + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_capabilities *pCap = &ah->caps; int chain; u32 regval, value, gpio; @@ -3646,7 +3647,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; if (AR_SREV_9565(ah)) { - if (ah->shared_chain_lnadiv) { + if (common->bt_ant_diversity) { regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S); } else { regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index f9fe9c81268f..55021f1a9c35 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1420,7 +1420,6 @@ static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) if (!AR_SREV_9565(ah)) return; - ah->shared_chain_lnadiv = enable; ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8bd602cba7f1..151443bddbde 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2056,7 +2056,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_apply_gpio_override(ah); - if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv) + if (AR_SREV_9565(ah) && common->bt_ant_diversity) REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); return 0; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c037718cf6e3..9dc677399631 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -767,7 +767,6 @@ struct ath_hw { bool aspm_enabled; bool is_monitoring; bool need_an_top2_fixup; - bool shared_chain_lnadiv; u16 tx_trig_level; u32 nf_regs[6]; -- cgit v1.2.3 From 31fd216db9cb7a50e0e64aff813bc6c12e9437d3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:22:01 +0530 Subject: ath9k: Set SWCOM value for CUS198 CUS198/CUS230 cards require a custom value to be programmed into the SWCOM register. Assign this during init time. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9dc677399631..38f461c11c33 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -312,6 +312,7 @@ struct ath9k_ops_config { /* Platform specific config */ u32 xlna_gpio; + u32 ant_ctrl_comm2g_switch_enable; bool xatten_margin_cfg; }; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index b678add8b3ee..4afe30e0bf49 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -526,6 +526,7 @@ static void ath9k_init_platform(struct ath_softc *sc) ATH9K_PCI_CUS230)) { ah->config.xlna_gpio = 9; ah->config.xatten_margin_cfg = true; + ah->config.ant_ctrl_comm2g_switch_enable = 0x000BBB88; sc->ant_comb.low_rssi_thresh = 20; sc->ant_comb.fast_div_bias = 3; -- cgit v1.2.3 From 84893817aa382b923e3d7491e7081eeb6d9ec213 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 4 Aug 2013 14:22:02 +0530 Subject: ath9k: Support ANT diversity for WB225 WB225 based cards like CUS198 and CUS230 support both fast antenna diversity and LNA combining. Add support for this and also program the SWCOM register with the correct "ant_ctrl_comm2g_switch_enable" value. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 5 +- drivers/net/wireless/ath/ath9k/ar9003_eeprom.h | 2 + drivers/net/wireless/ath/ath9k/ar9003_phy.c | 120 +++++++++++++++++-------- 3 files changed, 86 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index c2f1f18e364b..178052fc4d88 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3541,13 +3541,12 @@ static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is2ghz) return le16_to_cpu(ar9003_modal_header(ah, is2ghz)->switchcomspdt); } - -static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) +u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) { return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon); } -static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz) +u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz) { return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon2); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 874f6570bd1c..75d4fb41962f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -334,6 +334,8 @@ struct ar9300_eeprom { s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah); s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah); +u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz); +u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz); u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 55021f1a9c35..4898829e6549 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1414,58 +1414,102 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) { + struct ath9k_hw_capabilities *pCap = &ah->caps; u8 ant_div_ctl1; u32 regval; - if (!AR_SREV_9565(ah)) + if (!AR_SREV_9485(ah) && !AR_SREV_9565(ah)) return; + if (AR_SREV_9485(ah)) { + regval = ar9003_hw_ant_ctrl_common_2_get(ah, + IS_CHAN_2GHZ(ah->curchan)); + if (enable) { + regval &= ~AR_SWITCH_TABLE_COM2_ALL; + regval |= ah->config.ant_ctrl_comm2g_switch_enable; + } + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, + AR_SWITCH_TABLE_COM2_ALL, regval); + } + ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); + /* + * Set MAIN/ALT LNA conf. + * Set MAIN/ALT gain_tb. + */ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); regval &= (~AR_ANT_DIV_CTRL_ALL); regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S; - regval &= ~AR_PHY_ANT_DIV_LNADIV; - regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; - - if (enable) - regval |= AR_ANT_DIV_ENABLE; - REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); - regval = REG_READ(ah, AR_PHY_CCK_DETECT); - regval &= ~AR_FAST_DIV_ENABLE; - regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; - - if (enable) - regval |= AR_FAST_DIV_ENABLE; - - REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); - - if (enable) { - REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, - (1 << AR_PHY_ANT_SW_RX_PROT_S)); - if (ah->curchan && IS_CHAN_2GHZ(ah->curchan)) - REG_SET_BIT(ah, AR_PHY_RESTART, - AR_PHY_RESTART_ENABLE_DIV_M2FLAG); - REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, - AR_BTCOEX_WL_LNADIV_FORCE_ON); - } else { - REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE); - REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, - (1 << AR_PHY_ANT_SW_RX_PROT_S)); - REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE); - REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, - AR_BTCOEX_WL_LNADIV_FORCE_ON); - + if (AR_SREV_9485_11(ah)) { + /* + * Enable LNA diversity. + */ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); - regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF | - AR_PHY_ANT_DIV_ALT_LNACONF | - AR_PHY_ANT_DIV_MAIN_GAINTB | - AR_PHY_ANT_DIV_ALT_GAINTB); - regval |= (ATH_ANT_DIV_COMB_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S); - regval |= (ATH_ANT_DIV_COMB_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S); + regval &= ~AR_PHY_ANT_DIV_LNADIV; + regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; + if (enable) + regval |= AR_ANT_DIV_ENABLE; + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + + /* + * Enable fast antenna diversity. + */ + regval = REG_READ(ah, AR_PHY_CCK_DETECT); + regval &= ~AR_FAST_DIV_ENABLE; + regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; + if (enable) + regval |= AR_FAST_DIV_ENABLE; + + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); + + if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= (~(AR_PHY_ANT_DIV_MAIN_LNACONF | + AR_PHY_ANT_DIV_ALT_LNACONF | + AR_PHY_ANT_DIV_ALT_GAINTB | + AR_PHY_ANT_DIV_MAIN_GAINTB)); + /* + * Set MAIN to LNA1 and ALT to LNA2 at the + * beginning. + */ + regval |= (ATH_ANT_DIV_COMB_LNA1 << + AR_PHY_ANT_DIV_MAIN_LNACONF_S); + regval |= (ATH_ANT_DIV_COMB_LNA2 << + AR_PHY_ANT_DIV_ALT_LNACONF_S); + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + } + } else if (AR_SREV_9565(ah)) { + if (enable) { + REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, + (1 << AR_PHY_ANT_SW_RX_PROT_S)); + if (ah->curchan && IS_CHAN_2GHZ(ah->curchan)) + REG_SET_BIT(ah, AR_PHY_RESTART, + AR_PHY_RESTART_ENABLE_DIV_M2FLAG); + REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, + AR_BTCOEX_WL_LNADIV_FORCE_ON); + } else { + REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE); + REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, + (1 << AR_PHY_ANT_SW_RX_PROT_S)); + REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE); + REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, + AR_BTCOEX_WL_LNADIV_FORCE_ON); + + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF | + AR_PHY_ANT_DIV_ALT_LNACONF | + AR_PHY_ANT_DIV_MAIN_GAINTB | + AR_PHY_ANT_DIV_ALT_GAINTB); + regval |= (ATH_ANT_DIV_COMB_LNA1 << + AR_PHY_ANT_DIV_MAIN_LNACONF_S); + regval |= (ATH_ANT_DIV_COMB_LNA2 << + AR_PHY_ANT_DIV_ALT_LNACONF_S); + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + } } } -- cgit v1.2.3 From 0cbe8c87fe02513e6de981c18502d220ed4afe41 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Mon, 5 Aug 2013 07:18:28 +0400 Subject: hostap: do not return positive number on failure path in prism2_open() prism2_open() as an .ndo_open handler should not return positive numbers in case of failure, but it does return 1 in a couple of places. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 15f0fad39add..e4f56ad26cd8 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -667,7 +667,7 @@ static int prism2_open(struct net_device *dev) if (local->no_pri) { printk(KERN_DEBUG "%s: could not set interface UP - no PRI " "f/w\n", dev->name); - return 1; + return -ENODEV; } if ((local->func->card_present && !local->func->card_present(local)) || @@ -682,7 +682,7 @@ static int prism2_open(struct net_device *dev) printk(KERN_WARNING "%s: could not enable MAC port\n", dev->name); prism2_close(dev); - return 1; + return -ENODEV; } if (!local->dev_enabled) prism2_callback(local, PRISM2_CALLBACK_ENABLE); -- cgit v1.2.3 From 047dc3ac884f3285bc123461e5e3c38f44fb32a6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 5 Aug 2013 15:08:26 +0530 Subject: ath9k: Remove ath_ant_comb_update() During a HW reset, the diversity config is programmed in the set_board_values() eeprom callback, there is no need to do it again by calling ath_ant_comb_update(). Fixed antenna support is not fully handled for 1-stream cards, it can be done later. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 23 ----------------------- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/debug.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 3 --- 4 files changed, 1 insertion(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 85391e690931..dd1cc73d7946 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -867,26 +867,3 @@ div_comb_done: antcomb->main_recv_cnt = 0; antcomb->alt_recv_cnt = 0; } - -void ath_ant_comb_update(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_hw_antcomb_conf div_ant_conf; - u8 lna_conf; - - ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); - - if (sc->ant_rx == 1) - lna_conf = ATH_ANT_DIV_COMB_LNA1; - else - lna_conf = ATH_ANT_DIV_COMB_LNA2; - - div_ant_conf.main_lna_conf = lna_conf; - div_ant_conf.alt_lna_conf = lna_conf; - - ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); - - if (common->bt_ant_diversity) - ath9k_hw_set_bt_ant_diversity(ah, true); -} diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 18898abeef84..c497d529ce86 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -628,7 +628,6 @@ struct ath_ant_comb { }; void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); -void ath_ant_comb_update(struct ath_softc *sc); /********************/ /* Main driver core */ diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index daa316bf47b3..a155190e2c84 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -307,7 +307,7 @@ static ssize_t write_file_bt_ant_diversity(struct file *file, common->bt_ant_diversity = !!bt_ant_diversity; ath9k_ps_wakeup(sc); - ath_ant_comb_update(sc); + ath9k_hw_set_bt_ant_diversity(sc->sc_ah, common->bt_ant_diversity); ath_dbg(common, CONFIG, "Enable WLAN/BT RX Antenna diversity: %d\n", common->bt_ant_diversity); ath9k_ps_restore(sc); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1adb803a9d86..afeab3ca9a69 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -238,9 +238,6 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath_restart_work(sc); } - if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) - ath_ant_comb_update(sc); - ieee80211_wake_queues(sc->hw); return true; -- cgit v1.2.3 From b21e3e14aee617ef9f8d4b52a61913d6a359edf0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 5 Aug 2013 15:08:27 +0530 Subject: ath9k: Fix antenna control init for AR9485 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 178052fc4d88..abdc7ee87413 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3614,6 +3614,11 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) } value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); + if (AR_SREV_9485(ah) && common->bt_ant_diversity) { + regval &= ~AR_SWITCH_TABLE_COM2_ALL; + regval |= ah->config.ant_ctrl_comm2g_switch_enable; + + } REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) { @@ -3645,6 +3650,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) regval &= (~AR_PHY_ANT_DIV_LNADIV); regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; + if (AR_SREV_9485(ah) && common->bt_ant_diversity) + regval |= AR_ANT_DIV_ENABLE; + if (AR_SREV_9565(ah)) { if (common->bt_ant_diversity) { regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S); @@ -3656,10 +3664,14 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); - /*enable fast_div */ + /* enable fast_div */ regval = REG_READ(ah, AR_PHY_CCK_DETECT); regval &= (~AR_FAST_DIV_ENABLE); regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; + + if (AR_SREV_9485(ah) && common->bt_ant_diversity) + regval |= AR_FAST_DIV_ENABLE; + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { -- cgit v1.2.3 From 2952f6ef5195ea76279f7370f0a6571867e54438 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 5 Aug 2013 15:08:28 +0530 Subject: ath9k: Add more PCI IDs for WB225 cards Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 30652b4d076e..76e8c359bbf8 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -72,6 +72,78 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { 0xE075), .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV }, + /* WB225 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_ATHEROS, + 0x3119), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_ATHEROS, + 0x3122), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x185F, /* WNC */ + 0x3119), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x185F, /* WNC */ + 0x3027), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x4105), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x4106), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410D), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410E), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410F), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC706), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC680), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC708), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_LENOVO, + 0x3218), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_LENOVO, + 0x3219), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */ -- cgit v1.2.3 From 3848ab66827bddd7eb760c58dec909f0af1c00a5 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Tue, 30 Jul 2013 15:29:37 +0300 Subject: iwlwifi: mvm: Add RX statistics debugfs entry Add a debugfs entry for the RX statistics received from the firmware. Signed-off-by: Matti Gottlieb Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 138 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/iwlwifi/mvm/ops.c | 2 + drivers/net/wireless/iwlwifi/mvm/rx.c | 13 +++ 4 files changed, 155 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 15d52bad2d2a..2ee256d0acb7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -592,6 +592,142 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, } #undef BT_MBOX_PRINT +#define PRINT_STATS_LE32(_str, _val) \ + pos += scnprintf(buf + pos, bufsz - pos, \ + fmt_table, _str, \ + le32_to_cpu(_val)) + +static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + static const char *fmt_table = "\t%-30s %10u\n"; + static const char *fmt_header = "%-32s\n"; + int pos = 0; + char *buf; + int ret; + int bufsz = sizeof(struct mvm_statistics_rx_phy) * 20 + + sizeof(struct mvm_statistics_rx_non_phy) * 10 + + sizeof(struct mvm_statistics_rx_ht_phy) * 10 + 200; + struct mvm_statistics_rx_phy *ofdm; + struct mvm_statistics_rx_phy *cck; + struct mvm_statistics_rx_non_phy *general; + struct mvm_statistics_rx_ht_phy *ht; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&mvm->mutex); + + ofdm = &mvm->rx_stats.ofdm; + cck = &mvm->rx_stats.cck; + general = &mvm->rx_stats.general; + ht = &mvm->rx_stats.ofdm_ht; + + pos += scnprintf(buf + pos, bufsz - pos, fmt_header, + "Statistics_Rx - OFDM"); + PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt); + PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt); + PRINT_STATS_LE32("plcp_err", ofdm->plcp_err); + PRINT_STATS_LE32("crc32_err", ofdm->crc32_err); + PRINT_STATS_LE32("overrun_err", ofdm->overrun_err); + PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err); + PRINT_STATS_LE32("crc32_good", ofdm->crc32_good); + PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt); + PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt); + PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout); + PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout); + PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts); + PRINT_STATS_LE32("rxe_frame_lmt_overrun", + ofdm->rxe_frame_limit_overrun); + PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt); + PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt); + PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt); + PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill); + PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err); + PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum); + PRINT_STATS_LE32("reserved", ofdm->reserved); + + pos += scnprintf(buf + pos, bufsz - pos, fmt_header, + "Statistics_Rx - CCK"); + PRINT_STATS_LE32("ina_cnt", cck->ina_cnt); + PRINT_STATS_LE32("fina_cnt", cck->fina_cnt); + PRINT_STATS_LE32("plcp_err", cck->plcp_err); + PRINT_STATS_LE32("crc32_err", cck->crc32_err); + PRINT_STATS_LE32("overrun_err", cck->overrun_err); + PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err); + PRINT_STATS_LE32("crc32_good", cck->crc32_good); + PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt); + PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt); + PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout); + PRINT_STATS_LE32("fina_timeout", cck->fina_timeout); + PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts); + PRINT_STATS_LE32("rxe_frame_lmt_overrun", + cck->rxe_frame_limit_overrun); + PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt); + PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt); + PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt); + PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill); + PRINT_STATS_LE32("mh_format_err", cck->mh_format_err); + PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum); + PRINT_STATS_LE32("reserved", cck->reserved); + + pos += scnprintf(buf + pos, bufsz - pos, fmt_header, + "Statistics_Rx - GENERAL"); + PRINT_STATS_LE32("bogus_cts", general->bogus_cts); + PRINT_STATS_LE32("bogus_ack", general->bogus_ack); + PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames); + PRINT_STATS_LE32("filtered_frames", general->filtered_frames); + PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons); + PRINT_STATS_LE32("channel_beacons", general->channel_beacons); + PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon); + PRINT_STATS_LE32("adc_rx_saturation_time", + general->adc_rx_saturation_time); + PRINT_STATS_LE32("ina_detection_search_time", + general->ina_detection_search_time); + PRINT_STATS_LE32("beacon_silence_rssi_a", + general->beacon_silence_rssi_a); + PRINT_STATS_LE32("beacon_silence_rssi_b", + general->beacon_silence_rssi_b); + PRINT_STATS_LE32("beacon_silence_rssi_c", + general->beacon_silence_rssi_c); + PRINT_STATS_LE32("interference_data_flag", + general->interference_data_flag); + PRINT_STATS_LE32("channel_load", general->channel_load); + PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms); + PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a); + PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b); + PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c); + PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a); + PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b); + PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c); + PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills); + PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu); + + pos += scnprintf(buf + pos, bufsz - pos, fmt_header, + "Statistics_Rx - HT"); + PRINT_STATS_LE32("plcp_err", ht->plcp_err); + PRINT_STATS_LE32("overrun_err", ht->overrun_err); + PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err); + PRINT_STATS_LE32("crc32_good", ht->crc32_good); + PRINT_STATS_LE32("crc32_err", ht->crc32_err); + PRINT_STATS_LE32("mh_format_err", ht->mh_format_err); + PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good); + PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt); + PRINT_STATS_LE32("agg_cnt", ht->agg_cnt); + PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs); + + mutex_unlock(&mvm->mutex); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + + return ret; +} +#undef PRINT_STAT_LE32 + static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -924,6 +1060,7 @@ MVM_DEBUGFS_READ_FILE_OPS(stations); MVM_DEBUGFS_READ_FILE_OPS(bt_notif); MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); +MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); @@ -947,6 +1084,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 5dc5dfde916e..76f6a1fdf668 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -421,6 +421,8 @@ struct iwl_mvm { struct iwl_notif_wait_data notif_wait; + struct mvm_statistics_rx rx_stats; + unsigned long transport_queue_stop; u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 65e5fb86291f..2fcc8ef88a68 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -440,6 +440,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, else mvm->pm_ops = &pm_legacy_ops; + memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); + return op_mode; out_unregister: diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 6fd7fae30c0a..5057fd3bcb50 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -378,6 +378,18 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, return 0; } +static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, + struct iwl_notif_statistics *stats) +{ + /* + * NOTE FW aggregates the statistics - BUT the statistics are cleared + * when the driver issues REPLY_STATISTICS_CMD 0x9c with CLEAR_STATS + * bit set. + */ + lockdep_assert_held(&mvm->mutex); + memcpy(&mvm->rx_stats, &stats->rx, sizeof(struct mvm_statistics_rx)); +} + /* * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler * @@ -396,6 +408,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, mvm->temperature = le32_to_cpu(common->temperature); iwl_mvm_tt_handler(mvm); } + iwl_mvm_update_rx_statistics(mvm, stats); return 0; } -- cgit v1.2.3 From eeb89ab1f081a62bee1695d82442996b99a5b2b3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 30 Jul 2013 20:10:46 +0200 Subject: iwlwifi: pcie: fix resume when no opmode is present If no opmode is present during suspend/resume (i.e. if the iwldvm or iwlmvm isn't loaded) the driver crashes during resume, trying to call the rfkill notification. Avoid that, and also don't enable the rfkill interrupt in this case (to avoid crashing trying to handle the interrupt later.) Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/trans.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index cec0c8991285..601ee5904738 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -825,6 +825,9 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) { bool hw_rfkill; + if (!trans->op_mode) + return 0; + iwl_enable_rfkill_int(trans); hw_rfkill = iwl_is_rfkill_set(trans); -- cgit v1.2.3 From 977342bc3d672f6d11386c19ccee3f8b2400bcde Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 28 Jul 2013 23:02:44 +0000 Subject: iwlwifi: mvm: remove traffic load monitoring in rs The traffic load monitoring isn't used anymore to decide whether a Tx aggregation on a specific TID should be started. No point in collecting these statistics. Remove the relevant code. Signed-off-by: Eyal Shapira Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rs.c | 128 +++++----------------------------- drivers/net/wireless/iwlwifi/mvm/rs.h | 12 ---- 2 files changed, 17 insertions(+), 123 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index e4a7b3872d33..940f39d43201 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -260,82 +260,6 @@ static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) return (ant_type & valid_antenna) == ant_type; } -/* - * removes the old data from the statistics. All data that is older than - * TID_MAX_TIME_DIFF, will be deleted. - */ -static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time) -{ - /* The oldest age we want to keep */ - u32 oldest_time = curr_time - TID_MAX_TIME_DIFF; - - while (tl->queue_count && - (tl->time_stamp < oldest_time)) { - tl->total -= tl->packet_count[tl->head]; - tl->packet_count[tl->head] = 0; - tl->time_stamp += TID_QUEUE_CELL_SPACING; - tl->queue_count--; - tl->head++; - if (tl->head >= TID_QUEUE_MAX_SIZE) - tl->head = 0; - } -} - -/* - * increment traffic load value for tid and also remove - * any old values if passed the certain time period - */ -static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, - struct ieee80211_hdr *hdr) -{ - u32 curr_time = jiffies_to_msecs(jiffies); - u32 time_diff; - s32 index; - struct iwl_traffic_load *tl = NULL; - u8 tid; - - if (ieee80211_is_data_qos(hdr->frame_control)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } else { - return IWL_MAX_TID_COUNT; - } - - if (unlikely(tid >= IWL_MAX_TID_COUNT)) - return IWL_MAX_TID_COUNT; - - tl = &lq_data->load[tid]; - - curr_time -= curr_time % TID_ROUND_VALUE; - - /* Happens only for the first packet. Initialize the data */ - if (!(tl->queue_count)) { - tl->total = 1; - tl->time_stamp = curr_time; - tl->queue_count = 1; - tl->head = 0; - tl->packet_count[0] = 1; - return IWL_MAX_TID_COUNT; - } - - time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); - index = time_diff / TID_QUEUE_CELL_SPACING; - - /* The history is too long: remove data that is older than */ - /* TID_MAX_TIME_DIFF */ - if (index >= TID_QUEUE_MAX_SIZE) - rs_tl_rm_old_stats(tl, curr_time); - - index = (tl->head + index) % TID_QUEUE_MAX_SIZE; - tl->packet_count[index] = tl->packet_count[index] + 1; - tl->total = tl->total + 1; - - if ((index + 1) > tl->queue_count) - tl->queue_count = index + 1; - - return tid; -} - #ifdef CONFIG_MAC80211_DEBUGFS /** * Program the device to use fixed rate for frame transmit @@ -361,45 +285,11 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, } #endif -/* - get the traffic load value for tid -*/ -static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid) -{ - u32 curr_time = jiffies_to_msecs(jiffies); - u32 time_diff; - s32 index; - struct iwl_traffic_load *tl = NULL; - - if (tid >= IWL_MAX_TID_COUNT) - return 0; - - tl = &(lq_data->load[tid]); - - curr_time -= curr_time % TID_ROUND_VALUE; - - if (!(tl->queue_count)) - return 0; - - time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); - index = time_diff / TID_QUEUE_CELL_SPACING; - - /* The history is too long: remove data that is older than */ - /* TID_MAX_TIME_DIFF */ - if (index >= TID_QUEUE_MAX_SIZE) - rs_tl_rm_old_stats(tl, curr_time); - - return tl->total; -} - static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_data, u8 tid, struct ieee80211_sta *sta) { int ret = -EAGAIN; - u32 load; - - load = rs_tl_get_load(lq_data, tid); /* * Don't create TX aggregation sessions when in high @@ -2086,6 +1976,22 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm, iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); } +static u8 rs_get_tid(struct iwl_lq_sta *lq_data, + struct ieee80211_hdr *hdr) +{ + u8 tid = IWL_MAX_TID_COUNT; + + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + } + + if (unlikely(tid > IWL_MAX_TID_COUNT)) + tid = IWL_MAX_TID_COUNT; + + return tid; +} + /* * Do rate scaling and search for new modulation mode. */ @@ -2129,7 +2035,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; - tid = rs_tl_add_packet(lq_sta, hdr); + tid = rs_get_tid(lq_sta, hdr); if ((tid != IWL_MAX_TID_COUNT) && (lq_sta->tx_agg_tid_en & (1 << tid))) { tid_data = &sta_priv->tid_data[tid]; diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 29d699ac07c9..4a99a4d200ac 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -290,17 +290,6 @@ struct iwl_scale_tbl_info { struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ }; -struct iwl_traffic_load { - unsigned long time_stamp; /* age of the oldest statistics */ - u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time - * slice */ - u32 total; /* total num of packets during the - * last TID_MAX_TIME_DIFF */ - u8 queue_count; /* number of queues that has - * been used since the last cleanup */ - u8 head; /* start of the circular buffer */ -}; - /** * struct iwl_lq_sta -- driver's rate scaling private structure * @@ -337,7 +326,6 @@ struct iwl_lq_sta { struct iwl_lq_cmd lq; struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ - struct iwl_traffic_load load[IWL_MAX_TID_COUNT]; u8 tx_agg_tid_en; #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; -- cgit v1.2.3 From 17dbe56445328fcc275f2ca318c06e55d7d403df Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 1 Aug 2013 07:19:27 +0300 Subject: iwlwifi: mvm: fix signal reporting for < 3 antennas When fewer than three antennas are connected (as is always the case for the current devices), the signal strength reporting was wrong; fix it. Signed-off-by: Avri Altman Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rx.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 5057fd3bcb50..ee6547d22287 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -167,6 +167,9 @@ static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm, /* * iwl_mvm_get_signal_strength - use new rx PHY INFO API + * values are reported by the fw as positive values - need to negate + * to obtain their dBM. Account for missing antennas by replacing 0 + * values by -256dBm: practically 0 power and a non-feasible 8 bit value. */ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, struct iwl_rx_phy_info *phy_info, @@ -177,12 +180,15 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_ENERGY_ANT_ABC_IDX]); - energy_a = -((val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >> - IWL_RX_INFO_ENERGY_ANT_A_POS); - energy_b = -((val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >> - IWL_RX_INFO_ENERGY_ANT_B_POS); - energy_c = -((val & IWL_RX_INFO_ENERGY_ANT_C_MSK) >> - IWL_RX_INFO_ENERGY_ANT_C_POS); + energy_a = (val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >> + IWL_RX_INFO_ENERGY_ANT_A_POS; + energy_a = energy_a ? -energy_a : -256; + energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >> + IWL_RX_INFO_ENERGY_ANT_B_POS; + energy_b = energy_b ? -energy_b : -256; + energy_c = (val & IWL_RX_INFO_ENERGY_ANT_C_MSK) >> + IWL_RX_INFO_ENERGY_ANT_C_POS; + energy_c = energy_c ? -energy_c : -256; max_energy = max(energy_a, energy_b); max_energy = max(max_energy, energy_c); -- cgit v1.2.3 From f5e45f2d960cea226b9d173e232c94c4c388c1bc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 25 Jul 2013 22:36:27 +0200 Subject: iwlwifi: mvm: small cleanups in quota management code Use a C99 initializer to clear the command and move the lockdep assertion before the restart check. Since this causes problems with the BUILD_BUG_ON() with some compilers, change that a bit. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/quota.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 18973874b77a..5c6ae16ec52b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -131,7 +131,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) { - struct iwl_time_quota_cmd cmd; + struct iwl_time_quota_cmd cmd = {}; int i, idx, ret, num_active_macs, quota, quota_rem; struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, @@ -139,15 +139,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) .new_vif = newvif, }; + lockdep_assert_held(&mvm->mutex); + /* update all upon completion */ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) return 0; - BUILD_BUG_ON(data.colors[MAX_BINDINGS - 1] != -1); - - lockdep_assert_held(&mvm->mutex); - - memset(&cmd, 0, sizeof(cmd)); + /* iterator data above must match */ + BUILD_BUG_ON(MAX_BINDINGS != 4); ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, -- cgit v1.2.3 From e89044d75e50e047bd34db81ac8d18500626f40f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 16 Jul 2013 17:33:26 +0300 Subject: iwlwifi: fix some documentation typos Fix some typos. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-op-mode.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-trans.h | 6 +++--- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 +- drivers/net/wireless/iwlwifi/pcie/tx.c | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index 98c7aa7346da..976448a57d02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -93,7 +93,7 @@ struct iwl_cfg; * 1) The driver layer (iwl-drv.c) chooses the op_mode based on the * capabilities advertized by the fw file (in TLV format). * 2) The driver layer starts the op_mode (ops->start) - * 3) The op_mode registers registers mac80211 + * 3) The op_mode registers mac80211 * 4) The op_mode is governed by mac80211 * 5) The driver layer stops the op_mode */ @@ -112,7 +112,7 @@ struct iwl_cfg; * @stop: stop the op_mode. Must free all the memory allocated. * May sleep * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the - * HCMD the this Rx responds to. + * HCMD this Rx responds to. * This callback may sleep, it is called from a threaded IRQ handler. * @queue_full: notifies that a HW queue is full. * Must be atomic and called with BH disabled. diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8d91422c5982..523dc7ce294b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -180,7 +180,7 @@ struct iwl_rx_packet { * enum CMD_MODE - how to send the host commands ? * * @CMD_SYNC: The caller will be stalled until the fw responds to the command - * @CMD_ASYNC: Return right away and don't want for the response + * @CMD_ASYNC: Return right away and don't wait for the response * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the * response. The caller needs to call iwl_free_resp when done. */ @@ -218,7 +218,7 @@ struct iwl_device_cmd { * * @IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's * ring. The transport layer doesn't map the command's buffer to DMA, but - * rather copies it to an previously allocated DMA buffer. This flag tells + * rather copies it to a previously allocated DMA buffer. This flag tells * the transport layer not to copy the command, but to map the existing * buffer (that is passed in) instead. This saves the memcpy and allows * commands that are bigger than the fixed buffer to be submitted. @@ -243,7 +243,7 @@ enum iwl_hcmd_dataflag { * @handler_status: return value of the handler of the command * (put in setup_rx_handlers) - valid for SYNC mode only * @flags: can be CMD_* - * @len: array of the lenths of the chunks in data + * @len: array of the lengths of the chunks in data * @dataflags: IWL_HCMD_DFL_* * @id: id of the host command */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 76cdba65b321..deebe8f9c00d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -503,7 +503,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - /* Allocate resources for the MAC context, and add it the the fw */ + /* Allocate resources for the MAC context, and add it to the fw */ ret = iwl_mvm_mac_ctxt_init(mvm, vif); if (ret) goto out_unlock; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 7694b8fa4c37..f68ef9dd6a70 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -173,7 +173,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, } /* - * for data packets, rate info comes from the table inside he fw. This + * for data packets, rate info comes from the table inside the fw. This * table is controlled by LINK_QUALITY commands */ diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 134f7a109f47..f29cd5c0aeed 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1153,10 +1153,10 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) /* * iwl_pcie_enqueue_hcmd - enqueue a uCode command * @priv: device private data point - * @cmd: a point to the ucode command structure + * @cmd: a pointer to the ucode command structure * - * The function returns < 0 values to indicate the operation is - * failed. On success, it turns the index (> 0) of command in the + * The function returns < 0 values to indicate the operation + * failed. On success, it returns the index (>= 0) of command in the * command queue. */ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, -- cgit v1.2.3 From 1092b9bc0cdc1d8d456d2b9b1f857b06ef5523da Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 16 Jul 2013 17:53:43 +0300 Subject: iwlwifi: pcie: some little cleanups do some little cleanups in tx.c - eliminate duplicate checks, use locally cached fields and predefined macros. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/tx.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index f29cd5c0aeed..011167c22da8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -451,13 +451,10 @@ static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, return -EINVAL; } - if (WARN_ON(addr & ~DMA_BIT_MASK(36))) + if (WARN(addr & ~IWL_TX_DMA_MASK, + "Unaligned address = %llx\n", (unsigned long long)addr)) return -EINVAL; - if (unlikely(addr & ~IWL_TX_DMA_MASK)) - IWL_ERR(trans, "Unaligned address = %llx\n", - (unsigned long long)addr); - iwl_pcie_tfd_set_tb(tfd, num_tbs, addr, len); return 0; @@ -1631,7 +1628,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, * Check here that the packets are in the right place on the ring. */ wifi_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - WARN_ONCE(trans_pcie->txq[txq_id].ampdu && + WARN_ONCE(txq->ampdu && (wifi_seq & 0xff) != q->write_ptr, "Q: %d WiFi Seq %d tfdNum %d", txq_id, wifi_seq, q->write_ptr); @@ -1663,7 +1660,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, */ len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + hdr_len - IWL_HCMD_SCRATCHBUF_SIZE; - tb1_len = (len + 3) & ~3; + tb1_len = ALIGN(len, 4); /* Tell NIC about any 2-byte padding after MAC header */ if (tb1_len != len) -- cgit v1.2.3 From 5fdda0476c28ff2097ae37f43f40557b91eb0160 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Aug 2013 10:51:22 +0200 Subject: iwlwifi: remove transport suspend/resume indirection There's no reason for the transport to call itself through indirect function pointers, inline the (little) code there is and remove the indirection completely. Reviewed-by: Gregory Greenman Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-trans.h | 19 +------------------ drivers/net/wireless/iwlwifi/pcie/drv.c | 18 ++++++++++++------ drivers/net/wireless/iwlwifi/pcie/trans.c | 26 -------------------------- 3 files changed, 13 insertions(+), 50 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 523dc7ce294b..dd57a36ecb10 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -396,8 +396,6 @@ struct iwl_trans; * May sleep * @dbgfs_register: add the dbgfs files under this directory. Files will be * automatically deleted. - * @suspend: stop the device unless WoWLAN is configured - * @resume: resume activity of the device * @write8: write a u8 to a register at offset ofs from the BAR * @write32: write a u32 to a register at offset ofs from the BAR * @read32: read a u32 register at offset ofs from the BAR @@ -443,10 +441,7 @@ struct iwl_trans_ops { int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); int (*wait_tx_queue_empty)(struct iwl_trans *trans); -#ifdef CONFIG_PM_SLEEP - int (*suspend)(struct iwl_trans *trans); - int (*resume)(struct iwl_trans *trans); -#endif + void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); u32 (*read32)(struct iwl_trans *trans, u32 ofs); @@ -700,18 +695,6 @@ static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, return trans->ops->dbgfs_register(trans, dir); } -#ifdef CONFIG_PM_SLEEP -static inline int iwl_trans_suspend(struct iwl_trans *trans) -{ - return trans->ops->suspend(trans); -} - -static inline int iwl_trans_resume(struct iwl_trans *trans) -{ - return trans->ops->resume(trans); -} -#endif - static inline void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) { trans->ops->write8(trans, ofs, val); diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index db6be2491d7c..9ec8dfeb4354 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -367,21 +367,19 @@ static void iwl_pci_remove(struct pci_dev *pdev) static int iwl_pci_suspend(struct device *device) { - struct pci_dev *pdev = to_pci_dev(device); - struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); - /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx. */ - return iwl_trans_suspend(iwl_trans); + return 0; } static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); + struct iwl_trans *trans = pci_get_drvdata(pdev); + bool hw_rfkill; /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if @@ -394,7 +392,15 @@ static int iwl_pci_resume(struct device *device) */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - return iwl_trans_resume(iwl_trans); + if (!trans->op_mode) + return 0; + + iwl_enable_rfkill_int(trans); + + hw_rfkill = iwl_is_rfkill_set(trans); + iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + + return 0; } static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 601ee5904738..d88c0c748274 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -815,28 +815,6 @@ static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state) clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); } -#ifdef CONFIG_PM_SLEEP -static int iwl_trans_pcie_suspend(struct iwl_trans *trans) -{ - return 0; -} - -static int iwl_trans_pcie_resume(struct iwl_trans *trans) -{ - bool hw_rfkill; - - if (!trans->op_mode) - return 0; - - iwl_enable_rfkill_int(trans); - - hw_rfkill = iwl_is_rfkill_set(trans); - iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); - - return 0; -} -#endif /* CONFIG_PM_SLEEP */ - static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, unsigned long *flags) { @@ -1378,10 +1356,6 @@ static const struct iwl_trans_ops trans_ops_pcie = { .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, -#ifdef CONFIG_PM_SLEEP - .suspend = iwl_trans_pcie_suspend, - .resume = iwl_trans_pcie_resume, -#endif .write8 = iwl_trans_pcie_write8, .write32 = iwl_trans_pcie_write32, .read32 = iwl_trans_pcie_read32, -- cgit v1.2.3 From bd3351ba3e5e3e5b635532fab63da502129141f9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 16 Jul 2013 17:50:17 +0300 Subject: iwlwifi: mvm: add some missing cleanups in iwl_mvm_mac_add_interface iwl_mvm_mac_add_interface() didn't clean up beacon filtering configuration and ctxt allocation in some error cases. Signed-off-by: Eliad Peller Reviewed-by: Alexander Bondar Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index deebe8f9c00d..05daa90616b7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -564,6 +564,10 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, iwl_mvm_power_update_mode(mvm, vif); /* beacon filtering */ + ret = iwl_mvm_disable_beacon_filter(mvm, vif); + if (ret) + goto out_remove_mac; + if (!mvm->bf_allowed_vif && vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){ @@ -571,10 +575,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; } - ret = iwl_mvm_disable_beacon_filter(mvm, vif); - if (ret) - goto out_release; - /* * P2P_DEVICE interface does not have a channel context assigned to it, * so a dedicated PHY context is allocated to it and the corresponding @@ -585,7 +585,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); if (!mvmvif->phy_ctxt) { ret = -ENOSPC; - goto out_remove_mac; + goto out_free_bf; } iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); @@ -609,6 +609,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, iwl_mvm_binding_remove_vif(mvm, vif); out_unref_phy: iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); + out_free_bf: + if (mvm->bf_allowed_vif == mvmvif) { + mvm->bf_allowed_vif = NULL; + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + } out_remove_mac: mvmvif->phy_ctxt = NULL; iwl_mvm_mac_ctxt_remove(mvm, vif); -- cgit v1.2.3 From ef4394b9477f9078d78ae3e8359eae094c9b19d8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 16 Jul 2013 18:07:20 +0300 Subject: iwlwifi: mvm: use designated initialization for some arrays rs_ht_to_legacy and ant_toggle_lookup are arrays that represent some state-machine. initialize them explicitly with designated initialization to make them more clear and avoid errors. Signed-off-by: Eliad Peller Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rs.c | 36 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 940f39d43201..d680c891ce86 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -56,24 +56,30 @@ #define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) static u8 rs_ht_to_legacy[] = { - IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX, - IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, - IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, - IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX + [IWL_RATE_1M_INDEX] = IWL_RATE_6M_INDEX, + [IWL_RATE_2M_INDEX] = IWL_RATE_6M_INDEX, + [IWL_RATE_5M_INDEX] = IWL_RATE_6M_INDEX, + [IWL_RATE_11M_INDEX] = IWL_RATE_6M_INDEX, + [IWL_RATE_6M_INDEX] = IWL_RATE_6M_INDEX, + [IWL_RATE_9M_INDEX] = IWL_RATE_6M_INDEX, + [IWL_RATE_12M_INDEX] = IWL_RATE_9M_INDEX, + [IWL_RATE_18M_INDEX] = IWL_RATE_12M_INDEX, + [IWL_RATE_24M_INDEX] = IWL_RATE_18M_INDEX, + [IWL_RATE_36M_INDEX] = IWL_RATE_24M_INDEX, + [IWL_RATE_48M_INDEX] = IWL_RATE_36M_INDEX, + [IWL_RATE_54M_INDEX] = IWL_RATE_48M_INDEX, + [IWL_RATE_60M_INDEX] = IWL_RATE_54M_INDEX, }; static const u8 ant_toggle_lookup[] = { - /*ANT_NONE -> */ ANT_NONE, - /*ANT_A -> */ ANT_B, - /*ANT_B -> */ ANT_C, - /*ANT_AB -> */ ANT_BC, - /*ANT_C -> */ ANT_A, - /*ANT_AC -> */ ANT_AB, - /*ANT_BC -> */ ANT_AC, - /*ANT_ABC -> */ ANT_ABC, + [ANT_NONE] = ANT_NONE, + [ANT_A] = ANT_B, + [ANT_B] = ANT_C, + [ANT_AB] = ANT_BC, + [ANT_C] = ANT_A, + [ANT_AC] = ANT_AB, + [ANT_BC] = ANT_AC, + [ANT_ABC] = ANT_ABC, }; #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ -- cgit v1.2.3 From e7f1935c11269bc53cd52425b1025657adddb839 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 25 Jul 2013 21:45:17 +0200 Subject: wireless: make TU conversion macros available A few places in the code (mac80211 and iwlmvm) use the same TU_TO_JIFFIES() macro and could use TU_TO_EXP_TIME() that mac80211 has. Make these available to everyone and use them. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/time-event.c | 7 ++----- include/linux/ieee80211.h | 4 ++++ net/mac80211/ieee80211_i.h | 3 --- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index ad9bbca99213..9f100363b177 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -73,7 +73,6 @@ #include "iwl-prph.h" /* A TimeUnit is 1024 microsecond */ -#define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) #define MSEC_TO_TU(_msec) (_msec*1000/1024) /* @@ -191,8 +190,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, iwl_mvm_te_clear_data(mvm, te_data); } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) { te_data->running = true; - te_data->end_jiffies = jiffies + - TU_TO_JIFFIES(te_data->duration); + te_data->end_jiffies = TU_TO_EXP_TIME(te_data->duration); if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); @@ -329,8 +327,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); if (te_data->running && - time_after(te_data->end_jiffies, - jiffies + TU_TO_JIFFIES(min_duration))) { + time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) { IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", jiffies_to_msecs(te_data->end_jiffies - jiffies)); return; diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index b3ce299782af..23a8877f4ded 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2288,4 +2288,8 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim, return !!(tim->virtual_map[index] & mask); } +/* convert time units */ +#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) +#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) + #endif /* LINUX_IEEE80211_H */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e94c84050e9c..b6186517ec56 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -53,9 +53,6 @@ struct ieee80211_local; * increased memory use (about 2 kB of RAM per entry). */ #define IEEE80211_FRAGMENT_MAX 4 -#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) -#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) - /* power level hasn't been configured (or set to automatic) */ #define IEEE80211_UNSET_POWER_LEVEL INT_MIN -- cgit v1.2.3 From 8cc8df906f953ae0cfe785720989928021d7fe2d Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Fri, 2 Aug 2013 09:58:49 +0200 Subject: ath10k: add SoC power save option to PCI features map Unify the PCI options location. By default the SoC PS option is disabled to boost the performance and due to poor stability on early HW revisions. In future we can remove the module parameter and turn on/off the PS for given hardware. This change also makes the pci module parameter for SoC PS static. Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 22 ++++++++++++++-------- drivers/net/wireless/ath/ath10k/pci.h | 11 +++++++---- 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 503e380e4cc0..e2f9ef50b1bd 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -32,7 +32,7 @@ #include "ce.h" #include "pci.h" -unsigned int ath10k_target_ps; +static unsigned int ath10k_target_ps; module_param(ath10k_target_ps, uint, 0644); MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option"); @@ -1759,6 +1759,7 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) static int ath10k_pci_hif_power_up(struct ath10k *ar) { + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; ret = ath10k_pci_start_intr(ar); @@ -1783,13 +1784,9 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) if (ret) goto err_irq; - if (ath10k_target_ps) { - ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n"); - } else { + if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) /* Force AWAKE forever */ - ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save disabled\n"); ath10k_do_pci_wake(ar); - } ret = ath10k_pci_ce_init(ar); if (ret) @@ -1810,7 +1807,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) err_ce: ath10k_pci_ce_deinit(ar); err_ps: - if (!ath10k_target_ps) + if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); err_irq: ath10k_pci_stop_intr(ar); @@ -1820,9 +1817,12 @@ err: static void ath10k_pci_hif_power_down(struct ath10k *ar) { + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + ath10k_pci_stop_intr(ar); + ath10k_pci_ce_deinit(ar); - if (!ath10k_target_ps) + if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); } @@ -2272,6 +2272,9 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci) case ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND: ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n"); break; + case ATH10K_PCI_FEATURE_SOC_POWER_SAVE: + ath10k_dbg(ATH10K_DBG_PCI, "QCA98XX SoC power save enabled\n"); + break; } } } @@ -2307,6 +2310,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_ar_pci; } + if (ath10k_target_ps) + set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features); + ath10k_pci_dump_features(ar_pci); ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index d3a2e6cc9179..871bb339d56d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -153,6 +153,7 @@ struct service_to_pipe { enum ath10k_pci_features { ATH10K_PCI_FEATURE_MSI_X = 0, ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND = 1, + ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 2, /* keep last */ ATH10K_PCI_FEATURE_COUNT @@ -335,20 +336,22 @@ static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) return ioread32(ar_pci->mem + offset); } -extern unsigned int ath10k_target_ps; - void ath10k_do_pci_wake(struct ath10k *ar); void ath10k_do_pci_sleep(struct ath10k *ar); static inline void ath10k_pci_wake(struct ath10k *ar) { - if (ath10k_target_ps) + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_wake(ar); } static inline void ath10k_pci_sleep(struct ath10k *ar) { - if (ath10k_target_ps) + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); } -- cgit v1.2.3 From f32036e823c45cb4974aab1d0ae66d716bfc9aa6 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 20 Jun 2013 12:47:20 +0530 Subject: ath6kl: Fix race in heart beat polling Make sure to cancel heart beat timer before freeing wmi to avoid potential NULL pointer dereference. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/init.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 6a67881f94d6..4f316bdcbab5 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1836,6 +1836,9 @@ void ath6kl_stop_txrx(struct ath6kl *ar) clear_bit(WMI_READY, &ar->flag); + if (ar->fw_recovery.enable) + del_timer_sync(&ar->fw_recovery.hb_timer); + /* * After wmi_shudown all WMI events will be dropped. We * need to cleanup the buffers allocated in AP mode and -- cgit v1.2.3 From 9d0e2f0772d394060bf3b17cd1f3a35574365103 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 5 Aug 2013 10:19:22 +0530 Subject: ath6kl: Fix invalid pointer access on fuzz testing with AP mode In our Fuz testing, reference client corrupts the dest mac to "00:00:00:00:00:00" in the WPA2 handshake no 2. During driver init the sta_list entries mac addresses are by default "00:00:00:00:00:00". Driver returns an invalid pointer (conn) and the drver shall crash, if rxtids (aggr_conn) skb queues are accessed, since they would not be initialized. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index d4fcfcad57d0..5839fc23bdc7 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -29,6 +29,9 @@ struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr) struct ath6kl_sta *conn = NULL; u8 i, max_conn; + if (is_zero_ether_addr(node_addr)) + return NULL; + max_conn = (vif->nw_type == AP_NETWORK) ? AP_MAX_NUM_STA : 0; for (i = 0; i < max_conn; i++) { -- cgit v1.2.3 From 495191c79f378462cc85d1e669be3f8b9ef1c8e7 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Mon, 5 Aug 2013 14:16:45 +0300 Subject: iwlwifi: mvm: Fix beacon filtering enablement via debugfs The code was only enabling it when already enabled, which obviously can't work. Signed-off-by: Alexander Bondar Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 2ee256d0acb7..3cdc00591f6e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -895,10 +895,7 @@ static ssize_t iwl_dbgfs_bf_params_write(struct file *file, if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) { ret = iwl_mvm_disable_beacon_filter(mvm, vif); } else { - if (mvmvif->bf_enabled) - ret = iwl_mvm_enable_beacon_filter(mvm, vif); - else - ret = iwl_mvm_disable_beacon_filter(mvm, vif); + ret = iwl_mvm_enable_beacon_filter(mvm, vif); } mutex_unlock(&mvm->mutex); -- cgit v1.2.3 From f4f3c659846587aae9043d2df31f6434934965e1 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Tue, 6 Aug 2013 18:17:42 +0300 Subject: iwlwifi: introduce external debug level This debug level will be used in the future for logging interaction with external modules. Signed-off-by: Matti Gottlieb Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 7edb8519c8a4..b2bb32a781dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -145,6 +145,7 @@ do { \ #define IWL_DL_RX 0x01000000 #define IWL_DL_ISR 0x02000000 #define IWL_DL_HT 0x04000000 +#define IWL_DL_EXTERNAL 0x08000000 /* 0xF0000000 - 0x10000000 */ #define IWL_DL_11H 0x10000000 #define IWL_DL_STATS 0x20000000 @@ -153,6 +154,7 @@ do { \ #define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a) #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a) +#define IWL_DEBUG_EXTERNAL(p, f, a...) IWL_DEBUG(p, IWL_DL_EXTERNAL, f, ## a) #define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a) #define IWL_DEBUG_SCAN(p, f, a...) IWL_DEBUG(p, IWL_DL_SCAN, f, ## a) #define IWL_DEBUG_RX(p, f, a...) IWL_DEBUG(p, IWL_DL_RX, f, ## a) -- cgit v1.2.3 From a9b292464311d32441cd3284109263d92c413a48 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 15 Jul 2013 11:51:48 -0400 Subject: iwlwifi: pcie: Refactor iwl_queue_space Reduce the ambiguity spares to a single element if the window size is not smaller than the queue size. If smaller, no spares are required at all. Signed-off-by: Ido Yariv Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/tx.c | 36 ++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 011167c22da8..12c9c0030da6 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -65,18 +65,30 @@ ***************************************************/ static int iwl_queue_space(const struct iwl_queue *q) { - int s = q->read_ptr - q->write_ptr; - - if (q->read_ptr > q->write_ptr) - s -= q->n_bd; - - if (s <= 0) - s += q->n_window; - /* keep some reserve to not confuse empty and full situations */ - s -= 2; - if (s < 0) - s = 0; - return s; + unsigned int max; + unsigned int used; + + /* + * To avoid ambiguity between empty and completely full queues, there + * should always be less than q->n_bd elements in the queue. + * If q->n_window is smaller than q->n_bd, there is no need to reserve + * any queue entries for this purpose. + */ + if (q->n_window < q->n_bd) + max = q->n_window; + else + max = q->n_bd - 1; + + /* + * q->n_bd is a power of 2, so the following is equivalent to modulo by + * q->n_bd and is well defined for negative dividends. + */ + used = (q->write_ptr - q->read_ptr) & (q->n_bd - 1); + + if (WARN_ON(used > max)) + return 0; + + return max - used; } /* -- cgit v1.2.3 From 351746c9ad790260ffe5cc78f41e2a8a1e6ab8b6 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 15 Jul 2013 12:41:27 -0400 Subject: iwlwifi: pcie: Refactor iwl_rxq_space Simplify iwl_rxq_space to improve readability and reduce the ambiguity spares to a single element. Signed-off-by: Ido Yariv Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/rx.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 5fdb4eea146d..8c9641b863f7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -112,15 +112,16 @@ */ static int iwl_rxq_space(const struct iwl_rxq *rxq) { - int s = rxq->read - rxq->write; - - if (s <= 0) - s += RX_QUEUE_SIZE; - /* keep some buffer to not confuse full and empty queue */ - s -= 2; - if (s < 0) - s = 0; - return s; + /* Make sure RX_QUEUE_SIZE is a power of 2 */ + BUILD_BUG_ON(RX_QUEUE_SIZE & (RX_QUEUE_SIZE - 1)); + + /* + * There can be up to (RX_QUEUE_SIZE - 1) free slots, to avoid ambiguity + * between empty and completely full queues. + * The following is equivalent to modulo by RX_QUEUE_SIZE and is well + * defined for negative dividends. + */ + return (rxq->read - rxq->write - 1) & (RX_QUEUE_SIZE - 1); } /* -- cgit v1.2.3 From 6e8773c31497867b0dbbcaa60391ab3ec9156371 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 15 Jul 2013 16:01:48 -0400 Subject: iwlwifi: pcie: Remove duplicate code from pcie irq handlers Instead of having the same code sequentially, fall-through. Signed-off-by: Ido Yariv Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/rx.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 8c9641b863f7..3f237b42eb36 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1121,6 +1121,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) struct iwl_trans *trans = data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 inta, inta_mask; + irqreturn_t ret = IRQ_NONE; lockdep_assert_held(&trans_pcie->irq_lock); @@ -1169,10 +1170,8 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) /* the thread will service interrupts and re-enable them */ if (likely(inta)) return IRQ_WAKE_THREAD; - else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && - !trans_pcie->inta) - iwl_enable_interrupts(trans); - return IRQ_HANDLED; + + ret = IRQ_HANDLED; none: /* re-enable interrupts here since we don't have anything to service. */ @@ -1181,7 +1180,7 @@ none: !trans_pcie->inta) iwl_enable_interrupts(trans); - return IRQ_NONE; + return ret; } /* interrupt handler using ict table, with this interrupt driver will @@ -1200,6 +1199,7 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) u32 val = 0; u32 read; unsigned long flags; + irqreturn_t ret = IRQ_NONE; if (!trans) return IRQ_NONE; @@ -1212,7 +1212,7 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) * use legacy interrupt. */ if (unlikely(!trans_pcie->use_ict)) { - irqreturn_t ret = iwl_pcie_isr(irq, data); + ret = iwl_pcie_isr(irq, data); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return ret; } @@ -1281,17 +1281,9 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) if (likely(inta)) { spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_WAKE_THREAD; - } else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && - !trans_pcie->inta) { - /* Allow interrupt if was disabled by this handler and - * no tasklet was schedules, We should not enable interrupt, - * tasklet will enable it. - */ - iwl_enable_interrupts(trans); } - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - return IRQ_HANDLED; + ret = IRQ_HANDLED; none: /* re-enable interrupts here since we don't have anything to service. @@ -1302,5 +1294,5 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) iwl_enable_interrupts(trans); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - return IRQ_NONE; + return ret; } -- cgit v1.2.3 From 3f4e854a2d7d5fdb2f6e9e693903085a21ea0d5e Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 5 Aug 2013 18:51:57 -0700 Subject: mwifiex: rename mef macros Their names were generic. We need to define similar macros for coalesce feature. Hence they are renamed here. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 17 +++++++++-------- drivers/net/wireless/mwifiex/ioctl.h | 8 ++++---- drivers/net/wireless/mwifiex/sta_cmd.c | 4 ++-- 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index c5e21ede60f2..326f4d9a8462 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2327,12 +2327,12 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq) dont_care_byte = true; } - if (valid_byte_cnt > MAX_BYTESEQ) + if (valid_byte_cnt > MWIFIEX_MEF_MAX_BYTESEQ) return false; } } - byte_seq[MAX_BYTESEQ] = valid_byte_cnt; + byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = valid_byte_cnt; return true; } @@ -2345,7 +2345,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, struct mwifiex_mef_entry *mef_entry; int i, filt_num = 0, ret; bool first_pat = true; - u8 byte_seq[MAX_BYTESEQ + 1]; + u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; const u8 ipv4_mc_mac[] = {0x33, 0x33}; const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; struct mwifiex_private *priv = @@ -2383,16 +2383,16 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, if (!wowlan->patterns[i].pkt_offset) { if (!(byte_seq[0] & 0x01) && - (byte_seq[MAX_BYTESEQ] == 1)) { + (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; continue; } else if (is_broadcast_ether_addr(byte_seq)) { mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST; continue; } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && - (byte_seq[MAX_BYTESEQ] == 2)) || + (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 2)) || (!memcmp(byte_seq, ipv6_mc_mac, 3) && - (byte_seq[MAX_BYTESEQ] == 3))) { + (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 3))) { mef_cfg.criteria |= MWIFIEX_CRITERIA_MULTICAST; continue; } @@ -2418,7 +2418,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, mef_entry->filter[filt_num].repeat = 16; memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, ETH_ALEN); - mef_entry->filter[filt_num].byte_seq[MAX_BYTESEQ] = ETH_ALEN; + mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = + ETH_ALEN; mef_entry->filter[filt_num].offset = 14; mef_entry->filter[filt_num].filt_type = TYPE_EQ; if (filt_num) @@ -2491,7 +2492,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { #ifdef CONFIG_PM static const struct wiphy_wowlan_support mwifiex_wowlan_support = { .flags = WIPHY_WOWLAN_MAGIC_PKT, - .n_patterns = MWIFIEX_MAX_FILTERS, + .n_patterns = MWIFIEX_MEF_MAX_FILTERS, .pattern_min_len = 1, .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 7f27e45680b5..5ecda453f832 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -362,13 +362,13 @@ struct mwifiex_ds_misc_subsc_evt { struct subsc_evt_cfg bcn_h_rssi_cfg; }; -#define MAX_BYTESEQ 6 /* non-adjustable */ -#define MWIFIEX_MAX_FILTERS 10 +#define MWIFIEX_MEF_MAX_BYTESEQ 6 /* non-adjustable */ +#define MWIFIEX_MEF_MAX_FILTERS 10 struct mwifiex_mef_filter { u16 repeat; u16 offset; - s8 byte_seq[MAX_BYTESEQ + 1]; + s8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; u8 filt_type; u8 filt_action; }; @@ -376,7 +376,7 @@ struct mwifiex_mef_filter { struct mwifiex_mef_entry { u8 mode; u8 action; - struct mwifiex_mef_filter filter[MWIFIEX_MAX_FILTERS]; + struct mwifiex_mef_filter filter[MWIFIEX_MEF_MAX_FILTERS]; }; struct mwifiex_ds_mef_cfg { diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 9b75ed8563b6..448baf191321 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1070,7 +1070,7 @@ mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv, int i, byte_len; u8 *stack_ptr = *buffer; - for (i = 0; i < MWIFIEX_MAX_FILTERS; i++) { + for (i = 0; i < MWIFIEX_MEF_MAX_FILTERS; i++) { filter = &mef_entry->filter[i]; if (!filter->filt_type) break; @@ -1079,7 +1079,7 @@ mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv, *stack_ptr = TYPE_DNUM; stack_ptr += 1; - byte_len = filter->byte_seq[MAX_BYTESEQ]; + byte_len = filter->byte_seq[MWIFIEX_MEF_MAX_BYTESEQ]; memcpy(stack_ptr, filter->byte_seq, byte_len); stack_ptr += byte_len; *stack_ptr = byte_len; -- cgit v1.2.3 From 0434c464999ca73586be2c513aaa09fd1dc38595 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 5 Aug 2013 18:51:58 -0700 Subject: mwifiex: modify mwifiex_is_pattern_supported() routine It is modified so that it can be reused for coalesce feature. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 326f4d9a8462..62c3d9880607 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2309,7 +2309,8 @@ EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); #ifdef CONFIG_PM static bool -mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq) +mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, + u8 max_byte_seq) { int j, k, valid_byte_cnt = 0; bool dont_care_byte = false; @@ -2327,12 +2328,12 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq) dont_care_byte = true; } - if (valid_byte_cnt > MWIFIEX_MEF_MAX_BYTESEQ) + if (valid_byte_cnt > max_byte_seq) return false; } } - byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = valid_byte_cnt; + byte_seq[max_byte_seq] = valid_byte_cnt; return true; } @@ -2375,7 +2376,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, for (i = 0; i < wowlan->n_patterns; i++) { memset(byte_seq, 0, sizeof(byte_seq)); if (!mwifiex_is_pattern_supported(&wowlan->patterns[i], - byte_seq)) { + byte_seq, + MWIFIEX_MEF_MAX_BYTESEQ)) { wiphy_err(wiphy, "Pattern not supported\n"); kfree(mef_entry); return -EOPNOTSUPP; -- cgit v1.2.3 From afd84de47309cbdf96ea80d073233834f28393a5 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 5 Aug 2013 18:51:59 -0700 Subject: mwifiex: increase max supported pattern offset The offset number is increased to accomodate requests from user to match more fields in a Rx packet. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/fw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index c0dfc4dea75a..12c6223ebb8c 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -450,7 +450,7 @@ enum P2P_MODES { (((event_cause) >> 24) & 0x00ff) #define MWIFIEX_MAX_PATTERN_LEN 20 -#define MWIFIEX_MAX_OFFSET_LEN 50 +#define MWIFIEX_MAX_OFFSET_LEN 100 #define STACK_NBYTES 100 #define TYPE_DNUM 1 #define TYPE_BYTESEQ 2 -- cgit v1.2.3 From 562fc5b30f228d4a8c1dad90c82897a5440d7a0b Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 5 Aug 2013 18:52:00 -0700 Subject: mwifiex: add packet coalesce support Coalesce filters are configured in firmware based on settings received from cfg80211. Packet type which is required by firmware is determined based on provided patterns in a rule: Unicast: if pattern '01' with offset 0 is found Multicast: if pattern '33:33' or '01:00:5e' with offset 0 is found Broadcast: if pattern 'ff:ff:ff:ff' with offset 0 is found Some example coalesce configuration files: 1) Coalesce Rx data packets from 192.168.0.88 mac address of our device is 00:50:43:21:53:7A Source IP address offset comes out as 52 after following calculations: 32 bytes of HW 802.11 header + 8 bytes LLC + 12 bytes in IPV4 header till source IP address Destination mac is at offset 6 in HW header. delay=100 condition=1 patterns=01,6+00:50:43:22,10+53:7A,52+c0:a8:00:58 2) Coalesce all broadcast and multicast packets(Multiple packet types are not allowed in a single rule. Hence created separate rules) delay=400 condition=1 patterns=33:33 delay=400 condition=1 patterns=ff:ff:ff:ff Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 125 +++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/fw.h | 24 ++++++ drivers/net/wireless/mwifiex/ioctl.h | 35 ++++++++ drivers/net/wireless/mwifiex/sta_cmd.c | 68 ++++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 + 5 files changed, 254 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 62c3d9880607..07d23183898c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2455,6 +2455,119 @@ static void mwifiex_cfg80211_set_wakeup(struct wiphy *wiphy, } #endif +static int mwifiex_get_coalesce_pkt_type(u8 *byte_seq) +{ + const u8 ipv4_mc_mac[] = {0x33, 0x33}; + const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; + const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff}; + + if ((byte_seq[0] & 0x01) && + (byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 1)) + return PACKET_TYPE_UNICAST; + else if (!memcmp(byte_seq, bc_mac, 4)) + return PACKET_TYPE_BROADCAST; + else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && + byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 2) || + (!memcmp(byte_seq, ipv6_mc_mac, 3) && + byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 3)) + return PACKET_TYPE_MULTICAST; + + return 0; +} + +static int +mwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv, + struct cfg80211_coalesce_rules *crule, + struct mwifiex_coalesce_rule *mrule) +{ + u8 byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ + 1]; + struct filt_field_param *param; + int i; + + mrule->max_coalescing_delay = crule->delay; + + param = mrule->params; + + for (i = 0; i < crule->n_patterns; i++) { + memset(byte_seq, 0, sizeof(byte_seq)); + if (!mwifiex_is_pattern_supported(&crule->patterns[i], + byte_seq, + MWIFIEX_COALESCE_MAX_BYTESEQ)) { + dev_err(priv->adapter->dev, "Pattern not supported\n"); + return -EOPNOTSUPP; + } + + if (!crule->patterns[i].pkt_offset) { + u8 pkt_type; + + pkt_type = mwifiex_get_coalesce_pkt_type(byte_seq); + if (pkt_type && mrule->pkt_type) { + dev_err(priv->adapter->dev, + "Multiple packet types not allowed\n"); + return -EOPNOTSUPP; + } else if (pkt_type) { + mrule->pkt_type = pkt_type; + continue; + } + } + + if (crule->condition == NL80211_COALESCE_CONDITION_MATCH) + param->operation = RECV_FILTER_MATCH_TYPE_EQ; + else + param->operation = RECV_FILTER_MATCH_TYPE_NE; + + param->operand_len = byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ]; + memcpy(param->operand_byte_stream, byte_seq, + param->operand_len); + param->offset = crule->patterns[i].pkt_offset; + param++; + + mrule->num_of_fields++; + } + + if (!mrule->pkt_type) { + dev_err(priv->adapter->dev, + "Packet type can not be determined\n"); + return -EOPNOTSUPP; + } + + return 0; +} + +static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy, + struct cfg80211_coalesce *coalesce) +{ + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + int i, ret; + struct mwifiex_ds_coalesce_cfg coalesce_cfg; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + + memset(&coalesce_cfg, 0, sizeof(coalesce_cfg)); + if (!coalesce) { + dev_dbg(adapter->dev, + "Disable coalesce and reset all previous rules\n"); + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG, + HostCmd_ACT_GEN_SET, 0, + &coalesce_cfg); + } + + coalesce_cfg.num_of_rules = coalesce->n_rules; + for (i = 0; i < coalesce->n_rules; i++) { + ret = mwifiex_fill_coalesce_rule_info(priv, &coalesce->rules[i], + &coalesce_cfg.rule[i]); + if (ret) { + dev_err(priv->adapter->dev, + "Recheck the patterns provided for rule %d\n", + i + 1); + return ret; + } + } + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG, + HostCmd_ACT_GEN_SET, 0, &coalesce_cfg); +} + /* station cfg80211 operations */ static struct cfg80211_ops mwifiex_cfg80211_ops = { .add_virtual_intf = mwifiex_add_virtual_intf, @@ -2488,6 +2601,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .suspend = mwifiex_cfg80211_suspend, .resume = mwifiex_cfg80211_resume, .set_wakeup = mwifiex_cfg80211_set_wakeup, + .set_coalesce = mwifiex_cfg80211_set_coalesce, #endif }; @@ -2512,6 +2626,15 @@ static bool mwifiex_is_valid_alpha2(const char *alpha2) return false; } +static const struct wiphy_coalesce_support mwifiex_coalesce_support = { + .n_rules = MWIFIEX_COALESCE_MAX_RULES, + .max_delay = MWIFIEX_MAX_COALESCING_DELAY, + .n_patterns = MWIFIEX_COALESCE_MAX_FILTERS, + .pattern_min_len = 1, + .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, + .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, +}; + /* * This function registers the device with CFG802.11 subsystem. * @@ -2573,6 +2696,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->wowlan = &mwifiex_wowlan_support; #endif + wiphy->coalesce = &mwifiex_coalesce_support; + wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 12c6223ebb8c..c9ad1c0d338d 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -153,6 +153,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_UAP_PS_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 123) #define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145) #define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146) +#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -294,6 +295,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_CAU_REG_ACCESS 0x00ed #define HostCmd_CMD_SET_BSS_MODE 0x00f7 #define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa +#define HostCmd_CMD_COALESCE_CFG 0x010a #define HostCmd_CMD_MGMT_FRAME_REG 0x010c #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 @@ -1596,6 +1598,27 @@ struct host_cmd_ds_802_11_cfg_data { __le16 data_len; } __packed; +struct coalesce_filt_field_param { + u8 operation; + u8 operand_len; + __le16 offset; + u8 operand_byte_stream[4]; +}; + +struct coalesce_receive_filt_rule { + struct mwifiex_ie_types_header header; + u8 num_of_fields; + u8 pkt_type; + __le16 max_coalescing_delay; + struct coalesce_filt_field_param params[0]; +} __packed; + +struct host_cmd_ds_coalesce_cfg { + __le16 action; + __le16 num_of_rules; + struct coalesce_receive_filt_rule rule[0]; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -1656,6 +1679,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_sta_deauth sta_deauth; struct host_cmd_11ac_vht_cfg vht_cfg; struct host_cmd_ds_802_11_cfg_data cfg_data; + struct host_cmd_ds_coalesce_cfg coalesce_cfg; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 5ecda453f832..00a95f4c6a6c 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -397,4 +397,39 @@ enum { MWIFIEX_FUNC_SHUTDOWN, }; +enum COALESCE_OPERATION { + RECV_FILTER_MATCH_TYPE_EQ = 0x80, + RECV_FILTER_MATCH_TYPE_NE, +}; + +enum COALESCE_PACKET_TYPE { + PACKET_TYPE_UNICAST = 1, + PACKET_TYPE_MULTICAST = 2, + PACKET_TYPE_BROADCAST = 3 +}; + +#define MWIFIEX_COALESCE_MAX_RULES 8 +#define MWIFIEX_COALESCE_MAX_BYTESEQ 4 /* non-adjustable */ +#define MWIFIEX_COALESCE_MAX_FILTERS 4 +#define MWIFIEX_MAX_COALESCING_DELAY 100 /* in msecs */ + +struct filt_field_param { + u8 operation; + u8 operand_len; + u16 offset; + u8 operand_byte_stream[MWIFIEX_COALESCE_MAX_BYTESEQ]; +}; + +struct mwifiex_coalesce_rule { + u16 max_coalescing_delay; + u8 num_of_fields; + u8 pkt_type; + struct filt_field_param params[MWIFIEX_COALESCE_MAX_FILTERS]; +}; + +struct mwifiex_ds_coalesce_cfg { + u16 num_of_rules; + struct mwifiex_coalesce_rule rule[MWIFIEX_COALESCE_MAX_RULES]; +}; + #endif /* !_MWIFIEX_IOCTL_H_ */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 448baf191321..c0268b597748 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1184,6 +1184,70 @@ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv, return 0; } +static int +mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_coalesce_cfg *coalesce_cfg = + &cmd->params.coalesce_cfg; + struct mwifiex_ds_coalesce_cfg *cfg = data_buf; + struct coalesce_filt_field_param *param; + u16 cnt, idx, length; + struct coalesce_receive_filt_rule *rule; + + cmd->command = cpu_to_le16(HostCmd_CMD_COALESCE_CFG); + cmd->size = cpu_to_le16(S_DS_GEN); + + coalesce_cfg->action = cpu_to_le16(cmd_action); + coalesce_cfg->num_of_rules = cpu_to_le16(cfg->num_of_rules); + rule = coalesce_cfg->rule; + + for (cnt = 0; cnt < cfg->num_of_rules; cnt++) { + rule->header.type = cpu_to_le16(TLV_TYPE_COALESCE_RULE); + rule->max_coalescing_delay = + cpu_to_le16(cfg->rule[cnt].max_coalescing_delay); + rule->pkt_type = cfg->rule[cnt].pkt_type; + rule->num_of_fields = cfg->rule[cnt].num_of_fields; + + length = 0; + + param = rule->params; + for (idx = 0; idx < cfg->rule[cnt].num_of_fields; idx++) { + param->operation = cfg->rule[cnt].params[idx].operation; + param->operand_len = + cfg->rule[cnt].params[idx].operand_len; + param->offset = + cpu_to_le16(cfg->rule[cnt].params[idx].offset); + memcpy(param->operand_byte_stream, + cfg->rule[cnt].params[idx].operand_byte_stream, + param->operand_len); + + length += sizeof(struct coalesce_filt_field_param); + + param++; + } + + /* Total rule length is sizeof max_coalescing_delay(u16), + * num_of_fields(u8), pkt_type(u8) and total length of the all + * params + */ + rule->header.len = cpu_to_le16(length + sizeof(u16) + + sizeof(u8) + sizeof(u8)); + + /* Add the rule length to the command size*/ + le16_add_cpu(&cmd->size, le16_to_cpu(rule->header.len) + + sizeof(struct mwifiex_ie_types_header)); + + rule = (void *)((u8 *)rule->params + length); + } + + /* Add sizeof action, num_of_rules to total command length */ + le16_add_cpu(&cmd->size, sizeof(u16) + sizeof(u16)); + + return 0; +} + /* * This function prepares the commands before sending them to the firmware. * @@ -1407,6 +1471,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_MEF_CFG: ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf); break; + case HostCmd_CMD_COALESCE_CFG: + ret = mwifiex_cmd_coalesce_cfg(priv, cmd_ptr, cmd_action, + data_buf); + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd- %#x\n", cmd_no); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index d85df158cc6c..6a814eb2671a 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -997,6 +997,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_MEF_CFG: break; + case HostCmd_CMD_COALESCE_CFG: + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); -- cgit v1.2.3 From 36e8825e65c0b1d9511feceb6c464d8925e7c791 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 6 Aug 2013 12:44:15 +0530 Subject: ath9k: Fix build failure Make sure that CONFIG_ATH9K_BTCOEX_SUPPORT is used for the WLAN/BT RX diversity hooks. Reported by the kernel build testing backend. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_phy.c | 9 ++++++++- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 9 ++++++++- drivers/net/wireless/ath/ath9k/debug.c | 8 ++++++-- drivers/net/wireless/ath/ath9k/hw-ops.h | 4 ++++ drivers/net/wireless/ath/ath9k/hw.h | 5 ++++- 5 files changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 456d8b917396..1fc1fa955d44 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -555,6 +555,8 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); } +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) { struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; @@ -614,6 +616,8 @@ static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); } +#endif + static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, struct ath_spec_scan *param) { @@ -689,10 +693,13 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah) ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set; - ops->set_bt_ant_diversity = ar9002_hw_set_bt_ant_diversity; ops->spectral_scan_config = ar9002_hw_spectral_scan_config; ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger; ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait; +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + ops->set_bt_ant_diversity = ar9002_hw_set_bt_ant_diversity; +#endif + ar9002_hw_set_nf_limits(ah); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 4898829e6549..39c37309f39e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1412,6 +1412,8 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) { struct ath9k_hw_capabilities *pCap = &ah->caps; @@ -1513,6 +1515,8 @@ static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) } } +#endif + static int ar9003_hw_fast_chan_change(struct ath_hw *ah, struct ath9k_channel *chan, u8 *ini_reloaded) @@ -1688,11 +1692,14 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; - ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity; ops->spectral_scan_config = ar9003_hw_spectral_scan_config; ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger; ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait; +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity; +#endif + ar9003_hw_set_nf_limits(ah); ar9003_hw_set_radar_conf(ah); memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs)); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a155190e2c84..414584ed3f54 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -270,6 +270,8 @@ static const struct file_operations fops_ani = { .llseek = default_llseek, }; +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + static ssize_t read_file_bt_ant_diversity(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -323,6 +325,8 @@ static const struct file_operations fops_bt_ant_diversity = { .llseek = default_llseek, }; +#endif + void ath9k_debug_stat_ant(struct ath_softc *sc, struct ath_hw_antcomb_conf *div_ant_conf, int main_rssi_avg, int alt_rssi_avg) @@ -1935,11 +1939,11 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); - debugfs_create_file("bt_ant_diversity", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_bt_ant_diversity); debugfs_create_file("antenna_diversity", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_antenna_diversity); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + debugfs_create_file("bt_ant_diversity", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_bt_ant_diversity); debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_btcoex); #endif diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index a78d48c3ad21..83f4927aeaca 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -78,12 +78,16 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); } +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) { if (ath9k_hw_ops(ah)->set_bt_ant_diversity) ath9k_hw_ops(ah)->set_bt_ant_diversity(ah, enable); } +#endif + /* Private hardware call ops */ /* PHY ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 38f461c11c33..64ff8e61c243 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -719,11 +719,14 @@ struct ath_hw_ops { struct ath_hw_antcomb_conf *antconf); void (*antdiv_comb_conf_set)(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf); - void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable); void (*spectral_scan_config)(struct ath_hw *ah, struct ath_spec_scan *param); void (*spectral_scan_trigger)(struct ath_hw *ah); void (*spectral_scan_wait)(struct ath_hw *ah); + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable); +#endif }; struct ath_nf_limits { -- cgit v1.2.3 From 6cdfc1de173aa916c820195a040752bb603a21dd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 6 Aug 2013 17:36:03 +0900 Subject: net: wireless: rt2x00: Staticize rt2x00queue_pause_queue_nocheck() rt2x00queue_pause_queue_nocheck()is used only in this file. Fix the following sparse warning: drivers/net/wireless/rt2x00/rt2x00queue.c:939:6: warning: symbol 'rt2x00queue_pause_queue_nocheck' was not declared. Should it be static? Signed-off-by: Jingoo Han Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index aa95c6cf3545..6c8a33b6ee22 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -936,7 +936,7 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index) spin_unlock_irqrestore(&queue->index_lock, irqflags); } -void rt2x00queue_pause_queue_nocheck(struct data_queue *queue) +static void rt2x00queue_pause_queue_nocheck(struct data_queue *queue) { switch (queue->qid) { case QID_AC_VO: -- cgit v1.2.3 From e33354764dff11905f3f36f8da72ae46f177d890 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Aug 2013 11:13:19 +0200 Subject: brcmfmac: use CFG80211_TESTMODE_CMD This is essentially the same, but written shorter. Signed-off-by: Johannes Berg Acked-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 7fa71f73cfe8..c3dfea3f307d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4164,9 +4164,7 @@ static struct cfg80211_ops wl_cfg80211_ops = { .stop_p2p_device = brcmf_p2p_stop_device, .crit_proto_start = brcmf_cfg80211_crit_proto_start, .crit_proto_stop = brcmf_cfg80211_crit_proto_stop, -#ifdef CONFIG_NL80211_TESTMODE - .testmode_cmd = brcmf_cfg80211_testmode -#endif + CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode) }; static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type) -- cgit v1.2.3 From a7586ee441d50f0379a202d45d8fd0a7952cc918 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:02 +0200 Subject: ath9k: add utility functions for accessing tid queues Useful for further fixes / cleanups Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 51 ++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 52cd5219aba9..eaa9eaf91ee7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -168,6 +168,16 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, } } +static bool ath_tid_has_buffered(struct ath_atx_tid *tid) +{ + return !skb_queue_empty(&tid->buf_q); +} + +static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) +{ + return __skb_dequeue(&tid->buf_q); +} + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; @@ -182,7 +192,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) memset(&ts, 0, sizeof(ts)); - while ((skb = __skb_dequeue(&tid->buf_q))) { + while ((skb = ath_tid_dequeue(tid))) { fi = get_frame_info(skb); bf = fi->bf; @@ -266,7 +276,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); - while ((skb = __skb_dequeue(&tid->buf_q))) { + while ((skb = ath_tid_dequeue(tid))) { fi = get_frame_info(skb); bf = fi->bf; @@ -815,7 +825,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, static struct ath_buf * ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid) + struct ath_atx_tid *tid, struct sk_buff_head **q) { struct ath_frame_info *fi; struct sk_buff *skb; @@ -823,7 +833,8 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, u16 seqno; while (1) { - skb = skb_peek(&tid->buf_q); + *q = &tid->buf_q; + skb = skb_peek(*q); if (!skb) break; @@ -833,7 +844,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { - __skb_unlink(skb, &tid->buf_q); + __skb_unlink(skb, *q); ath_txq_skb_done(sc, txq, skb); ieee80211_free_txskb(sc->hw, skb); continue; @@ -852,7 +863,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_head); list_add(&bf->list, &bf_head); - __skb_unlink(skb, &tid->buf_q); + __skb_unlink(skb, *q); ath_tx_update_baw(sc, tid, seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); continue; @@ -881,9 +892,10 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, struct ieee80211_tx_info *tx_info; struct ath_frame_info *fi; struct sk_buff *skb; + struct sk_buff_head *tid_q; do { - bf = ath_tx_get_tid_subframe(sc, txq, tid); + bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); if (!bf) { status = ATH_AGGR_BAW_CLOSED; break; @@ -940,14 +952,14 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); bf->bf_state.ndelim = ndelim; - __skb_unlink(skb, &tid->buf_q); + __skb_unlink(skb, tid_q); list_add_tail(&bf->list, bf_q); if (bf_prev) bf_prev->bf_next = bf; bf_prev = bf; - } while (!skb_queue_empty(&tid->buf_q)); + } while (ath_tid_has_buffered(tid)); *aggr_len = al; @@ -1250,7 +1262,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, int aggr_len; do { - if (skb_queue_empty(&tid->buf_q)) + if (!ath_tid_has_buffered(tid)) return; INIT_LIST_HEAD(&bf_q); @@ -1354,7 +1366,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, ath_txq_lock(sc, txq); - buffered = !skb_queue_empty(&tid->buf_q); + buffered = ath_tid_has_buffered(tid); tid->sched = false; list_del(&tid->list); @@ -1386,7 +1398,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) ath_txq_lock(sc, txq); ac->clear_ps_filter = true; - if (!skb_queue_empty(&tid->buf_q) && !tid->paused) { + if (!tid->paused && ath_tid_has_buffered(tid)) { ath_tx_queue_tid(txq, tid); ath_txq_schedule(sc, txq); } @@ -1411,7 +1423,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; tid->paused = false; - if (!skb_queue_empty(&tid->buf_q)) { + if (ath_tid_has_buffered(tid)) { ath_tx_queue_tid(txq, tid); ath_txq_schedule(sc, txq); } @@ -1431,6 +1443,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_tx_info *info; struct list_head bf_q; struct ath_buf *bf_tail = NULL, *bf; + struct sk_buff_head *tid_q; int sent = 0; int i; @@ -1446,12 +1459,12 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, continue; ath_txq_lock(sc, tid->ac->txq); - while (!skb_queue_empty(&tid->buf_q) && nframes > 0) { - bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid); + while (nframes > 0) { + bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q); if (!bf) break; - __skb_unlink(bf->bf_mpdu, &tid->buf_q); + __skb_unlink(bf->bf_mpdu, tid_q); list_add_tail(&bf->list, &bf_q); ath_set_rates(tid->an->vif, tid->an->sta, bf); ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); @@ -1464,7 +1477,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, sent++; TX_STAT_INC(txq->axq_qnum, a_queued_hw); - if (skb_queue_empty(&tid->buf_q)) + if (!ath_tid_has_buffered(tid)) ieee80211_sta_set_buffered(an->sta, i, false); } ath_txq_unlock_complete(sc, tid->ac->txq); @@ -1750,7 +1763,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) * add tid to round-robin queue if more frames * are pending for the tid */ - if (!skb_queue_empty(&tid->buf_q)) + if (ath_tid_has_buffered(tid)) ath_tx_queue_tid(txq, tid); if (tid == last_tid || @@ -1859,7 +1872,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq, * - seqno is not within block-ack window * - h/w queue depth exceeds low water mark */ - if ((!skb_queue_empty(&tid->buf_q) || tid->paused || + if ((ath_tid_has_buffered(tid) || tid->paused || !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) || txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) && txq != sc->tx.uapsdq) { -- cgit v1.2.3 From bb195ff61f2e205886ec246465f0809e5c6cd52f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:03 +0200 Subject: ath9k: split tid retry packets into a separate queue Improves packet retry order and helps with further tx queueing improvements. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/xmit.c | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index c497d529ce86..2ce79c1e94bf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -241,6 +241,7 @@ struct ath_buf { struct ath_atx_tid { struct list_head list; struct sk_buff_head buf_q; + struct sk_buff_head retry_q; struct ath_node *an; struct ath_atx_ac *ac; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index eaa9eaf91ee7..c2b6cf0de903 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -170,12 +170,18 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, static bool ath_tid_has_buffered(struct ath_atx_tid *tid) { - return !skb_queue_empty(&tid->buf_q); + return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q); } static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) { - return __skb_dequeue(&tid->buf_q); + struct sk_buff *skb; + + skb = __skb_dequeue(&tid->retry_q); + if (!skb) + skb = __skb_dequeue(&tid->buf_q); + + return skb; } static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) @@ -593,7 +599,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (an->sleeping) ieee80211_sta_set_buffered(sta, tid->tidno, true); - skb_queue_splice(&bf_pending, &tid->buf_q); + skb_queue_splice_tail(&bf_pending, &tid->retry_q); if (!an->sleeping) { ath_tx_queue_tid(txq, tid); @@ -833,7 +839,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, u16 seqno; while (1) { - *q = &tid->buf_q; + *q = &tid->retry_q; + if (skb_queue_empty(*q)) + *q = &tid->buf_q; + skb = skb_peek(*q); if (!skb) break; @@ -2636,6 +2645,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->paused = false; tid->active = false; __skb_queue_head_init(&tid->buf_q); + __skb_queue_head_init(&tid->retry_q); acno = TID_TO_WME_AC(tidno); tid->ac = &an->ac[acno]; } -- cgit v1.2.3 From 1803d02d7a262e451b26e6134786cced02ab2d1e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:04 +0200 Subject: ath9k: add function for getting the tx tid for a packet Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c2b6cf0de903..350429b4d535 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -168,6 +168,20 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, } } +static struct ath_atx_tid * +ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + u8 tidno = 0; + + hdr = (struct ieee80211_hdr *) skb->data; + if (ieee80211_is_data_qos(hdr->frame_control)) + tidno = ieee80211_get_qos_ctl(hdr)[0]; + + tidno &= IEEE80211_QOS_CTL_TID_MASK; + return ATH_AN_2_TID(an, tidno); +} + static bool ath_tid_has_buffered(struct ath_atx_tid *tid) { return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q); @@ -419,7 +433,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_tx_rate rates[4]; struct ath_frame_info *fi; int nframes; - u8 tidno; bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH); int i, retries; int bar_index = -1; @@ -456,8 +469,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } an = (struct ath_node *)sta->drv_priv; - tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; - tid = ATH_AN_2_TID(an, tidno); + tid = ath_get_skb_tid(sc, an, skb); seq_first = tid->seq_start; isba = ts->ts_flags & ATH9K_TX_BA; @@ -469,7 +481,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * Only BlockAcks have a TID and therefore normal Acks cannot be * checked */ - if (isba && tidno != ts->tid) + if (isba && tid->tidno != ts->tid) txok = false; isaggr = bf_isaggr(bf); @@ -2116,7 +2128,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_txq *txq = txctl->txq; struct ath_atx_tid *tid = NULL; struct ath_buf *bf; - u8 tidno; int q; int ret; @@ -2147,9 +2158,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, } if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { - tidno = ieee80211_get_qos_ctl(hdr)[0] & - IEEE80211_QOS_CTL_TID_MASK; - tid = ATH_AN_2_TID(txctl->an, tidno); + tid = ath_get_skb_tid(sc, txctl->an, skb); WARN_ON(tid->ac->txq != txctl->txq); } -- cgit v1.2.3 From 18fcf1c6a6ff4b00fe06e1d0ef05ff76ed2fe86c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:05 +0200 Subject: ath9k: add CAB queue info to debugfs Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 43 +++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 414584ed3f54..c10cec5650c6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -732,6 +732,28 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, return retval; } +static ssize_t print_queue(struct ath_softc *sc, struct ath_txq *txq, + char *buf, ssize_t size) +{ + ssize_t len = 0; + + ath_txq_lock(sc, txq); + + len += snprintf(buf + len, size - len, "%s: %d ", + "qnum", txq->axq_qnum); + len += snprintf(buf + len, size - len, "%s: %2d ", + "qdepth", txq->axq_depth); + len += snprintf(buf + len, size - len, "%s: %2d ", + "ampdu-depth", txq->axq_ampdu_depth); + len += snprintf(buf + len, size - len, "%s: %3d ", + "pending", txq->pending_frames); + len += snprintf(buf + len, size - len, "%s: %d\n", + "stopped", txq->stopped); + + ath_txq_unlock(sc, txq); + return len; +} + static ssize_t read_file_queues(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -749,24 +771,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf, for (i = 0; i < IEEE80211_NUM_ACS; i++) { txq = sc->tx.txq_map[i]; - len += snprintf(buf + len, size - len, "(%s): ", qname[i]); - - ath_txq_lock(sc, txq); - - len += snprintf(buf + len, size - len, "%s: %d ", - "qnum", txq->axq_qnum); - len += snprintf(buf + len, size - len, "%s: %2d ", - "qdepth", txq->axq_depth); - len += snprintf(buf + len, size - len, "%s: %2d ", - "ampdu-depth", txq->axq_ampdu_depth); - len += snprintf(buf + len, size - len, "%s: %3d ", - "pending", txq->pending_frames); - len += snprintf(buf + len, size - len, "%s: %d\n", - "stopped", txq->stopped); - - ath_txq_unlock(sc, txq); + len += snprintf(buf + len, size - len, "(%s): ", qname[i]); + len += print_queue(sc, txq, buf + len, size - len); } + len += snprintf(buf + len, size - len, "(CAB): "); + len += print_queue(sc, sc->beacon.cabq, buf + len, size - len); + if (len > size) len = size; -- cgit v1.2.3 From a1cd94d345a8f68300c8ccd8422434e54199f68d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:06 +0200 Subject: ath9k: simplify ath_tx_form_aggr The check for ATH_AMPDU_SUBFRAME_DEFAULT is unnecessary, since it's set to half the maximum BlockAck Window size, which is already the maximum value that h_baw could possibly have. Also remove unnecessary variables. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/xmit.c | 33 ++++++++++++--------------------- 2 files changed, 12 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2ce79c1e94bf..725515fd5ffe 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -137,7 +137,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_AGGR_ENCRYPTDELIM 10 /* minimum h/w qdepth to be sustained to maximize aggregation */ #define ATH_AGGR_MIN_QDEPTH 2 -#define ATH_AMPDU_SUBFRAME_DEFAULT 32 #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 350429b4d535..887f2d4a4452 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -906,9 +906,9 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, { #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL; - int rl = 0, nframes = 0, ndelim, prev_al = 0; + int nframes = 0, ndelim; u16 aggr_limit = 0, al = 0, bpad = 0, - al_delta, h_baw = tid->baw_size / 2; + al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; struct ieee80211_tx_info *tx_info; struct ath_frame_info *fi; @@ -925,33 +925,24 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, skb = bf->bf_mpdu; fi = get_frame_info(skb); - if (!bf_first) + if (!bf_first) { bf_first = bf; - - if (!rl) { ath_set_rates(tid->an->vif, tid->an->sta, bf); aggr_limit = ath_lookup_rate(sc, bf, tid); - rl = 1; } /* do not exceed aggregation limit */ al_delta = ATH_AGGR_DELIM_SZ + fi->framelen; + if (nframes) { + if (aggr_limit < al + bpad + al_delta || + ath_lookup_legacy(bf) || nframes >= h_baw) { + status = ATH_AGGR_LIMITED; + break; + } - if (nframes && - ((aggr_limit < (al + bpad + al_delta + prev_al)) || - ath_lookup_legacy(bf))) { - status = ATH_AGGR_LIMITED; - break; - } - - tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); - if (nframes && (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) - break; - - /* do not exceed subframe limit */ - if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) { - status = ATH_AGGR_LIMITED; - break; + tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + break; } /* add padding for previous frame to aggregation length */ -- cgit v1.2.3 From 8fed14085595c703612b5b712ffe114ef0370929 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:07 +0200 Subject: ath9k: fix block ack window tracking check When a packet has been tracked as part of the BlockAck window and added to the hardware queue, it can end up back in the TID queue again with fi->retries still set to 0 (e.g. if the frame was filtered). Keep an extra bit for the BAW tracking status to fix this corner case. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++- drivers/net/wireless/ath/ath9k/xmit.c | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 725515fd5ffe..126f98066f1b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -211,8 +211,9 @@ struct ath_frame_info { int framelen; enum ath9k_key_type keytype; u8 keyix; - u8 retries; u8 rtscts_rate; + u8 retries : 7; + u8 baw_tracked : 1; }; struct ath_buf_state { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 887f2d4a4452..d66e8b855f85 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -225,7 +225,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) } } - if (fi->retries) { + if (fi->baw_tracked) { 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); @@ -262,13 +262,16 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, } static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - u16 seqno) + struct ath_buf *bf) { + struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); + u16 seqno = bf->bf_state.seqno; int index, cindex; index = ATH_BA_INDEX(tid->seq_start, seqno); cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); __set_bit(cindex, tid->tx_buf); + fi->baw_tracked = 1; if (index >= ((tid->baw_tail - tid->baw_head) & (ATH_TID_MAX_BUFS - 1))) { @@ -960,8 +963,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, bf->bf_next = NULL; /* link buffers of this frame to the aggregate */ - if (!fi->retries) - ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); + if (!fi->baw_tracked) + ath_tx_addto_baw(sc, tid, bf); bf->bf_state.ndelim = ndelim; __skb_unlink(skb, tid_q); @@ -1479,7 +1482,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, __skb_unlink(bf->bf_mpdu, tid_q); list_add_tail(&bf->list, &bf_q); ath_set_rates(tid->an->vif, tid->an->sta, bf); - ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); + ath_tx_addto_baw(sc, tid, bf); bf->bf_state.bf_type &= ~BUF_AGGR; if (bf_tail) bf_tail->bf_next = bf; @@ -1912,7 +1915,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq, list_add(&bf->list, &bf_head); /* Add sub-frame to BAW */ - ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); + ath_tx_addto_baw(sc, tid, bf); /* Queue to h/w without aggregation */ TX_STAT_INC(txq->axq_qnum, a_queued_hw); -- cgit v1.2.3 From 73364b0c470a9c0361a389f3460357a7c7ffd75d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:08 +0200 Subject: ath9k: prepare queueing code for handling unaggregated traffic - Allow ath_tx_get_tid_subframe to return non-AMPDU subframes. - Reset the tid paused state on aggregation stop - Initialize software queues even when HT is not supported Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 3 --- drivers/net/wireless/ath/ath9k/xmit.c | 20 ++++++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index afeab3ca9a69..252497ae5089 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1371,9 +1371,6 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_node *an = (struct ath_node *) sta->drv_priv; - if (!sta->ht_cap.ht_supported) - return; - switch (cmd) { case STA_NOTIFY_SLEEP: an->sleeping = true; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d66e8b855f85..e69f7fef7887 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -672,7 +672,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, } else ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush) + if (!flush) ath_txq_schedule(sc, txq); } @@ -848,6 +848,7 @@ static struct ath_buf * ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct sk_buff_head **q) { + struct ieee80211_tx_info *tx_info; struct ath_frame_info *fi; struct sk_buff *skb; struct ath_buf *bf; @@ -874,6 +875,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, continue; } + bf->bf_next = NULL; + bf->bf_lastbf = bf; + + tx_info = IEEE80211_SKB_CB(skb); + tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; + if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { + bf->bf_state.bf_type = 0; + return bf; + } + bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; seqno = bf->bf_state.seqno; @@ -893,8 +904,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, continue; } - bf->bf_next = NULL; - bf->bf_lastbf = bf; return bf; } @@ -1356,7 +1365,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) ath_txq_lock(sc, txq); txtid->active = false; - txtid->paused = true; + txtid->paused = false; ath_tx_flush_tid(sc, txtid); ath_txq_unlock_complete(sc, txq); } @@ -2425,8 +2434,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) - ath_txq_schedule(sc, txq); + ath_txq_schedule(sc, txq); break; } bf = list_first_entry(&txq->axq_q, struct ath_buf, list); -- cgit v1.2.3 From 897d7fd9b5f1bee657d000b882c642541bb2ba3e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:09 +0200 Subject: ath9k: fix clearing expired A-MPDU subframes in tx completion When the tid aggregation state has been marked as inactive, free completed tx packets immediately. When a new aggregation session has not been initialized yet, the BAW checks do not recognize it as expired. Might fix potential stalls in setting up a new aggregation session. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e69f7fef7887..3ede3e95a751 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -520,7 +520,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, tx_info = IEEE80211_SKB_CB(skb); fi = get_frame_info(skb); - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno) || + !tid->active) { /* * Outside of the current BlockAck window, * maybe part of a previous session -- cgit v1.2.3 From 026d5b07c03458f9c0ccd19c3850564a5409c325 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:10 +0200 Subject: ath9k: always clear ps filter bit on new assoc Otherwise in some cases, EAPOL frames might be filtered during the initial handshake, causing delays and assoc failures. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3ede3e95a751..dfa85f1aee73 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2665,6 +2665,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) for (acno = 0, ac = &an->ac[acno]; acno < IEEE80211_NUM_ACS; acno++, ac++) { ac->sched = false; + ac->clear_ps_filter = true; ac->txq = sc->tx.txq_map[acno]; INIT_LIST_HEAD(&ac->tid_q); } -- cgit v1.2.3 From 2800e82bcc3ba8d2a2bbb42557e2f320f8b27da1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:11 +0200 Subject: ath9k: use software queues for un-aggregated data packets This is a first step for improving fairness between legacy and 802.11n traffic, and it should also improve reliability of resets and channel changes by keeping the hardware queue depth very short. When an aggregation session is torn down, all packets in the retry queue will be removed from the BAW and freed. For all subframes that have not been transmitted yet, the A-MPDU flag will be cleared, and a sequence number allocated. This ensures that the next A-MPDU session will get the correct initial sequence number. This happens both on aggregation session start and stop. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 8 +- drivers/net/wireless/ath/ath9k/xmit.c | 264 ++++++++++++++++++--------------- 2 files changed, 145 insertions(+), 127 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 126f98066f1b..41ea3fd5b9bb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -137,6 +137,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_AGGR_ENCRYPTDELIM 10 /* minimum h/w qdepth to be sustained to maximize aggregation */ #define ATH_AGGR_MIN_QDEPTH 2 +/* minimum h/w qdepth for non-aggregated traffic */ +#define ATH_NON_AGGR_MIN_QDEPTH 8 #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 @@ -173,12 +175,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_TX_COMPLETE_POLL_INT 1000 -enum ATH_AGGR_STATUS { - ATH_AGGR_DONE, - ATH_AGGR_BAW_CLOSED, - ATH_AGGR_LIMITED, -}; - #define ATH_TXFIFO_DEPTH 8 struct ath_txq { int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index dfa85f1aee73..3b66f2b67fec 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -198,6 +198,41 @@ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) return skb; } +/* + * ath_tx_tid_change_state: + * - clears a-mpdu flag of previous session + * - force sequence number allocation to fix next BlockAck Window + */ +static void +ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) +{ + struct ath_txq *txq = tid->ac->txq; + struct ieee80211_tx_info *tx_info; + struct sk_buff *skb, *tskb; + struct ath_buf *bf; + struct ath_frame_info *fi; + + skb_queue_walk_safe(&tid->buf_q, skb, tskb) { + fi = get_frame_info(skb); + bf = fi->bf; + + tx_info = IEEE80211_SKB_CB(skb); + tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; + + if (bf) + continue; + + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + if (!bf) { + __skb_unlink(skb, &tid->buf_q); + ath_txq_skb_done(sc, txq, skb); + ieee80211_free_txskb(sc->hw, skb); + continue; + } + } + +} + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; @@ -212,28 +247,22 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) memset(&ts, 0, sizeof(ts)); - while ((skb = ath_tid_dequeue(tid))) { + while ((skb = __skb_dequeue(&tid->retry_q))) { fi = get_frame_info(skb); bf = fi->bf; - if (!bf) { - bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) { - ath_txq_skb_done(sc, txq, skb); - ieee80211_free_txskb(sc->hw, skb); - continue; - } + ath_txq_skb_done(sc, txq, skb); + ieee80211_free_txskb(sc->hw, skb); + continue; } if (fi->baw_tracked) { - 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); sendbar = true; - } else { - ath_set_rates(tid->an->vif, tid->an->sta, bf); - ath_tx_send_normal(sc, txq, NULL, skb); } + + list_add_tail(&bf->list, &bf_head); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); } if (sendbar) { @@ -911,50 +940,39 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, return NULL; } -static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, - struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_q, - int *aggr_len) +static bool +ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, struct list_head *bf_q, + struct ath_buf *bf_first, struct sk_buff_head *tid_q, + int *aggr_len) { #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) - struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL; + struct ath_buf *bf = bf_first, *bf_prev = NULL; int nframes = 0, ndelim; u16 aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw = tid->baw_size / 2; - enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; struct ieee80211_tx_info *tx_info; struct ath_frame_info *fi; struct sk_buff *skb; - struct sk_buff_head *tid_q; + bool closed = false; - do { - bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); - if (!bf) { - status = ATH_AGGR_BAW_CLOSED; - break; - } + bf = bf_first; + aggr_limit = ath_lookup_rate(sc, bf, tid); + do { skb = bf->bf_mpdu; fi = get_frame_info(skb); - if (!bf_first) { - bf_first = bf; - ath_set_rates(tid->an->vif, tid->an->sta, bf); - aggr_limit = ath_lookup_rate(sc, bf, tid); - } - /* do not exceed aggregation limit */ al_delta = ATH_AGGR_DELIM_SZ + fi->framelen; if (nframes) { if (aggr_limit < al + bpad + al_delta || - ath_lookup_legacy(bf) || nframes >= h_baw) { - status = ATH_AGGR_LIMITED; + ath_lookup_legacy(bf) || nframes >= h_baw) break; - } tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); - if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || + !(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) break; } @@ -984,11 +1002,26 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, bf_prev = bf; + bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); + if (!bf) { + closed = true; + break; + } } while (ath_tid_has_buffered(tid)); + bf = bf_first; + bf->bf_lastbf = bf_prev; + + if (bf == bf_prev) { + al = get_frame_info(bf->bf_mpdu)->framelen; + bf->bf_state.bf_type = BUF_AMPDU; + } else { + TX_STAT_INC(txq->axq_qnum, a_aggr); + } + *aggr_len = al; - return status; + return closed; #undef PADBYTES } @@ -1277,14 +1310,50 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, } } +static void +ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, struct list_head *bf_q, + struct ath_buf *bf_first, struct sk_buff_head *tid_q) +{ + struct ath_buf *bf = bf_first, *bf_prev = NULL; + struct sk_buff *skb; + int nframes = 0; + + do { + struct ieee80211_tx_info *tx_info; + skb = bf->bf_mpdu; + + nframes++; + __skb_unlink(skb, tid_q); + list_add_tail(&bf->list, bf_q); + if (bf_prev) + bf_prev->bf_next = bf; + bf_prev = bf; + + if (nframes >= 2) + break; + + bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); + if (!bf) + break; + + tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + break; + + ath_set_rates(tid->an->vif, tid->an->sta, bf); + } while (1); +} + static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { struct ath_buf *bf; - enum ATH_AGGR_STATUS status; struct ieee80211_tx_info *tx_info; + struct sk_buff_head *tid_q; struct list_head bf_q; - int aggr_len; + int aggr_len = 0; + bool aggr, last = true; do { if (!ath_tid_has_buffered(tid)) @@ -1292,38 +1361,34 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_q); - status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len); - - /* - * no frames picked up to be aggregated; - * block-ack window is not open. - */ - if (list_empty(&bf_q)) + bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); + if (!bf) break; - bf = list_first_entry(&bf_q, struct ath_buf, list); - bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); + if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || + (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) + break; + + ath_set_rates(tid->an->vif, tid->an->sta, bf); + if (aggr) + last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, + tid_q, &aggr_len); + else + ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q); + + if (list_empty(&bf_q)) + return; if (tid->ac->clear_ps_filter) { tid->ac->clear_ps_filter = false; tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; - } else { - tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; - } - - /* if only one frame, send as non-aggregate */ - if (bf == bf->bf_lastbf) { - aggr_len = get_frame_info(bf->bf_mpdu)->framelen; - bf->bf_state.bf_type = BUF_AMPDU; - } else { - TX_STAT_INC(txq->axq_qnum, a_aggr); } ath_tx_fill_desc(sc, bf, txq, aggr_len); ath_tx_txqaddbuf(sc, txq, &bf_q, false); - } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH && - status != ATH_AGGR_BAW_CLOSED); + } while (!last); } int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, @@ -1347,6 +1412,9 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, an->mpdudensity = density; } + /* force sequence number allocation for pending frames */ + ath_tx_tid_change_state(sc, txtid); + txtid->active = true; txtid->paused = true; *ssn = txtid->seq_start = txtid->seq_next; @@ -1368,6 +1436,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) txtid->active = false; txtid->paused = false; ath_tx_flush_tid(sc, txtid); + ath_tx_tid_change_state(sc, txtid); ath_txq_unlock_complete(sc, txq); } @@ -1882,58 +1951,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, } } -static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, struct sk_buff *skb, - struct ath_tx_control *txctl) -{ - struct ath_frame_info *fi = get_frame_info(skb); - struct list_head bf_head; - struct ath_buf *bf; - - /* - * Do not queue to h/w when any of the following conditions is true: - * - there are pending frames in software queue - * - the TID is currently paused for ADDBA/BAR request - * - seqno is not within block-ack window - * - h/w queue depth exceeds low water mark - */ - if ((ath_tid_has_buffered(tid) || tid->paused || - !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) || - txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) && - txq != sc->tx.uapsdq) { - /* - * Add this frame to software queue for scheduling later - * for aggregation. - */ - TX_STAT_INC(txq->axq_qnum, a_queued_sw); - __skb_queue_tail(&tid->buf_q, skb); - if (!txctl->an || !txctl->an->sleeping) - ath_tx_queue_tid(txq, tid); - return; - } - - bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) { - ath_txq_skb_done(sc, txq, skb); - ieee80211_free_txskb(sc->hw, skb); - return; - } - - ath_set_rates(tid->an->vif, tid->an->sta, bf); - bf->bf_state.bf_type = BUF_AMPDU; - INIT_LIST_HEAD(&bf_head); - list_add(&bf->list, &bf_head); - - /* Add sub-frame to BAW */ - ath_tx_addto_baw(sc, tid, bf); - - /* Queue to h/w without aggregation */ - TX_STAT_INC(txq->axq_qnum, a_queued_hw); - bf->bf_lastbf = bf; - ath_tx_fill_desc(sc, bf, txq, fi->framelen); - ath_tx_txqaddbuf(sc, txq, &bf_head, false); -} - static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct sk_buff *skb) { @@ -2159,20 +2176,25 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, ath_txq_unlock(sc, txq); txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); - } - - if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { + } else if (txctl->an && + ieee80211_is_data_present(hdr->frame_control)) { tid = ath_get_skb_tid(sc, txctl->an, skb); WARN_ON(tid->ac->txq != txctl->txq); - } - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && tid) { + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + tid->ac->clear_ps_filter = true; + /* - * Try aggregation if it's a unicast data frame - * and the destination is HT capable. + * Add this frame to software queue for scheduling later + * for aggregation. */ - ath_tx_send_ampdu(sc, txq, tid, skb, txctl); + TX_STAT_INC(txq->axq_qnum, a_queued_sw); + __skb_queue_tail(&tid->buf_q, skb); + if (!txctl->an->sleeping) + ath_tx_queue_tid(txq, tid); + + ath_txq_schedule(sc, txq); goto out; } -- cgit v1.2.3 From 020f20f693c254a6daa727473d6e855a63c3e502 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:12 +0200 Subject: ath9k: improve tx scheduling fairness Instead of trying to schedule the same TID multiple times in a loop, iterate over other TIDs/stations first. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 89 ++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3b66f2b67fec..f9e6eb2a4e0b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1345,8 +1345,8 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, } while (1); } -static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid) +static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, bool *stop) { struct ath_buf *bf; struct ieee80211_tx_info *tx_info; @@ -1355,40 +1355,41 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, int aggr_len = 0; bool aggr, last = true; - do { - if (!ath_tid_has_buffered(tid)) - return; + if (!ath_tid_has_buffered(tid)) + return false; - INIT_LIST_HEAD(&bf_q); + INIT_LIST_HEAD(&bf_q); - bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); - if (!bf) - break; + bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); + if (!bf) + return false; - tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); - aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); - if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || - (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) - break; + tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); + if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || + (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { + *stop = true; + return false; + } - ath_set_rates(tid->an->vif, tid->an->sta, bf); - if (aggr) - last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, - tid_q, &aggr_len); - else - ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q); + ath_set_rates(tid->an->vif, tid->an->sta, bf); + if (aggr) + last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, + tid_q, &aggr_len); + else + ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q); - if (list_empty(&bf_q)) - return; + if (list_empty(&bf_q)) + return false; - if (tid->ac->clear_ps_filter) { - tid->ac->clear_ps_filter = false; - tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; - } + if (tid->ac->clear_ps_filter) { + tid->ac->clear_ps_filter = false; + tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + } - ath_tx_fill_desc(sc, bf, txq, aggr_len); - ath_tx_txqaddbuf(sc, txq, &bf_q, false); - } while (!last); + ath_tx_fill_desc(sc, bf, txq, aggr_len); + ath_tx_txqaddbuf(sc, txq, &bf_q, false); + return true; } int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, @@ -1824,25 +1825,27 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) */ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { - struct ath_atx_ac *ac, *ac_tmp, *last_ac; + struct ath_atx_ac *ac, *last_ac; struct ath_atx_tid *tid, *last_tid; + bool sent = false; if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || - list_empty(&txq->axq_acq) || - txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) + list_empty(&txq->axq_acq)) return; rcu_read_lock(); - ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); + while (!list_empty(&txq->axq_acq)) { + bool stop = false; - list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { + ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); list_del(&ac->list); ac->sched = false; while (!list_empty(&ac->tid_q)) { + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); list_del(&tid->list); @@ -1851,7 +1854,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (tid->paused) continue; - ath_tx_sched_aggr(sc, txq, tid); + if (ath_tx_sched_aggr(sc, txq, tid, &stop)) + sent = true; /* * add tid to round-robin queue if more frames @@ -1860,8 +1864,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (ath_tid_has_buffered(tid)) ath_tx_queue_tid(txq, tid); - if (tid == last_tid || - txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) + if (stop || tid == last_tid) break; } @@ -1870,9 +1873,17 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) list_add_tail(&ac->list, &txq->axq_acq); } - if (ac == last_ac || - txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) + if (stop) break; + + if (ac == last_ac) { + if (!sent) + break; + + sent = false; + last_ac = list_entry(txq->axq_acq.prev, + struct ath_atx_ac, list); + } } rcu_read_unlock(); -- cgit v1.2.3 From f89d1bc4271153ac7864051778c0f2443e5cf2cd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 6 Aug 2013 14:18:13 +0200 Subject: ath9k: use software queueing for multicast traffic Create a per-vif dummy node entry for keeping the multicast software queues. This helps in setups with a lot of mulitcast traffic that could otherwise potentially drown out unicast traffic to stations. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/main.c | 11 +++++++++++ drivers/net/wireless/ath/ath9k/xmit.c | 12 ++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 41ea3fd5b9bb..505c615ada1b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -265,6 +265,7 @@ struct ath_node { u8 mpdudensity; bool sleeping; + bool no_ps_filter; #if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) struct dentry *node_stat; @@ -364,6 +365,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, /********/ struct ath_vif { + struct ath_node mcast_node; int av_bslot; bool primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 252497ae5089..911744f5c43c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -963,6 +963,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_node *an = &avp->mcast_node; mutex_lock(&sc->mutex); @@ -976,6 +978,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); + an->sc = sc; + an->sta = NULL; + an->vif = vif; + an->no_ps_filter = true; + ath_tx_node_init(sc, an); + mutex_unlock(&sc->mutex); return 0; } @@ -1013,6 +1021,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (void *)vif->drv_priv; ath_dbg(common, CONFIG, "Detach Interface\n"); @@ -1027,6 +1036,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_calculate_summary_state(hw, NULL); ath9k_ps_restore(sc); + ath_tx_node_cleanup(sc, &avp->mcast_node); + mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f9e6eb2a4e0b..d8dfb3ec818a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -135,6 +135,9 @@ static struct ath_frame_info *get_frame_info(struct sk_buff *skb) static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno) { + if (!tid->an->sta) + return; + ieee80211_send_bar(tid->an->vif, tid->an->sta->addr, tid->tidno, seqno << IEEE80211_SEQ_SEQ_SHIFT); } @@ -1382,7 +1385,7 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, if (list_empty(&bf_q)) return false; - if (tid->ac->clear_ps_filter) { + if (tid->ac->clear_ps_filter || tid->an->no_ps_filter) { tid->ac->clear_ps_filter = false; tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; } @@ -1572,7 +1575,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, sent++; TX_STAT_INC(txq->axq_qnum, a_queued_hw); - if (!ath_tid_has_buffered(tid)) + if (an->sta && !ath_tid_has_buffered(tid)) ieee80211_sta_set_buffered(an->sta, i, false); } ath_txq_unlock_complete(sc, tid->ac->txq); @@ -2104,6 +2107,7 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = txctl->sta; struct ieee80211_vif *vif = info->control.vif; + struct ath_vif *avp; struct ath_softc *sc = hw->priv; int frmlen = skb->len + FCS_LEN; int padpos, padsize; @@ -2111,6 +2115,10 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, /* NOTE: sta can be NULL according to net/mac80211.h */ if (sta) txctl->an = (struct ath_node *)sta->drv_priv; + else if (vif && ieee80211_is_data(hdr->frame_control)) { + avp = (void *)vif->drv_priv; + txctl->an = &avp->mcast_node; + } if (info->control.hw_key) frmlen += info->control.hw_key->icv_len; -- cgit v1.2.3 From 7d845871ffcafee22889c286ff3f1fb1f64be0c0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 7 Aug 2013 12:29:27 +0530 Subject: ath9k: Fix BTCOEX usage for RX diversity BTCOEX has to be *disabled* for WLAN RX diversity to work on combo cards. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4afe30e0bf49..3b56c2e7efe7 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -645,11 +645,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, /* * Enable WLAN/BT RX Antenna diversity only when: * - * - BTCOEX is enabled + * - BTCOEX is disabled. * - the user manually requests the feature. * - the HW cap is set using the platform data. */ - if (common->btcoex_enabled && ath9k_bt_ant_diversity && + if (!common->btcoex_enabled && ath9k_bt_ant_diversity && (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV)) common->bt_ant_diversity = 1; -- cgit v1.2.3 From 16fe28e9b4a7a5def2b20f79488546b6e2e3f2e7 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 7 Aug 2013 12:54:30 +0530 Subject: ath9k: Run the LNA combining algorithm properly The LNA combining algorithm has to be run for cards that support the required diversity features, make sure that that correct conditions are met before enabing this algorithm. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 44 ++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 865e043e8aa6..62dff97c1ae4 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1157,6 +1157,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb; struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; + struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hw *hw = sc->hw; struct ieee80211_hdr *hdr; @@ -1328,11 +1329,30 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) skb = hdr_skb; } + if (rxs->flag & RX_FLAG_MMIC_STRIPPED) + skb_trim(skb, skb->len - 8); - if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA)) || + ath9k_check_auto_sleep(sc)) + ath_rx_ps(sc, skb, rs.is_mybeacon); + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + /* + * Run the LNA combining algorithm only in these cases: + * + * Standalone WLAN cards with both LNA/Antenna diversity + * enabled in the EEPROM. + * + * WLAN+BT cards which are in the supported card list + * in ath_pci_id_table and the user has loaded the + * driver with "bt_ant_diversity" set to true. + */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { /* - * change the default rx antenna if rx diversity + * Change the default rx antenna if rx diversity * chooses the other antenna 3 times in a row. */ if (sc->rx.defant != rs.rs_antenna) { @@ -1342,22 +1362,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) sc->rx.rxotherant = 0; } + if (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV) { + if (common->bt_ant_diversity) + ath_ant_comb_scan(sc, &rs); + } else { + ath_ant_comb_scan(sc, &rs); + } } - if (rxs->flag & RX_FLAG_MMIC_STRIPPED) - skb_trim(skb, skb->len - 8); - - spin_lock_irqsave(&sc->sc_pm_lock, flags); - if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA)) || - ath9k_check_auto_sleep(sc)) - ath_rx_ps(sc, skb, rs.is_mybeacon); - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - - if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) - ath_ant_comb_scan(sc, &rs); - ath9k_apply_ampdu_details(sc, &rs, rxs); ieee80211_rx(hw, skb); -- cgit v1.2.3 From af61a165187bb94b1dc7628ef815c23d0eacf40b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jul 2013 18:09:12 +0200 Subject: mac80211: add control port protocol TX control flag A lot of drivers check the frame protocol for ETH_P_PAE, for various reasons (like making those more reliable). Add a new flags bitmap to the TX control info and a new flag indicating the control port protocol is in use to let all drivers also apply such logic to other control port protocols, should they be configured. Also use the new flag in the iwlwifi drivers. Signed-off-by: Johannes Berg --- Documentation/DocBook/80211.tmpl | 1 + drivers/net/wireless/iwlwifi/dvm/tx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-devtrace.h | 7 ++++--- drivers/net/wireless/iwlwifi/mvm/tx.c | 9 ++++----- include/net/mac80211.h | 19 ++++++++++++++++--- net/mac80211/rc80211_minstrel_ht.c | 5 +++-- net/mac80211/tx.c | 8 +++++--- 7 files changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index 49267ea97568..f403ec3c5c9a 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -325,6 +325,7 @@ functions/definitions !Finclude/net/mac80211.h ieee80211_rx_status !Finclude/net/mac80211.h mac80211_rx_flags +!Finclude/net/mac80211.h mac80211_tx_info_flags !Finclude/net/mac80211.h mac80211_tx_control_flags !Finclude/net/mac80211.h mac80211_rate_control_flags !Finclude/net/mac80211.h ieee80211_tx_rate diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 5ee983faa679..f364583b1535 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -87,7 +87,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, priv->lib->bt_params->advanced_bt_coexist && (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc) || - skb->protocol == cpu_to_be16(ETH_P_PAE))) + info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) tx_flags |= TX_CMD_FLG_IGNORE_BT; diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 4491c1c72cc7..684c416d3493 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -33,10 +33,11 @@ static inline bool iwl_trace_data(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (void *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - if (ieee80211_is_data(hdr->frame_control)) - return skb->protocol != cpu_to_be16(ETH_P_PAE); - return false; + if (!ieee80211_is_data(hdr->frame_control)) + return false; + return !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO); } static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index f0e96a927407..d62a6d3053ff 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -91,11 +91,10 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ - if (info->band == IEEE80211_BAND_2GHZ && - (skb->protocol == cpu_to_be16(ETH_P_PAE) || - is_multicast_ether_addr(hdr->addr1) || - ieee80211_is_back_req(fc) || - ieee80211_is_mgmt(fc))) + if (info->band == IEEE80211_BAND_2GHZ && + (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || + is_multicast_ether_addr(hdr->addr1) || + ieee80211_is_back_req(fc) || ieee80211_is_mgmt(fc))) tx_flags |= TX_CMD_FLG_BT_DIS; if (ieee80211_has_morefrags(fc)) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9cda3728c2cb..b70c00111323 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -375,7 +375,7 @@ struct ieee80211_bss_conf { }; /** - * enum mac80211_tx_control_flags - flags to describe transmission information/status + * enum mac80211_tx_info_flags - flags to describe transmission information/status * * These flags are used with the @flags member of &ieee80211_tx_info. * @@ -471,7 +471,7 @@ struct ieee80211_bss_conf { * Note: If you have to add new flags to the enumeration, then don't * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. */ -enum mac80211_tx_control_flags { +enum mac80211_tx_info_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1), IEEE80211_TX_CTL_NO_ACK = BIT(2), @@ -507,6 +507,18 @@ enum mac80211_tx_control_flags { #define IEEE80211_TX_CTL_STBC_SHIFT 23 +/** + * enum mac80211_tx_control_flags - flags to describe transmit control + * + * @IEEE80211_TX_CTRL_PORT_CTRL_PROTO: this frame is a port control + * protocol frame (e.g. EAP) + * + * These flags are used in tx_info->control.flags. + */ +enum mac80211_tx_control_flags { + IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0), +}; + /* * This definition is used as a mask to clear all temporary flags, which are * set by the tx handlers for each transmission attempt by the mac80211 stack. @@ -680,7 +692,8 @@ struct ieee80211_tx_info { /* NB: vif can be NULL for injected frames */ struct ieee80211_vif *vif; struct ieee80211_key_conf *hw_key; - /* 8 bytes free */ + u32 flags; + /* 4 bytes free */ } control; struct { struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 7475a7a33797..9eff3824f2d1 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -439,12 +439,13 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 tid; if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) return; - if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) + if (unlikely(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) return; tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; @@ -776,7 +777,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, /* Don't use EAPOL frames for sampling on non-mrr hw */ if (mp->hw->max_rates == 1 && - txrc->skb->protocol == cpu_to_be16(ETH_P_PAE)) + (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) sample_idx = -1; else sample_idx = minstrel_get_sample_rate(mp, mi); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0e42322aa6b1..098ae854ad3c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -539,9 +539,11 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); - if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol && - tx->sdata->control_port_no_encrypt)) - info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol)) { + if (tx->sdata->control_port_no_encrypt) + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO; + } return TX_CONTINUE; } -- cgit v1.2.3 From fc73f11f5fa230f8c687d51b0fddb00433092ce0 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 31 Jul 2013 18:04:15 +0300 Subject: cfg80211: add wdev to testmode cmd To allow drivers to implement per-interface testmode operations more easily, pass a wdev pointer if any identification for one was given from userspace. Clean up the code a bit while at it. Signed-off-by: David Spinadel Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/testmode.c | 3 ++- drivers/net/wireless/ath/ath6kl/testmode.h | 7 +++++-- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 4 +++- include/net/cfg80211.h | 5 +++-- net/mac80211/cfg.c | 4 +++- net/wireless/nl80211.c | 23 ++++++++++++++++------ net/wireless/rdev-ops.h | 5 +++-- net/wireless/trace.h | 8 +++++--- 8 files changed, 41 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c index acc9aa832f76..d67170ea1038 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/drivers/net/wireless/ath/ath6kl/testmode.c @@ -66,7 +66,8 @@ nla_put_failure: ath6kl_warn("nla_put failed on testmode rx skb!\n"); } -int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) +int ath6kl_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, + void *data, int len) { struct ath6kl *ar = wiphy_priv(wiphy); struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h index fe651d6707df..9fbcdec3e208 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.h +++ b/drivers/net/wireless/ath/ath6kl/testmode.h @@ -20,7 +20,8 @@ #ifdef CONFIG_NL80211_TESTMODE void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len); -int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len); +int ath6kl_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, + void *data, int len); #else @@ -29,7 +30,9 @@ static inline void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, { } -static inline int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) +static inline int ath6kl_tm_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + void *data, int len) { return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 277b37ae7126..b7d885020dd7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -3152,7 +3152,9 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, } #ifdef CONFIG_NL80211_TESTMODE -static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) +static int brcmf_cfg80211_testmode(struct wiphy *wiphy, + struct wireless_dev *wdev, + void *data, int len) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = cfg_to_ndev(cfg); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b7495c72061c..9ab7a0690d93 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2081,7 +2081,7 @@ struct cfg80211_update_ft_ies_params { * @mgmt_tx_cancel_wait: Cancel the wait time from transmitting a management * frame on another channel * - * @testmode_cmd: run a test mode command + * @testmode_cmd: run a test mode command; @wdev may be %NULL * @testmode_dump: Implement a test mode dump. The cb->args[2] and up may be * used by the function, but 0 and 1 must not be touched. Additionally, * return error codes other than -ENOBUFS and -ENOENT will terminate the @@ -2290,7 +2290,8 @@ struct cfg80211_ops { void (*rfkill_poll)(struct wiphy *wiphy); #ifdef CONFIG_NL80211_TESTMODE - int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); + int (*testmode_cmd)(struct wiphy *wiphy, struct wireless_dev *wdev, + void *data, int len); int (*testmode_dump)(struct wiphy *wiphy, struct sk_buff *skb, struct netlink_callback *cb, void *data, int len); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 44449ceb7966..c77916ffe74c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2300,7 +2300,9 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy) } #ifdef CONFIG_NL80211_TESTMODE -static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +static int ieee80211_testmode_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + void *data, int len) { struct ieee80211_local *local = wiphy_priv(wiphy); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c2a40a2e56bd..334697de5cc0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6591,19 +6591,30 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = { static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev = + __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs); int err; + if (!rdev->ops->testmode_cmd) + return -EOPNOTSUPP; + + if (IS_ERR(wdev)) { + err = PTR_ERR(wdev); + if (err != -EINVAL) + return err; + wdev = NULL; + } else if (wdev->wiphy != &rdev->wiphy) { + return -EINVAL; + } + if (!info->attrs[NL80211_ATTR_TESTDATA]) return -EINVAL; - err = -EOPNOTSUPP; - if (rdev->ops->testmode_cmd) { - rdev->testmode_info = info; - err = rdev_testmode_cmd(rdev, + rdev->testmode_info = info; + err = rdev_testmode_cmd(rdev, wdev, nla_data(info->attrs[NL80211_ATTR_TESTDATA]), nla_len(info->attrs[NL80211_ATTR_TESTDATA])); - rdev->testmode_info = NULL; - } + rdev->testmode_info = NULL; return err; } diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index de870d4d0bcc..37ce9fdfe934 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -516,11 +516,12 @@ static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev) #ifdef CONFIG_NL80211_TESTMODE static inline int rdev_testmode_cmd(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, void *data, int len) { int ret; - trace_rdev_testmode_cmd(&rdev->wiphy); - ret = rdev->ops->testmode_cmd(&rdev->wiphy, data, len); + trace_rdev_testmode_cmd(&rdev->wiphy, wdev); + ret = rdev->ops->testmode_cmd(&rdev->wiphy, wdev, data, len); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index f0ebdcd394ef..ba5f0d6614d5 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1293,15 +1293,17 @@ TRACE_EVENT(rdev_return_int_int, #ifdef CONFIG_NL80211_TESTMODE TRACE_EVENT(rdev_testmode_cmd, - TP_PROTO(struct wiphy *wiphy), - TP_ARGS(wiphy), + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev), TP_STRUCT__entry( WIPHY_ENTRY + WDEV_ENTRY ), TP_fast_assign( WIPHY_ASSIGN; + WDEV_ASSIGN; ), - TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG) + TP_printk(WIPHY_PR_FMT WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) ); TRACE_EVENT(rdev_testmode_dump, -- cgit v1.2.3 From 52981cd79461e47fe683febfcbd3d380c72b1c6c Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 31 Jul 2013 18:06:22 +0300 Subject: mac80211: add vif to testmode cmd Pass the wdev from cfg80211 on to the driver as the vif if given and it's valid for the driver. Signed-off-by: David Spinadel Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + drivers/net/wireless/ti/wlcore/testmode.c | 3 ++- drivers/net/wireless/ti/wlcore/testmode.h | 3 ++- include/net/mac80211.h | 7 ++++--- net/mac80211/cfg.c | 11 ++++++++++- 5 files changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7b2a6229eedb..a0d2aacd5e09 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1364,6 +1364,7 @@ static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { static int hwsim_fops_ps_write(void *dat, u64 val); static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, void *data, int len) { struct mac80211_hwsim_data *hwsim = hw->priv; diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c index f3442762d884..527590f2adfb 100644 --- a/drivers/net/wireless/ti/wlcore/testmode.c +++ b/drivers/net/wireless/ti/wlcore/testmode.c @@ -356,7 +356,8 @@ out: return ret; } -int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) +int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len) { struct wl1271 *wl = hw->priv; struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; diff --git a/drivers/net/wireless/ti/wlcore/testmode.h b/drivers/net/wireless/ti/wlcore/testmode.h index 8071654259ea..61d8434d859a 100644 --- a/drivers/net/wireless/ti/wlcore/testmode.h +++ b/drivers/net/wireless/ti/wlcore/testmode.h @@ -26,6 +26,7 @@ #include -int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len); +int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len); #endif /* __WL1271_TESTMODE_H__ */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index b70c00111323..df93c77c97ab 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2516,8 +2516,8 @@ enum ieee80211_roc_type { * in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout * accordingly. This callback is not required and may sleep. * - * @testmode_cmd: Implement a cfg80211 test mode command. - * The callback can sleep. + * @testmode_cmd: Implement a cfg80211 test mode command. The passed @vif may + * be %NULL. The callback can sleep. * @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep. * * @flush: Flush all pending frames from the hardware queue, making sure @@ -2778,7 +2778,8 @@ struct ieee80211_ops { void (*rfkill_poll)(struct ieee80211_hw *hw); void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class); #ifdef CONFIG_NL80211_TESTMODE - int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); + int (*testmode_cmd)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len); int (*testmode_dump)(struct ieee80211_hw *hw, struct sk_buff *skb, struct netlink_callback *cb, void *data, int len); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c77916ffe74c..7aa38ce0b524 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2305,11 +2305,20 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) { struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_vif *vif = NULL; if (!local->ops->testmode_cmd) return -EOPNOTSUPP; - return local->ops->testmode_cmd(&local->hw, data, len); + if (wdev) { + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + if (sdata->flags & IEEE80211_SDATA_IN_DRIVER) + vif = &sdata->vif; + } + + return local->ops->testmode_cmd(&local->hw, vif, data, len); } static int ieee80211_testmode_dump(struct wiphy *wiphy, -- cgit v1.2.3 From f8f03c3edc39f179457a4a5c6095f45a8300db9b Mon Sep 17 00:00:00 2001 From: Eytan Lifshitz Date: Wed, 7 Aug 2013 19:36:42 +0300 Subject: iwlwifi: mvm: add support to the new FW time event API The time event firmware API will change, add the support for that. Use the new API throughout and convert to the old where needed. Signed-off-by: Eytan Lifshitz Reviewed-by: Guy Cohen Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-fw.h | 2 + drivers/net/wireless/iwlwifi/mvm/fw-api.h | 226 ++++++++++++++++++++------ drivers/net/wireless/iwlwifi/mvm/time-event.c | 96 ++++++++--- 3 files changed, 251 insertions(+), 73 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index bd335f0c40d1..1705d245dbe9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -76,6 +76,7 @@ * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api + * @IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six * (rather than two) IPv6 addresses * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API @@ -88,6 +89,7 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), + IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = BIT(9), IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11), }; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 55854a309f94..b1047102ea47 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -499,71 +499,199 @@ enum iwl_time_event_type { TE_MAX }; /* MAC_EVENT_TYPE_API_E_VER_1 */ + + +/* Time event - defines for command API v1 */ + +/* + * @TE_V1_FRAG_NONE: fragmentation of the time event is NOT allowed. + * @TE_V1_FRAG_SINGLE: fragmentation of the time event is allowed, but only + * the first fragment is scheduled. + * @TE_V1_FRAG_DUAL: fragmentation of the time event is allowed, but only + * the first 2 fragments are scheduled. + * @TE_V1_FRAG_ENDLESS: fragmentation of the time event is allowed, and any + * number of fragments are valid. + * + * Other than the constant defined above, specifying a fragmentation value 'x' + * means that the event can be fragmented but only the first 'x' will be + * scheduled. + */ +enum { + TE_V1_FRAG_NONE = 0, + TE_V1_FRAG_SINGLE = 1, + TE_V1_FRAG_DUAL = 2, + TE_V1_FRAG_ENDLESS = 0xffffffff +}; + +/* If a Time Event can be fragmented, this is the max number of fragments */ +#define TE_V1_FRAG_MAX_MSK 0x0fffffff +/* Repeat the time event endlessly (until removed) */ +#define TE_V1_REPEAT_ENDLESS 0xffffffff +/* If a Time Event has bounded repetitions, this is the maximal value */ +#define TE_V1_REPEAT_MAX_MSK_V1 0x0fffffff + /* Time Event dependencies: none, on another TE, or in a specific time */ enum { - TE_INDEPENDENT = 0, - TE_DEP_OTHER = 1, - TE_DEP_TSF = 2, - TE_EVENT_SOCIOPATHIC = 4, + TE_V1_INDEPENDENT = 0, + TE_V1_DEP_OTHER = BIT(0), + TE_V1_DEP_TSF = BIT(1), + TE_V1_EVENT_SOCIOPATHIC = BIT(2), }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ + /* + * @TE_V1_NOTIF_NONE: no notifications + * @TE_V1_NOTIF_HOST_EVENT_START: request/receive notification on event start + * @TE_V1_NOTIF_HOST_EVENT_END:request/receive notification on event end + * @TE_V1_NOTIF_INTERNAL_EVENT_START: internal FW use + * @TE_V1_NOTIF_INTERNAL_EVENT_END: internal FW use. + * @TE_V1_NOTIF_HOST_FRAG_START: request/receive notification on frag start + * @TE_V1_NOTIF_HOST_FRAG_END:request/receive notification on frag end + * @TE_V1_NOTIF_INTERNAL_FRAG_START: internal FW use. + * @TE_V1_NOTIF_INTERNAL_FRAG_END: internal FW use. + * * Supported Time event notifications configuration. * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment * notification for monolithic events. - * - * @TE_NOTIF_NONE: no notifications - * @TE_NOTIF_HOST_EVENT_START: request/receive notification on event start - * @TE_NOTIF_HOST_EVENT_END:request/receive notification on event end - * @TE_NOTIF_INTERNAL_EVENT_START: internal FW use - * @TE_NOTIF_INTERNAL_EVENT_END: internal FW use. - * @TE_NOTIF_HOST_FRAG_START: request/receive notification on frag start - * @TE_NOTIF_HOST_FRAG_END:request/receive notification on frag end - * @TE_NOTIF_INTERNAL_FRAG_START: internal FW use. - * @TE_NOTIF_INTERNAL_FRAG_END: internal FW use. */ enum { - TE_NOTIF_NONE = 0, - TE_NOTIF_HOST_EVENT_START = 0x1, - TE_NOTIF_HOST_EVENT_END = 0x2, - TE_NOTIF_INTERNAL_EVENT_START = 0x4, - TE_NOTIF_INTERNAL_EVENT_END = 0x8, - TE_NOTIF_HOST_FRAG_START = 0x10, - TE_NOTIF_HOST_FRAG_END = 0x20, - TE_NOTIF_INTERNAL_FRAG_START = 0x40, - TE_NOTIF_INTERNAL_FRAG_END = 0x80 + TE_V1_NOTIF_NONE = 0, + TE_V1_NOTIF_HOST_EVENT_START = BIT(0), + TE_V1_NOTIF_HOST_EVENT_END = BIT(1), + TE_V1_NOTIF_INTERNAL_EVENT_START = BIT(2), + TE_V1_NOTIF_INTERNAL_EVENT_END = BIT(3), + TE_V1_NOTIF_HOST_FRAG_START = BIT(4), + TE_V1_NOTIF_HOST_FRAG_END = BIT(5), + TE_V1_NOTIF_INTERNAL_FRAG_START = BIT(6), + TE_V1_NOTIF_INTERNAL_FRAG_END = BIT(7), }; /* MAC_EVENT_ACTION_API_E_VER_2 */ + +/** + * struct iwl_time_event_cmd_api_v1 - configuring Time Events + * with struct MAC_TIME_EVENT_DATA_API_S_VER_1 (see also + * with version 2. determined by IWL_UCODE_TLV_FLAGS) + * ( TIME_EVENT_CMD = 0x29 ) + * @id_and_color: ID and color of the relevant MAC + * @action: action to perform, one of FW_CTXT_ACTION_* + * @id: this field has two meanings, depending on the action: + * If the action is ADD, then it means the type of event to add. + * For all other actions it is the unique event ID assigned when the + * event was added by the FW. + * @apply_time: When to start the Time Event (in GP2) + * @max_delay: maximum delay to event's start (apply time), in TU + * @depends_on: the unique ID of the event we depend on (if any) + * @interval: interval between repetitions, in TU + * @interval_reciprocal: 2^32 / interval + * @duration: duration of event in TU + * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS + * @dep_policy: one of TE_V1_INDEPENDENT, TE_V1_DEP_OTHER, TE_V1_DEP_TSF + * and TE_V1_EVENT_SOCIOPATHIC + * @is_present: 0 or 1, are we present or absent during the Time Event + * @max_frags: maximal number of fragments the Time Event can be divided to + * @notify: notifications using TE_V1_NOTIF_* (whom to notify when) + */ +struct iwl_time_event_cmd_v1 { + /* COMMON_INDEX_HDR_API_S_VER_1 */ + __le32 id_and_color; + __le32 action; + __le32 id; + /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ + __le32 apply_time; + __le32 max_delay; + __le32 dep_policy; + __le32 depends_on; + __le32 is_present; + __le32 max_frags; + __le32 interval; + __le32 interval_reciprocal; + __le32 duration; + __le32 repeat; + __le32 notify; +} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ + + +/* Time event - defines for command API v2 */ + /* - * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed. - * @TE_FRAG_SINGLE: fragmentation of the time event is allowed, but only + * @TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. + * @TE_V2_FRAG_SINGLE: fragmentation of the time event is allowed, but only * the first fragment is scheduled. - * @TE_FRAG_DUAL: fragmentation of the time event is allowed, but only + * @TE_V2_FRAG_DUAL: fragmentation of the time event is allowed, but only * the first 2 fragments are scheduled. - * @TE_FRAG_ENDLESS: fragmentation of the time event is allowed, and any number - * of fragments are valid. + * @TE_V2_FRAG_ENDLESS: fragmentation of the time event is allowed, and any + * number of fragments are valid. * * Other than the constant defined above, specifying a fragmentation value 'x' * means that the event can be fragmented but only the first 'x' will be * scheduled. */ enum { - TE_FRAG_NONE = 0, - TE_FRAG_SINGLE = 1, - TE_FRAG_DUAL = 2, - TE_FRAG_ENDLESS = 0xffffffff + TE_V2_FRAG_NONE = 0, + TE_V2_FRAG_SINGLE = 1, + TE_V2_FRAG_DUAL = 2, + TE_V2_FRAG_MAX = 0xfe, + TE_V2_FRAG_ENDLESS = 0xff }; /* Repeat the time event endlessly (until removed) */ -#define TE_REPEAT_ENDLESS (0xffffffff) +#define TE_V2_REPEAT_ENDLESS 0xff /* If a Time Event has bounded repetitions, this is the maximal value */ -#define TE_REPEAT_MAX_MSK (0x0fffffff) -/* If a Time Event can be fragmented, this is the max number of fragments */ -#define TE_FRAG_MAX_MSK (0x0fffffff) +#define TE_V2_REPEAT_MAX 0xfe + +#define TE_V2_PLACEMENT_POS 12 +#define TE_V2_ABSENCE_POS 15 + +/* Time event policy values (for time event cmd api v2) + * A notification (both event and fragment) includes a status indicating weather + * the FW was able to schedule the event or not. For fragment start/end + * notification the status is always success. There is no start/end fragment + * notification for monolithic events. + * + * @TE_V2_DEFAULT_POLICY: independent, social, present, unoticable + * @TE_V2_NOTIF_HOST_EVENT_START: request/receive notification on event start + * @TE_V2_NOTIF_HOST_EVENT_END:request/receive notification on event end + * @TE_V2_NOTIF_INTERNAL_EVENT_START: internal FW use + * @TE_V2_NOTIF_INTERNAL_EVENT_END: internal FW use. + * @TE_V2_NOTIF_HOST_FRAG_START: request/receive notification on frag start + * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end + * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. + * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. + * @TE_V2_DEP_OTHER: depends on another time event + * @TE_V2_DEP_TSF: depends on a specific time + * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC + * @TE_V2_ABSENCE: are we present or absent during the Time Event. + */ +enum { + TE_V2_DEFAULT_POLICY = 0x0, + + /* notifications (event start/stop, fragment start/stop) */ + TE_V2_NOTIF_HOST_EVENT_START = BIT(0), + TE_V2_NOTIF_HOST_EVENT_END = BIT(1), + TE_V2_NOTIF_INTERNAL_EVENT_START = BIT(2), + TE_V2_NOTIF_INTERNAL_EVENT_END = BIT(3), + + TE_V2_NOTIF_HOST_FRAG_START = BIT(4), + TE_V2_NOTIF_HOST_FRAG_END = BIT(5), + TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), + TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), + + TE_V2_NOTIF_MSK = 0xff, + + /* placement characteristics */ + TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), + TE_V2_DEP_TSF = BIT(TE_V2_PLACEMENT_POS + 1), + TE_V2_EVENT_SOCIOPATHIC = BIT(TE_V2_PLACEMENT_POS + 2), + + /* are we present or absent during the Time Event. */ + TE_V2_ABSENCE = BIT(TE_V2_ABSENCE_POS), +}; /** - * struct iwl_time_event_cmd - configuring Time Events + * struct iwl_time_event_cmd_api_v2 - configuring Time Events + * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also + * with version 1. determined by IWL_UCODE_TLV_FLAGS) * ( TIME_EVENT_CMD = 0x29 ) * @id_and_color: ID and color of the relevant MAC * @action: action to perform, one of FW_CTXT_ACTION_* @@ -575,32 +703,30 @@ enum { * @max_delay: maximum delay to event's start (apply time), in TU * @depends_on: the unique ID of the event we depend on (if any) * @interval: interval between repetitions, in TU - * @interval_reciprocal: 2^32 / interval * @duration: duration of event in TU * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS - * @dep_policy: one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF - * @is_present: 0 or 1, are we present or absent during the Time Event * @max_frags: maximal number of fragments the Time Event can be divided to - * @notify: notifications using TE_NOTIF_* (whom to notify when) + * @policy: defines whether uCode shall notify the host or other uCode modules + * on event and/or fragment start and/or end + * using one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF + * TE_EVENT_SOCIOPATHIC + * using TE_ABSENCE and using TE_NOTIF_* */ -struct iwl_time_event_cmd { +struct iwl_time_event_cmd_v2 { /* COMMON_INDEX_HDR_API_S_VER_1 */ __le32 id_and_color; __le32 action; __le32 id; - /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ + /* MAC_TIME_EVENT_DATA_API_S_VER_2 */ __le32 apply_time; __le32 max_delay; - __le32 dep_policy; __le32 depends_on; - __le32 is_present; - __le32 max_frags; __le32 interval; - __le32 interval_reciprocal; __le32 duration; - __le32 repeat; - __le32 notify; -} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ + u8 repeat; + u8 max_frags; + __le16 policy; +} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_2 */ /** * struct iwl_time_event_resp - response structure to iwl_time_event_cmd diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index ad9bbca99213..7ed94a089d5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -166,7 +166,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, WARN_ONCE(!le32_to_cpu(notif->status), "Failed to schedule time event\n"); - if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) { + if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_END) { IWL_DEBUG_TE(mvm, "TE ended - current time %lu, estimated end %lu\n", jiffies, te_data->end_jiffies); @@ -189,7 +189,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, } iwl_mvm_te_clear_data(mvm, te_data); - } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) { + } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) { te_data->running = true; te_data->end_jiffies = jiffies + TU_TO_JIFFIES(te_data->duration); @@ -257,10 +257,67 @@ static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, return true; } +/* used to convert from time event API v2 to v1 */ +#define TE_V2_DEP_POLICY_MSK (TE_V2_DEP_OTHER | TE_V2_DEP_TSF |\ + TE_V2_EVENT_SOCIOPATHIC) +static inline u16 te_v2_get_notify(__le16 policy) +{ + return le16_to_cpu(policy) & TE_V2_NOTIF_MSK; +} + +static inline u16 te_v2_get_dep_policy(__le16 policy) +{ + return (le16_to_cpu(policy) & TE_V2_DEP_POLICY_MSK) >> + TE_V2_PLACEMENT_POS; +} + +static inline u16 te_v2_get_absence(__le16 policy) +{ + return (le16_to_cpu(policy) & TE_V2_ABSENCE) >> TE_V2_ABSENCE_POS; +} + +static void iwl_mvm_te_v2_to_v1(const struct iwl_time_event_cmd_v2 *cmd_v2, + struct iwl_time_event_cmd_v1 *cmd_v1) +{ + cmd_v1->id_and_color = cmd_v2->id_and_color; + cmd_v1->action = cmd_v2->action; + cmd_v1->id = cmd_v2->id; + cmd_v1->apply_time = cmd_v2->apply_time; + cmd_v1->max_delay = cmd_v2->max_delay; + cmd_v1->depends_on = cmd_v2->depends_on; + cmd_v1->interval = cmd_v2->interval; + cmd_v1->duration = cmd_v2->duration; + if (cmd_v2->repeat == TE_V2_REPEAT_ENDLESS) + cmd_v1->repeat = cpu_to_le32(TE_V1_REPEAT_ENDLESS); + else + cmd_v1->repeat = cpu_to_le32(cmd_v2->repeat); + cmd_v1->max_frags = cpu_to_le32(cmd_v2->max_frags); + cmd_v1->interval_reciprocal = 0; /* unused */ + + cmd_v1->dep_policy = cpu_to_le32(te_v2_get_dep_policy(cmd_v2->policy)); + cmd_v1->is_present = cpu_to_le32(!te_v2_get_absence(cmd_v2->policy)); + cmd_v1->notify = cpu_to_le32(te_v2_get_notify(cmd_v2->policy)); +} + +static int iwl_mvm_send_time_event_cmd(struct iwl_mvm *mvm, + const struct iwl_time_event_cmd_v2 *cmd) +{ + struct iwl_time_event_cmd_v1 cmd_v1; + + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2) + return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, + sizeof(*cmd), cmd); + + iwl_mvm_te_v2_to_v1(cmd, &cmd_v1); + return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, + sizeof(cmd_v1), &cmd_v1); +} + + static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_time_event_data *te_data, - struct iwl_time_event_cmd *te_cmd) + struct iwl_time_event_cmd_v2 *te_cmd) { static const u8 time_event_response[] = { TIME_EVENT_CMD }; struct iwl_notification_wait wait_time_event; @@ -296,8 +353,7 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, ARRAY_SIZE(time_event_response), iwl_mvm_time_event_response, te_data); - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, - sizeof(*te_cmd), te_cmd); + ret = iwl_mvm_send_time_event_cmd(mvm, te_cmd); if (ret) { IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); iwl_remove_notification(&mvm->notif_wait, &wait_time_event); @@ -324,7 +380,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - struct iwl_time_event_cmd time_cmd = {}; + struct iwl_time_event_cmd_v2 time_cmd = {}; lockdep_assert_held(&mvm->mutex); @@ -359,17 +415,14 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, time_cmd.apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); - time_cmd.dep_policy = TE_INDEPENDENT; - time_cmd.is_present = cpu_to_le32(1); - time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); + time_cmd.max_frags = TE_V2_FRAG_NONE; time_cmd.max_delay = cpu_to_le32(500); /* TODO: why do we need to interval = bi if it is not periodic? */ time_cmd.interval = cpu_to_le32(1); - time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1)); time_cmd.duration = cpu_to_le32(duration); - time_cmd.repeat = cpu_to_le32(1); - time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | - TE_NOTIF_HOST_EVENT_END); + time_cmd.repeat = 1; + time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | + TE_V2_NOTIF_HOST_EVENT_END); iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } @@ -383,7 +436,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif, struct iwl_mvm_time_event_data *te_data) { - struct iwl_time_event_cmd time_cmd = {}; + struct iwl_time_event_cmd_v2 time_cmd = {}; u32 id, uid; int ret; @@ -420,8 +473,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, - sizeof(time_cmd), &time_cmd); + ret = iwl_mvm_send_time_event_cmd(mvm, &time_cmd); if (WARN_ON(ret)) return; } @@ -441,7 +493,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - struct iwl_time_event_cmd time_cmd = {}; + struct iwl_time_event_cmd_v2 time_cmd = {}; lockdep_assert_held(&mvm->mutex); if (te_data->running) { @@ -472,8 +524,6 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } time_cmd.apply_time = cpu_to_le32(0); - time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); - time_cmd.is_present = cpu_to_le32(1); time_cmd.interval = cpu_to_le32(1); /* @@ -482,12 +532,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * scheduled. To improve the chances of it being scheduled, allow them * to be fragmented, and in addition allow them to be delayed. */ - time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20); + time_cmd.max_frags = min(MSEC_TO_TU(duration)/50, TE_V2_FRAG_ENDLESS); time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); - time_cmd.repeat = cpu_to_le32(1); - time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | - TE_NOTIF_HOST_EVENT_END); + time_cmd.repeat = 1; + time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | + TE_V2_NOTIF_HOST_EVENT_END); return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } -- cgit v1.2.3 From 6965a3540a4b45ee5b6fa91276a8134e25e17b63 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Sat, 10 Aug 2013 16:35:45 +0300 Subject: iwlwifi: pcie: don't swallow error codes in iwl_trans_pcie_alloc() The iwl_trans_pcie_alloc() function doesn't pass up error codes returned from functions it calls, swallowing them and returning NULL in all failure cases. The caller checks if the return value is NULL and returns -ENOMEM. This is not correct, because in certain cases the failure was not due to an OOM situation. To fix this, modify the iwl_trans_pcie_alloc() function to use ERR_PTR() to return error codes and clean up the error handling code a bit. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/drv.c | 4 ++-- drivers/net/wireless/iwlwifi/pcie/trans.c | 26 +++++++++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 9ec8dfeb4354..e179efeddc8d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -324,8 +324,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int ret; iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg); - if (iwl_trans == NULL) - return -ENOMEM; + if (IS_ERR(iwl_trans)) + return PTR_ERR(iwl_trans); pci_set_drvdata(pdev, iwl_trans); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index d88c0c748274..ff9787fac205 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1381,9 +1381,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans = kzalloc(sizeof(struct iwl_trans) + sizeof(struct iwl_trans_pcie), GFP_KERNEL); - - if (!trans) - return NULL; + if (!trans) { + err = -ENOMEM; + goto out; + } trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1406,10 +1407,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, PCIE_LINK_STATE_CLKPM); } - if (pci_enable_device(pdev)) { - err = -ENODEV; + err = pci_enable_device(pdev); + if (err) goto out_no_pci; - } pci_set_master(pdev); @@ -1478,17 +1478,20 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, SLAB_HWCACHE_ALIGN, NULL); - if (!trans->dev_cmd_pool) + if (!trans->dev_cmd_pool) { + err = -ENOMEM; goto out_pci_disable_msi; + } trans_pcie->inta_mask = CSR_INI_SET_MASK; if (iwl_pcie_alloc_ict(trans)) goto out_free_cmd_pool; - if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict, - iwl_pcie_irq_handler, - IRQF_SHARED, DRV_NAME, trans)) { + err = request_threaded_irq(pdev->irq, iwl_pcie_isr_ict, + iwl_pcie_irq_handler, + IRQF_SHARED, DRV_NAME, trans); + if (err) { IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); goto out_free_ict; } @@ -1507,5 +1510,6 @@ out_pci_disable_device: pci_disable_device(pdev); out_no_pci: kfree(trans); - return NULL; +out: + return ERR_PTR(err); } -- cgit v1.2.3 From ab3077009f3e5237aaddaf0d5d139b1fd59d3b32 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 4 Aug 2013 12:40:37 +0300 Subject: iwlwifi: mvm: remove rate_scale_data debugfs entry This isn't very informative and can be deduced from rate_scale_table. Remove as a preparation for dropping iwl_rs_rate_info.ieee. Signed-off-by: Eyal Shapira Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rs.c | 30 ------------------------------ drivers/net/wireless/iwlwifi/mvm/rs.h | 1 - 2 files changed, 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index d680c891ce86..199f0cfdaadf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -3009,32 +3009,6 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .llseek = default_llseek, }; -static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - struct iwl_lq_sta *lq_sta = file->private_data; - struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; - char buff[120]; - int desc = 0; - - if (is_Ht(tbl->lq_type)) - desc += sprintf(buff+desc, - "Bit Rate= %d Mb/s\n", - tbl->expected_tpt[lq_sta->last_txrate_idx]); - else - desc += sprintf(buff+desc, - "Bit Rate= %d Mb/s\n", - iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); - - return simple_read_from_buffer(user_buf, count, ppos, buff, desc); -} - -static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { - .read = rs_sta_dbgfs_rate_scale_data_read, - .open = simple_open, - .llseek = default_llseek, -}; - static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) { struct iwl_lq_sta *lq_sta = mvm_sta; @@ -3044,9 +3018,6 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) lq_sta->rs_sta_dbgfs_stats_table_file = debugfs_create_file("rate_stats_table", S_IRUSR, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); - lq_sta->rs_sta_dbgfs_rate_scale_data_file = - debugfs_create_file("rate_scale_data", S_IRUSR, dir, - lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, &lq_sta->tx_agg_tid_en); @@ -3057,7 +3028,6 @@ static void rs_remove_debugfs(void *mvm, void *mvm_sta) struct iwl_lq_sta *lq_sta = mvm_sta; debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file); debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); } #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 4a99a4d200ac..917a48f32350 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -330,7 +330,6 @@ struct iwl_lq_sta { #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; struct dentry *rs_sta_dbgfs_stats_table_file; - struct dentry *rs_sta_dbgfs_rate_scale_data_file; struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; u32 dbg_fixed_rate; #endif -- cgit v1.2.3 From 2ab9ba0fdfa20e81c4454c57f534585a264cb238 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 11 Aug 2013 02:03:21 +0300 Subject: iwlwifi: pcie: returning positive instead of negative There is a missing '-' character here so we return positive 'ENOMEM' instead of negative. The caller doesn't care. All non-zero returns are translated to '-ENOMEM' in iwl_pcie_nic_init(). This is just a cleanup. Signed-off-by: Dan Carpenter Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 12c9c0030da6..f45eb29c2ede 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -838,7 +838,7 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) sizeof(struct iwl_txq), GFP_KERNEL); if (!trans_pcie->txq) { IWL_ERR(trans, "Not enough memory for txq\n"); - ret = ENOMEM; + ret = -ENOMEM; goto error; } -- cgit v1.2.3 From ab055ce9f5a9ff7dddf73f58bf1164e96b8af713 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 4 Aug 2013 13:10:31 +0300 Subject: iwlwifi: mvm: remove unused fields of iwl_rs_rate_info Some more cleanups of unused fields and their initializations. Signed-off-by: Eyal Shapira Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rs.c | 37 +++++++++++++++-------------------- drivers/net/wireless/iwlwifi/mvm/rs.h | 22 --------------------- 2 files changed, 16 insertions(+), 43 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 199f0cfdaadf..a69bd4c2de2a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -82,41 +82,36 @@ static const u8 ant_toggle_lookup[] = { [ANT_ABC] = ANT_ABC, }; -#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ +#define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ IWL_RATE_SISO_##s##M_PLCP, \ IWL_RATE_MIMO2_##s##M_PLCP,\ IWL_RATE_MIMO3_##s##M_PLCP,\ - IWL_RATE_##r##M_IEEE, \ - IWL_RATE_##ip##M_INDEX, \ - IWL_RATE_##in##M_INDEX, \ IWL_RATE_##rp##M_INDEX, \ - IWL_RATE_##rn##M_INDEX, \ - IWL_RATE_##pp##M_INDEX, \ - IWL_RATE_##np##M_INDEX } + IWL_RATE_##rn##M_INDEX } /* * Parameter order: - * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate + * rate, ht rate, prev rate, next rate * * If there isn't a valid next or previous rate then INV is used which * maps to IWL_RATE_INVALID * */ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { - IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ - IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ - IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ - IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ - IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ - IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ - IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ - IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ - IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ - IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ - IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ - IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ - IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ + IWL_DECLARE_RATE_INFO(1, INV, INV, 2), /* 1mbps */ + IWL_DECLARE_RATE_INFO(2, INV, 1, 5), /* 2mbps */ + IWL_DECLARE_RATE_INFO(5, INV, 2, 11), /*5.5mbps */ + IWL_DECLARE_RATE_INFO(11, INV, 9, 12), /* 11mbps */ + IWL_DECLARE_RATE_INFO(6, 6, 5, 11), /* 6mbps */ + IWL_DECLARE_RATE_INFO(9, 6, 6, 11), /* 9mbps */ + IWL_DECLARE_RATE_INFO(12, 12, 11, 18), /* 12mbps */ + IWL_DECLARE_RATE_INFO(18, 18, 12, 24), /* 18mbps */ + IWL_DECLARE_RATE_INFO(24, 24, 18, 36), /* 24mbps */ + IWL_DECLARE_RATE_INFO(36, 36, 24, 48), /* 36mbps */ + IWL_DECLARE_RATE_INFO(48, 48, 36, 54), /* 48mbps */ + IWL_DECLARE_RATE_INFO(54, 54, 48, INV), /* 54mbps */ + IWL_DECLARE_RATE_INFO(60, 60, 48, INV), /* 60mbps */ /* FIXME:RS: ^^ should be INV (legacy) */ }; diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 917a48f32350..9ac7c0b4e306 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -39,13 +39,8 @@ struct iwl_rs_rate_info { u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ - u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ - u8 prev_ieee; /* previous rate in IEEE speeds */ - u8 next_ieee; /* next rate in IEEE speeds */ u8 prev_rs; /* previous rate used in rs algo */ u8 next_rs; /* next rate used in rs algo */ - u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ - u8 next_rs_tgg; /* next rate used in TGG rs algo */ }; #define IWL_RATE_60M_PLCP 3 @@ -120,23 +115,6 @@ enum { IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, }; -/* MAC header values for bit rates */ -enum { - IWL_RATE_6M_IEEE = 12, - IWL_RATE_9M_IEEE = 18, - IWL_RATE_12M_IEEE = 24, - IWL_RATE_18M_IEEE = 36, - IWL_RATE_24M_IEEE = 48, - IWL_RATE_36M_IEEE = 72, - IWL_RATE_48M_IEEE = 96, - IWL_RATE_54M_IEEE = 108, - IWL_RATE_60M_IEEE = 120, - IWL_RATE_1M_IEEE = 2, - IWL_RATE_2M_IEEE = 4, - IWL_RATE_5M_IEEE = 11, - IWL_RATE_11M_IEEE = 22, -}; - #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) #define IWL_INVALID_VALUE -1 -- cgit v1.2.3 From faec6f91f52838ead8dabb8545b1312bdd32da4b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 17 Jul 2013 09:16:30 +0300 Subject: iwlwifi: mvm: don't clear tbl->win mistakenly rs_get_tbl_info_from_mcs() mistakenly clears the rate histories window, overriding its initialization values (i.e. filling it with 0, instead of -1). Signed-off-by: Eliad Peller Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index a69bd4c2de2a..a587b21e1fe1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -492,7 +492,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); u8 mcs; - memset(tbl, 0, sizeof(struct iwl_scale_tbl_info)); + memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win)); *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); if (*rate_idx == IWL_RATE_INVALID) { -- cgit v1.2.3 From e3c588ec0d9ef4e52caf0704a007440fb381d97f Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Sun, 7 Apr 2013 14:08:59 +0300 Subject: iwlwifi: mvm: Add basic uAPSD client support Implement basic uAPSD client support adding the following: - Advertise uAPSD support in HW capabilities - Set all ACs trigger- and delivery-enabled - Set max SP length to 2 buffered frames - Assign QNDP with the highest TID with no mandatory admission control required - Set uAPSD related parameters in Power Table command Signed-off-by: Alexander Bondar Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/constants.h | 6 ++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 16 +-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 7 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 + drivers/net/wireless/iwlwifi/mvm/power.c | 127 ++++++++++++++++++++---- 6 files changed, 135 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 64656e0c8f91..33f98fc26e2d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -67,5 +67,11 @@ #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) +#define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) +#define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) +#define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 +#define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 20 +#define IWL_MVM_PS_HEAVY_TX_THLD_PERCENT 50 +#define IWL_MVM_PS_HEAVY_RX_THLD_PERCENT 50 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 3cdc00591f6e..14811a583d2b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -424,7 +424,7 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file, struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->dbgfs_data; - char buf[256]; + char buf[512]; int bufsz = sizeof(buf); int pos; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 060e630b3d82..bb010b323b0f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -164,10 +164,10 @@ struct iwl_powertable_cmd { * Use IEEE80211_WMM_IE_STA_QOSINFO_AC* for correct values. * @uapsd_max_sp: Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct * values. - * @heavy_traffic_thr_tx_pkts: TX threshold measured in number of packets - * @heavy_traffic_thr_rx_pkts: RX threshold measured in number of packets - * @heavy_traffic_thr_tx_load: TX threshold measured in load's percentage - * @heavy_traffic_thr_rx_load: RX threshold measured in load's percentage + * @heavy_tx_thld_packets: TX threshold measured in number of packets + * @heavy_rx_thld_packets: RX threshold measured in number of packets + * @heavy_tx_thld_percentage: TX threshold measured in load's percentage + * @heavy_rx_thld_percentage: RX threshold measured in load's percentage * @limited_ps_threshold: */ struct iwl_mac_power_cmd { @@ -189,10 +189,10 @@ struct iwl_mac_power_cmd { u8 qndp_tid; u8 uapsd_ac_flags; u8 uapsd_max_sp; - u8 heavy_traffic_threshold_tx_packets; - u8 heavy_traffic_threshold_rx_packets; - u8 heavy_traffic_threshold_tx_percentage; - u8 heavy_traffic_threshold_rx_percentage; + u8 heavy_tx_thld_packets; + u8 heavy_rx_thld_packets; + u8 heavy_tx_thld_percentage; + u8 heavy_rx_thld_percentage; u8 limited_ps_threshold; u8 reserved; } __packed; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 05daa90616b7..66803b99cca8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -155,7 +155,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IEEE80211_HW_TIMING_BEACON_ONLY | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; + IEEE80211_HW_SUPPORTS_STATIC_SMPS | + IEEE80211_HW_SUPPORTS_UAPSD; hw->queues = IWL_MVM_FIRST_AGG_QUEUE; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; @@ -190,6 +191,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->max_remain_on_channel_duration = 10000; hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; + hw->uapsd_queues = IWL_UAPSD_AC_INFO; + hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; /* Extract MAC address */ memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); @@ -812,7 +815,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, */ iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); - } else if (changes & BSS_CHANGED_PS) { + } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_QOS)) { ret = iwl_mvm_power_update_mode(mvm, vif); if (ret) IWL_ERR(mvm, "failed to update power mode\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 76f6a1fdf668..014d77931c56 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -153,6 +153,11 @@ enum iwl_power_scheme { }; #define IWL_CONN_MAX_LISTEN_INTERVAL 70 +#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_BK |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) +#define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 struct iwl_mvm_power_ops { int (*power_update_mode)(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 4e7c9f245846..9c9b5bafb577 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -140,17 +140,30 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm, IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", le16_to_cpu(cmd->keep_alive_seconds)); - if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { - IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", - le32_to_cpu(cmd->rx_data_timeout)); - IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", - le32_to_cpu(cmd->tx_data_timeout)); - if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) - IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", - cmd->skip_dtim_periods); - if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) - IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", - cmd->lprx_rssi_threshold); + if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) { + IWL_DEBUG_POWER(mvm, "Disable power management\n"); + return; + } + + IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", + le32_to_cpu(cmd->rx_data_timeout)); + IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", + le32_to_cpu(cmd->tx_data_timeout)); + if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) + IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", + cmd->skip_dtim_periods); + if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) + IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", + cmd->lprx_rssi_threshold); + if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { + IWL_DEBUG_POWER(mvm, "uAPSD enabled\n"); + IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n", + le32_to_cpu(cmd->rx_data_timeout_uapsd)); + IWL_DEBUG_POWER(mvm, "Tx timeout (uAPSD) = %u usec\n", + le32_to_cpu(cmd->tx_data_timeout_uapsd)); + IWL_DEBUG_POWER(mvm, "QNDP TID = %d\n", cmd->qndp_tid); + IWL_DEBUG_POWER(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags); + IWL_DEBUG_POWER(mvm, "Max SP = %d\n", cmd->uapsd_max_sp); } } @@ -166,6 +179,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, bool radar_detect = false; struct iwl_mvm_vif *mvmvif __maybe_unused = iwl_mvm_vif_from_mac80211(vif); + enum ieee80211_ac_numbers ac; + bool tid_found = false; cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); @@ -235,6 +250,49 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); } + for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) { + if (!mvmvif->queue_params[ac].uapsd) + continue; + + cmd->flags |= cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK); + cmd->uapsd_ac_flags |= BIT(ac); + + /* QNDP TID - the highest TID with no admission control */ + if (!tid_found && !mvmvif->queue_params[ac].acm) { + tid_found = true; + switch (ac) { + case IEEE80211_AC_VO: + cmd->qndp_tid = 6; + break; + case IEEE80211_AC_VI: + cmd->qndp_tid = 5; + break; + case IEEE80211_AC_BE: + cmd->qndp_tid = 0; + break; + case IEEE80211_AC_BK: + cmd->qndp_tid = 1; + break; + } + } + } + + if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { + cmd->rx_data_timeout_uapsd = + cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT); + cmd->tx_data_timeout_uapsd = + cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT); + cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP; + cmd->heavy_tx_thld_packets = + IWL_MVM_PS_HEAVY_TX_THLD_PACKETS; + cmd->heavy_rx_thld_packets = + IWL_MVM_PS_HEAVY_RX_THLD_PACKETS; + cmd->heavy_tx_thld_percentage = + IWL_MVM_PS_HEAVY_TX_THLD_PERCENT; + cmd->heavy_rx_thld_percentage = + IWL_MVM_PS_HEAVY_RX_THLD_PERCENT; + } + #ifdef CONFIG_IWLWIFI_DEBUGFS if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) cmd->keep_alive_seconds = @@ -342,8 +400,6 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? 0 : 1); - pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", - cmd.skip_dtim_periods); pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", iwlmvm_mod_params.power_scheme); pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", @@ -356,14 +412,51 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, (cmd.flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0); - pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", - le32_to_cpu(cmd.rx_data_timeout)); - pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", - le32_to_cpu(cmd.tx_data_timeout)); + pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", + cmd.skip_dtim_periods); + if (!(cmd.flags & + cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) { + pos += scnprintf(buf+pos, bufsz-pos, + "rx_data_timeout = %d\n", + le32_to_cpu(cmd.rx_data_timeout)); + pos += scnprintf(buf+pos, bufsz-pos, + "tx_data_timeout = %d\n", + le32_to_cpu(cmd.tx_data_timeout)); + } if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) pos += scnprintf(buf+pos, bufsz-pos, "lprx_rssi_threshold = %d\n", cmd.lprx_rssi_threshold); + if (cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { + pos += + scnprintf(buf+pos, bufsz-pos, + "rx_data_timeout_uapsd = %d\n", + le32_to_cpu(cmd.rx_data_timeout_uapsd)); + pos += + scnprintf(buf+pos, bufsz-pos, + "tx_data_timeout_uapsd = %d\n", + le32_to_cpu(cmd.tx_data_timeout_uapsd)); + pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", + cmd.qndp_tid); + pos += scnprintf(buf+pos, bufsz-pos, + "uapsd_ac_flags = 0x%x\n", + cmd.uapsd_ac_flags); + pos += scnprintf(buf+pos, bufsz-pos, + "uapsd_max_sp = %d\n", + cmd.uapsd_max_sp); + pos += scnprintf(buf+pos, bufsz-pos, + "heavy_tx_thld_packets = %d\n", + cmd.heavy_tx_thld_packets); + pos += scnprintf(buf+pos, bufsz-pos, + "heavy_rx_thld_packets = %d\n", + cmd.heavy_rx_thld_packets); + pos += scnprintf(buf+pos, bufsz-pos, + "heavy_tx_thld_percentage = %d\n", + cmd.heavy_tx_thld_percentage); + pos += scnprintf(buf+pos, bufsz-pos, + "heavy_rx_thld_percentage = %d\n", + cmd.heavy_rx_thld_percentage); + } } return pos; } -- cgit v1.2.3 From d972ab31b90cf1c61f6f77a1968244280930c000 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 28 Jul 2013 23:02:45 +0000 Subject: iwlwifi: mvm: remove MIMO3 from rate scale code Current and future chips supported by mvm will only have a maximum of 2 antennas so all the MIMO3 related code and states can be dropped. Signed-off-by: Eyal Shapira Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rs.c | 393 ++++------------------------------ drivers/net/wireless/iwlwifi/mvm/rs.h | 41 +--- 2 files changed, 45 insertions(+), 389 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index a587b21e1fe1..5cb3132b8b37 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -86,7 +86,6 @@ static const u8 ant_toggle_lookup[] = { [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ IWL_RATE_SISO_##s##M_PLCP, \ IWL_RATE_MIMO2_##s##M_PLCP,\ - IWL_RATE_MIMO3_##s##M_PLCP,\ IWL_RATE_##rp##M_INDEX, \ IWL_RATE_##rn##M_INDEX } @@ -129,9 +128,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) if (rate_n_flags & RATE_MCS_HT_MSK) { idx = rs_extract_rate(rate_n_flags); - if (idx >= IWL_RATE_MIMO3_6M_PLCP) - idx = idx - IWL_RATE_MIMO3_6M_PLCP; - else if (idx >= IWL_RATE_MIMO2_6M_PLCP) + WARN_ON_ONCE(idx >= IWL_RATE_MIMO3_6M_PLCP); + if (idx >= IWL_RATE_MIMO2_6M_PLCP) idx = idx - IWL_RATE_MIMO2_6M_PLCP; idx += IWL_FIRST_OFDM_RATE; @@ -213,20 +211,6 @@ static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ }; -static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ - {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ - {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ - {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ -}; - -static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ - {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ - {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ - {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */ -}; - /* mbps, mcs */ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { { "1", "BPSK DSSS"}, @@ -274,7 +258,6 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n", lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); @@ -454,7 +437,7 @@ static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm, else if (is_mimo2(tbl->lq_type)) rate_n_flags |= iwl_rates[index].plcp_mimo2; else - rate_n_flags |= iwl_rates[index].plcp_mimo3; + WARN_ON_ONCE(1); } else { IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); } @@ -531,12 +514,8 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { if (num_of_ant == 2) tbl->lq_type = LQ_MIMO2; - /* MIMO3 */ } else { - if (num_of_ant == 3) { - tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; - tbl->lq_type = LQ_MIMO3; - } + WARN_ON_ONCE(num_of_ant == 3); } } return 0; @@ -602,10 +581,10 @@ static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, } else { if (is_siso(rate_type)) return lq_sta->active_siso_rate; - else if (is_mimo2(rate_type)) + else { + WARN_ON_ONCE(!is_mimo2(rate_type)); return lq_sta->active_mimo2_rate; - else - return lq_sta->active_mimo3_rate; + } } } @@ -980,7 +959,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, } /* Choose among many HT tables depending on number of streams - * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation + * (SISO/MIMO2), channel width (20/40), SGI, and aggregation * status */ if (is_siso(tbl->lq_type) && !tbl->is_ht40) ht_tbl_pointer = expected_tpt_siso20MHz; @@ -988,12 +967,10 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, ht_tbl_pointer = expected_tpt_siso40MHz; else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40) ht_tbl_pointer = expected_tpt_mimo2_20MHz; - else if (is_mimo2(tbl->lq_type)) + else { + WARN_ON_ONCE(!is_mimo2(tbl->lq_type)); ht_tbl_pointer = expected_tpt_mimo2_40MHz; - else if (is_mimo3(tbl->lq_type) && !tbl->is_ht40) - ht_tbl_pointer = expected_tpt_mimo3_20MHz; - else /* if (is_mimo3(tbl->lq_type)) <-- must be true */ - ht_tbl_pointer = expected_tpt_mimo3_40MHz; + } if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ tbl->expected_tpt = ht_tbl_pointer[0]; @@ -1164,58 +1141,6 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, return 0; } -/* - * Set up search table for MIMO3 - */ -static int rs_switch_to_mimo3(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, - struct iwl_scale_tbl_info *tbl, int index) -{ - u16 rate_mask; - s32 rate; - s8 is_green = lq_sta->is_green; - - if (!sta->ht_cap.ht_supported) - return -1; - - if (sta->smps_mode == IEEE80211_SMPS_STATIC) - return -1; - - /* Need both Tx chains/antennas to support MIMO */ - if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 3) - return -1; - - IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n"); - - tbl->lq_type = LQ_MIMO3; - tbl->action = 0; - tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; - rate_mask = lq_sta->active_mimo3_rate; - - if (iwl_is_ht40_tx_allowed(sta)) - tbl->is_ht40 = 1; - else - tbl->is_ht40 = 0; - - rs_set_expected_tpt_table(lq_sta, tbl); - - rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); - - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 best rate %d mask %X\n", - rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", - rate, rate_mask); - return -1; - } - tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); - - IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate, is_green); - return 0; -} - /* * Set up search table for SISO */ @@ -1325,21 +1250,14 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, } break; - case IWL_LEGACY_SWITCH_MIMO2_AB: - case IWL_LEGACY_SWITCH_MIMO2_AC: - case IWL_LEGACY_SWITCH_MIMO2_BC: + case IWL_LEGACY_SWITCH_MIMO2: IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n"); /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = 0; - if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB) - search_tbl->ant_type = ANT_AB; - else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC) - search_tbl->ant_type = ANT_AC; - else - search_tbl->ant_type = ANT_BC; + search_tbl->ant_type = ANT_AB; if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) @@ -1352,30 +1270,11 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, goto out; } break; - - case IWL_LEGACY_SWITCH_MIMO3_ABC: - IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO3\n"); - - /* Set up search table to try MIMO3 */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - - search_tbl->ant_type = ANT_ABC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo3(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) { - lq_sta->action_counter = 0; - goto out; - } - break; + default: + WARN_ON_ONCE(1); } tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; if (tbl->action == start_action) @@ -1387,7 +1286,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; @@ -1422,7 +1321,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, case IWL_BT_COEX_TRAFFIC_LOAD_LOW: /* avoid antenna B unless MIMO */ if (tbl->action == IWL_SISO_SWITCH_ANTENNA2) - tbl->action = IWL_SISO_SWITCH_MIMO2_AB; + tbl->action = IWL_SISO_SWITCH_MIMO2; break; case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: @@ -1464,19 +1363,12 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, goto out; } break; - case IWL_SISO_SWITCH_MIMO2_AB: - case IWL_SISO_SWITCH_MIMO2_AC: - case IWL_SISO_SWITCH_MIMO2_BC: + case IWL_SISO_SWITCH_MIMO2: IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n"); memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = 0; - if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB) - search_tbl->ant_type = ANT_AB; - else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC) - search_tbl->ant_type = ANT_AC; - else - search_tbl->ant_type = ANT_BC; + search_tbl->ant_type = ANT_AB; if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) @@ -1517,24 +1409,11 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, index, is_green); update_search_tbl_counter = 1; goto out; - case IWL_SISO_SWITCH_MIMO3_ABC: - IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO3\n"); - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_ABC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo3(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - break; + default: + WARN_ON_ONCE(1); } tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) + if (tbl->action > IWL_SISO_SWITCH_GI) tbl->action = IWL_SISO_SWITCH_ANTENNA1; if (tbl->action == start_action) @@ -1546,7 +1425,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC) + if (tbl->action > IWL_SISO_SWITCH_GI) tbl->action = IWL_SISO_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; @@ -1587,8 +1466,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, break; case IWL_BT_COEX_TRAFFIC_LOAD_LOW: /* avoid antenna B unless MIMO */ - if (tbl->action == IWL_MIMO2_SWITCH_SISO_B || - tbl->action == IWL_MIMO2_SWITCH_SISO_C) + if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) tbl->action = IWL_MIMO2_SWITCH_SISO_A; break; default: @@ -1621,7 +1499,6 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, break; case IWL_MIMO2_SWITCH_SISO_A: case IWL_MIMO2_SWITCH_SISO_B: - case IWL_MIMO2_SWITCH_SISO_C: IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); /* Set up new search table for SISO */ @@ -1629,10 +1506,8 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) search_tbl->ant_type = ANT_A; - else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) + else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */ search_tbl->ant_type = ANT_B; - else - search_tbl->ant_type = ANT_C; if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) @@ -1675,26 +1550,11 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, index, is_green); update_search_tbl_counter = 1; goto out; - - case IWL_MIMO2_SWITCH_MIMO3_ABC: - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to MIMO3\n"); - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_ABC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo3(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - - break; + default: + WARN_ON_ONCE(1); } tbl->action++; - if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) + if (tbl->action > IWL_MIMO2_SWITCH_GI) tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; if (tbl->action == start_action) @@ -1705,7 +1565,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) + if (tbl->action > IWL_MIMO2_SWITCH_GI) tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; @@ -1713,171 +1573,6 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, return 0; } -/* - * Try to switch to new modulation mode from MIMO3 - */ -static int rs_move_mimo3_to_other(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, int index) -{ - s8 is_green = lq_sta->is_green; - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct iwl_rate_scale_data *window = &(tbl->win[index]); - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action; - u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); - u8 tx_chains_num = num_of_ant(valid_tx_ant); - int ret; - u8 update_search_tbl_counter = 0; - - switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { - case IWL_BT_COEX_TRAFFIC_LOAD_NONE: - /* nothing */ - break; - case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: - case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: - /* avoid antenna B and MIMO */ - if (tbl->action != IWL_MIMO3_SWITCH_SISO_A) - tbl->action = IWL_MIMO3_SWITCH_SISO_A; - break; - case IWL_BT_COEX_TRAFFIC_LOAD_LOW: - /* avoid antenna B unless MIMO */ - if (tbl->action == IWL_MIMO3_SWITCH_SISO_B || - tbl->action == IWL_MIMO3_SWITCH_SISO_C) - tbl->action = IWL_MIMO3_SWITCH_SISO_A; - break; - default: - IWL_ERR(mvm, "Invalid BT load %d", - BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)); - break; - } - - start_action = tbl->action; - while (1) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_MIMO3_SWITCH_ANTENNA1: - case IWL_MIMO3_SWITCH_ANTENNA2: - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle Antennas\n"); - - if (tx_chains_num <= 3) - break; - - if (window->success_ratio >= IWL_RS_GOOD_RATIO) - break; - - memcpy(search_tbl, tbl, sz); - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, - search_tbl)) - goto out; - break; - case IWL_MIMO3_SWITCH_SISO_A: - case IWL_MIMO3_SWITCH_SISO_B: - case IWL_MIMO3_SWITCH_SISO_C: - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to SISO\n"); - - /* Set up new search table for SISO */ - memcpy(search_tbl, tbl, sz); - - if (tbl->action == IWL_MIMO3_SWITCH_SISO_A) - search_tbl->ant_type = ANT_A; - else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B) - search_tbl->ant_type = ANT_B; - else - search_tbl->ant_type = ANT_C; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_siso(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - - break; - - case IWL_MIMO3_SWITCH_MIMO2_AB: - case IWL_MIMO3_SWITCH_MIMO2_AC: - case IWL_MIMO3_SWITCH_MIMO2_BC: - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to MIMO2\n"); - - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB) - search_tbl->ant_type = ANT_AB; - else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC) - search_tbl->ant_type = ANT_AC; - else - search_tbl->ant_type = ANT_BC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo2(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - - break; - - case IWL_MIMO3_SWITCH_GI: - if (!tbl->is_ht40 && !(ht_cap->cap & - IEEE80211_HT_CAP_SGI_20)) - break; - if (tbl->is_ht40 && !(ht_cap->cap & - IEEE80211_HT_CAP_SGI_40)) - break; - - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle SGI/NGI\n"); - - /* Set up new search table for MIMO */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = !tbl->is_SGI; - rs_set_expected_tpt_table(lq_sta, search_tbl); - /* - * If active table already uses the fastest possible - * modulation (dual stream with short guard interval), - * and it's working well, there's no need to look - * for a better type of modulation! - */ - if (tbl->is_SGI) { - s32 tpt = lq_sta->last_tpt / 100; - if (tpt >= search_tbl->expected_tpt[index]) - break; - } - search_tbl->current_rate = - rate_n_flags_from_tbl(mvm, search_tbl, - index, is_green); - update_search_tbl_counter = 1; - goto out; - } - tbl->action++; - if (tbl->action > IWL_MIMO3_SWITCH_GI) - tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; - - if (tbl->action == start_action) - break; - } - search_tbl->lq_type = LQ_NONE; - return 0; - out: - lq_sta->search_better_tbl = 1; - tbl->action++; - if (tbl->action > IWL_MIMO3_SWITCH_GI) - tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; - if (update_search_tbl_counter) - search_tbl->action = tbl->action; - - return 0; -} - /* * Check whether we should continue using same modulation mode, or * begin search for a new mode, based on: @@ -2284,8 +1979,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, scale_action = 0; if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= - IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && - (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) { + IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && (is_mimo(tbl->lq_type))) { if (lq_sta->last_bt_traffic > BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { /* @@ -2302,8 +1996,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD); if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= - IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && - (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) { + IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && is_mimo(tbl->lq_type)) { /* search for a new modulation */ rs_stay_in_table(lq_sta, true); goto lq_update; @@ -2363,7 +2056,7 @@ lq_update: else if (is_mimo2(tbl->lq_type)) rs_move_mimo2_to_other(mvm, lq_sta, sta, index); else - rs_move_mimo3_to_other(mvm, lq_sta, sta, index); + WARN_ON_ONCE(1); /* If new "search" mode was selected, set up in uCode table */ if (lq_sta->search_better_tbl) { @@ -2528,11 +2221,10 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, rate_idx -= IWL_FIRST_OFDM_RATE; /* 6M and 9M shared same MCS index */ rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; + WARN_ON_ONCE(rs_extract_rate(lq_sta->last_rate_n_flags) >= + IWL_RATE_MIMO3_6M_PLCP); if (rs_extract_rate(lq_sta->last_rate_n_flags) >= - IWL_RATE_MIMO3_6M_PLCP) - rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM); - else if (rs_extract_rate(lq_sta->last_rate_n_flags) >= - IWL_RATE_MIMO2_6M_PLCP) + IWL_RATE_MIMO2_6M_PLCP) rate_idx = rate_idx + MCS_INDEX_PER_STREAM; info->control.rates[0].flags = IEEE80211_TX_RC_MCS; if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) @@ -2631,16 +2323,10 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1; - lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1; - lq_sta->active_mimo3_rate &= ~((u16)0x2); - lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; - IWL_DEBUG_RATE(mvm, - "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n", + "SISO-RATE=%X MIMO2-RATE=%X\n", lq_sta->active_siso_rate, - lq_sta->active_mimo2_rate, - lq_sta->active_mimo3_rate); + lq_sta->active_mimo2_rate); /* These values will be overridden later */ lq_sta->lq.single_stream_ant_msk = @@ -2903,8 +2589,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); if (is_Ht(tbl->lq_type)) { desc += sprintf(buff+desc, " %s", - (is_siso(tbl->lq_type)) ? "SISO" : - ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); + (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2"); desc += sprintf(buff+desc, " %s", (tbl->is_ht40) ? "40MHz" : "20MHz"); desc += sprintf(buff+desc, " %s %s %s\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 9ac7c0b4e306..335cf1682902 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -38,7 +38,6 @@ struct iwl_rs_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ - u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ u8 prev_rs; /* previous rate used in rs algo */ u8 next_rs; /* next rate used in rs algo */ }; @@ -143,47 +142,22 @@ enum { #define IWL_LEGACY_SWITCH_ANTENNA1 0 #define IWL_LEGACY_SWITCH_ANTENNA2 1 #define IWL_LEGACY_SWITCH_SISO 2 -#define IWL_LEGACY_SWITCH_MIMO2_AB 3 -#define IWL_LEGACY_SWITCH_MIMO2_AC 4 -#define IWL_LEGACY_SWITCH_MIMO2_BC 5 -#define IWL_LEGACY_SWITCH_MIMO3_ABC 6 +#define IWL_LEGACY_SWITCH_MIMO2 3 /* possible actions when in siso mode */ #define IWL_SISO_SWITCH_ANTENNA1 0 #define IWL_SISO_SWITCH_ANTENNA2 1 -#define IWL_SISO_SWITCH_MIMO2_AB 2 -#define IWL_SISO_SWITCH_MIMO2_AC 3 -#define IWL_SISO_SWITCH_MIMO2_BC 4 -#define IWL_SISO_SWITCH_GI 5 -#define IWL_SISO_SWITCH_MIMO3_ABC 6 - +#define IWL_SISO_SWITCH_MIMO2 2 +#define IWL_SISO_SWITCH_GI 3 /* possible actions when in mimo mode */ #define IWL_MIMO2_SWITCH_ANTENNA1 0 #define IWL_MIMO2_SWITCH_ANTENNA2 1 #define IWL_MIMO2_SWITCH_SISO_A 2 #define IWL_MIMO2_SWITCH_SISO_B 3 -#define IWL_MIMO2_SWITCH_SISO_C 4 -#define IWL_MIMO2_SWITCH_GI 5 -#define IWL_MIMO2_SWITCH_MIMO3_ABC 6 - - -/* possible actions when in mimo3 mode */ -#define IWL_MIMO3_SWITCH_ANTENNA1 0 -#define IWL_MIMO3_SWITCH_ANTENNA2 1 -#define IWL_MIMO3_SWITCH_SISO_A 2 -#define IWL_MIMO3_SWITCH_SISO_B 3 -#define IWL_MIMO3_SWITCH_SISO_C 4 -#define IWL_MIMO3_SWITCH_MIMO2_AB 5 -#define IWL_MIMO3_SWITCH_MIMO2_AC 6 -#define IWL_MIMO3_SWITCH_MIMO2_BC 7 -#define IWL_MIMO3_SWITCH_GI 8 - - -#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI -#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC +#define IWL_MIMO2_SWITCH_GI 4 -/*FIXME:RS:add possible actions for MIMO3*/ +#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_GI #define IWL_ACTION_LIMIT 3 /* # possible actions */ @@ -218,15 +192,13 @@ enum iwl_table_type { LQ_A, LQ_SISO, /* high-throughput types */ LQ_MIMO2, - LQ_MIMO3, LQ_MAX, }; #define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) #define is_siso(tbl) ((tbl) == LQ_SISO) #define is_mimo2(tbl) ((tbl) == LQ_MIMO2) -#define is_mimo3(tbl) ((tbl) == LQ_MIMO3) -#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl)) +#define is_mimo(tbl) is_mimo2(tbl) #define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) #define is_a_band(tbl) ((tbl) == LQ_A) #define is_g_and(tbl) ((tbl) == LQ_G) @@ -298,7 +270,6 @@ struct iwl_lq_sta { u16 active_legacy_rate; u16 active_siso_rate; u16 active_mimo2_rate; - u16 active_mimo3_rate; s8 max_rate_idx; /* Max rate set by user */ u8 missed_rate_counter; -- cgit v1.2.3 From d1e2586f484dfc36eee2b2d3a6c6c77be67ca492 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 9 Aug 2013 21:09:06 -0700 Subject: mwifiex: fix build error when CONFIG_PM is not set config: make ARCH=m68k allmodconfig All error/warnings: drivers/net/wireless/mwifiex/cfg80211.c: In function 'mwifiex_fill_coalesce_rule_info': >> drivers/net/wireless/mwifiex/cfg80211.c:2493:3: error: implicit declaration of function 'mwifiex_is_pattern_supported' [-Werror=implicit-function-declaration] drivers/net/wireless/mwifiex/cfg80211.c: At top level: drivers/net/wireless/mwifiex/cfg80211.c:2537:12: warning: 'mwifiex_cfg80211_set_coalesce' defined but not used [-Wunused-function] cc1: some warnings being treated as errors Reported-by: kbuild test robot Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 07d23183898c..ca149aea1517 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2307,7 +2307,6 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) } EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); -#ifdef CONFIG_PM static bool mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, u8 max_byte_seq) @@ -2338,6 +2337,7 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, return true; } +#ifdef CONFIG_PM static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowlan) { @@ -2601,8 +2601,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .suspend = mwifiex_cfg80211_suspend, .resume = mwifiex_cfg80211_resume, .set_wakeup = mwifiex_cfg80211_set_wakeup, - .set_coalesce = mwifiex_cfg80211_set_coalesce, #endif + .set_coalesce = mwifiex_cfg80211_set_coalesce, }; #ifdef CONFIG_PM -- cgit v1.2.3 From 4061f895088a2825b15312947aedb8574e2d8de5 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 10 Aug 2013 12:27:19 +0200 Subject: brcmfmac: use irq safe spinlock in brcmf_sdbrcm_txdata() Firmware-signalling needs transmit to firmware to be atomic and uses a spinlock with irq disabled. Therefor, brcmf_sdbrcm_txdata() should not use spin_unlock_bh() as it would enable the interrupts. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 6 +++++- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 080395f49fa5..9249b6d42066 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -36,7 +36,11 @@ struct brcmf_bus_dcmd { * * @init: prepare for communication with dongle. * @stop: clear pending frames, disable data flow. - * @txdata: send a data frame to the dongle (callee disposes skb). + * @txdata: send a data frame to the dongle. When the data + * has been transferred, the common driver must be + * notified using brcmf_txcomplete(). The common + * driver calls this function with interrupts + * disabled. * @txctl: transmit a control request message to dongle. * @rxctl: receive a control response message from dongle. * @gettxq: obtain a reference of bus transmit queue (optional). diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 264111968320..5cbce1dff093 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2276,6 +2276,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; + ulong flags; brcmf_dbg(TRACE, "Enter\n"); @@ -2293,7 +2294,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) bus->sdcnt.fcqueued++; /* Priority based enq */ - spin_lock_bh(&bus->txqlock); + spin_lock_irqsave(&bus->txqlock, flags); if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { skb_pull(pkt, SDPCM_HDRLEN); brcmf_txcomplete(bus->sdiodev->dev, pkt, false); @@ -2307,7 +2308,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) bus->txoff = true; brcmf_txflowblock(bus->sdiodev->dev, true); } - spin_unlock_bh(&bus->txqlock); + spin_unlock_irqrestore(&bus->txqlock, flags); #ifdef DEBUG if (pktq_plen(&bus->txq, prec) > qcount[prec]) -- cgit v1.2.3 From 04779fddeff723cf5afe529e4ed67fc86f25ba37 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 10 Aug 2013 12:27:20 +0200 Subject: brcmfmac: .txdata() bus callback should not call brcmf_txcomplete() With firmware-signalling the packet handed to the bus specific driver layer should not be discarded with brcmf_txcomplete() in the failure path. Instead only an error is returned and the caller decides what to do with the packet. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 1 - drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 6 +++++- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 5cbce1dff093..db31312eba6a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2297,7 +2297,6 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) spin_lock_irqsave(&bus->txqlock, flags); if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { skb_pull(pkt, SDPCM_HDRLEN); - brcmf_txcomplete(bus->sdiodev->dev, pkt, false); brcmf_err("out of bus->txq !!!\n"); ret = -ENOSR; } else { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 29b1f24c2d0f..601b0d05169c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -1745,6 +1745,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) int fifo = BRCMF_FWS_FIFO_BCMC; bool multicast = is_multicast_ether_addr(eh->h_dest); bool pae = eh->h_proto == htons(ETH_P_PAE); + int ret; /* determine the priority */ if (!skb->priority) @@ -1759,7 +1760,10 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb); /* Use bus module to send data frame */ - return brcmf_bus_txdata(drvr->bus_if, skb); + ret = brcmf_bus_txdata(drvr->bus_if, skb); + if (ret < 0) + brcmf_txfinalize(drvr, skb, false); + return ret; } /* set control buffer information */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 322cadc51ded..39e01a7c8556 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -614,7 +614,6 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) return 0; fail: - brcmf_txcomplete(dev, skb, false); return ret; } -- cgit v1.2.3 From 87edd8916ee261cd8c49b736f156d602054bd9fd Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 10 Aug 2013 12:27:21 +0200 Subject: brcmfmac: add AMPDU reordering functionality This feature moves the responsibility of collecting all MPDUs in an AMPDU session in the correct order from the firmware to the host driver. This reduces buffer requirement on the firmware side. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 27 +++ .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 270 +++++++++++++++++++-- drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 13 +- 3 files changed, 283 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 86cbfe2c7c6c..3943fb834179 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -209,6 +209,8 @@ #define BRCMF_DCMD_MEDLEN 1536 #define BRCMF_DCMD_MAXLEN 8192 +#define BRCMF_AMPDU_RX_REORDER_MAXFLOWS 256 + /* Pattern matching filter. Specifies an offset within received packets to * start matching, the pattern to match, the size of the pattern, and a bitmask * that indicates which bits within the pattern should be matched. @@ -505,6 +507,25 @@ struct brcmf_dcmd { uint needed; /* bytes needed (optional) */ }; +/** + * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info + * + * @pktslots: dynamic allocated array for ordering AMPDU packets. + * @flow_id: AMPDU flow identifier. + * @cur_idx: last AMPDU index from firmware. + * @exp_idx: expected next AMPDU index. + * @max_idx: maximum amount of packets per AMPDU. + * @pend_pkts: number of packets currently in @pktslots. + */ +struct brcmf_ampdu_rx_reorder { + struct sk_buff **pktslots; + u8 flow_id; + u8 cur_idx; + u8 exp_idx; + u8 max_idx; + u8 pend_pkts; +}; + /* Forward decls for struct brcmf_pub (see below) */ struct brcmf_proto; /* device communication protocol info */ struct brcmf_cfg80211_dev; /* cfg80211 device info */ @@ -539,6 +560,9 @@ struct brcmf_pub { bool fw_signals; struct brcmf_fws_info *fws; spinlock_t fws_spinlock; + + struct brcmf_ampdu_rx_reorder + *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS]; #ifdef DEBUG struct dentry *dbgfs_dir; #endif @@ -604,6 +628,9 @@ struct brcmf_if { wait_queue_head_t pend_8021x_wait; }; +struct brcmf_skb_reorder_data { + u8 *reorder; +}; extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 80099016d21f..9bc2785b4240 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -38,6 +38,19 @@ MODULE_LICENSE("Dual BSD/GPL"); #define MAX_WAIT_FOR_8021X_TX 50 /* msecs */ +/* AMPDU rx reordering definitions */ +#define BRCMF_RXREORDER_FLOWID_OFFSET 0 +#define BRCMF_RXREORDER_MAXIDX_OFFSET 2 +#define BRCMF_RXREORDER_FLAGS_OFFSET 4 +#define BRCMF_RXREORDER_CURIDX_OFFSET 6 +#define BRCMF_RXREORDER_EXPIDX_OFFSET 8 + +#define BRCMF_RXREORDER_DEL_FLOW 0x01 +#define BRCMF_RXREORDER_FLUSH_ALL 0x02 +#define BRCMF_RXREORDER_CURIDX_VALID 0x04 +#define BRCMF_RXREORDER_EXPIDX_VALID 0x08 +#define BRCMF_RXREORDER_NEW_HOLE 0x10 + /* Error bits */ int brcmf_msg_level; module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR); @@ -279,16 +292,243 @@ void brcmf_txflowblock(struct device *dev, bool state) } } +static void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) +{ + skb->dev = ifp->ndev; + skb->protocol = eth_type_trans(skb, skb->dev); + + if (skb->pkt_type == PACKET_MULTICAST) + ifp->stats.multicast++; + + /* Process special event packets */ + brcmf_fweh_process_skb(ifp->drvr, skb); + + if (!(ifp->ndev->flags & IFF_UP)) { + brcmu_pkt_buf_free_skb(skb); + return; + } + + ifp->stats.rx_bytes += skb->len; + ifp->stats.rx_packets++; + + brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol)); + if (in_interrupt()) + netif_rx(skb); + else + /* If the receive is not processed inside an ISR, + * the softirqd must be woken explicitly to service + * the NET_RX_SOFTIRQ. This is handled by netif_rx_ni(). + */ + netif_rx_ni(skb); +} + +static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi, + u8 start, u8 end, + struct sk_buff_head *skb_list) +{ + /* initialize return list */ + __skb_queue_head_init(skb_list); + + if (rfi->pend_pkts == 0) { + brcmf_dbg(INFO, "no packets in reorder queue\n"); + return; + } + + do { + if (rfi->pktslots[start]) { + __skb_queue_tail(skb_list, rfi->pktslots[start]); + rfi->pktslots[start] = NULL; + } + start++; + if (start > rfi->max_idx) + start = 0; + } while (start != end); + rfi->pend_pkts -= skb_queue_len(skb_list); +} + +static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data, + struct sk_buff *pkt) +{ + u8 flow_id, max_idx, cur_idx, exp_idx, end_idx; + struct brcmf_ampdu_rx_reorder *rfi; + struct sk_buff_head reorder_list; + struct sk_buff *pnext; + u8 flags; + u32 buf_size; + + flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET]; + flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET]; + + /* validate flags and flow id */ + if (flags == 0xFF) { + brcmf_err("invalid flags...so ignore this packet\n"); + brcmf_netif_rx(ifp, pkt); + return; + } + + rfi = ifp->drvr->reorder_flows[flow_id]; + if (flags & BRCMF_RXREORDER_DEL_FLOW) { + brcmf_dbg(INFO, "flow-%d: delete\n", + flow_id); + + if (rfi == NULL) { + brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n", + flow_id); + brcmf_netif_rx(ifp, pkt); + return; + } + + brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx, + &reorder_list); + /* add the last packet */ + __skb_queue_tail(&reorder_list, pkt); + kfree(rfi); + ifp->drvr->reorder_flows[flow_id] = NULL; + goto netif_rx; + } + /* from here on we need a flow reorder instance */ + if (rfi == NULL) { + buf_size = sizeof(*rfi); + max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET]; + + buf_size += (max_idx + 1) * sizeof(pkt); + + /* allocate space for flow reorder info */ + brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n", + flow_id, max_idx); + rfi = kzalloc(buf_size, GFP_ATOMIC); + if (rfi == NULL) { + brcmf_err("failed to alloc buffer\n"); + brcmf_netif_rx(ifp, pkt); + return; + } + + ifp->drvr->reorder_flows[flow_id] = rfi; + rfi->pktslots = (struct sk_buff **)(rfi+1); + rfi->max_idx = max_idx; + } + if (flags & BRCMF_RXREORDER_NEW_HOLE) { + if (rfi->pend_pkts) { + brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, + rfi->exp_idx, + &reorder_list); + WARN_ON(rfi->pend_pkts); + } else { + __skb_queue_head_init(&reorder_list); + } + rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET]; + rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; + rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET]; + rfi->pktslots[rfi->cur_idx] = pkt; + rfi->pend_pkts++; + brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n", + flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts); + } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) { + cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET]; + exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; + + if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) { + /* still in the current hole */ + /* enqueue the current on the buffer chain */ + if (rfi->pktslots[cur_idx] != NULL) { + brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n"); + brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]); + rfi->pktslots[cur_idx] = NULL; + } + rfi->pktslots[cur_idx] = pkt; + rfi->pend_pkts++; + rfi->cur_idx = cur_idx; + brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n", + flow_id, cur_idx, exp_idx, rfi->pend_pkts); + + /* can return now as there is no reorder + * list to process. + */ + return; + } + if (rfi->exp_idx == cur_idx) { + if (rfi->pktslots[cur_idx] != NULL) { + brcmf_dbg(INFO, "error buffer pending..free it\n"); + brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]); + rfi->pktslots[cur_idx] = NULL; + } + rfi->pktslots[cur_idx] = pkt; + rfi->pend_pkts++; + + /* got the expected one. flush from current to expected + * and update expected + */ + brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n", + flow_id, cur_idx, exp_idx, rfi->pend_pkts); + + rfi->cur_idx = cur_idx; + rfi->exp_idx = exp_idx; + + brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx, + &reorder_list); + brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n", + flow_id, skb_queue_len(&reorder_list), + rfi->pend_pkts); + } else { + u8 end_idx; + + brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n", + flow_id, flags, rfi->cur_idx, rfi->exp_idx, + cur_idx, exp_idx); + if (flags & BRCMF_RXREORDER_FLUSH_ALL) + end_idx = rfi->exp_idx; + else + end_idx = exp_idx; + + /* flush pkts first */ + brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx, + &reorder_list); + + if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) { + __skb_queue_tail(&reorder_list, pkt); + } else { + rfi->pktslots[cur_idx] = pkt; + rfi->pend_pkts++; + } + rfi->exp_idx = exp_idx; + rfi->cur_idx = cur_idx; + } + } else { + /* explicity window move updating the expected index */ + exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; + + brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n", + flow_id, flags, rfi->exp_idx, exp_idx); + if (flags & BRCMF_RXREORDER_FLUSH_ALL) + end_idx = rfi->exp_idx; + else + end_idx = exp_idx; + + brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx, + &reorder_list); + __skb_queue_tail(&reorder_list, pkt); + /* set the new expected idx */ + rfi->exp_idx = exp_idx; + } +netif_rx: + skb_queue_walk_safe(&reorder_list, pkt, pnext) { + __skb_unlink(pkt, &reorder_list); + brcmf_netif_rx(ifp, pkt); + } +} + void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) { struct sk_buff *skb, *pnext; struct brcmf_if *ifp; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_skb_reorder_data *rd; u8 ifidx; int ret; - brcmf_dbg(DATA, "Enter\n"); + brcmf_dbg(DATA, "Enter: %s: count=%u\n", dev_name(dev), + skb_queue_len(skb_list)); skb_queue_walk_safe(skb_list, skb, pnext) { skb_unlink(skb, skb_list); @@ -304,31 +544,11 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) continue; } - skb->dev = ifp->ndev; - skb->protocol = eth_type_trans(skb, skb->dev); - - if (skb->pkt_type == PACKET_MULTICAST) - ifp->stats.multicast++; - - /* Process special event packets */ - brcmf_fweh_process_skb(drvr, skb); - - if (!(ifp->ndev->flags & IFF_UP)) { - brcmu_pkt_buf_free_skb(skb); - continue; - } - - ifp->stats.rx_bytes += skb->len; - ifp->stats.rx_packets++; - - if (in_interrupt()) - netif_rx(skb); + rd = (struct brcmf_skb_reorder_data *)skb->cb; + if (rd->reorder) + brcmf_rxreorder_process_info(ifp, rd->reorder, skb); else - /* If the receive is not processed inside an ISR, - * the softirqd must be woken explicitly to service the - * NET_RX_SOFTIRQ. This is handled by netif_rx_ni(). - */ - netif_rx_ni(skb); + brcmf_netif_rx(ifp, skb); } } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 601b0d05169c..438c7b940a61 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -1483,6 +1483,7 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp, int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, struct sk_buff *skb) { + struct brcmf_skb_reorder_data *rd; struct brcmf_fws_info *fws = drvr->fws; u8 *signal_data; s16 data_len; @@ -1536,9 +1537,12 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, err = BRCMF_FWS_RET_OK_NOSCHEDULE; switch (type) { - case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: case BRCMF_FWS_TYPE_COMP_TXSTATUS: break; + case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: + rd = (struct brcmf_skb_reorder_data *)skb->cb; + rd->reorder = data; + break; case BRCMF_FWS_TYPE_MACDESC_ADD: case BRCMF_FWS_TYPE_MACDESC_DEL: brcmf_fws_macdesc_indicate(fws, type, data); @@ -1747,6 +1751,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) bool pae = eh->h_proto == htons(ETH_P_PAE); int ret; + brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); /* determine the priority */ if (!skb->priority) skb->priority = cfg80211_classify8021d(skb); @@ -1915,7 +1920,8 @@ int brcmf_fws_init(struct brcmf_pub *drvr) if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE) tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS | BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS | - BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE; + BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE | + BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE; rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP, brcmf_fws_notify_credit_map); @@ -1940,6 +1946,9 @@ int brcmf_fws_init(struct brcmf_pub *drvr) goto fail_event; } + if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1)) + brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n"); + brcmf_fws_hanger_init(&drvr->fws->hanger); brcmf_fws_macdesc_init(&drvr->fws->desc.other, NULL, 0); brcmf_fws_macdesc_set_name(drvr->fws, &drvr->fws->desc.other); -- cgit v1.2.3 From 0a4254be94fd3afc17fb84a88adabd4460dd4c56 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sat, 10 Aug 2013 12:27:22 +0200 Subject: brcmfmac: always use worker thread for tx data. When fw signalling is disabled tx is sent immediately. Using queues and worker thread allows usb to do synchronous autopm. This patch makes fws use queues and worker thread even if signalling is not supported by FW or not enabled. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 1 - .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 13 +-- drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 96 ++++++++++++---------- 3 files changed, 54 insertions(+), 56 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 3943fb834179..df94d0e9fab9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -557,7 +557,6 @@ struct brcmf_pub { struct brcmf_fweh_info fweh; - bool fw_signals; struct brcmf_fws_info *fws; spinlock_t fws_spinlock; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 9bc2785b4240..e067aec1fbf1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -278,18 +278,10 @@ void brcmf_txflowblock(struct device *dev, bool state) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; - int i; brcmf_dbg(TRACE, "Enter\n"); - if (brcmf_fws_fc_active(drvr->fws)) { - brcmf_fws_bus_blocked(drvr, state); - } else { - for (i = 0; i < BRCMF_MAX_IFS; i++) - brcmf_txflowblock_if(drvr->iflist[i], - BRCMF_NETIF_STOP_REASON_BLOCK_BUS, - state); - } + brcmf_fws_bus_blocked(drvr, state); } static void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) @@ -534,7 +526,7 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) skb_unlink(skb, skb_list); /* process and remove protocol-specific header */ - ret = brcmf_proto_hdrpull(drvr, drvr->fw_signals, &ifidx, skb); + ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb); ifp = drvr->iflist[ifidx]; if (ret || !ifp || !ifp->ndev) { @@ -1109,7 +1101,6 @@ int brcmf_bus_start(struct device *dev) if (ret < 0) goto fail; - drvr->fw_signals = true; ret = brcmf_fws_init(drvr); if (ret < 0) goto fail; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 438c7b940a61..15fc807e8747 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -425,6 +425,7 @@ struct brcmf_fws_info { struct brcmf_fws_stats stats; struct brcmf_fws_hanger hanger; enum brcmf_fws_fcmode fcmode; + bool fw_signals; bool bcmc_credit_check; struct brcmf_fws_macdesc_table desc; struct workqueue_struct *fws_wq; @@ -1160,7 +1161,8 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws, static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws) { /* only schedule dequeue when there are credits for delayed traffic */ - if (fws->fifo_credit_map & fws->fifo_delay_map) + if ((fws->fifo_credit_map & fws->fifo_delay_map) || + (!brcmf_fws_fc_active(fws) && fws->fifo_delay_map)) queue_work(fws->fws_wq, &fws->fws_dequeue_work); } @@ -1498,8 +1500,10 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, WARN_ON(signal_len > skb->len); + if (!signal_len) + return 0; /* if flow control disabled, skip to packet data and leave */ - if (!signal_len || !drvr->fw_signals) { + if (!fws->fw_signals) { skb_pull(skb, signal_len); return 0; } @@ -1749,7 +1753,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) int fifo = BRCMF_FWS_FIFO_BCMC; bool multicast = is_multicast_ether_addr(eh->h_dest); bool pae = eh->h_proto == htons(ETH_P_PAE); - int ret; brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); /* determine the priority */ @@ -1760,17 +1763,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) if (pae) atomic_inc(&ifp->pend_8021x_cnt); - if (!brcmf_fws_fc_active(fws)) { - /* If the protocol uses a data header, apply it */ - brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb); - - /* Use bus module to send data frame */ - ret = brcmf_bus_txdata(drvr->bus_if, skb); - if (ret < 0) - brcmf_txfinalize(drvr, skb, false); - return ret; - } - /* set control buffer information */ skcb->if_flags = 0; skcb->state = BRCMF_FWS_SKBSTATE_NEW; @@ -1818,7 +1810,7 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp) struct brcmf_fws_info *fws = ifp->drvr->fws; struct brcmf_fws_mac_descriptor *entry; - if (!ifp->ndev || !ifp->drvr->fw_signals) + if (!ifp->ndev) return; entry = &fws->desc.iface[ifp->ifidx]; @@ -1849,15 +1841,38 @@ void brcmf_fws_del_interface(struct brcmf_if *ifp) static void brcmf_fws_dequeue_worker(struct work_struct *worker) { struct brcmf_fws_info *fws; + struct brcmf_pub *drvr; struct sk_buff *skb; ulong flags; int fifo; + u32 hslot; + u32 ifidx; + int ret; fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work); + drvr = fws->drvr; - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(drvr, flags); for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked; fifo--) { + if (!brcmf_fws_fc_active(fws)) { + while ((skb = brcmf_fws_deq(fws, fifo)) != NULL) { + hslot = brcmf_skb_htod_tag_get_field(skb, + HSLOT); + brcmf_fws_hanger_poppkt(&fws->hanger, hslot, + &skb, true); + ifidx = brcmf_skb_if_flags_get_field(skb, + INDEX); + brcmf_proto_hdrpush(drvr, ifidx, 0, skb); + /* Use bus module to send data frame */ + ret = brcmf_bus_txdata(drvr->bus_if, skb); + if (ret < 0) + brcmf_txfinalize(drvr, skb, false); + if (fws->bus_flow_blocked) + break; + } + continue; + } while ((fws->fifo_credit[fifo]) || ((!fws->bcmc_credit_check) && (fifo == BRCMF_FWS_FIFO_BCMC))) { skb = brcmf_fws_deq(fws, fifo); @@ -1885,17 +1900,15 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) } } } - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(drvr, flags); } int brcmf_fws_init(struct brcmf_pub *drvr) { + struct brcmf_fws_info *fws; u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS; int rc; - if (!drvr->fw_signals) - return 0; - spin_lock_init(&drvr->fws_spinlock); drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL); @@ -1904,20 +1917,21 @@ int brcmf_fws_init(struct brcmf_pub *drvr) goto fail; } + fws = drvr->fws; /* set linkage back */ - drvr->fws->drvr = drvr; - drvr->fws->fcmode = fcmode; + fws->drvr = drvr; + fws->fcmode = fcmode; - drvr->fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq"); - if (drvr->fws->fws_wq == NULL) { + fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq"); + if (fws->fws_wq == NULL) { brcmf_err("workqueue creation failed\n"); rc = -EBADF; goto fail; } - INIT_WORK(&drvr->fws->fws_dequeue_work, brcmf_fws_dequeue_worker); + INIT_WORK(&fws->fws_dequeue_work, brcmf_fws_dequeue_worker); /* enable firmware signalling if fcmode active */ - if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE) + if (fws->fcmode != BRCMF_FWS_FCMODE_NONE) tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS | BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS | BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE | @@ -1937,34 +1951,33 @@ int brcmf_fws_init(struct brcmf_pub *drvr) goto fail; } - /* setting the iovar may fail if feature is unsupported + /* Setting the iovar may fail if feature is unsupported * so leave the rc as is so driver initialization can - * continue. + * continue. Set mode back to none indicating not enabled. */ + fws->fw_signals = true; if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) { brcmf_err("failed to set bdcv2 tlv signaling\n"); - goto fail_event; + fws->fcmode = BRCMF_FWS_FCMODE_NONE; + fws->fw_signals = false; } if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1)) brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n"); - brcmf_fws_hanger_init(&drvr->fws->hanger); - brcmf_fws_macdesc_init(&drvr->fws->desc.other, NULL, 0); - brcmf_fws_macdesc_set_name(drvr->fws, &drvr->fws->desc.other); - brcmu_pktq_init(&drvr->fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT, + brcmf_fws_hanger_init(&fws->hanger); + brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0); + brcmf_fws_macdesc_set_name(fws, &fws->desc.other); + brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT, BRCMF_FWS_PSQ_LEN); /* create debugfs file for statistics */ - brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats); + brcmf_debugfs_create_fws_stats(drvr, &fws->stats); brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n", - drvr->fw_signals ? "enabled" : "disabled", tlv); + fws->fw_signals ? "enabled" : "disabled", tlv); return 0; -fail_event: - brcmf_fweh_unregister(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT); - brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP); fail: brcmf_fws_deinit(drvr); return rc; @@ -1978,11 +1991,6 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr) if (!fws) return; - /* disable firmware signalling entirely - * to avoid using the workqueue. - */ - drvr->fw_signals = false; - if (drvr->fws->fws_wq) destroy_workqueue(drvr->fws->fws_wq); @@ -1998,7 +2006,7 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr) bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) { - if (!fws) + if (!fws->creditmap_received) return false; return fws->fcmode != BRCMF_FWS_FCMODE_NONE; -- cgit v1.2.3 From 3f4f910fdc3b9eff06a007ab28762cd3d6720d51 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sat, 10 Aug 2013 12:27:23 +0200 Subject: brcmfmac: no fws locking outside fws module. FWS uses locking to protect its data while being called from various entries. On bus_txdata the lock was kept resulting in unnecessary long locking, but also creating possibility for deadlock. This update changes the locking to release lock when bus_txdata is called. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 1 - drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 127 ++++++++++----------- 2 files changed, 62 insertions(+), 66 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index df94d0e9fab9..1273dfdb521b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -558,7 +558,6 @@ struct brcmf_pub { struct brcmf_fweh_info fweh; struct brcmf_fws_info *fws; - spinlock_t fws_spinlock; struct brcmf_ampdu_rx_reorder *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS]; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 15fc807e8747..82f9140f3d35 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -422,6 +422,8 @@ struct brcmf_fws_macdesc_table { struct brcmf_fws_info { struct brcmf_pub *drvr; + spinlock_t spinlock; + ulong flags; struct brcmf_fws_stats stats; struct brcmf_fws_hanger hanger; enum brcmf_fws_fcmode fcmode; @@ -484,6 +486,18 @@ static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws, } #undef BRCMF_FWS_TLV_DEF +static void brcmf_fws_lock(struct brcmf_fws_info *fws) + __acquires(&fws->spinlock) +{ + spin_lock_irqsave(&fws->spinlock, fws->flags); +} + +static void brcmf_fws_unlock(struct brcmf_fws_info *fws) + __releases(&fws->spinlock) +{ + spin_unlock_irqrestore(&fws->spinlock, fws->flags); +} + static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg) { u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX); @@ -870,8 +884,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws, skcb->state = BRCMF_FWS_SKBSTATE_TIM; bus = fws->drvr->bus_if; err = brcmf_fws_hdrpush(fws, skb); - if (err == 0) + if (err == 0) { + brcmf_fws_unlock(fws); err = brcmf_bus_txdata(bus, skb); + brcmf_fws_lock(fws); + } if (err) brcmu_pkt_buf_free_skb(skb); return true; @@ -906,26 +923,10 @@ static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) return 0; } -/* using macro so sparse checking does not complain - * about locking imbalance. - */ -#define brcmf_fws_lock(drvr, flags) \ -do { \ - flags = 0; \ - spin_lock_irqsave(&((drvr)->fws_spinlock), (flags)); \ -} while (0) - -/* using macro so sparse checking does not complain - * about locking imbalance. - */ -#define brcmf_fws_unlock(drvr, flags) \ - spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags)) - static int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) { struct brcmf_fws_mac_descriptor *entry, *existing; - ulong flags; u8 mac_handle; u8 ifidx; u8 *addr; @@ -939,10 +940,10 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) if (entry->occupied) { brcmf_dbg(TRACE, "deleting %s mac %pM\n", entry->name, addr); - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(fws); brcmf_fws_macdesc_cleanup(fws, entry, -1); brcmf_fws_macdesc_deinit(entry); - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); } else fws->stats.mac_update_failed++; return 0; @@ -951,13 +952,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) existing = brcmf_fws_macdesc_lookup(fws, addr); if (IS_ERR(existing)) { if (!entry->occupied) { - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(fws); entry->mac_handle = mac_handle; brcmf_fws_macdesc_init(entry, addr, ifidx); brcmf_fws_macdesc_set_name(fws, entry); brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, BRCMF_FWS_PSQ_LEN); - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr); } else { fws->stats.mac_update_failed++; @@ -965,13 +966,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) } else { if (entry != existing) { brcmf_dbg(TRACE, "copy mac %s\n", existing->name); - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(fws); memcpy(entry, existing, offsetof(struct brcmf_fws_mac_descriptor, psq)); entry->mac_handle = mac_handle; brcmf_fws_macdesc_deinit(existing); brcmf_fws_macdesc_set_name(fws, entry); - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name, addr); } else { @@ -987,7 +988,6 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) { struct brcmf_fws_mac_descriptor *entry; - ulong flags; u8 mac_handle; int ret; @@ -997,7 +997,7 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws, fws->stats.mac_ps_update_failed++; return -ESRCH; } - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(fws); /* a state update should wipe old credits */ entry->requested_credit = 0; entry->requested_packet = 0; @@ -1012,7 +1012,7 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws, brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true); ret = BRCMF_FWS_RET_OK_NOSCHEDULE; } - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); return ret; } @@ -1020,7 +1020,6 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) { struct brcmf_fws_mac_descriptor *entry; - ulong flags; u8 ifidx; int ret; @@ -1039,7 +1038,7 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type, entry->name); - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(fws); switch (type) { case BRCMF_FWS_TYPE_INTERFACE_OPEN: entry->state = BRCMF_FWS_STATE_OPEN; @@ -1051,10 +1050,10 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, break; default: ret = -EINVAL; - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); goto fail; } - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); return ret; fail: @@ -1066,7 +1065,6 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) { struct brcmf_fws_mac_descriptor *entry; - ulong flags; entry = &fws->desc.nodes[data[1] & 0x1F]; if (!entry->occupied) { @@ -1080,14 +1078,14 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type, brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n", brcmf_fws_get_tlv_name(type), type, entry->name, data[0], data[2]); - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(fws); if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT) entry->requested_credit = data[0]; else entry->requested_packet = data[0]; entry->ac_bitmap = data[2]; - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); return BRCMF_FWS_RET_OK_SCHEDULE; } @@ -1385,7 +1383,6 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, u8 *data) { - ulong flags; int i; if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) { @@ -1394,19 +1391,18 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, } brcmf_dbg(DATA, "enter: data %pM\n", data); - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(fws); for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++) brcmf_fws_return_credits(fws, i, data[i]); brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map, fws->fifo_delay_map); - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); return BRCMF_FWS_RET_OK_SCHEDULE; } static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) { - ulong lflags; __le32 status_le; u32 status; u32 hslot; @@ -1420,9 +1416,9 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) hslot = brcmf_txstatus_get_field(status, HSLOT); genbit = brcmf_txstatus_get_field(status, GENERATION); - brcmf_fws_lock(fws->drvr, lflags); + brcmf_fws_lock(fws); brcmf_fws_txs_process(fws, flags, hslot, genbit); - brcmf_fws_unlock(fws->drvr, lflags); + brcmf_fws_unlock(fws); return BRCMF_FWS_RET_OK_NOSCHEDULE; } @@ -1442,7 +1438,6 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, { struct brcmf_fws_info *fws = ifp->drvr->fws; int i; - ulong flags; u8 *credits = data; if (e->datalen < BRCMF_FWS_FIFO_COUNT) { @@ -1455,7 +1450,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, fws->creditmap_received = true; brcmf_dbg(TRACE, "enter: credits %pM\n", credits); - brcmf_fws_lock(ifp->drvr, flags); + brcmf_fws_lock(fws); for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) { if (*credits) fws->fifo_credit_map |= 1 << i; @@ -1464,7 +1459,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, fws->fifo_credit[i] = *credits++; } brcmf_fws_schedule_deq(fws); - brcmf_fws_unlock(ifp->drvr, flags); + brcmf_fws_unlock(fws); return 0; } @@ -1473,12 +1468,11 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp, void *data) { struct brcmf_fws_info *fws = ifp->drvr->fws; - ulong flags; - brcmf_fws_lock(ifp->drvr, flags); + brcmf_fws_lock(fws); if (fws) fws->bcmc_credit_check = true; - brcmf_fws_unlock(ifp->drvr, flags); + brcmf_fws_unlock(fws); return 0; } @@ -1702,17 +1696,22 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo, return PTR_ERR(entry); brcmf_fws_precommit_skb(fws, fifo, skb); + entry->transit_count++; + if (entry->suppressed) + entry->suppr_transit_count++; + brcmf_fws_unlock(fws); rc = brcmf_bus_txdata(bus, skb); + brcmf_fws_lock(fws); brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name, skcb->if_flags, skcb->htod, rc); if (rc < 0) { + entry->transit_count--; + if (entry->suppressed) + entry->suppr_transit_count--; brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); goto rollback; } - entry->transit_count++; - if (entry->suppressed) - entry->suppr_transit_count++; fws->stats.pkt2bus++; fws->stats.send_pkts[fifo]++; if (brcmf_skb_if_flags_get_field(skb, REQUESTED)) @@ -1749,7 +1748,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) struct brcmf_fws_info *fws = drvr->fws; struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb); struct ethhdr *eh = (struct ethhdr *)(skb->data); - ulong flags; int fifo = BRCMF_FWS_FIFO_BCMC; bool multicast = is_multicast_ether_addr(eh->h_dest); bool pae = eh->h_proto == htons(ETH_P_PAE); @@ -1770,7 +1768,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) if (!multicast) fifo = brcmf_fws_prio2fifo[skb->priority]; - brcmf_fws_lock(drvr, flags); + brcmf_fws_lock(fws); if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC) fws->borrow_defer_timestamp = jiffies + BRCMF_FWS_BORROW_DEFER_PERIOD; @@ -1790,7 +1788,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) } brcmu_pkt_buf_free_skb(skb); } - brcmf_fws_unlock(drvr, flags); + brcmf_fws_unlock(fws); return 0; } @@ -1825,17 +1823,16 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp) void brcmf_fws_del_interface(struct brcmf_if *ifp) { struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc; - ulong flags; if (!entry) return; - brcmf_fws_lock(ifp->drvr, flags); + brcmf_fws_lock(ifp->drvr->fws); ifp->fws_desc = NULL; brcmf_dbg(TRACE, "deleting %s\n", entry->name); brcmf_fws_macdesc_deinit(entry); brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx); - brcmf_fws_unlock(ifp->drvr, flags); + brcmf_fws_unlock(ifp->drvr->fws); } static void brcmf_fws_dequeue_worker(struct work_struct *worker) @@ -1843,7 +1840,6 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) struct brcmf_fws_info *fws; struct brcmf_pub *drvr; struct sk_buff *skb; - ulong flags; int fifo; u32 hslot; u32 ifidx; @@ -1852,7 +1848,7 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work); drvr = fws->drvr; - brcmf_fws_lock(drvr, flags); + brcmf_fws_lock(fws); for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked; fifo--) { if (!brcmf_fws_fc_active(fws)) { @@ -1865,7 +1861,9 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) INDEX); brcmf_proto_hdrpush(drvr, ifidx, 0, skb); /* Use bus module to send data frame */ + brcmf_fws_unlock(fws); ret = brcmf_bus_txdata(drvr->bus_if, skb); + brcmf_fws_lock(fws); if (ret < 0) brcmf_txfinalize(drvr, skb, false); if (fws->bus_flow_blocked) @@ -1900,7 +1898,7 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) } } } - brcmf_fws_unlock(drvr, flags); + brcmf_fws_unlock(fws); } int brcmf_fws_init(struct brcmf_pub *drvr) @@ -1909,8 +1907,6 @@ int brcmf_fws_init(struct brcmf_pub *drvr) u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS; int rc; - spin_lock_init(&drvr->fws_spinlock); - drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL); if (!drvr->fws) { rc = -ENOMEM; @@ -1918,6 +1914,9 @@ int brcmf_fws_init(struct brcmf_pub *drvr) } fws = drvr->fws; + + spin_lock_init(&fws->spinlock); + /* set linkage back */ fws->drvr = drvr; fws->fcmode = fcmode; @@ -1986,7 +1985,6 @@ fail: void brcmf_fws_deinit(struct brcmf_pub *drvr) { struct brcmf_fws_info *fws = drvr->fws; - ulong flags; if (!fws) return; @@ -1995,10 +1993,10 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr) destroy_workqueue(drvr->fws->fws_wq); /* cleanup */ - brcmf_fws_lock(drvr, flags); + brcmf_fws_lock(fws); brcmf_fws_cleanup(fws, -1); drvr->fws = NULL; - brcmf_fws_unlock(drvr, flags); + brcmf_fws_unlock(fws); /* free top structure */ kfree(fws); @@ -2014,17 +2012,16 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb) { - ulong flags; u32 hslot; if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) { brcmu_pkt_buf_free_skb(skb); return; } - brcmf_fws_lock(fws->drvr, flags); + brcmf_fws_lock(fws); hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0); - brcmf_fws_unlock(fws->drvr, flags); + brcmf_fws_unlock(fws); } void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked) -- cgit v1.2.3 From 2ee8382fc6c763c76396a6aaff77a27089eed3aa Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 10 Aug 2013 12:27:24 +0200 Subject: brcmfmac: ignore IF event if firmware indicates it Not every IF event from the firmware needs to result in a related interface, netdev or wdev, on the host. This is indicated in the event message. Handle that flag and effectively ignore the firmware event. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 2 ++ drivers/net/wireless/brcm80211/brcmfmac/fweh.c | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 1273dfdb521b..2eb9e642c9bf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -194,6 +194,8 @@ #define BRCMF_E_IF_DEL 2 #define BRCMF_E_IF_CHANGE 3 +#define BRCMF_E_IF_FLAG_NOIF 1 + #define BRCMF_E_IF_ROLE_STA 0 #define BRCMF_E_IF_ROLE_AP 1 #define BRCMF_E_IF_ROLE_WDS 2 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index 83ee53a7c76e..fad77dd2a3a5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -185,6 +185,10 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, ifevent->action, ifevent->ifidx, ifevent->bssidx, ifevent->flags, ifevent->role); + if (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) { + brcmf_dbg(EVENT, "event can be ignored\n"); + return; + } if (ifevent->ifidx >= BRCMF_MAX_IFS) { brcmf_err("invalid interface index: %u\n", ifevent->ifidx); -- cgit v1.2.3 From 89c2f382fff4ec8adf04264925e07e951d0552ce Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 10 Aug 2013 12:27:25 +0200 Subject: brcmfmac: add support for manual TDLS operations Implement the .tdls_oper() callback and indicate TDLS support in the wiphy flags. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/fwil_types.h | 21 ++++++++ .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 57 +++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index 665ef69e974b..ecabb04f33c3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -69,4 +69,25 @@ struct brcmf_fil_bss_enable_le { __le32 enable; }; +/** + * struct tdls_iovar - common structure for tdls iovars. + * + * @ea: ether address of peer station. + * @mode: mode value depending on specific tdls iovar. + * @chanspec: channel specification. + * @pad: unused (for future use). + */ +struct brcmf_tdls_iovar_le { + u8 ea[ETH_ALEN]; /* Station address */ + u8 mode; /* mode: depends on iovar */ + __le16 chanspec; + __le32 pad; /* future */ +}; + +enum brcmf_tdls_manual_ep_ops { + BRCMF_TDLS_MANUAL_EP_CREATE = 1, + BRCMF_TDLS_MANUAL_EP_DELETE = 3, + BRCMF_TDLS_MANUAL_EP_DISCOVERY = 6 +}; + #endif /* FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index c3dfea3f307d..0370e44cec11 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4126,6 +4126,53 @@ static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy, clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); } +static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper) +{ + int ret; + + switch (oper) { + case NL80211_TDLS_DISCOVERY_REQ: + ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY; + break; + case NL80211_TDLS_SETUP: + ret = BRCMF_TDLS_MANUAL_EP_CREATE; + break; + case NL80211_TDLS_TEARDOWN: + ret = BRCMF_TDLS_MANUAL_EP_DELETE; + break; + default: + brcmf_err("unsupported operation: %d\n", oper); + ret = -EOPNOTSUPP; + } + return ret; +} + +static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *ndev, u8 *peer, + enum nl80211_tdls_operation oper) +{ + struct brcmf_if *ifp; + struct brcmf_tdls_iovar_le info; + int ret = 0; + + ret = brcmf_convert_nl80211_tdls_oper(oper); + if (ret < 0) + return ret; + + ifp = netdev_priv(ndev); + memset(&info, 0, sizeof(info)); + info.mode = (u8)ret; + if (peer) + memcpy(info.ea, peer, ETH_ALEN); + + ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint", + &info, sizeof(info)); + if (ret < 0) + brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret); + + return ret; +} + static struct cfg80211_ops wl_cfg80211_ops = { .add_virtual_intf = brcmf_cfg80211_add_iface, .del_virtual_intf = brcmf_cfg80211_del_iface, @@ -4164,6 +4211,7 @@ static struct cfg80211_ops wl_cfg80211_ops = { .stop_p2p_device = brcmf_p2p_stop_device, .crit_proto_start = brcmf_cfg80211_crit_proto_start, .crit_proto_stop = brcmf_cfg80211_crit_proto_stop, + .tdls_oper = brcmf_cfg80211_tdls_oper, CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode) }; @@ -4285,7 +4333,8 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | WIPHY_FLAG_OFFCHAN_TX | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_SUPPORTS_TDLS; wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; brcmf_wiphy_pno_params(wiphy); @@ -4906,6 +4955,12 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, goto cfg80211_p2p_attach_out; } + err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); + if (err) { + brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); + wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; + } + err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type); if (err) { -- cgit v1.2.3 From b05e92545d9582be15699e4a33d0f93ac00b37dd Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Sat, 10 Aug 2013 12:27:26 +0200 Subject: brcmfmac: abstract tx packet processing functions Abstract brcmf_sdio_txpkt_prep and brcmf_sdio_txpkt_postp as a preparation of chained tx packets for host side tx glomming. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 16 +- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 237 +++++++++++++++------ .../net/wireless/brcm80211/brcmfmac/sdio_host.h | 2 +- include/linux/platform_data/brcmfmac-sdio.h | 6 + 4 files changed, 183 insertions(+), 78 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index e3f3c48f86d4..e13b1a65c65f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -592,6 +592,7 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, uint flags, u8 *buf, uint nbytes) { struct sk_buff *mypkt; + struct sk_buff_head pktq; int err; mypkt = brcmu_pkt_buf_get_skb(nbytes); @@ -602,7 +603,10 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, } memcpy(mypkt->data, buf, nbytes); - err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt); + __skb_queue_head_init(&pktq); + __skb_queue_tail(&pktq, mypkt); + err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, &pktq); + __skb_dequeue_tail(&pktq); brcmu_pkt_buf_free_skb(mypkt); return err; @@ -611,22 +615,18 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, int brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, struct sk_buff *pkt) + uint flags, struct sk_buff_head *pktq) { uint width; int err = 0; - struct sk_buff_head pkt_list; brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n", - fn, addr, pkt->len); + fn, addr, pktq->qlen); width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; brcmf_sdio_addrprep(sdiodev, width, &addr); - skb_queue_head_init(&pkt_list); - skb_queue_tail(&pkt_list, pkt); - err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, &pkt_list); - skb_dequeue_tail(&pkt_list); + err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, pktq); return err; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index db31312eba6a..aa4cacaf8b03 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -510,7 +510,6 @@ struct brcmf_sdio { #ifdef DEBUG static int qcount[NUMPRIO]; -static int tx_packets[NUMPRIO]; #endif /* DEBUG */ #define DEFAULT_SDIO_DRIVE_STRENGTH 6 /* in milliamps */ @@ -1759,85 +1758,185 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus) return; } +/* flag marking a dummy skb added for DMA alignment requirement */ +#define DUMMY_SKB_FLAG 0x10000 +/* bit mask of data length chopped from the previous packet */ +#define DUMMY_SKB_CHOP_LEN_MASK 0xffff +/** + * brcmf_sdio_txpkt_prep - packet preparation for transmit + * @bus: brcmf_sdio structure pointer + * @pktq: packet list pointer + * @chan: virtual channel to transmit the packet + * + * Processes to be applied to the packet + * - Align data buffer pointer + * - Align data buffer length + * - Prepare header + * Return: negative value if there is error + */ +static int +brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, + uint chan) +{ + u16 head_pad, tail_pad, tail_chop, pkt_len; + u16 head_align, sg_align; + u32 sw_header; + int ntail; + struct sk_buff *pkt_next, *pkt_new; + u8 *dat_buf; + unsigned blksize = bus->sdiodev->func[SDIO_FUNC_2]->cur_blksize; + + /* SDIO ADMA requires at least 32 bit alignment */ + head_align = 4; + sg_align = 4; + if (bus->sdiodev->pdata) { + head_align = bus->sdiodev->pdata->sd_head_align > 4 ? + bus->sdiodev->pdata->sd_head_align : 4; + sg_align = bus->sdiodev->pdata->sd_sgentry_align > 4 ? + bus->sdiodev->pdata->sd_sgentry_align : 4; + } + /* sg entry alignment should be a divisor of block size */ + WARN_ON(blksize % sg_align); + + pkt_next = pktq->next; + dat_buf = (u8 *)(pkt_next->data); + + /* Check head padding */ + head_pad = ((unsigned long)dat_buf % head_align); + if (head_pad) { + if (skb_headroom(pkt_next) < head_pad) { + bus->sdiodev->bus_if->tx_realloc++; + head_pad = 0; + if (skb_cow(pkt_next, head_pad)) + return -ENOMEM; + } + skb_push(pkt_next, head_pad); + dat_buf = (u8 *)(pkt_next->data); + memset(dat_buf, 0, head_pad + SDPCM_HDRLEN); + } + + /* Check tail padding */ + pkt_new = NULL; + tail_chop = pkt_next->len % sg_align; + tail_pad = sg_align - tail_chop; + tail_pad += blksize - (pkt_next->len + tail_pad) % blksize; + if (skb_tailroom(pkt_next) < tail_pad && pkt_next->len > blksize) { + pkt_new = brcmu_pkt_buf_get_skb(tail_pad + tail_chop); + if (pkt_new == NULL) + return -ENOMEM; + memcpy(pkt_new->data, + pkt_next->data + pkt_next->len - tail_chop, + tail_chop); + *(u32 *)(pkt_new->cb) = DUMMY_SKB_FLAG + tail_chop; + skb_trim(pkt_next, pkt_next->len - tail_chop); + __skb_queue_after(pktq, pkt_next, pkt_new); + } else { + ntail = pkt_next->data_len + tail_pad - + (pkt_next->end - pkt_next->tail); + if (skb_cloned(pkt_next) || ntail > 0) + if (pskb_expand_head(pkt_next, 0, ntail, GFP_ATOMIC)) + return -ENOMEM; + if (skb_linearize(pkt_next)) + return -ENOMEM; + dat_buf = (u8 *)(pkt_next->data); + __skb_put(pkt_next, tail_pad); + } + + /* Now prep the header */ + /* 4 bytes hardware header (frame tag) + * Byte 0~1: Frame length + * Byte 2~3: Checksum, bit-wise inverse of frame length + */ + if (pkt_new) + pkt_len = pkt_next->len + tail_chop; + else + pkt_len = pkt_next->len - tail_pad; + *(__le16 *)dat_buf = cpu_to_le16(pkt_len); + *(((__le16 *)dat_buf) + 1) = cpu_to_le16(~pkt_len); + /* 8 bytes software header + * Byte 0: Tx sequence number + * Byte 1: 4 MSB Channel number + * Byte 2: Reserved + * Byte 3: Data offset + * Byte 4~7: Reserved + */ + sw_header = bus->tx_seq; + sw_header |= ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK); + sw_header |= ((head_pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & + SDPCM_DOFFSET_MASK; + *(((__le32 *)dat_buf) + 1) = cpu_to_le32(sw_header); + *(((__le32 *)dat_buf) + 2) = 0; + + if (BRCMF_BYTES_ON() && + ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || + (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) + brcmf_dbg_hex_dump(true, pkt_next, pkt_len, "Tx Frame:\n"); + else if (BRCMF_HDRS_ON()) + brcmf_dbg_hex_dump(true, pkt_next, head_pad + SDPCM_HDRLEN, + "Tx Header:\n"); + + return 0; +} + +/** + * brcmf_sdio_txpkt_postp - packet post processing for transmit + * @bus: brcmf_sdio structure pointer + * @pktq: packet list pointer + * + * Processes to be applied to the packet + * - Remove head padding + * - Remove tail padding + */ +static void +brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq) +{ + u8 *hdr; + u32 dat_offset; + u32 dummy_flags, chop_len; + struct sk_buff *pkt_next, *tmp, *pkt_prev; + + skb_queue_walk_safe(pktq, pkt_next, tmp) { + dummy_flags = *(u32 *)(pkt_next->cb); + if (dummy_flags & DUMMY_SKB_FLAG) { + chop_len = dummy_flags & DUMMY_SKB_CHOP_LEN_MASK; + if (chop_len) { + pkt_prev = pkt_next->prev; + memcpy(pkt_prev->data + pkt_prev->len, + pkt_next->data, chop_len); + skb_put(pkt_prev, chop_len); + } + __skb_unlink(pkt_next, pktq); + brcmu_pkt_buf_free_skb(pkt_next); + } else { + hdr = pkt_next->data + SDPCM_FRAMETAG_LEN; + dat_offset = le32_to_cpu(*(__le32 *)hdr); + dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >> + SDPCM_DOFFSET_SHIFT; + skb_pull(pkt_next, dat_offset); + } + } +} + /* Writes a HW/SW header into the packet and sends it. */ /* Assumes: (a) header space already there, (b) caller holds lock */ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, uint chan) { int ret; - u8 *frame; - u16 len, pad = 0; - u32 swheader; int i; + struct sk_buff_head localq; brcmf_dbg(TRACE, "Enter\n"); - frame = (u8 *) (pkt->data); - - /* Add alignment padding, allocate new packet if needed */ - pad = ((unsigned long)frame % BRCMF_SDALIGN); - if (pad) { - if (skb_headroom(pkt) < pad) { - brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n", - skb_headroom(pkt), pad); - bus->sdiodev->bus_if->tx_realloc++; - ret = skb_cow(pkt, BRCMF_SDALIGN); - if (ret) - goto done; - pad = ((unsigned long)frame % BRCMF_SDALIGN); - } - skb_push(pkt, pad); - frame = (u8 *) (pkt->data); - memset(frame, 0, pad + SDPCM_HDRLEN); - } - /* precondition: pad < BRCMF_SDALIGN */ - - /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - len = (u16) (pkt->len); - *(__le16 *) frame = cpu_to_le16(len); - *(((__le16 *) frame) + 1) = cpu_to_le16(~len); - - /* Software tag: channel, sequence number, data offset */ - swheader = - ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | - (((pad + - SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); - - *(((__le32 *) frame) + 1) = cpu_to_le32(swheader); - *(((__le32 *) frame) + 2) = 0; - -#ifdef DEBUG - tx_packets[pkt->priority]++; -#endif - - brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && - ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || - (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)), - frame, len, "Tx Frame:\n"); - brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && - ((BRCMF_CTL_ON() && - chan == SDPCM_CONTROL_CHANNEL) || - (BRCMF_DATA_ON() && - chan != SDPCM_CONTROL_CHANNEL))) && - BRCMF_HDRS_ON(), - frame, min_t(u16, len, 16), "TxHdr:\n"); - - /* Raise len to next SDIO block to eliminate tail command */ - if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - u16 pad = bus->blocksize - (len % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize)) - len += pad; - } else if (len % BRCMF_SDALIGN) { - len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); - } - - /* Some controllers have trouble with odd bytes -- round to even */ - if (len & (ALIGNMENT - 1)) - len = roundup(len, ALIGNMENT); + __skb_queue_head_init(&localq); + __skb_queue_tail(&localq, pkt); + ret = brcmf_sdio_txpkt_prep(bus, &localq, chan); + if (ret) + goto done; sdio_claim_host(bus->sdiodev->func[1]); ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, pkt); + SDIO_FUNC_2, F2SYNC, &localq); bus->sdcnt.f2txdata++; if (ret < 0) { @@ -1868,8 +1967,8 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; done: - /* restore pkt buffer pointer before calling tx complete routine */ - skb_pull(pkt, SDPCM_HDRLEN + pad); + brcmf_sdio_txpkt_postp(bus, &localq); + __skb_dequeue_tail(&localq); brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0); return ret; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 09786a539950..2b5407f002e5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -208,7 +208,7 @@ extern int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, */ extern int brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, struct sk_buff *pkt); + uint flags, struct sk_buff_head *pktq); extern int brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, uint flags, u8 *buf, uint nbytes); diff --git a/include/linux/platform_data/brcmfmac-sdio.h b/include/linux/platform_data/brcmfmac-sdio.h index b7174998c24a..e75dcbf2b230 100644 --- a/include/linux/platform_data/brcmfmac-sdio.h +++ b/include/linux/platform_data/brcmfmac-sdio.h @@ -94,6 +94,10 @@ void __init brcmfmac_init_pdata(void) * Set this to true if the SDIO host controller has higher align requirement * than 32 bytes for each scatterlist item. * + * sd_head_align: alignment requirement for start of data buffer + * + * sd_sgentry_align: length alignment requirement for each sg entry + * * power_on: This function is called by the brcmfmac when the module gets * loaded. This can be particularly useful for low power devices. The platform * spcific routine may for example decide to power up the complete device. @@ -121,6 +125,8 @@ struct brcmfmac_sdio_platform_data { unsigned int oob_irq_nr; unsigned long oob_irq_flags; bool broken_sg_support; + unsigned short sd_head_align; + unsigned short sd_sgentry_align; void (*power_on)(void); void (*power_off)(void); void (*reset)(void); -- cgit v1.2.3 From cb7f79682a9289634094e2c3b5180611635332f5 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Sat, 10 Aug 2013 12:27:27 +0200 Subject: brcmfmac: remove align from brcmf_bus structure remove align from brcmf_bus since it is only used by sdio bus layer internally Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 1 - drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 2 -- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 25 +++++++++++++++------- 3 files changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 289e386f01f6..64f4a2bc8dde 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -350,7 +350,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, sdiodev->bus_if = bus_if; bus_if->bus_priv.sdio = sdiodev; - bus_if->align = BRCMF_SDALIGN; dev_set_drvdata(&func->dev, bus_if); dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); sdiodev->dev = &sdiodev->func[1]->dev; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 9249b6d42066..f7c1985844e4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -69,7 +69,6 @@ struct brcmf_bus_ops { * @maxctl: maximum size for rxctl request message. * @tx_realloc: number of tx packets realloced for headroom. * @dstats: dongle-based statistical data. - * @align: alignment requirement for the bus. * @dcmd_list: bus/device specific dongle initialization commands. * @chip: device identifier of the dongle chip. * @chiprev: revision of the dongle chip. @@ -84,7 +83,6 @@ struct brcmf_bus { enum brcmf_bus_state state; uint maxctl; unsigned long tx_realloc; - u8 align; u32 chip; u32 chiprev; struct list_head dcmd_list; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index aa4cacaf8b03..25638753b214 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -1166,7 +1166,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) { u16 dlen, totlen; u8 *dptr, num = 0; - + u32 align = 0; u16 sublen; struct sk_buff *pfirst, *pnext; @@ -1181,6 +1181,11 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) brcmf_dbg(SDIO, "start: glomd %p glom %p\n", bus->glomd, skb_peek(&bus->glom)); + if (bus->sdiodev->pdata) + align = bus->sdiodev->pdata->sd_sgentry_align; + if (align < 4) + align = 4; + /* If there's a descriptor, generate the packet chain */ if (bus->glomd) { pfirst = pnext = NULL; @@ -1204,9 +1209,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) pnext = NULL; break; } - if (sublen % BRCMF_SDALIGN) { + if (sublen % align) { brcmf_err("sublen %d not multiple of %d\n", - sublen, BRCMF_SDALIGN); + sublen, align); } totlen += sublen; @@ -1219,7 +1224,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) } /* Allocate/chain packet for next subframe */ - pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN); + pnext = brcmu_pkt_buf_get_skb(sublen + align); if (pnext == NULL) { brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n", num, sublen); @@ -1228,7 +1233,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) skb_queue_tail(&bus->glom, pnext); /* Adhere to start alignment requirements */ - pkt_align(pnext, sublen, BRCMF_SDALIGN); + pkt_align(pnext, sublen, align); } /* If all allocations succeeded, save packet chain @@ -3832,7 +3837,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) struct brcmf_sdio *bus; struct brcmf_bus_dcmd *dlst; u32 dngl_txglom; - u32 dngl_txglomalign; + u32 txglomalign = 0; u8 idx; brcmf_dbg(TRACE, "Enter\n"); @@ -3926,9 +3931,13 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) dlst->param_len = sizeof(u32); } else { /* otherwise, set txglomalign */ - dngl_txglomalign = bus->sdiodev->bus_if->align; + if (sdiodev->pdata) + txglomalign = sdiodev->pdata->sd_sgentry_align; + /* SDIO ADMA requires at least 32 bit alignment */ + if (txglomalign < 4) + txglomalign = 4; dlst->name = "bus:txglomalign"; - dlst->param = (char *)&dngl_txglomalign; + dlst->param = (char *)&txglomalign; dlst->param_len = sizeof(u32); } list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list); -- cgit v1.2.3 From 6bc52319c2c688fdcbb203a4917576ca4cd4d51e Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Sat, 10 Aug 2013 12:27:28 +0200 Subject: brcmfmac: streamline sdio bus header code Streamlining sdio bus specific header related code as preparation for host tx glomming Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 243 ++++++++++----------- 1 file changed, 120 insertions(+), 123 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 25638753b214..02ab5cdbe29b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -201,13 +201,6 @@ struct rte_console { #define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */ #define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */ -/* HW frame tag */ -#define SDPCM_FRAMETAG_LEN 4 /* 2 bytes len, 2 bytes check val */ - -/* Total length of frame header for dongle protocol */ -#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) -#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN) - /* * Software allocation of To SB Mailbox resources */ @@ -250,38 +243,6 @@ struct rte_console { /* Current protocol version */ #define SDPCM_PROT_VERSION 4 -/* SW frame header */ -#define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff) - -#define SDPCM_CHANNEL_MASK 0x00000f00 -#define SDPCM_CHANNEL_SHIFT 8 -#define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f) - -#define SDPCM_NEXTLEN_OFFSET 2 - -/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ -#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ -#define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) -#define SDPCM_DOFFSET_MASK 0xff000000 -#define SDPCM_DOFFSET_SHIFT 24 -#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ -#define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff) -#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ -#define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) - -#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ - -/* logical channel numbers */ -#define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */ -#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ -#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ -#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */ -#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ - -#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */ - -#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80) - /* * Shared structure between dongle and the host. * The structure contains pointers to trap or assert information. @@ -396,8 +357,8 @@ struct sdpcm_shared_le { __le32 brpt_addr; }; -/* SDIO read frame info */ -struct brcmf_sdio_read { +/* dongle SDIO bus specific header info */ +struct brcmf_sdio_hdrinfo { u8 seq_num; u8 channel; u16 len; @@ -431,7 +392,7 @@ struct brcmf_sdio { u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ u8 rx_seq; /* Receive sequence number (expected) */ - struct brcmf_sdio_read cur_read; + struct brcmf_sdio_hdrinfo cur_read; /* info of current read frame */ bool rxskip; /* Skip receive (awaiting NAK ACK) */ bool rxpending; /* Data frame pending in dongle */ @@ -1042,18 +1003,64 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) } } -static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, - struct brcmf_sdio_read *rd, - enum brcmf_sdio_frmtype type) +/** + * brcmfmac sdio bus specific header + * This is the lowest layer header wrapped on the packets transmitted between + * host and WiFi dongle which contains information needed for SDIO core and + * firmware + * + * It consists of 2 parts: hw header and software header + * hardware header (frame tag) - 4 bytes + * Byte 0~1: Frame length + * Byte 2~3: Checksum, bit-wise inverse of frame length + * software header - 8 bytes + * Byte 0: Rx/Tx sequence number + * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag + * Byte 2: Length of next data frame, reserved for Tx + * Byte 3: Data offset + * Byte 4: Flow control bits, reserved for Tx + * Byte 5: Maximum Sequence number allowed by firmware for Tx, N/A for Tx packet + * Byte 6~7: Reserved + */ +#define SDPCM_HWHDR_LEN 4 +#define SDPCM_SWHDR_LEN 8 +#define SDPCM_HDRLEN (SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN) +#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN) +/* software header */ +#define SDPCM_SEQ_MASK 0x000000ff +#define SDPCM_SEQ_WRAP 256 +#define SDPCM_CHANNEL_MASK 0x00000f00 +#define SDPCM_CHANNEL_SHIFT 8 +#define SDPCM_CONTROL_CHANNEL 0 /* Control */ +#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication */ +#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv */ +#define SDPCM_GLOM_CHANNEL 3 /* Coalesced packets */ +#define SDPCM_TEST_CHANNEL 15 /* Test/debug packets */ +#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80) +#define SDPCM_NEXTLEN_MASK 0x00ff0000 +#define SDPCM_NEXTLEN_SHIFT 16 +#define SDPCM_DOFFSET_MASK 0xff000000 +#define SDPCM_DOFFSET_SHIFT 24 +#define SDPCM_FCMASK_MASK 0x000000ff +#define SDPCM_WINDOW_MASK 0x0000ff00 +#define SDPCM_WINDOW_SHIFT 8 + +static inline u8 brcmf_sdio_getdatoffset(u8 *swheader) +{ + u32 hdrvalue; + hdrvalue = *(u32 *)swheader; + return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT); +} + +static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header, + struct brcmf_sdio_hdrinfo *rd, + enum brcmf_sdio_frmtype type) { u16 len, checksum; u8 rx_seq, fc, tx_seq_max; + u32 swheader; - /* - * 4 bytes hardware header (frame tag) - * Byte 0~1: Frame length - * Byte 2~3: Checksum, bit-wise inverse of frame length - */ + /* hw header */ len = get_unaligned_le16(header); checksum = get_unaligned_le16(header + sizeof(u16)); /* All zero means no more to read */ @@ -1082,24 +1089,16 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, } rd->len = len; - /* - * 8 bytes hardware header - * Byte 0: Rx sequence number - * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag - * Byte 2: Length of next data frame - * Byte 3: Data offset - * Byte 4: Flow control bits - * Byte 5: Maximum Sequence number allow for Tx - * Byte 6~7: Reserved - */ - if (type == BRCMF_SDIO_FT_SUPER && - SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) { + /* software header */ + header += SDPCM_HWHDR_LEN; + swheader = le32_to_cpu(*(__le32 *)header); + if (type == BRCMF_SDIO_FT_SUPER && SDPCM_GLOMDESC(header)) { brcmf_err("Glom descriptor found in superframe head\n"); rd->len = 0; return -EINVAL; } - rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]); - rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]); + rx_seq = (u8)(swheader & SDPCM_SEQ_MASK); + rd->channel = (swheader & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT; if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && type != BRCMF_SDIO_FT_SUPER) { brcmf_err("HW header length too long\n"); @@ -1119,7 +1118,7 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, rd->len = 0; return -EINVAL; } - rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]); + rd->dat_offset = brcmf_sdio_getdatoffset(header); if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) { brcmf_err("seq %d: bad data offset\n", rx_seq); bus->sdcnt.rx_badhdr++; @@ -1136,14 +1135,15 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, /* no need to check the reset for subframe */ if (type == BRCMF_SDIO_FT_SUB) return 0; - rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; + rd->len_nxtfrm = (swheader & SDPCM_NEXTLEN_MASK) >> SDPCM_NEXTLEN_SHIFT; if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) { /* only warm for NON glom packet */ if (rd->channel != SDPCM_GLOM_CHANNEL) brcmf_err("seq %d: next length error\n", rx_seq); rd->len_nxtfrm = 0; } - fc = SDPCM_FCMASK_VALUE(&header[SDPCM_FRAMETAG_LEN]); + swheader = le32_to_cpu(*(__le32 *)(header + 4)); + fc = swheader & SDPCM_FCMASK_MASK; if (bus->flowcontrol != fc) { if (~bus->flowcontrol & fc) bus->sdcnt.fc_xoff++; @@ -1152,7 +1152,7 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, bus->sdcnt.fc_rcvd++; bus->flowcontrol = fc; } - tx_seq_max = SDPCM_WINDOW_VALUE(&header[SDPCM_FRAMETAG_LEN]); + tx_seq_max = (swheader & SDPCM_WINDOW_MASK) >> SDPCM_WINDOW_SHIFT; if ((u8)(tx_seq_max - bus->tx_seq) > 0x40) { brcmf_err("seq %d: max tx seq number error\n", rx_seq); tx_seq_max = bus->tx_seq + 2; @@ -1162,6 +1162,28 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, return 0; } +static inline void brcmf_sdio_update_hwhdr(u8 *header, u16 frm_length) +{ + *(__le16 *)header = cpu_to_le16(frm_length); + *(((__le16 *)header) + 1) = cpu_to_le16(~frm_length); +} + +static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header, + struct brcmf_sdio_hdrinfo *hd_info) +{ + u32 sw_header; + + brcmf_sdio_update_hwhdr(header, hd_info->len); + + sw_header = bus->tx_seq; + sw_header |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) & + SDPCM_CHANNEL_MASK; + sw_header |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) & + SDPCM_DOFFSET_MASK; + *(((__le32 *)header) + 1) = cpu_to_le32(sw_header); + *(((__le32 *)header) + 2) = 0; +} + static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) { u16 dlen, totlen; @@ -1173,7 +1195,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) int errcode; u8 doff, sfdoff; - struct brcmf_sdio_read rd_new; + struct brcmf_sdio_hdrinfo rd_new; /* If packets, issue read(s) and send up packet chain */ /* Return sequence numbers consumed? */ @@ -1309,8 +1331,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) rd_new.seq_num = rxseq; rd_new.len = dlen; sdio_claim_host(bus->sdiodev->func[1]); - errcode = brcmf_sdio_hdparser(bus, pfirst->data, &rd_new, - BRCMF_SDIO_FT_SUPER); + errcode = brcmf_sdio_hdparse(bus, pfirst->data, &rd_new, + BRCMF_SDIO_FT_SUPER); sdio_release_host(bus->sdiodev->func[1]); bus->cur_read.len = rd_new.len_nxtfrm << 4; @@ -1328,8 +1350,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) rd_new.len = pnext->len; rd_new.seq_num = rxseq++; sdio_claim_host(bus->sdiodev->func[1]); - errcode = brcmf_sdio_hdparser(bus, pnext->data, &rd_new, - BRCMF_SDIO_FT_SUB); + errcode = brcmf_sdio_hdparse(bus, pnext->data, &rd_new, + BRCMF_SDIO_FT_SUB); sdio_release_host(bus->sdiodev->func[1]); brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), pnext->data, 32, "subframe:\n"); @@ -1361,7 +1383,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) skb_queue_walk_safe(&bus->glom, pfirst, pnext) { dptr = (u8 *) (pfirst->data); sublen = get_unaligned_le16(dptr); - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); + doff = brcmf_sdio_getdatoffset(&dptr[SDPCM_HWHDR_LEN]); brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), dptr, pfirst->len, @@ -1539,7 +1561,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) uint rxleft = 0; /* Remaining number of frames allowed */ int ret; /* Return code from calls */ uint rxcount = 0; /* Total frames read */ - struct brcmf_sdio_read *rd = &bus->cur_read, rd_new; + struct brcmf_sdio_hdrinfo *rd = &bus->cur_read, rd_new; u8 head_read = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -1587,8 +1609,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) bus->rxhdr, SDPCM_HDRLEN, "RxHdr:\n"); - if (brcmf_sdio_hdparser(bus, bus->rxhdr, rd, - BRCMF_SDIO_FT_NORMAL)) { + if (brcmf_sdio_hdparse(bus, bus->rxhdr, rd, + BRCMF_SDIO_FT_NORMAL)) { sdio_release_host(bus->sdiodev->func[1]); if (!bus->rxpending) break; @@ -1652,8 +1674,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN); rd_new.seq_num = rd->seq_num; sdio_claim_host(bus->sdiodev->func[1]); - if (brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new, - BRCMF_SDIO_FT_NORMAL)) { + if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new, + BRCMF_SDIO_FT_NORMAL)) { rd->len = 0; brcmu_pkt_buf_free_skb(pkt); } @@ -1697,7 +1719,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) /* Save superframe descriptor and allocate packet frame */ if (rd->channel == SDPCM_GLOM_CHANNEL) { - if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { + if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_HWHDR_LEN])) { brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", rd->len); brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), @@ -1783,13 +1805,12 @@ static int brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, uint chan) { - u16 head_pad, tail_pad, tail_chop, pkt_len; - u16 head_align, sg_align; - u32 sw_header; + u16 head_pad, tail_pad, tail_chop, head_align, sg_align; int ntail; struct sk_buff *pkt_next, *pkt_new; u8 *dat_buf; unsigned blksize = bus->sdiodev->func[SDIO_FUNC_2]->cur_blksize; + struct brcmf_sdio_hdrinfo hd_info = {0}; /* SDIO ADMA requires at least 32 bit alignment */ head_align = 4; @@ -1848,34 +1869,18 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, } /* Now prep the header */ - /* 4 bytes hardware header (frame tag) - * Byte 0~1: Frame length - * Byte 2~3: Checksum, bit-wise inverse of frame length - */ if (pkt_new) - pkt_len = pkt_next->len + tail_chop; + hd_info.len = pkt_next->len + tail_chop; else - pkt_len = pkt_next->len - tail_pad; - *(__le16 *)dat_buf = cpu_to_le16(pkt_len); - *(((__le16 *)dat_buf) + 1) = cpu_to_le16(~pkt_len); - /* 8 bytes software header - * Byte 0: Tx sequence number - * Byte 1: 4 MSB Channel number - * Byte 2: Reserved - * Byte 3: Data offset - * Byte 4~7: Reserved - */ - sw_header = bus->tx_seq; - sw_header |= ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK); - sw_header |= ((head_pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & - SDPCM_DOFFSET_MASK; - *(((__le32 *)dat_buf) + 1) = cpu_to_le32(sw_header); - *(((__le32 *)dat_buf) + 2) = 0; + hd_info.len = pkt_next->len - tail_pad; + hd_info.channel = chan; + hd_info.dat_offset = head_pad + SDPCM_HDRLEN; + brcmf_sdio_hdpack(bus, dat_buf, &hd_info); if (BRCMF_BYTES_ON() && ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) - brcmf_dbg_hex_dump(true, pkt_next, pkt_len, "Tx Frame:\n"); + brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, "Tx Frame:\n"); else if (BRCMF_HDRS_ON()) brcmf_dbg_hex_dump(true, pkt_next, head_pad + SDPCM_HDRLEN, "Tx Header:\n"); @@ -1913,7 +1918,7 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq) __skb_unlink(pkt_next, pktq); brcmu_pkt_buf_free_skb(pkt_next); } else { - hdr = pkt_next->data + SDPCM_FRAMETAG_LEN; + hdr = pkt_next->data + SDPCM_HWHDR_LEN; dat_offset = le32_to_cpu(*(__le32 *)hdr); dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; @@ -1969,7 +1974,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, } sdio_release_host(bus->sdiodev->func[1]); if (ret == 0) - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; done: brcmf_sdio_txpkt_postp(bus, &localq); @@ -2325,7 +2330,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) } } else { - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; } sdio_release_host(bus->sdiodev->func[1]); bus->ctrl_frame_stat = false; @@ -2540,7 +2545,7 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) return ret; } - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; return ret; } @@ -2550,13 +2555,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) { u8 *frame; u16 len; - u32 swheader; uint retries = 0; u8 doff = 0; int ret = -1; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; + struct brcmf_sdio_hdrinfo hd_info = {0}; brcmf_dbg(TRACE, "Enter\n"); @@ -2595,18 +2600,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) brcmf_sdbrcm_bus_sleep(bus, false, false); sdio_release_host(bus->sdiodev->func[1]); - /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - *(__le16 *) frame = cpu_to_le16((u16) msglen); - *(((__le16 *) frame) + 1) = cpu_to_le16(~msglen); - - /* Software tag: channel, sequence number, data offset */ - swheader = - ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & - SDPCM_CHANNEL_MASK) - | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & - SDPCM_DOFFSET_MASK); - put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); - put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); + hd_info.len = (u16)msglen; + hd_info.channel = SDPCM_CONTROL_CHANNEL; + hd_info.dat_offset = doff; + brcmf_sdio_hdpack(bus, frame, &hd_info); if (!data_ok(bus)) { brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", @@ -3856,7 +3853,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->txbound = BRCMF_TXBOUND; bus->rxbound = BRCMF_RXBOUND; bus->txminmax = BRCMF_TXMINMAX; - bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; + bus->tx_seq = SDPCM_SEQ_WRAP - 1; INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); -- cgit v1.2.3 From 706478cba544584a1f8d515646f8d677d096395e Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Sat, 10 Aug 2013 12:27:29 +0200 Subject: brcmfmac: use configurable sdio bus header length for tx packet Host tx glomming require an extended hardware sdio bus header to store information for dongle. Introduce a variable in struct brcmf_sdio to replace macro SDPCM_HDRLEN Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 30 ++++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 02ab5cdbe29b..1aa75d5951b8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -461,6 +461,8 @@ struct brcmf_sdio { struct brcmf_sdio_count sdcnt; bool sr_enabled; /* SaveRestore enabled */ bool sleeping; /* SDIO bus sleeping */ + + u8 tx_hdrlen; /* sdio bus header length for tx packet */ }; /* clkstate */ @@ -1025,7 +1027,6 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) #define SDPCM_HWHDR_LEN 4 #define SDPCM_SWHDR_LEN 8 #define SDPCM_HDRLEN (SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN) -#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN) /* software header */ #define SDPCM_SEQ_MASK 0x000000ff #define SDPCM_SEQ_WRAP 256 @@ -1838,7 +1839,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, } skb_push(pkt_next, head_pad); dat_buf = (u8 *)(pkt_next->data); - memset(dat_buf, 0, head_pad + SDPCM_HDRLEN); + memset(dat_buf, 0, head_pad + bus->tx_hdrlen); } /* Check tail padding */ @@ -1874,7 +1875,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, else hd_info.len = pkt_next->len - tail_pad; hd_info.channel = chan; - hd_info.dat_offset = head_pad + SDPCM_HDRLEN; + hd_info.dat_offset = head_pad + bus->tx_hdrlen; brcmf_sdio_hdpack(bus, dat_buf, &hd_info); if (BRCMF_BYTES_ON() && @@ -1882,7 +1883,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, "Tx Frame:\n"); else if (BRCMF_HDRS_ON()) - brcmf_dbg_hex_dump(true, pkt_next, head_pad + SDPCM_HDRLEN, + brcmf_dbg_hex_dump(true, pkt_next, head_pad + bus->tx_hdrlen, "Tx Header:\n"); return 0; @@ -1989,7 +1990,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) u32 intstatus = 0; int ret = 0, prec_out; uint cnt = 0; - uint datalen; u8 tx_prec_map; brcmf_dbg(TRACE, "Enter\n"); @@ -2005,7 +2005,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) break; } spin_unlock_bh(&bus->txqlock); - datalen = pkt->len - SDPCM_HDRLEN; ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL); @@ -2392,7 +2391,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) datalen = pkt->len; /* Add space for the header */ - skb_push(pkt, SDPCM_HDRLEN); + skb_push(pkt, bus->tx_hdrlen); /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ prec = prio2prec((pkt->priority & PRIOMASK)); @@ -2405,7 +2404,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) /* Priority based enq */ spin_lock_irqsave(&bus->txqlock, flags); if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { - skb_pull(pkt, SDPCM_HDRLEN); + skb_pull(pkt, bus->tx_hdrlen); brcmf_err("out of bus->txq !!!\n"); ret = -ENOSR; } else { @@ -2566,8 +2565,8 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) brcmf_dbg(TRACE, "Enter\n"); /* Back the pointer to make a room for bus header */ - frame = msg - SDPCM_HDRLEN; - len = (msglen += SDPCM_HDRLEN); + frame = msg - bus->tx_hdrlen; + len = (msglen += bus->tx_hdrlen); /* Add alignment padding (optional for ctl frames) */ doff = ((unsigned long)frame % BRCMF_SDALIGN); @@ -2575,10 +2574,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) frame -= doff; len += doff; msglen += doff; - memset(frame, 0, doff + SDPCM_HDRLEN); + memset(frame, 0, doff + bus->tx_hdrlen); } /* precondition: doff < BRCMF_SDALIGN */ - doff += SDPCM_HDRLEN; + doff += bus->tx_hdrlen; /* Round send length to next SDIO block */ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { @@ -3895,8 +3894,11 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->sdiodev->bus_if->chip = bus->ci->chip; bus->sdiodev->bus_if->chiprev = bus->ci->chiprev; - /* Attach to the brcmf/OS/network interface */ - ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); + /* default sdio bus header length for tx packet */ + bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; + + /* Attach to the common layer, reserve hdr space */ + ret = brcmf_attach(bus->tx_hdrlen, bus->sdiodev->dev); if (ret != 0) { brcmf_err("brcmf_attach failed\n"); goto fail; -- cgit v1.2.3 From e96542e55a2aacf4bdeccfe2f17b77c4895b4df2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 10 Aug 2013 15:59:15 +0200 Subject: ath9k: fix rx descriptor related race condition Similar to a race condition that exists in the tx path, the hardware might re-read the 'next' pointer of a descriptor of the last completed frame. This only affects non-EDMA (pre-AR93xx) devices. To deal with this race, defer clearing and re-linking a completed rx descriptor until the next one has been processed. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 5 +---- drivers/net/wireless/ath/ath9k/recv.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 505c615ada1b..0d69b136aac9 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -79,10 +79,6 @@ struct ath_config { sizeof(struct ath_buf_state)); \ } while (0) -#define ATH_RXBUF_RESET(_bf) do { \ - (_bf)->bf_stale = false; \ - } while (0) - /** * enum buffer_type - Buffer type flags * @@ -315,6 +311,7 @@ struct ath_rx { struct ath_descdma rxdma; struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; + struct ath_buf *buf_hold; struct sk_buff *frag; u32 ampdu_ref; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 62dff97c1ae4..2dd851a72a50 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -42,8 +42,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) struct ath_desc *ds; struct sk_buff *skb; - ATH_RXBUF_RESET(bf); - ds = bf->bf_desc; ds->ds_link = 0; /* link to null */ ds->ds_data = bf->bf_buf_addr; @@ -70,6 +68,14 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) sc->rx.rxlink = &ds->ds_link; } +static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_buf *bf) +{ + if (sc->rx.buf_hold) + ath_rx_buf_link(sc, sc->rx.buf_hold); + + sc->rx.buf_hold = bf; +} + static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) { /* XXX block beacon interrupts */ @@ -117,7 +123,6 @@ static bool ath_rx_edma_buf_link(struct ath_softc *sc, skb = bf->bf_mpdu; - ATH_RXBUF_RESET(bf); memset(skb->data, 0, ah->caps.rx_status_len); dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, ah->caps.rx_status_len, DMA_TO_DEVICE); @@ -432,6 +437,7 @@ int ath_startrecv(struct ath_softc *sc) if (list_empty(&sc->rx.rxbuf)) goto start_recv; + sc->rx.buf_hold = NULL; sc->rx.rxlink = NULL; list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { ath_rx_buf_link(sc, bf); @@ -677,6 +683,9 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, } bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + if (bf == sc->rx.buf_hold) + return NULL; + ds = bf->bf_desc; /* @@ -1387,7 +1396,7 @@ requeue: if (edma) { ath_rx_edma_buf_link(sc, qtype); } else { - ath_rx_buf_link(sc, bf); + ath_rx_buf_relink(sc, bf); ath9k_hw_rxena(ah); } } while (1); -- cgit v1.2.3 From 50676b811148314f43f0d874502fe9ac5f7d686d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 10 Aug 2013 15:59:16 +0200 Subject: ath9k: shrink a few data structures by reordering fields Also reduce the size of a few fields where possible Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 12 ++++++------ drivers/net/wireless/ath/ath9k/xmit.c | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0d69b136aac9..7b1d03650e16 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -72,7 +72,6 @@ struct ath_config { /*************************/ #define ATH_TXBUF_RESET(_bf) do { \ - (_bf)->bf_stale = false; \ (_bf)->bf_lastbf = NULL; \ (_bf)->bf_next = NULL; \ memset(&((_bf)->bf_state), 0, \ @@ -192,10 +191,10 @@ struct ath_txq { struct ath_atx_ac { struct ath_txq *txq; - int sched; struct list_head list; struct list_head tid_q; bool clear_ps_filter; + bool sched; }; struct ath_frame_info { @@ -212,6 +211,7 @@ struct ath_buf_state { u8 bf_type; u8 bfs_paprd; u8 ndelim; + bool stale; u16 seqno; unsigned long bfs_paprd_timestamp; }; @@ -225,7 +225,6 @@ struct ath_buf { void *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */ - bool bf_stale; struct ieee80211_tx_rate rates[4]; struct ath_buf_state bf_state; }; @@ -237,13 +236,14 @@ struct ath_atx_tid { struct ath_node *an; struct ath_atx_ac *ac; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; - int bar_index; u16 seq_start; u16 seq_next; u16 baw_size; - int tidno; + u8 tidno; int baw_head; /* first un-acked tx buffer */ int baw_tail; /* next unused tx buffer slot */ + + s8 bar_index; bool sched; bool paused; bool active; @@ -255,10 +255,10 @@ struct ath_node { struct ieee80211_vif *vif; /* interface with which we're associated */ struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; struct ath_atx_ac ac[IEEE80211_NUM_ACS]; - int ps_key; u16 maxampdu; u8 mpdudensity; + s8 ps_key; bool sleeping; bool no_ps_filter; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d8dfb3ec818a..4fc80e3aef6f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -493,7 +493,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, while (bf) { bf_next = bf->bf_next; - if (!bf->bf_stale || bf_next != NULL) + if (!bf->bf_state.stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0); @@ -586,7 +586,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * not a holding desc. */ INIT_LIST_HEAD(&bf_head); - if (bf_next != NULL || !bf_last->bf_stale) + if (bf_next != NULL || !bf_last->bf_state.stale) list_move_tail(&bf->list, &bf_head); if (!txpending) { @@ -610,7 +610,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ieee80211_sta_eosp(sta); } /* retry the un-acked ones */ - if (bf->bf_next == NULL && bf_last->bf_stale) { + if (bf->bf_next == NULL && bf_last->bf_state.stale) { struct ath_buf *tbf; tbf = ath_clone_txbuf(sc, bf_last); @@ -1734,7 +1734,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, while (!list_empty(list)) { bf = list_first_entry(list, struct ath_buf, list); - if (bf->bf_stale) { + if (bf->bf_state.stale) { list_del(&bf->list); ath_tx_return_buffer(sc, bf); @@ -2490,7 +2490,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * it with the STALE flag. */ bf_held = NULL; - if (bf->bf_stale) { + if (bf->bf_state.stale) { bf_held = bf; if (list_is_last(&bf_held->list, &txq->axq_q)) break; @@ -2514,7 +2514,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * however leave the last descriptor back as the holding * descriptor for hw. */ - lastbf->bf_stale = true; + lastbf->bf_state.stale = true; INIT_LIST_HEAD(&bf_head); if (!list_is_singular(&lastbf->list)) list_cut_position(&bf_head, @@ -2585,7 +2585,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) } bf = list_first_entry(fifo_list, struct ath_buf, list); - if (bf->bf_stale) { + if (bf->bf_state.stale) { list_del(&bf->list); ath_tx_return_buffer(sc, bf); bf = list_first_entry(fifo_list, struct ath_buf, list); @@ -2607,7 +2607,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_tx_txqaddbuf(sc, txq, &bf_q, true); } } else { - lastbf->bf_stale = true; + lastbf->bf_state.stale = true; if (bf != lastbf) list_cut_position(&bf_head, fifo_list, lastbf->list.prev); -- cgit v1.2.3 From f5bde5b8524fb2b8584af3750dbffda6557234e6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 13 Aug 2013 12:33:26 +0200 Subject: ath9k: remove ath9k_sta_remove_debugfs mac80211 uses debugfs_remove_recursive, so there's no need for the driver to do an explicit cleanup of its sta debugfs entry. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ---- drivers/net/wireless/ath/ath9k/debug.c | 12 +----------- drivers/net/wireless/ath/ath9k/debug.h | 4 ---- drivers/net/wireless/ath/ath9k/main.c | 1 - 4 files changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7b1d03650e16..df1c4957e3f0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -262,10 +262,6 @@ struct ath_node { bool sleeping; bool no_ps_filter; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - struct dentry *node_stat; -#endif }; struct ath_tx_control { diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index c10cec5650c6..e5c8333eb55a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1725,17 +1725,7 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, struct dentry *dir) { struct ath_node *an = (struct ath_node *)sta->drv_priv; - an->node_stat = debugfs_create_file("node_stat", S_IRUGO, - dir, an, &fops_node_stat); -} - -void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir) -{ - struct ath_node *an = (struct ath_node *)sta->drv_priv; - debugfs_remove(an->node_stat); + debugfs_create_file("node_stat", S_IRUGO, dir, an, &fops_node_stat); } /* Ethtool support for get-stats */ diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 01c5c6a22e1b..6e1556fa2f3e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -292,10 +292,6 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); -void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir); void ath_debug_send_fft_sample(struct ath_softc *sc, struct fft_sample_tlv *fft_sample); void ath9k_debug_stat_ant(struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 911744f5c43c..0bee105064bd 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2364,7 +2364,6 @@ struct ieee80211_ops ath9k_ops = { #if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) .sta_add_debugfs = ath9k_sta_add_debugfs, - .sta_remove_debugfs = ath9k_sta_remove_debugfs, #endif .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, -- cgit v1.2.3 From ca6d4a74c4dea24277d4ce2df4940da6003a2a16 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 13 Aug 2013 12:33:27 +0200 Subject: ath9k: simplify debugfs chainmask handling Writing to that file is unnecessary and quirky, the antenna API should be used instead. Use debugfs_create_u8 to allow reading the values. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 92 ++-------------------------------- 1 file changed, 4 insertions(+), 88 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index e5c8333eb55a..c088744a6bfb 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -88,90 +88,6 @@ static const struct file_operations fops_debug = { #define DMA_BUF_LEN 1024 -static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "0x%08x\n", ah->txchainmask); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_tx_chainmask(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - unsigned long mask; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &mask)) - return -EINVAL; - - ah->txchainmask = mask; - ah->caps.tx_chainmask = mask; - return count; -} - -static const struct file_operations fops_tx_chainmask = { - .read = read_file_tx_chainmask, - .write = write_file_tx_chainmask, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - - -static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "0x%08x\n", ah->rxchainmask); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_rx_chainmask(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - unsigned long mask; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &mask)) - return -EINVAL; - - ah->rxchainmask = mask; - ah->caps.rx_chainmask = mask; - return count; -} - -static const struct file_operations fops_rx_chainmask = { - .read = read_file_rx_chainmask, - .write = write_file_rx_chainmask, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; static ssize_t read_file_ani(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1896,10 +1812,10 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_reset); debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_recv); - debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_rx_chainmask); - debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_tx_chainmask); + debugfs_create_u8("rx_chainmask", S_IRUSR, sc->debug.debugfs_phy, + &ah->rxchainmask); + debugfs_create_u8("tx_chainmask", S_IRUSR, sc->debug.debugfs_phy, + &ah->txchainmask); debugfs_create_file("ani", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_ani); debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, -- cgit v1.2.3 From a1c781bb20ac1e03280e420abd47a99eb8bbdd3b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 13 Aug 2013 12:33:28 +0200 Subject: ath9k: avoid accessing MRC registers on single-chain devices They are not implemented, and accessing them might trigger errors Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 39c37309f39e..18a5aa4fe406 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1172,6 +1172,10 @@ skip_ws_det: * is_on == 0 means MRC CCK is OFF (more noise imm) */ bool is_on = param ? 1 : 0; + + if (ah->caps.rx_chainmask == 1) + break; + REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_ENABLE, is_on); REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, -- cgit v1.2.3 From 8f536b87950aa5a5c2d29eb684ed6813e1f9e800 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 13 Aug 2013 12:33:29 +0200 Subject: ath9k: simplify ath_tid_drain ath_tid_drain is only called when a station entry is being removed, so there is no point in still tracking BAW state. Remove some unnecessary code and a bogus TODO comment related to this. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 4fc80e3aef6f..cb06c1c08942 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -312,12 +312,6 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, } } -/* - * TODO: For frame(s) that are in the retry state, we will reuse the - * sequence number(s) without setting the retry bit. The - * alternative is to give up on these and BAR the receiver's window - * forward. - */ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) @@ -341,14 +335,8 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, } 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); } - - tid->seq_next = tid->seq_start; - tid->baw_tail = tid->baw_head; - tid->bar_index = -1; } static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, -- cgit v1.2.3 From 563299d82fb2492e8d2390b94b00b668feebb229 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 13 Aug 2013 12:33:30 +0200 Subject: ath9k: reset buffer stale flag in ath_tx_get_tid_subframe If that flag stays set for a buffer that already ran through the tx path once, it might cause issues in tx completion processing. Better clear it early to ensure that this does not happen Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index cb06c1c08942..7223e303f3a1 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -888,6 +888,8 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, bf = fi->bf; if (!fi->bf) bf = ath_tx_setup_buffer(sc, txq, tid, skb); + else + bf->bf_state.stale = false; if (!bf) { __skb_unlink(skb, *q); -- cgit v1.2.3 From 4a68ab100f24eca34c5d79b937df4dbd0cbc0b4a Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Tue, 13 Aug 2013 15:25:32 +0300 Subject: wil6210: let IP stack re-check HW TCP/UDP csum errors Fix for TCP iperf from Windows to Linux stall after about 1sec Hardware reports false errors in some situations: Microsoft IP stack, in violation of RFC 1624, set TCP checksum that should be 0x0 as 0xffff. hardware report Rx csum error. If HW csum absolutely trusted, this frame can be never received, as re-transmitted one will have same csum problem. In addition, it mess up block ack reorder buffer, as if packet dropped, it is not score boarded there. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index ea1abeb18e5b..d505b2676a73 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -416,13 +416,13 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, */ if (d->dma.status & RX_DMA_STATUS_L4_IDENT) { /* L4 protocol identified, csum calculated */ - if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) { + if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - wil_err(wil, "Incorrect checksum reported\n"); - kfree_skb(skb); - return NULL; - } + /* If HW reports bad checksum, let IP stack re-check it + * For example, HW don't understand Microsoft IP stack that + * mis-calculates TCP checksum - if it should be 0x0, + * it writes 0xffff in violation of RFC 1624 + */ } ds_bits = wil_rxdesc_ds_bits(d); -- cgit v1.2.3 From 2b721118b7821107757eb1d37af4b60e877b27e7 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 13 Aug 2013 21:10:19 +0200 Subject: ath9k_htc: do not use bulk on EP3 and EP4 If usb auto suspend is enabled or system run in to suspend/resume cycle, ath9k-htc adapter will stop to response. It is reproducible on xhci HCs. Host part of problem: XHCI do timing calculation based on Transfer Type and bInterval, immediately after device was detected. Ath9k-htc try to overwrite this parameters on module probe and some changes in FW, since we do not initiate usb reset from the driver this changes are not took to account. So, before any kind of suspend or reset, host controller will operate with old parameters. Only after suspend/resume and if interface id stay unchanged, new parameters will by applied. Host will send bulk data with no intervals (?), which will cause overflow on FIFO of EP4. Firmware part of problem: By default, ath9k-htc adapters configured with EP3 and EP4 as interrupt endpoints. Current firmware will try to overwrite ConfigDescriptor to make EP3 and EP4 bulk. FIFO for this endpoints stay not reconfigured, so under the hood it is still Int EP. This patch is revert of 4a0e8ecca4ee commit which trying to reduce CPU usage on some systems. Since it will produce more bug as fixes, we will need to find other way to fix it. here is comment from kernel source which has some more explanation: * Some buggy high speed devices have bulk endpoints using * maxpacket sizes other than 512. High speed HCDs may not * be able to handle that particular bug, so let's warn... in our case EP3 and EP4 have maxpacket sizes = 64!!! Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 38 +++++++++----------------------- 1 file changed, 11 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 5205a3625e84..6d5d716adc1b 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -115,10 +115,10 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, cmd->skb = skb; cmd->hif_dev = hif_dev; - usb_fill_bulk_urb(urb, hif_dev->udev, - usb_sndbulkpipe(hif_dev->udev, USB_REG_OUT_PIPE), + usb_fill_int_urb(urb, hif_dev->udev, + usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE), skb->data, skb->len, - hif_usb_regout_cb, cmd); + hif_usb_regout_cb, cmd, 1); usb_anchor_urb(urb, &hif_dev->regout_submitted); ret = usb_submit_urb(urb, GFP_KERNEL); @@ -723,11 +723,11 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) return; } - usb_fill_bulk_urb(urb, hif_dev->udev, - usb_rcvbulkpipe(hif_dev->udev, + usb_fill_int_urb(urb, hif_dev->udev, + usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), nskb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, nskb); + ath9k_hif_usb_reg_in_cb, nskb, 1); } resubmit: @@ -909,11 +909,11 @@ static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev) goto err_skb; } - usb_fill_bulk_urb(urb, hif_dev->udev, - usb_rcvbulkpipe(hif_dev->udev, + usb_fill_int_urb(urb, hif_dev->udev, + usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), skb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, skb); + ath9k_hif_usb_reg_in_cb, skb, 1); /* Anchor URB */ usb_anchor_urb(urb, &hif_dev->reg_in_submitted); @@ -1031,9 +1031,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) { - struct usb_host_interface *alt = &hif_dev->interface->altsetting[0]; - struct usb_endpoint_descriptor *endp; - int ret, idx; + int ret; ret = ath9k_hif_usb_download_fw(hif_dev); if (ret) { @@ -1043,20 +1041,6 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) return ret; } - /* On downloading the firmware to the target, the USB descriptor of EP4 - * is 'patched' to change the type of the endpoint to Bulk. This will - * bring down CPU usage during the scan period. - */ - for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) { - endp = &alt->endpoint[idx].desc; - if ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT) { - endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK; - endp->bmAttributes |= USB_ENDPOINT_XFER_BULK; - endp->bInterval = 0; - } - } - /* Alloc URBs */ ret = ath9k_hif_usb_alloc_urbs(hif_dev); if (ret) { @@ -1268,7 +1252,7 @@ static void ath9k_hif_usb_reboot(struct usb_device *udev) if (!buf) return; - ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE), + ret = usb_interrupt_msg(udev, usb_sndintpipe(udev, USB_REG_OUT_PIPE), buf, 4, NULL, HZ); if (ret) dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n"); -- cgit v1.2.3 From f6307dda7f0478c721450e6de956fb5c4fdcb6a4 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:09 +0530 Subject: ath9k: Use a subroutine to check for "mybeacon" Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 36 ++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2dd851a72a50..0c23053a49f6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1160,6 +1160,24 @@ static void ath9k_apply_ampdu_details(struct ath_softc *sc, } } +static bool ath9k_is_mybeacon(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); + + if (ieee80211_is_beacon(hdr->frame_control)) { + RX_STAT_INC(rx_beacons); + if (!is_zero_ether_addr(common->curbssid) && + ether_addr_equal(hdr->addr3, common->curbssid)) + return true; + } + + return false; +} + int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { struct ath_buf *bf; @@ -1175,7 +1193,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) enum ath9k_rx_qtype qtype; bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int dma_type; - u8 rx_status_len = ah->caps.rx_status_len; u64 tsf = 0; u32 tsf_lower = 0; unsigned long flags; @@ -1216,18 +1233,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) else hdr_skb = skb; - hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); - rxs = IEEE80211_SKB_RXCB(hdr_skb); - if (ieee80211_is_beacon(hdr->frame_control)) { - RX_STAT_INC(rx_beacons); - if (!is_zero_ether_addr(common->curbssid) && - ether_addr_equal(hdr->addr3, common->curbssid)) - rs.is_mybeacon = true; - else - rs.is_mybeacon = false; - } - else - rs.is_mybeacon = false; + rs.is_mybeacon = ath9k_is_mybeacon(sc, hdr_skb); + + hdr = (struct ieee80211_hdr *) (hdr_skb->data + + ah->caps.rx_status_len); if (ieee80211_is_data_present(hdr->frame_control) && !ieee80211_is_qos_nullfunc(hdr->frame_control)) @@ -1235,6 +1244,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ath_debug_stat_rx(sc, &rs); + rxs = IEEE80211_SKB_RXCB(hdr_skb); memset(rxs, 0, sizeof(struct ieee80211_rx_status)); rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; -- cgit v1.2.3 From 0cab329d6037775bda6eee6ed742797c868f09cc Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:10 +0530 Subject: ath9k: Fix phy error handling for DFS Since the DFS code appears to process the phy errors ATH9K_PHYERR_RADAR and ATH9K_PHYERR_FALSE_RADAR_EXT, check for the correct phyerr status in the main RX tasklet routine. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 0c23053a49f6..83b3fc57cabb 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1256,10 +1256,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) rxs->mactime += 0x100000000ULL; - if (rs.rs_phyerr == ATH9K_PHYERR_RADAR) + if (rs.rs_status & ATH9K_RXERR_PHY) { ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime); - if (rs.rs_status & ATH9K_RXERR_PHY) { if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) { RX_STAT_INC(rx_spectral); goto requeue_drop_frag; -- cgit v1.2.3 From 5871d2d787bc2fc45e43c9f8ecabdd2db37ad666 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:11 +0530 Subject: ath9k: Discard invalid frames early Frames with invalid or zero length can be discarded early, there is no need to check the crypto bits. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 38 ++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 83b3fc57cabb..f8cc2b3b38d9 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -764,7 +764,6 @@ static bool ath9k_rx_accept(struct ath_common *common, bool is_mc, is_valid_tkip, strip_mic, mic_error; struct ath_hw *ah = common->ah; __le16 fc; - u8 rx_status_len = ah->caps.rx_status_len; fc = hdr->frame_control; @@ -786,21 +785,6 @@ static bool ath9k_rx_accept(struct ath_common *common, !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; - if (!rx_stats->rs_datalen) { - RX_STAT_INC(rx_len_err); - return false; - } - - /* - * rs_status follows rs_datalen so if rs_datalen is too large - * we can take a hint that hardware corrupted it, so ignore - * those frames. - */ - if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) { - RX_STAT_INC(rx_len_err); - return false; - } - /* Only use error bits from the last fragment */ if (rx_stats->rs_more) return true; @@ -949,10 +933,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, struct ath_common *common = ath9k_hw_common(ah); bool discard_current = sc->rx.discard_next; + /* + * Discard corrupt descriptors which are marked in + * ath_get_next_rx_buf(). + */ sc->rx.discard_next = rx_stats->rs_more; if (discard_current) return -EINVAL; + /* + * Discard zero-length packets. + */ + if (!rx_stats->rs_datalen) { + RX_STAT_INC(rx_len_err); + return -EINVAL; + } + + /* + * rs_status follows rs_datalen so if rs_datalen is too large + * we can take a hint that hardware corrupted it, so ignore + * those frames. + */ + if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { + RX_STAT_INC(rx_len_err); + return -EINVAL; + } + /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. -- cgit v1.2.3 From 4a470647415276d43daf9238a5bd70acc2119555 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:12 +0530 Subject: ath9k: Fix RX crypto processing The keymiss events are valid only in the last descriptor of a packet. Fix this by making sure that we return early in case of chained descriptors. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index f8cc2b3b38d9..b04a9711eb31 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -785,10 +785,6 @@ static bool ath9k_rx_accept(struct ath_common *common, !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; - /* Only use error bits from the last fragment */ - if (rx_stats->rs_more) - return true; - mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && !ieee80211_has_morefrags(fc) && !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && @@ -959,6 +955,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, return -EINVAL; } + /* Only use status info from the last fragment */ + if (rx_stats->rs_more) + return 0; + /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. @@ -966,10 +966,6 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) return -EINVAL; - /* Only use status info from the last fragment */ - if (rx_stats->rs_more) - return 0; - if (ath9k_process_rate(common, hw, rx_stats, rx_status)) return -EINVAL; -- cgit v1.2.3 From e0dd1a960bba04898bb590e96cf33ecbe3bf53e6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:13 +0530 Subject: ath9k: Fix TSF processing There is no need to calculate the mactime for chained descriptor packets, so make sure that this is done only for the last fragment of valid packets. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b04a9711eb31..9fabd5f111ec 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -913,6 +913,22 @@ static void ath9k_process_rssi(struct ath_common *common, ah->stats.avgbrssi = rssi; } +static void ath9k_process_tsf(struct ath_rx_status *rs, + struct ieee80211_rx_status *rxs, + u64 tsf) +{ + u32 tsf_lower = tsf & 0xffffffff; + + rxs->mactime = (tsf & ~0xffffffffULL) | rs->rs_tstamp; + if (rs->rs_tstamp > tsf_lower && + unlikely(rs->rs_tstamp - tsf_lower > 0x10000000)) + rxs->mactime -= 0x100000000ULL; + + if (rs->rs_tstamp < tsf_lower && + unlikely(tsf_lower - rs->rs_tstamp > 0x10000000)) + rxs->mactime += 0x100000000ULL; +} + /* * For Decrypt or Demic errors, we only mark packet status here and always push * up the frame up to let mac80211 handle the actual error case, be it no @@ -922,7 +938,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, struct ieee80211_hdr *hdr, struct ath_rx_status *rx_stats, struct ieee80211_rx_status *rx_status, - bool *decrypt_error) + bool *decrypt_error, u64 tsf) { struct ieee80211_hw *hw = sc->hw; struct ath_hw *ah = sc->sc_ah; @@ -959,6 +975,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (rx_stats->rs_more) return 0; + ath9k_process_tsf(rx_stats, rx_status, tsf); + /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. @@ -1196,7 +1214,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int dma_type; u64 tsf = 0; - u32 tsf_lower = 0; unsigned long flags; dma_addr_t new_buf_addr; @@ -1208,7 +1225,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; tsf = ath9k_hw_gettsf64(ah); - tsf_lower = tsf & 0xffffffff; do { bool decrypt_error = false; @@ -1249,15 +1265,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) rxs = IEEE80211_SKB_RXCB(hdr_skb); memset(rxs, 0, sizeof(struct ieee80211_rx_status)); - rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; - if (rs.rs_tstamp > tsf_lower && - unlikely(rs.rs_tstamp - tsf_lower > 0x10000000)) - rxs->mactime -= 0x100000000ULL; - - if (rs.rs_tstamp < tsf_lower && - unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) - rxs->mactime += 0x100000000ULL; - if (rs.rs_status & ATH9K_RXERR_PHY) { ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime); @@ -1268,7 +1275,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) } retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs, - &decrypt_error); + &decrypt_error, tsf); if (retval) goto requeue_drop_frag; -- cgit v1.2.3 From 3105b67276f2d3b09669e0a2b1337c9d99f573bd Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:14 +0530 Subject: ath9k: Reorder some functions Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 220 +++++++++++++++++----------------- 1 file changed, 110 insertions(+), 110 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9fabd5f111ec..51e7d16841d6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -929,6 +929,116 @@ static void ath9k_process_tsf(struct ath_rx_status *rs, rxs->mactime += 0x100000000ULL; } +#ifdef CONFIG_ATH9K_DEBUGFS +static s8 fix_rssi_inv_only(u8 rssi_val) +{ + if (rssi_val == 128) + rssi_val = 0; + return (s8) rssi_val; +} +#endif + +/* returns 1 if this was a spectral frame, even if not handled. */ +static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, + struct ath_rx_status *rs, u64 tsf) +{ +#ifdef CONFIG_ATH9K_DEBUGFS + struct ath_hw *ah = sc->sc_ah; + u8 bins[SPECTRAL_HT20_NUM_BINS]; + u8 *vdata = (u8 *)hdr; + struct fft_sample_ht20 fft_sample; + struct ath_radar_info *radar_info; + struct ath_ht20_mag_info *mag_info; + int len = rs->rs_datalen; + int dc_pos; + u16 length, max_magnitude; + + /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer + * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT + * yet, but this is supposed to be possible as well. + */ + if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && + rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && + rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) + return 0; + + /* check if spectral scan bit is set. This does not have to be checked + * if received through a SPECTRAL phy error, but shouldn't hurt. + */ + radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; + if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) + return 0; + + /* Variation in the data length is possible and will be fixed later. + * Note that we only support HT20 for now. + * + * TODO: add HT20_40 support as well. + */ + if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || + (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) + return 1; + + fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; + length = sizeof(fft_sample) - sizeof(fft_sample.tlv); + fft_sample.tlv.length = __cpu_to_be16(length); + + fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq); + fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); + fft_sample.noise = ah->noise; + + switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) { + case 0: + /* length correct, nothing to do. */ + memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS); + break; + case -1: + /* first byte missing, duplicate it. */ + memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1); + bins[0] = vdata[0]; + break; + case 2: + /* MAC added 2 extra bytes at bin 30 and 32, remove them. */ + memcpy(bins, vdata, 30); + bins[30] = vdata[31]; + memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31); + break; + case 1: + /* MAC added 2 extra bytes AND first byte is missing. */ + bins[0] = vdata[0]; + memcpy(&bins[0], vdata, 30); + bins[31] = vdata[31]; + memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); + break; + default: + return 1; + } + + /* DC value (value in the middle) is the blind spot of the spectral + * sample and invalid, interpolate it. + */ + dc_pos = SPECTRAL_HT20_NUM_BINS / 2; + bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; + + /* mag data is at the end of the frame, in front of radar_info */ + mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; + + /* copy raw bins without scaling them */ + memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS); + fft_sample.max_exp = mag_info->max_exp & 0xf; + + max_magnitude = spectral_max_magnitude(mag_info->all_bins); + fft_sample.max_magnitude = __cpu_to_be16(max_magnitude); + fft_sample.max_index = spectral_max_index(mag_info->all_bins); + fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); + fft_sample.tsf = __cpu_to_be64(tsf); + + ath_debug_send_fft_sample(sc, &fft_sample.tlv); + return 1; +#else + return 0; +#endif +} + /* * For Decrypt or Demic errors, we only mark packet status here and always push * up the frame up to let mac80211 handle the actual error case, be it no @@ -1052,116 +1162,6 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common, rxs->flag &= ~RX_FLAG_DECRYPTED; } -#ifdef CONFIG_ATH9K_DEBUGFS -static s8 fix_rssi_inv_only(u8 rssi_val) -{ - if (rssi_val == 128) - rssi_val = 0; - return (s8) rssi_val; -} -#endif - -/* returns 1 if this was a spectral frame, even if not handled. */ -static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, - struct ath_rx_status *rs, u64 tsf) -{ -#ifdef CONFIG_ATH9K_DEBUGFS - struct ath_hw *ah = sc->sc_ah; - u8 bins[SPECTRAL_HT20_NUM_BINS]; - u8 *vdata = (u8 *)hdr; - struct fft_sample_ht20 fft_sample; - struct ath_radar_info *radar_info; - struct ath_ht20_mag_info *mag_info; - int len = rs->rs_datalen; - int dc_pos; - u16 length, max_magnitude; - - /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer - * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT - * yet, but this is supposed to be possible as well. - */ - if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && - rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && - rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) - return 0; - - /* check if spectral scan bit is set. This does not have to be checked - * if received through a SPECTRAL phy error, but shouldn't hurt. - */ - radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; - if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) - return 0; - - /* Variation in the data length is possible and will be fixed later. - * Note that we only support HT20 for now. - * - * TODO: add HT20_40 support as well. - */ - if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || - (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) - return 1; - - fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; - length = sizeof(fft_sample) - sizeof(fft_sample.tlv); - fft_sample.tlv.length = __cpu_to_be16(length); - - fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq); - fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); - fft_sample.noise = ah->noise; - - switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) { - case 0: - /* length correct, nothing to do. */ - memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS); - break; - case -1: - /* first byte missing, duplicate it. */ - memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1); - bins[0] = vdata[0]; - break; - case 2: - /* MAC added 2 extra bytes at bin 30 and 32, remove them. */ - memcpy(bins, vdata, 30); - bins[30] = vdata[31]; - memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31); - break; - case 1: - /* MAC added 2 extra bytes AND first byte is missing. */ - bins[0] = vdata[0]; - memcpy(&bins[0], vdata, 30); - bins[31] = vdata[31]; - memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); - break; - default: - return 1; - } - - /* DC value (value in the middle) is the blind spot of the spectral - * sample and invalid, interpolate it. - */ - dc_pos = SPECTRAL_HT20_NUM_BINS / 2; - bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; - - /* mag data is at the end of the frame, in front of radar_info */ - mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; - - /* copy raw bins without scaling them */ - memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS); - fft_sample.max_exp = mag_info->max_exp & 0xf; - - max_magnitude = spectral_max_magnitude(mag_info->all_bins); - fft_sample.max_magnitude = __cpu_to_be16(max_magnitude); - fft_sample.max_index = spectral_max_index(mag_info->all_bins); - fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); - fft_sample.tsf = __cpu_to_be64(tsf); - - ath_debug_send_fft_sample(sc, &fft_sample.tlv); - return 1; -#else - return 0; -#endif -} - static void ath9k_apply_ampdu_details(struct ath_softc *sc, struct ath_rx_status *rs, struct ieee80211_rx_status *rxs) { -- cgit v1.2.3 From 6b87d71c1ad41a3d0402286534909d0dc6285a51 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:15 +0530 Subject: ath9k: Fix PHY error processing Parse the PHY error details only for the last fragment in case descriptors are chained. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 51e7d16841d6..e18adde1df6c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -803,8 +803,6 @@ static bool ath9k_rx_accept(struct ath_common *common, rxs->flag |= RX_FLAG_FAILED_FCS_CRC; mic_error = false; } - if (rx_stats->rs_status & ATH9K_RXERR_PHY) - return false; if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { @@ -1087,6 +1085,18 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, ath9k_process_tsf(rx_stats, rx_status, tsf); + /* + * Process PHY errors and return so that the packet + * can be dropped. + */ + if (rx_stats->rs_status & ATH9K_RXERR_PHY) { + ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime); + if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) + RX_STAT_INC(rx_spectral); + + return -EINVAL; + } + /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. @@ -1265,15 +1275,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) rxs = IEEE80211_SKB_RXCB(hdr_skb); memset(rxs, 0, sizeof(struct ieee80211_rx_status)); - if (rs.rs_status & ATH9K_RXERR_PHY) { - ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime); - - if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) { - RX_STAT_INC(rx_spectral); - goto requeue_drop_frag; - } - } - retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs, &decrypt_error, tsf); if (retval) -- cgit v1.2.3 From 5e85a32aca03aba3ce7e7123943b4529d2969a95 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:16 +0530 Subject: ath9k: Fix RX debug statistics The various error bits that ath_debug_stat_rx() checks are valid only for the last descriptor for a chained packet, handle this correctly. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index e18adde1df6c..2d0017cc2ee2 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1084,6 +1084,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, return 0; ath9k_process_tsf(rx_stats, rx_status, tsf); + ath_debug_stat_rx(sc, rx_stats); /* * Process PHY errors and return so that the packet @@ -1270,8 +1271,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) !ieee80211_is_qos_nullfunc(hdr->frame_control)) sc->rx.num_pkts++; - ath_debug_stat_rx(sc, &rs); - rxs = IEEE80211_SKB_RXCB(hdr_skb); memset(rxs, 0, sizeof(struct ieee80211_rx_status)); -- cgit v1.2.3 From a5525d9c8246cad653858044ccfd8a16143e84f6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:17 +0530 Subject: ath9k: Fix RX packet counter Handle chained descriptors and increment the RX counter only for valid packets. Since this is used only by MCI, use CONFIG_ATH9K_BTCOEX_SUPPORT. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2d0017cc2ee2..823b4111e282 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1119,6 +1119,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; sc->rx.discard_next = false; + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + if (ieee80211_is_data_present(hdr->frame_control) && + !ieee80211_is_qos_nullfunc(hdr->frame_control)) + sc->rx.num_pkts++; +#endif + return 0; } @@ -1267,10 +1274,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) hdr = (struct ieee80211_hdr *) (hdr_skb->data + ah->caps.rx_status_len); - if (ieee80211_is_data_present(hdr->frame_control) && - !ieee80211_is_qos_nullfunc(hdr->frame_control)) - sc->rx.num_pkts++; - rxs = IEEE80211_SKB_RXCB(hdr_skb); memset(rxs, 0, sizeof(struct ieee80211_rx_status)); -- cgit v1.2.3 From 6f38482eb0630e0be304d5c4fa0e2e5c0a701e91 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:18 +0530 Subject: ath9k: Fix RX beacon processing Make sure that chained descriptors are handled correctly before the packet is parsed to determine if it is a beacon. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 823b4111e282..090c27e756b8 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1037,13 +1037,28 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, #endif } +static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + if (ieee80211_is_beacon(hdr->frame_control)) { + RX_STAT_INC(rx_beacons); + if (!is_zero_ether_addr(common->curbssid) && + ether_addr_equal(hdr->addr3, common->curbssid)) + return true; + } + + return false; +} + /* * For Decrypt or Demic errors, we only mark packet status here and always push * up the frame up to let mac80211 handle the actual error case, be it no * decryption key or real decryption error. This let us keep statistics there. */ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, - struct ieee80211_hdr *hdr, + struct sk_buff *skb, struct ath_rx_status *rx_stats, struct ieee80211_rx_status *rx_status, bool *decrypt_error, u64 tsf) @@ -1051,6 +1066,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, struct ieee80211_hw *hw = sc->hw; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hdr *hdr; bool discard_current = sc->rx.discard_next; /* @@ -1083,6 +1099,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (rx_stats->rs_more) return 0; + hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); + ath9k_process_tsf(rx_stats, rx_status, tsf); ath_debug_stat_rx(sc, rx_stats); @@ -1105,6 +1123,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) return -EINVAL; + rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr); + if (ath9k_process_rate(common, hw, rx_stats, rx_status)) return -EINVAL; @@ -1198,24 +1218,6 @@ static void ath9k_apply_ampdu_details(struct ath_softc *sc, } } -static bool ath9k_is_mybeacon(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_hdr *hdr; - - hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); - - if (ieee80211_is_beacon(hdr->frame_control)) { - RX_STAT_INC(rx_beacons); - if (!is_zero_ether_addr(common->curbssid) && - ether_addr_equal(hdr->addr3, common->curbssid)) - return true; - } - - return false; -} - int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { struct ath_buf *bf; @@ -1225,7 +1227,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hw *hw = sc->hw; - struct ieee80211_hdr *hdr; int retval; struct ath_rx_status rs; enum ath9k_rx_qtype qtype; @@ -1269,15 +1270,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) else hdr_skb = skb; - rs.is_mybeacon = ath9k_is_mybeacon(sc, hdr_skb); - - hdr = (struct ieee80211_hdr *) (hdr_skb->data + - ah->caps.rx_status_len); - rxs = IEEE80211_SKB_RXCB(hdr_skb); memset(rxs, 0, sizeof(struct ieee80211_rx_status)); - retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs, + retval = ath9k_rx_skb_preprocess(sc, hdr_skb, &rs, rxs, &decrypt_error, tsf); if (retval) goto requeue_drop_frag; -- cgit v1.2.3 From eb5f952c31abdd5849fb9005beb3dc4ac734c355 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:19 +0530 Subject: ath9k: Move the RX poll check to preprocess() Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 090c27e756b8..5b84ce4ee45e 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1124,6 +1124,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, return -EINVAL; rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr); + if (rx_stats->is_mybeacon) { + sc->hw_busy_count = 0; + ath_start_rx_poll(sc, 3); + } if (ath9k_process_rate(common, hw, rx_stats, rx_status)) return -EINVAL; @@ -1278,10 +1282,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (retval) goto requeue_drop_frag; - if (rs.is_mybeacon) { - sc->hw_busy_count = 0; - ath_start_rx_poll(sc, 3); - } /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC); -- cgit v1.2.3 From b09255957b69d7b5ea1ad9d2b455a4f8769e06e7 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:20 +0530 Subject: ath9k: Handle corrupt descriptors properly The MIC/PHYERR/CRC error bits are valid only for the last desc. for chained packets. Check this early in the preprocess() routine and bail out. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 5b84ce4ee45e..30cb7267c12b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1099,6 +1099,16 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (rx_stats->rs_more) return 0; + /* + * Return immediately if the RX descriptor has been marked + * as corrupt based on the various error bits. + * + * This is different from the other corrupt descriptor + * condition handled above. + */ + if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) + return -EINVAL; + hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); ath9k_process_tsf(rx_stats, rx_status, tsf); @@ -1335,8 +1345,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) sc->rx.frag = skb; goto requeue; } - if (rs.rs_status & ATH9K_RXERR_CORRUPT_DESC) - goto requeue_drop_frag; if (sc->rx.frag) { int space = skb->len - skb_tailroom(hdr_skb); -- cgit v1.2.3 From 7c5c73cde03c876b23d840e82f4df687bce83b44 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:21 +0530 Subject: ath9k: Fix error condition for corrupt descriptors In case a descriptor has the "done" bit clear and the next descriptor has it set, we drop both of them. If the packet that is received after these two packets is dropped for some reason, "discard_next" will not cleared. Fix this. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 30cb7267c12b..ec8928041da0 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1068,6 +1068,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hdr *hdr; bool discard_current = sc->rx.discard_next; + int ret = 0; /* * Discard corrupt descriptors which are marked in @@ -1106,8 +1107,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, * This is different from the other corrupt descriptor * condition handled above. */ - if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) - return -EINVAL; + if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) { + ret = -EINVAL; + goto exit; + } hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); @@ -1123,15 +1126,18 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) RX_STAT_INC(rx_spectral); - return -EINVAL; + ret = -EINVAL; + goto exit; } /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. */ - if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) - return -EINVAL; + if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) { + ret = -EINVAL; + goto exit; + } rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr); if (rx_stats->is_mybeacon) { @@ -1139,8 +1145,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, ath_start_rx_poll(sc, 3); } - if (ath9k_process_rate(common, hw, rx_stats, rx_status)) - return -EINVAL; + if (ath9k_process_rate(common, hw, rx_stats, rx_status)) { + ret =-EINVAL; + goto exit; + } ath9k_process_rssi(common, hw, hdr, rx_stats); @@ -1152,15 +1160,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (rx_stats->rs_moreaggr) rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; - sc->rx.discard_next = false; - #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT if (ieee80211_is_data_present(hdr->frame_control) && !ieee80211_is_qos_nullfunc(hdr->frame_control)) sc->rx.num_pkts++; #endif - return 0; +exit: + sc->rx.discard_next = false; + return ret; } static void ath9k_rx_skb_postprocess(struct ath_common *common, -- cgit v1.2.3 From ea3ef101d750f78dc1e532bcf759ab9afea295df Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 09:11:22 +0530 Subject: ath9k: Remove unused function argument Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ec8928041da0..3b47198239f9 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -885,7 +885,6 @@ static int ath9k_process_rate(struct ath_common *common, static void ath9k_process_rssi(struct ath_common *common, struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, struct ath_rx_status *rx_stats) { struct ath_softc *sc = hw->priv; @@ -1150,7 +1149,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, goto exit; } - ath9k_process_rssi(common, hw, hdr, rx_stats); + ath9k_process_rssi(common, hw, rx_stats); rx_status->band = hw->conf.chandef.chan->band; rx_status->freq = hw->conf.chandef.chan->center_freq; -- cgit v1.2.3 From e3acd13d2141fa25566877e8f575065f204317f5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 21:15:54 +0530 Subject: ath9k: Handle invalid RSSI The combined RSSI can be invalid which is indicated by the value -128. Use RX_FLAG_NO_SIGNAL_VAL for such cases. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 49 +++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 3b47198239f9..6ad7d6196b2e 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -885,29 +885,49 @@ static int ath9k_process_rate(struct ath_common *common, static void ath9k_process_rssi(struct ath_common *common, struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats) + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = common->ah; int last_rssi; int rssi = rx_stats->rs_rssi; - if (!rx_stats->is_mybeacon || - ((ah->opmode != NL80211_IFTYPE_STATION) && - (ah->opmode != NL80211_IFTYPE_ADHOC))) + /* + * RSSI is not available for subframes in an A-MPDU. + */ + if (rx_stats->rs_moreaggr) { + rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; + return; + } + + /* + * Check if the RSSI for the last subframe in an A-MPDU + * or an unaggregated frame is valid. + */ + if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { + rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; return; + } - if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) + /* + * Update Beacon RSSI, this is used by ANI. + */ + if (rx_stats->is_mybeacon && + ((ah->opmode == NL80211_IFTYPE_STATION) || + (ah->opmode == NL80211_IFTYPE_ADHOC))) { ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); + last_rssi = sc->last_rssi; + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); + if (rssi < 0) + rssi = 0; - last_rssi = sc->last_rssi; - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); - if (rssi < 0) - rssi = 0; + ah->stats.avgbrssi = rssi; + } - /* Update Beacon RSSI, this is used by ANI. */ - ah->stats.avgbrssi = rssi; + rxs->signal = ah->noise + rx_stats->rs_rssi; } static void ath9k_process_tsf(struct ath_rx_status *rs, @@ -1149,15 +1169,12 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, goto exit; } - ath9k_process_rssi(common, hw, rx_stats); + ath9k_process_rssi(common, hw, rx_stats, rx_status); rx_status->band = hw->conf.chandef.chan->band; rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_END; - if (rx_stats->rs_moreaggr) - rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT if (ieee80211_is_data_present(hdr->frame_control) && -- cgit v1.2.3 From 009af8fb69c9d6274b3a49377be5ba2379e188d6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 21:15:55 +0530 Subject: ath9k: Identify first subframe in an A-MPDU Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 1 + drivers/net/wireless/ath/ath9k/mac.c | 4 ++-- drivers/net/wireless/ath/ath9k/mac.h | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 5163abd3937c..f6c5c1b50471 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -491,6 +491,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_rate = MS(rxsp->status1, AR_RxRate); rxs->rs_more = (rxsp->status2 & AR_RxMore) ? 1 : 0; + rxs->rs_firstaggr = (rxsp->status11 & AR_RxFirstAggr) ? 1 : 0; rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 2ef05ebffbcf..a3eff0986a3f 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -583,9 +583,9 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate); rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; + rs->rs_firstaggr = (ads.ds_rxstatus8 & AR_RxFirstAggr) ? 1 : 0; rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; - rs->rs_moreaggr = - (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; + rs->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); /* directly mapped flags for ieee80211_rx_status */ diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index b02dfce964b4..bfccaceed44e 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -140,6 +140,7 @@ struct ath_rx_status { int8_t rs_rssi_ext1; int8_t rs_rssi_ext2; u8 rs_isaggr; + u8 rs_firstaggr; u8 rs_moreaggr; u8 rs_num_delims; u8 rs_flags; @@ -569,6 +570,7 @@ struct ar5416_desc { #define AR_RxAggr 0x00020000 #define AR_PostDelimCRCErr 0x00040000 #define AR_RxStatusRsvd71 0x3ff80000 +#define AR_RxFirstAggr 0x20000000 #define AR_DecryptBusyErr 0x40000000 #define AR_KeyMiss 0x80000000 -- cgit v1.2.3 From c3124df7962f7a58177073d54d451e1661ffb71f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 21:15:56 +0530 Subject: ath9k: Optimize LNA check The documentation for antenna diversity says: "The decision of diversity is done at 802.11 preamble. So, for 11G/11B, for every MAC packet hardware will do a decision. But in 11N with aggregation, the decision is made only at the preamble and all other MPDUs will use the same LNA as the first MPDU." Make use of rs_firstaggr to avoid needlessly scanning for LNA changes. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 77 +++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6ad7d6196b2e..6161d148cd0c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1238,6 +1238,52 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common, rxs->flag &= ~RX_FLAG_DECRYPTED; } +/* + * Run the LNA combining algorithm only in these cases: + * + * Standalone WLAN cards with both LNA/Antenna diversity + * enabled in the EEPROM. + * + * WLAN+BT cards which are in the supported card list + * in ath_pci_id_table and the user has loaded the + * driver with "bt_ant_diversity" set to true. + */ +static void ath9k_antenna_check(struct ath_softc *sc, + struct ath_rx_status *rs) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) + return; + + /* + * All MPDUs in an aggregate will use the same LNA + * as the first MPDU. + */ + if (rs->rs_isaggr && !rs->rs_firstaggr) + return; + + /* + * Change the default rx antenna if rx diversity + * chooses the other antenna 3 times in a row. + */ + if (sc->rx.defant != rs->rs_antenna) { + if (++sc->rx.rxotherant >= 3) + ath_setdefantenna(sc, rs->rs_antenna); + } else { + sc->rx.rxotherant = 0; + } + + if (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV) { + if (common->bt_ant_diversity) + ath_ant_comb_scan(sc, rs); + } else { + ath_ant_comb_scan(sc, rs); + } +} + static void ath9k_apply_ampdu_details(struct ath_softc *sc, struct ath_rx_status *rs, struct ieee80211_rx_status *rxs) { @@ -1262,7 +1308,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb; struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hw *hw = sc->hw; int retval; @@ -1398,35 +1443,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ath_rx_ps(sc, skb, rs.is_mybeacon); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - /* - * Run the LNA combining algorithm only in these cases: - * - * Standalone WLAN cards with both LNA/Antenna diversity - * enabled in the EEPROM. - * - * WLAN+BT cards which are in the supported card list - * in ath_pci_id_table and the user has loaded the - * driver with "bt_ant_diversity" set to true. - */ - if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { - /* - * Change the default rx antenna if rx diversity - * chooses the other antenna 3 times in a row. - */ - if (sc->rx.defant != rs.rs_antenna) { - if (++sc->rx.rxotherant >= 3) - ath_setdefantenna(sc, rs.rs_antenna); - } else { - sc->rx.rxotherant = 0; - } - - if (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV) { - if (common->bt_ant_diversity) - ath_ant_comb_scan(sc, &rs); - } else { - ath_ant_comb_scan(sc, &rs); - } - } + ath9k_antenna_check(sc, &rs); ath9k_apply_ampdu_details(sc, &rs, rxs); -- cgit v1.2.3 From 5d07cca2128c214ea6029a6b65082e642ee7355e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 14 Aug 2013 21:15:57 +0530 Subject: ath9k: Use lockless variant to initialize RX fifo Since the rx_fifo queue is accessed only using the various lockless SKB queue routines, there is no need to initialize the lock and __skb_queue_head_init() can be used. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6161d148cd0c..653f7fc0647e 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -190,7 +190,7 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc) static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size) { - skb_queue_head_init(&rx_edma->rx_fifo); + __skb_queue_head_init(&rx_edma->rx_fifo); rx_edma->rx_fifo_hwsize = size; } -- cgit v1.2.3 From e5b417e73efa52b9179ce2a2b7676f08425c62e3 Mon Sep 17 00:00:00 2001 From: Mark Schulte Date: Wed, 31 Jul 2013 00:08:27 -0700 Subject: rtlwifi: sparse warnings: cast to restricted type Adding type casts to suppress sparse warnings: * warning: cast to restricted __le32/__le16 Signed-off-by: Mark Schulte Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/ps.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 298b615964e8..f646b7585d9b 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -688,7 +688,7 @@ static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, find_p2p_ie = true; /*to find noa ie*/ while (ie + 1 < end) { - noa_len = READEF2BYTE(&ie[1]); + noa_len = READEF2BYTE((__le16 *)&ie[1]); if (ie + 3 + ie[1] > end) return; @@ -717,13 +717,13 @@ static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, READEF1BYTE(ie+index); index += 1; p2pinfo->noa_duration[i] = - READEF4BYTE(ie+index); + READEF4BYTE((__le32 *)ie+index); index += 4; p2pinfo->noa_interval[i] = - READEF4BYTE(ie+index); + READEF4BYTE((__le32 *)ie+index); index += 4; p2pinfo->noa_start_time[i] = - READEF4BYTE(ie+index); + READEF4BYTE((__le32 *)ie+index); index += 4; } @@ -780,7 +780,7 @@ static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n"); /*to find noa ie*/ while (ie + 1 < end) { - noa_len = READEF2BYTE(&ie[1]); + noa_len = READEF2BYTE((__le16 *)&ie[1]); if (ie + 3 + ie[1] > end) return; @@ -809,13 +809,13 @@ static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, READEF1BYTE(ie+index); index += 1; p2pinfo->noa_duration[i] = - READEF4BYTE(ie+index); + READEF4BYTE((__le32 *)ie+index); index += 4; p2pinfo->noa_interval[i] = - READEF4BYTE(ie+index); + READEF4BYTE((__le32 *)ie+index); index += 4; p2pinfo->noa_start_time[i] = - READEF4BYTE(ie+index); + READEF4BYTE((__le32 *)ie+index); index += 4; } -- cgit v1.2.3 From 67d0cf50bd32b66eab709871714e55725ee30ce4 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 9 Aug 2013 13:36:21 -0400 Subject: brcmsmac: Fix WARNING caused by lack of calls to dma_mapping_error() The driver fails to check the results of DMA mapping in twp places, which results in the following warning: [ 28.078515] ------------[ cut here ]------------ [ 28.078529] WARNING: at lib/dma-debug.c:937 check_unmap+0x47e/0x930() [ 28.078533] bcma-pci-bridge 0000:0e:00.0: DMA-API: device driver failed to check map error[device address=0x00000000b5d60d6c] [size=1876 bytes] [mapped as single] [ 28.078536] Modules linked in: bnep bluetooth vboxpci(O) vboxnetadp(O) vboxnetflt(O) vboxdrv(O) ipv6 b43 brcmsmac rtl8192cu rtl8192c_common rtlwifi mac802 11 brcmutil cfg80211 snd_hda_codec_conexant rng_core snd_hda_intel kvm_amd snd_hda_codec ssb kvm mmc_core snd_pcm snd_seq snd_timer snd_seq_device snd k8temp cordic joydev serio_raw hwmon sr_mod sg pcmcia pcmcia_core soundcore cdrom i2c_nforce2 i2c_core forcedeth bcma snd_page_alloc autofs4 ext4 jbd2 mbcache crc1 6 scsi_dh_alua scsi_dh_hp_sw scsi_dh_rdac scsi_dh_emc scsi_dh ata_generic pata_amd [ 28.078602] CPU: 1 PID: 2570 Comm: NetworkManager Tainted: G O 3.10.0-rc7-wl+ #42 [ 28.078605] Hardware name: Hewlett-Packard HP Pavilion dv2700 Notebook PC/30D6, BIOS F.27 11/27/2008 [ 28.078607] 0000000000000009 ffff8800bbb03ad8 ffffffff8144f898 ffff8800bbb03b18 [ 28.078612] ffffffff8103e1eb 0000000000000002 ffff8800b719f480 ffff8800b7b9c010 [ 28.078617] ffffffff824204c0 ffffffff81754d57 0000000000000754 ffff8800bbb03b78 [ 28.078622] Call Trace: [ 28.078624] [] dump_stack+0x19/0x1b [ 28.078634] [] warn_slowpath_common+0x6b/0xa0 [ 28.078638] [] warn_slowpath_fmt+0x41/0x50 [ 28.078650] [] check_unmap+0x47e/0x930 [ 28.078655] [] debug_dma_unmap_page+0x5c/0x70 [ 28.078679] [] dma64_getnextrxp+0x10c/0x190 [brcmsmac] [ 28.078691] [] dma_rx+0x62/0x240 [brcmsmac] [ 28.078707] [] brcms_c_dpc+0x211/0x9d0 [brcmsmac] [ 28.078717] [] ? brcms_dpc+0x27/0xf0 [brcmsmac] [ 28.078731] [] brcms_dpc+0x47/0xf0 [brcmsmac] [ 28.078736] [] tasklet_action+0x6c/0xf0 --snip-- [ 28.078974] [] SyS_sendmsg+0xd/0x20 [ 28.078979] [] tracesys+0xdd/0xe2 [ 28.078982] ---[ end trace 6164d1a08148e9c8 ]--- [ 28.078984] Mapped at: [ 28.078985] [] debug_dma_map_page+0x9d/0x150 [ 28.078989] [] dma_rxfill+0x102/0x3d0 [brcmsmac] [ 28.079001] [] brcms_c_init+0x87d/0x1100 [brcmsmac] [ 28.079010] [] brcms_init+0x21/0x30 [brcmsmac] [ 28.079018] [] brcms_c_up+0x150/0x430 [brcmsmac] As the patch adds a new failure mechanism to dma_rxfill(). When I changed the comment at the start of the routine to add that information, I also polished the wording. Signed-off-by: Larry Finger Cc: Stable Cc: Brett Rudley Cc: Franky (Zhenhui) Lin Cc: Hante Meuleman Cc: brcm80211-dev-list@broadcom.com Acked-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/dma.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 1860c572b3c4..4fb9635d3919 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -1015,9 +1015,10 @@ static bool dma64_txidle(struct dma_info *di) /* * post receive buffers - * return false is refill failed completely and ring is empty this will stall - * the rx dma and user might want to call rxfill again asap. This unlikely - * happens on memory-rich NIC, but often on memory-constrained dongle + * Return false if refill failed completely or dma mapping failed. The ring + * is empty, which will stall the rx dma and user might want to call rxfill + * again asap. This is unlikely to happen on a memory-rich NIC, but often on + * memory-constrained dongle. */ bool dma_rxfill(struct dma_pub *pub) { @@ -1078,6 +1079,8 @@ bool dma_rxfill(struct dma_pub *pub) pa = dma_map_single(di->dmadev, p->data, di->rxbufsize, DMA_FROM_DEVICE); + if (dma_mapping_error(di->dmadev, pa)) + return false; /* save the free packet pointer */ di->rxp[rxout] = p; @@ -1284,7 +1287,11 @@ static void dma_txenq(struct dma_info *di, struct sk_buff *p) /* get physical address of buffer start */ pa = dma_map_single(di->dmadev, data, len, DMA_TO_DEVICE); - + /* if mapping failed, free skb */ + if (dma_mapping_error(di->dmadev, pa)) { + brcmu_pkt_buf_free_skb(p); + return; + } /* With a DMA segment list, Descriptor table is filled * using the segment list instead of looping over * buffers in multi-chain DMA. Therefore, EOF for SGLIST -- cgit v1.2.3 From 3571ac3370ef4e81ed5d60d810682c7b7bd95264 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 29 Jul 2013 17:08:48 +0300 Subject: iwlwifi: mvm: remove unused param of rs_dbgfs_set_mcs clean it up Signed-off-by: Eyal Shapira Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/rs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 5cb3132b8b37..9ae1bad8a359 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -161,10 +161,10 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); #ifdef CONFIG_MAC80211_DEBUGFS static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, - u32 *rate_n_flags, int index); + u32 *rate_n_flags); #else static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, - u32 *rate_n_flags, int index) + u32 *rate_n_flags) {} #endif @@ -2370,7 +2370,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; /* Override starting rate (index 0) if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); + rs_dbgfs_set_mcs(lq_sta, &new_rate); /* Interpret new_rate (rate_n_flags) */ rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, @@ -2417,7 +2417,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, } /* Override next rate if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); + rs_dbgfs_set_mcs(lq_sta, &new_rate); /* Fill next table entry */ lq_cmd->rs_table[index] = @@ -2459,7 +2459,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, use_ht_possible = 0; /* Override next rate if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); + rs_dbgfs_set_mcs(lq_sta, &new_rate); /* Fill next table entry */ lq_cmd->rs_table[index] = cpu_to_le32(new_rate); @@ -2504,7 +2504,7 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, #ifdef CONFIG_MAC80211_DEBUGFS static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, - u32 *rate_n_flags, int index) + u32 *rate_n_flags) { struct iwl_mvm *mvm; u8 valid_tx_ant; -- cgit v1.2.3 From 7abc4632bf1259a491188266a9aaa82ddeb55ff3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Aug 2013 18:28:26 +0200 Subject: iwlwifi: mvm: refactor resume from WoWLAN code To be able to add more logic to the resume code, refactor it a bit, moving some status checking/reporting logic into a new function. The locking becomes a bit odd (one of the new functions now unlocks the mutex) but this will be required to call new mac80211 APIs in there later. Reviewed-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/d3.c | 151 ++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index ebf7f9468926..ec07f0abbc6f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1104,73 +1104,16 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) return __iwl_mvm_suspend(hw, wowlan, false); } -static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_wowlan_status *status) { - u32 base = mvm->error_event_table; - struct error_table_start { - /* cf. struct iwl_error_event_table */ - u32 valid; - u32 error_id; - } err_info; + struct sk_buff *pkt = NULL; struct cfg80211_wowlan_wakeup wakeup = { .pattern_idx = -1, }; struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; - struct iwl_host_cmd cmd = { - .id = WOWLAN_GET_STATUSES, - .flags = CMD_SYNC | CMD_WANT_SKB, - }; - struct iwl_wowlan_status *status; - u32 reasons; - int ret, len; - struct sk_buff *pkt = NULL; - - iwl_trans_read_mem_bytes(mvm->trans, base, - &err_info, sizeof(err_info)); - - if (err_info.valid) { - IWL_INFO(mvm, "error table is valid (%d)\n", - err_info.valid); - if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { - wakeup.rfkill_release = true; - ieee80211_report_wowlan_wakeup(vif, &wakeup, - GFP_KERNEL); - } - return; - } - - /* only for tracing for now */ - ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); - if (ret) - IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); - - ret = iwl_mvm_send_cmd(mvm, &cmd); - if (ret) { - IWL_ERR(mvm, "failed to query status (%d)\n", ret); - return; - } - - /* RF-kill already asserted again... */ - if (!cmd.resp_pkt) - return; - - len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; - if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { - IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); - goto out; - } - - status = (void *)cmd.resp_pkt->data; - - if (len - sizeof(struct iwl_cmd_header) != - sizeof(*status) + - ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) { - IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); - goto out; - } - - reasons = le32_to_cpu(status->wakeup_reasons); + u32 reasons = le32_to_cpu(status->wakeup_reasons); if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { wakeup_report = NULL; @@ -1233,6 +1176,12 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, pktsize -= hdrlen; if (ieee80211_has_protected(hdr->frame_control)) { + /* + * This is unlocked and using gtk_i(c)vlen, + * but since everything is under RTNL still + * that's not really a problem - changing + * it would be difficult. + */ if (is_multicast_ether_addr(hdr->addr1)) { ivlen = mvm->gtk_ivlen; icvlen += mvm->gtk_icvlen; @@ -1283,9 +1232,82 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, report: ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); kfree_skb(pkt); +} - out: +/* releases the MVM mutex */ +static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + u32 base = mvm->error_event_table; + struct error_table_start { + /* cf. struct iwl_error_event_table */ + u32 valid; + u32 error_id; + } err_info; + struct iwl_host_cmd cmd = { + .id = WOWLAN_GET_STATUSES, + .flags = CMD_SYNC | CMD_WANT_SKB, + }; + struct iwl_wowlan_status *status; + int ret, len; + + iwl_trans_read_mem_bytes(mvm->trans, base, + &err_info, sizeof(err_info)); + + if (err_info.valid) { + IWL_INFO(mvm, "error table is valid (%d)\n", + err_info.valid); + if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { + struct cfg80211_wowlan_wakeup wakeup = { + .rfkill_release = true, + }; + ieee80211_report_wowlan_wakeup(vif, &wakeup, + GFP_KERNEL); + } + goto out_unlock; + } + + /* only for tracing for now */ + ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); + if (ret) + IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) { + IWL_ERR(mvm, "failed to query status (%d)\n", ret); + goto out_unlock; + } + + /* RF-kill already asserted again... */ + if (!cmd.resp_pkt) + goto out_unlock; + + len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { + IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); + goto out_free_resp; + } + + status = (void *)cmd.resp_pkt->data; + + if (len - sizeof(struct iwl_cmd_header) != + sizeof(*status) + + ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) { + IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); + goto out_free_resp; + } + + /* now we have all the data we need, unlock to avoid mac80211 issues */ + mutex_unlock(&mvm->mutex); + + iwl_mvm_report_wakeup_reasons(mvm, vif, status); + iwl_free_resp(&cmd); + return; + + out_free_resp: iwl_free_resp(&cmd); + out_unlock: + mutex_unlock(&mvm->mutex); } static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) @@ -1342,10 +1364,13 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) iwl_mvm_read_d3_sram(mvm); iwl_mvm_query_wakeup_reasons(mvm, vif); + /* has unlocked the mutex, so skip that */ + goto out; out_unlock: mutex_unlock(&mvm->mutex); + out: if (!test && vif) ieee80211_resume_disconnect(vif); -- cgit v1.2.3 From 66140adc22aacd95037ac9f89eeff61676d36cce Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 12 Aug 2013 19:30:21 +0300 Subject: iwlwifi: use a macro for default probe length Instead of assigning the default max probe length to 200 in the main code, create a macro for consistency and clarity. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-drv.c | 2 +- drivers/net/wireless/iwlwifi/iwl-fw.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index d0162d426f88..e88397bd95eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -843,7 +843,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) int i; bool load_module = false; - fw->ucode_capa.max_probe_length = 200; + fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; fw->ucode_capa.standard_phy_calibration_size = IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 1705d245dbe9..a1223680bc70 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -99,6 +99,9 @@ enum iwl_ucode_tlv_flag { #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 +/* The default max probe length if not specified by the firmware file */ +#define IWL_DEFAULT_MAX_PROBE_LENGTH 200 + /** * enum iwl_ucode_type * -- cgit v1.2.3 From 3b1995ad83709ac2e1e86c99b37d5ba9ce410f56 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 12 Aug 2013 21:58:36 +0300 Subject: iwlwifi: Kconfig: fix help texts wrt 7260 and 3160 devices Fix the help texts to properly reflect the 7260 and 3160 devices support. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/Kconfig | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index e5c133ee7901..3eb2102ce236 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -22,6 +22,8 @@ config IWLWIFI Intel Wireless WiFi Link 6150BGN 2 Adapter Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN) Intel 2000 Series Wi-Fi Adapters + Intel 7260 Wi-Fi Adapter + Intel 3160 Wi-Fi Adapter This driver uses the kernel's mac80211 subsystem. @@ -46,17 +48,16 @@ config IWLDVM depends on IWLWIFI default IWLWIFI help - This is the driver supporting the DVM firmware which is - currently the only firmware available for existing devices. + This is the driver that supports the DVM firmware which is + used by most existing devices (with the exception of 7260 + and 3160). config IWLMVM tristate "Intel Wireless WiFi MVM Firmware support" depends on IWLWIFI help - This is the driver supporting the MVM firmware which is - currently only available for 7000 series devices. - - Say yes if you have such a device. + This is the driver that supports the MVM firmware which is + currently only available for 7260 and 3160 devices. # don't call it _MODULE -- will confuse Kconfig/fixdep/... config IWLWIFI_OPMODE_MODULAR -- cgit v1.2.3 From eafe25e0afaf45a4e38f9b3560ac774a2395c695 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 13 Aug 2013 10:34:55 +0300 Subject: iwlwifi: return -ENOMEM instead of NULL when OOM in iwl_drv_start() The callers of iwl_drv_start() are probe functions. If a probe function returns 0, it means it succeeded. So if NULL was returned by iwl_drv_start(), it would be considered as a success. Fix this by returning -ENOMEM if the driver struct allocation fails in iwl_drv_start(). Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-drv.c | 8 +++++--- drivers/net/wireless/iwlwifi/pcie/drv.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index e88397bd95eb..99e1da3123c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1032,8 +1032,10 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, int ret; drv = kzalloc(sizeof(*drv), GFP_KERNEL); - if (!drv) - return NULL; + if (!drv) { + ret = -ENOMEM; + goto err; + } drv->trans = trans; drv->dev = trans->dev; @@ -1078,7 +1080,7 @@ err_free_dbgfs: err_free_drv: #endif kfree(drv); - +err: return ERR_PTR(ret); } diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index e179efeddc8d..567ef014c30a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -332,7 +332,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); trans_pcie->drv = iwl_drv_start(iwl_trans, cfg); - if (IS_ERR_OR_NULL(trans_pcie->drv)) { + if (IS_ERR(trans_pcie->drv)) { ret = PTR_ERR(trans_pcie->drv); goto out_free_trans; } -- cgit v1.2.3 From a20fd398666dbf5cdee3fe97722350cc10619c84 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Sun, 21 Jul 2013 17:23:59 +0300 Subject: iwlwifi: mvm: Implement CQM offloading Use beacon statistics notification to track RSSI. Notify mac80211 when the tresholds are crossed. The roaming treshold is configured to be equal to cqm_thold. If the beacon filtering command is not supported by fw fall back and use mac80211 mechanism. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 2 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 22 +++++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 20 +++++++++- drivers/net/wireless/iwlwifi/mvm/power.c | 37 +++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/rx.c | 61 ++++++++++++++++++++++++++++- 6 files changed, 133 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 14811a583d2b..c67b17aa7dfb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -920,7 +920,7 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, }; iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); - if (mvmvif->bf_enabled) + if (mvmvif->bf_data.bf_enabled) cmd.bf_enable_beacon_filter = cpu_to_le32(1); else cmd.bf_enable_beacon_filter = 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index b1047102ea47..66264cc5a016 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1321,7 +1321,7 @@ struct mvm_statistics_general { struct mvm_statistics_general_common common; __le32 beacon_filtered; __le32 missed_beacons; - __s8 beacon_filter_everage_energy; + __s8 beacon_filter_average_energy; __s8 beacon_filter_reason; __s8 beacon_filter_current_energy; __s8 beacon_filter_reserved; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 66803b99cca8..692d2ea211e8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -575,7 +575,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){ mvm->bf_allowed_vif = mvmvif; - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; } /* @@ -615,7 +616,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, out_free_bf: if (mvm->bf_allowed_vif == mvmvif) { mvm->bf_allowed_vif = NULL; - vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_CQM_RSSI); } out_remove_mac: mvmvif->phy_ctxt = NULL; @@ -681,7 +683,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, if (mvm->bf_allowed_vif == mvmvif) { mvm->bf_allowed_vif = NULL; - vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_CQM_RSSI); } iwl_mvm_vif_dbgfs_clean(mvm, vif); @@ -799,6 +802,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to update quotas\n"); } + + /* reset rssi values */ + mvmvif->bf_data.ave_beacon_signal = 0; + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD)) { /* Workaround for FW bug, otherwise FW disables device * power save upon disassociation @@ -825,6 +832,15 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, bss_conf->txpower); iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); } + + if (changes & BSS_CHANGED_CQM) { + IWL_DEBUG_MAC80211(mvm, "cqm info_changed"); + /* reset cqm events tracking */ + mvmvif->bf_data.last_cqm_event = 0; + ret = iwl_mvm_update_beacon_filter(mvm, vif); + if (ret) + IWL_ERR(mvm, "failed to update CQM thresholds\n"); + } } static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 014d77931c56..ee46dea69509 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -232,6 +232,21 @@ enum iwl_mvm_smps_type_request { NUM_IWL_MVM_SMPS_REQ, }; +/** +* struct iwl_mvm_vif_bf_data - beacon filtering related data +* @bf_enabled: indicates if beacon filtering is enabled +* @ba_enabled: indicated if beacon abort is enabled +* @last_beacon_signal: last beacon rssi signal in dbm +* @ave_beacon_signal: average beacon signal +* @last_cqm_event: rssi of the last cqm event +*/ +struct iwl_mvm_vif_bf_data { + bool bf_enabled; + bool ba_enabled; + s8 ave_beacon_signal; + s8 last_cqm_event; +}; + /** * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context * @id: between 0 and 3 @@ -257,8 +272,7 @@ struct iwl_mvm_vif { bool uploaded; bool ap_active; bool monitor_active; - /* indicate whether beacon filtering is enabled */ - bool bf_enabled; + struct iwl_mvm_vif_bf_data bf_data; u32 ap_beacon_time; @@ -758,6 +772,8 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, struct iwl_beacon_filter_cmd *cmd); int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool enable); +int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); /* SMPS */ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 9c9b5bafb577..a5529b85de8b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -110,6 +110,23 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, return ret; } +static +void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_beacon_filter_cmd *cmd) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (vif->bss_conf.cqm_rssi_thold) { + cmd->bf_energy_delta = + cpu_to_le32(vif->bss_conf.cqm_rssi_hyst); + /* fw uses an absolute value for this */ + cmd->bf_roaming_state = + cpu_to_le32(-vif->bss_conf.cqm_rssi_thold); + } + cmd->ba_enable_beacon_abort = cpu_to_le32(mvmvif->bf_data.ba_enabled); +} + int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool enable) { @@ -120,12 +137,14 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, .ba_enable_beacon_abort = cpu_to_le32(enable), }; - if (!mvmvif->bf_enabled) + if (!mvmvif->bf_data.bf_enabled) return 0; if (mvm->cur_ucode == IWL_UCODE_WOWLAN) cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); + mvmvif->bf_data.ba_enabled = enable; + iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); } @@ -510,11 +529,12 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; + iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); if (!ret) - mvmvif->bf_enabled = true; + mvmvif->bf_data.bf_enabled = true; return ret; } @@ -533,11 +553,22 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); if (!ret) - mvmvif->bf_enabled = false; + mvmvif->bf_data.bf_enabled = false; return ret; } +int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (!mvmvif->bf_data.bf_enabled) + return 0; + + return iwl_mvm_enable_beacon_filter(mvm, vif); +} + const struct iwl_mvm_power_ops pm_mac_ops = { .power_update_mode = iwl_mvm_power_mac_update_mode, .power_disable = iwl_mvm_power_mac_disable, diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index ee6547d22287..2a8cb5a60535 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -396,11 +396,62 @@ static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, memcpy(&mvm->rx_stats, &stats->rx, sizeof(struct mvm_statistics_rx)); } +struct iwl_mvm_stat_data { + struct iwl_notif_statistics *stats; + struct iwl_mvm *mvm; +}; + +static void iwl_mvm_stat_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_stat_data *data = _data; + struct iwl_notif_statistics *stats = data->stats; + struct iwl_mvm *mvm = data->mvm; + int sig = -stats->general.beacon_filter_average_energy; + int last_event; + int thold = vif->bss_conf.cqm_rssi_thold; + int hyst = vif->bss_conf.cqm_rssi_hyst; + u16 id = le32_to_cpu(stats->rx.general.mac_id); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (mvmvif->id != id) + return; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + mvmvif->bf_data.ave_beacon_signal = sig; + + if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) + return; + + /* CQM Notification */ + last_event = mvmvif->bf_data.last_cqm_event; + if (thold && sig < thold && (last_event == 0 || + sig < last_event - hyst)) { + mvmvif->bf_data.last_cqm_event = sig; + IWL_DEBUG_RX(mvm, "cqm_iterator cqm low %d\n", + sig); + ieee80211_cqm_rssi_notify( + vif, + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + GFP_KERNEL); + } else if (sig > thold && + (last_event == 0 || sig > last_event + hyst)) { + mvmvif->bf_data.last_cqm_event = sig; + IWL_DEBUG_RX(mvm, "cqm_iterator cqm high %d\n", + sig); + ieee80211_cqm_rssi_notify( + vif, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + GFP_KERNEL); + } +} + /* * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler * * TODO: This handler is implemented partially. - * It only gets the NIC's temperature. */ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, @@ -409,6 +460,10 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_notif_statistics *stats = (void *)&pkt->data; struct mvm_statistics_general_common *common = &stats->general.common; + struct iwl_mvm_stat_data data = { + .stats = stats, + .mvm = mvm, + }; if (mvm->temperature != le32_to_cpu(common->temperature)) { mvm->temperature = le32_to_cpu(common->temperature); @@ -416,5 +471,9 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, } iwl_mvm_update_rx_statistics(mvm, stats); + ieee80211_iterate_active_interfaces(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_stat_iterator, + &data); return 0; } -- cgit v1.2.3 From 89716344806bd49d213ad5960661e8c2d38c4982 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Sun, 4 Aug 2013 17:52:23 +0300 Subject: iwlwifi: mvm: Add PBW snoozing enablement The Performance Based Window snooze mechanism is based on uAPSD and is used in low-medium traffic scenarios, in order to provide better power performance while insuring low latency and jitter for the incoming traffic. This patch enables PBW snoozing in case uAPSD is enabled and all ACs are uAPSD trigger and delivery enabled. Signed-off-by: Alexander Bondar Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/constants.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 8 ++++++ drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 8 ++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/power.c | 35 +++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 33f98fc26e2d..2bf29f7992ee 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -73,5 +73,8 @@ #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 20 #define IWL_MVM_PS_HEAVY_TX_THLD_PERCENT 50 #define IWL_MVM_PS_HEAVY_RX_THLD_PERCENT 50 +#define IWL_MVM_PS_SNOOZE_INTERVAL 25 +#define IWL_MVM_PS_SNOOZE_WINDOW 50 +#define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index c67b17aa7dfb..2e60be2a7ee3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -352,6 +352,10 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val); dbgfs_pm->lprx_rssi_threshold = val; break; + case MVM_DEBUGFS_PM_SNOOZE_ENABLE: + IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val); + dbgfs_pm->snooze_ena = val; + break; } } @@ -405,6 +409,10 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file, POWER_LPRX_RSSI_THRESHOLD_MIN) return -EINVAL; param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD; + } else if (!strncmp("snooze_enable=", buf, 14)) { + if (sscanf(buf + 14, "%d", &val) != 1) + return -EINVAL; + param = MVM_DEBUGFS_PM_SNOOZE_ENABLE; } else { return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index bb010b323b0f..8e7ab41079ca 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -155,8 +155,12 @@ struct iwl_powertable_cmd { * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. * Default: 80dbm * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set - * @snooze_interval: TBD - * @snooze_window: TBD + * @snooze_interval: Maximum time between attempts to retrieve buffered data + * from the AP [msec] + * @snooze_window: A window of time in which PBW snoozing insures that all + * packets received. It is also the minimum time from last + * received unicast RX packet, before client stops snoozing + * for data. [msec] * @snooze_step: TBD * @qndp_tid: TID client shall use for uAPSD QNDP triggers * @uapsd_ac_flags: Set trigger-enabled and delivery-enabled indication for diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index ee46dea69509..0f33d7f20890 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -180,6 +180,7 @@ enum iwl_dbgfs_pm_mask { MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5), MVM_DEBUGFS_PM_LPRX_ENA = BIT(6), MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7), + MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8), }; struct iwl_dbgfs_pm { @@ -191,6 +192,7 @@ struct iwl_dbgfs_pm { bool disable_power_off; bool lprx_ena; u32 lprx_rssi_threshold; + bool snooze_ena; int mask; }; diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index a5529b85de8b..21407a353a3b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -301,6 +301,20 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT); cmd->tx_data_timeout_uapsd = cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT); + + if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) | + BIT(IEEE80211_AC_VI) | + BIT(IEEE80211_AC_BE) | + BIT(IEEE80211_AC_BK))) { + cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); + cmd->snooze_interval = + cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL); + cmd->snooze_window = + (mvm->cur_ucode == IWL_UCODE_WOWLAN) ? + cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) : + cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW); + } + cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP; cmd->heavy_tx_thld_packets = IWL_MVM_PS_HEAVY_TX_THLD_PACKETS; @@ -340,6 +354,14 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, } if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold; + if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SNOOZE_ENABLE) { + if (mvmvif->dbgfs_pm.snooze_ena) + cmd->flags |= + cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); + else + cmd->flags &= + cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK); + } #endif /* CONFIG_IWLWIFI_DEBUGFS */ } @@ -475,6 +497,19 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n", cmd.heavy_rx_thld_percentage); + pos += + scnprintf(buf+pos, bufsz-pos, "snooze_enable = %d\n", + (cmd.flags & + cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) ? + 1 : 0); + } + if (cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) { + pos += scnprintf(buf+pos, bufsz-pos, + "snooze_interval = %d\n", + cmd.snooze_interval); + pos += scnprintf(buf+pos, bufsz-pos, + "snooze_window = %d\n", + cmd.snooze_window); } } return pos; -- cgit v1.2.3 From 92367fe7f24159d6ba83276bc7a0f45c6f663837 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 14 Aug 2013 08:01:30 +0200 Subject: ath9k: always use SIFS times from OFDM for 5/10 MHz 5/10 MHz channels should always use SIFS times as defined in IEEE 802.11-2012 18.4.4 (OFDM PHY characteristics). This makes it compatible to ath5k, which does the same. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 151443bddbde..b3a6891fe3d7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1069,7 +1069,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 11; - sifstime *= 2; + sifstime = 32; ack_offset = 16; slottime = 13; } else if (IS_CHAN_QUARTER_RATE(chan)) { @@ -1079,7 +1079,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 22; - sifstime *= 4; + sifstime = 64; ack_offset = 32; slottime = 21; } else { @@ -1116,7 +1116,6 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ctstimeout += 48 - sifstime - ah->slottime; } - ath9k_hw_set_sifs_time(ah, sifstime); ath9k_hw_setslottime(ah, slottime); ath9k_hw_set_ack_timeout(ah, acktimeout); -- cgit v1.2.3 From 0671894f977b6f03b63fddc33743474f495db4eb Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Fri, 16 Aug 2013 10:46:04 +0200 Subject: ath9k: use chandef instead of channel_type To enable support for 5/10 MHz, some internal functions must be converted from using the (old) channel_type to chandef. This is a good chance to change all remaining occurences. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.c | 67 ++++++++++++++++----------- drivers/net/wireless/ath/ath9k/common.h | 3 +- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 5 +- drivers/net/wireless/ath/ath9k/init.c | 4 +- drivers/net/wireless/ath/ath9k/main.c | 8 ++-- drivers/net/wireless/ath/ath9k/rc.c | 4 +- 6 files changed, 51 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 344fdde1d7a3..d3063c21e16c 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -49,37 +49,40 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) } EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); -static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) +static u32 ath9k_get_extchanmode(struct cfg80211_chan_def *chandef) { u32 chanmode = 0; - switch (chan->band) { + switch (chandef->chan->band) { case IEEE80211_BAND_2GHZ: - switch (channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: chanmode = CHANNEL_G_HT20; break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_G_HT40PLUS; + case NL80211_CHAN_WIDTH_40: + if (chandef->center_freq1 > chandef->chan->center_freq) + chanmode = CHANNEL_G_HT40PLUS; + else + chanmode = CHANNEL_G_HT40MINUS; break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_G_HT40MINUS; + default: break; } break; case IEEE80211_BAND_5GHZ: - switch (channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: chanmode = CHANNEL_A_HT20; break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_A_HT40PLUS; + case NL80211_CHAN_WIDTH_40: + if (chandef->center_freq1 > chandef->chan->center_freq) + chanmode = CHANNEL_A_HT40PLUS; + else + chanmode = CHANNEL_A_HT40MINUS; break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_A_HT40MINUS; + default: break; } break; @@ -94,13 +97,12 @@ static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, * Update internal channel flags. */ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) + struct cfg80211_chan_def *chandef) { - ichan->channel = chan->center_freq; - ichan->chan = chan; + ichan->channel = chandef->chan->center_freq; + ichan->chan = chandef->chan; - if (chan->band == IEEE80211_BAND_2GHZ) { + if (chandef->chan->band == IEEE80211_BAND_2GHZ) { ichan->chanmode = CHANNEL_G; ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; } else { @@ -108,8 +110,22 @@ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; } - if (channel_type != NL80211_CHAN_NO_HT) - ichan->chanmode = ath9k_get_extchanmode(chan, channel_type); + switch (chandef->width) { + case NL80211_CHAN_WIDTH_5: + ichan->channelFlags |= CHANNEL_QUARTER; + break; + case NL80211_CHAN_WIDTH_10: + ichan->channelFlags |= CHANNEL_HALF; + break; + case NL80211_CHAN_WIDTH_20_NOHT: + break; + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_40: + ichan->chanmode = ath9k_get_extchanmode(chandef); + break; + default: + WARN_ON(1); + } } EXPORT_SYMBOL(ath9k_cmn_update_ichannel); @@ -125,8 +141,7 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, chan_idx = curchan->hw_value; channel = &ah->channels[chan_idx]; - ath9k_cmn_update_ichannel(channel, curchan, - cfg80211_get_chandef_type(&hw->conf.chandef)); + ath9k_cmn_update_ichannel(channel, &hw->conf.chandef); return channel; } diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 207d06995b15..e039bcbfbd79 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -44,8 +44,7 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type); + struct cfg80211_chan_def *chandef); struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, struct ath_hw *ah); int ath9k_cmn_count_streams(unsigned int chainmask, int max); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 5c1bec18c9e3..d44258172c0f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1203,16 +1203,13 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) { struct ieee80211_channel *curchan = hw->conf.chandef.chan; - enum nl80211_channel_type channel_type = - cfg80211_get_chandef_type(&hw->conf.chandef); int pos = curchan->hw_value; ath_dbg(common, CONFIG, "Set channel: %d MHz\n", curchan->center_freq); ath9k_cmn_update_ichannel(&priv->ah->channels[pos], - hw->conf.chandef.chan, - channel_type); + &hw->conf.chandef); if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { ath_err(common, "Unable to set channel\n"); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 3b56c2e7efe7..85015bf537c2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -726,13 +726,15 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; struct ath_hw *ah = sc->sc_ah; + struct cfg80211_chan_def chandef; int i; sband = &sc->sbands[band]; for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; ah->curchan = &ah->channels[chan->hw_value]; - ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20); + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); + ath9k_cmn_update_ichannel(ah->curchan, &chandef); ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true); } } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0bee105064bd..ba382a8c8b9a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1201,8 +1201,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { struct ieee80211_channel *curchan = hw->conf.chandef.chan; - enum nl80211_channel_type channel_type = - cfg80211_get_chandef_type(&conf->chandef); int pos = curchan->hw_value; int old_pos = -1; unsigned long flags; @@ -1210,8 +1208,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (ah->curchan) old_pos = ah->curchan - &ah->channels[0]; - ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n", - curchan->center_freq, channel_type); + ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", + curchan->center_freq, hw->conf.chandef.width); /* update survey stats for the old channel before switching */ spin_lock_irqsave(&common->cc_lock, flags); @@ -1219,7 +1217,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_irqrestore(&common->cc_lock, flags); ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], - curchan, channel_type); + &conf->chandef); /* * If the operating channel changes, change the survey in-use flags diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a3c4ca0c94bf..7e86abb98808 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1326,8 +1326,8 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, ath_rc_init(sc, priv_sta); ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, - "Operating HT Bandwidth changed to: %d\n", - cfg80211_get_chandef_type(&sc->hw->conf.chandef)); + "Operating Bandwidth changed to: %d\n", + sc->hw->conf.chandef.width); } } -- cgit v1.2.3 From f819c0e72951f9238c53d6b7675bbd7a82c78b83 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 14 Aug 2013 08:01:32 +0200 Subject: ath9k: report 5/10 MHz channels Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 653f7fc0647e..4ee472a5a4e4 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -852,6 +852,17 @@ static int ath9k_process_rate(struct ath_common *common, band = hw->conf.chandef.chan->band; sband = hw->wiphy->bands[band]; + switch (hw->conf.chandef.width) { + case NL80211_CHAN_WIDTH_5: + rxs->flag |= RX_FLAG_5MHZ; + break; + case NL80211_CHAN_WIDTH_10: + rxs->flag |= RX_FLAG_10MHZ; + break; + default: + break; + } + if (rx_stats->rs_rate & 0x80) { /* HT rate */ rxs->flag |= RX_FLAG_HT; -- cgit v1.2.3 From 67a5533015be005caff61ee9cae42920a54e3a9b Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 14 Aug 2013 08:01:33 +0200 Subject: ath9k: set 5/10 MHz supported channels and fix bitrate Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 24 ++++++++++++++++-------- drivers/net/wireless/ath/ath9k/rc.c | 5 +++++ 2 files changed, 21 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 85015bf537c2..6347378fc389 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -146,14 +146,22 @@ static struct ieee80211_rate ath9k_legacy_rates[] = { RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0x0b, 0), - RATE(90, 0x0f, 0), - RATE(120, 0x0a, 0), - RATE(180, 0x0e, 0), - RATE(240, 0x09, 0), - RATE(360, 0x0d, 0), - RATE(480, 0x08, 0), - RATE(540, 0x0c, 0), + RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), }; #ifdef CONFIG_MAC80211_LEDS diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 7e86abb98808..d3d7c51fa6c8 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1282,9 +1282,14 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_rate_priv *ath_rc_priv = priv_sta; int i, j = 0; + u32 rate_flags = ieee80211_chandef_rate_flags(&sc->hw->conf.chandef); for (i = 0; i < sband->n_bitrates; i++) { if (sta->supp_rates[sband->band] & BIT(i)) { + if ((rate_flags & sband->bitrates[i].flags) + != rate_flags) + continue; + ath_rc_priv->neg_rates.rs_rates[j] = (sband->bitrates[i].bitrate * 2) / 10; j++; -- cgit v1.2.3 From 6fac8bbcd5cd77ea561409c3c0ae16b4e7b9fc3e Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 14 Aug 2013 08:01:34 +0200 Subject: ath9k: announce that ath9k supports 5/10 MHz Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 6347378fc389..60bb4d6f1d82 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -860,6 +860,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; #ifdef CONFIG_PM_SLEEP if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && -- cgit v1.2.3 From 312a64435bda34bc7974140f8eb53a252b4ba4ed Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 14 Aug 2013 08:01:35 +0200 Subject: ath5k: report 5/10 MHz channels Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ce67ab791eae..260a6fce89b5 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1400,6 +1400,16 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, rxs->rate_idx = ath5k_hw_to_driver_rix(ah, rs->rs_rate); rxs->flag |= ath5k_rx_decrypted(ah, skb, rs); + switch (ah->ah_bwmode) { + case AR5K_BWMODE_5MHZ: + rxs->flag |= RX_FLAG_5MHZ; + break; + case AR5K_BWMODE_10MHZ: + rxs->flag |= RX_FLAG_10MHZ; + break; + default: + break; + } if (rxs->rate_idx >= 0 && rs->rs_rate == ah->sbands[ah->curchan->band].bitrates[rxs->rate_idx].hw_value_short) -- cgit v1.2.3 From 6a09ae95ed248d6d946407bb1f955e5f2624663d Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 14 Aug 2013 08:01:36 +0200 Subject: ath5k: set 5/10 MHz supported channels and fix duration Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 24 ++++++++++++++++-------- drivers/net/wireless/ath/ath5k/pcu.c | 2 ++ drivers/net/wireless/ath/ath5k/qcu.c | 25 ++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 260a6fce89b5..7c298af35d42 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -165,28 +165,36 @@ static const struct ieee80211_rate ath5k_rates[] = { .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 60, .hw_value = ATH5K_RATE_CODE_6M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 90, .hw_value = ATH5K_RATE_CODE_9M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 120, .hw_value = ATH5K_RATE_CODE_12M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 180, .hw_value = ATH5K_RATE_CODE_18M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 240, .hw_value = ATH5K_RATE_CODE_24M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 360, .hw_value = ATH5K_RATE_CODE_36M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 480, .hw_value = ATH5K_RATE_CODE_48M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 540, .hw_value = ATH5K_RATE_CODE_54M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, }; static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 1f16b4227d8f..c60d36aa13e2 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -144,11 +144,13 @@ ath5k_hw_get_frame_duration(struct ath5k_hw *ah, enum ieee80211_band band, sifs = AR5K_INIT_SIFS_HALF_RATE; preamble *= 2; sym_time *= 2; + bitrate = DIV_ROUND_UP(bitrate, 2); break; case AR5K_BWMODE_5MHZ: sifs = AR5K_INIT_SIFS_QUARTER_RATE; preamble *= 4; sym_time *= 4; + bitrate = DIV_ROUND_UP(bitrate, 4); break; default: sifs = AR5K_INIT_SIFS_DEFAULT_BG; diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 65fe929529a8..0583c69d26db 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -566,9 +566,11 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) { struct ieee80211_channel *channel = ah->ah_current_channel; enum ieee80211_band band; + struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock; u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); + u32 rate_flags, i; if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX) return -EINVAL; @@ -605,7 +607,28 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) else band = IEEE80211_BAND_2GHZ; - rate = &ah->sbands[band].bitrates[0]; + switch (ah->ah_bwmode) { + case AR5K_BWMODE_5MHZ: + rate_flags = IEEE80211_RATE_SUPPORTS_5MHZ; + break; + case AR5K_BWMODE_10MHZ: + rate_flags = IEEE80211_RATE_SUPPORTS_10MHZ; + break; + default: + rate_flags = 0; + break; + } + sband = &ah->sbands[band]; + rate = NULL; + for (i = 0; i < sband->n_bitrates; i++) { + if ((rate_flags & sband->bitrates[i].flags) != rate_flags) + continue; + rate = &sband->bitrates[i]; + break; + } + if (WARN_ON(!rate)) + return -EINVAL; + ack_tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, false); /* ack_tx_time includes an SIFS already */ -- cgit v1.2.3 From 4d70f2fbe12118c5526a1d761f8ef562cecbbc2c Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 14 Aug 2013 08:01:37 +0200 Subject: ath5k: enable support for 5 MHz and 10 MHz channels Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/base.c | 25 ++++++++++++++++++++++--- drivers/net/wireless/ath/ath5k/base.h | 2 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 2d691b8b95b9..74bd54d6aceb 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -29,6 +29,7 @@ #include #include #include +#include /* RX/TX descriptor hw structs * TODO: Driver part should only see sw structs */ diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7c298af35d42..48161edec8de 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -56,6 +56,7 @@ #include #include +#include #include #include @@ -443,11 +444,27 @@ ath5k_setup_bands(struct ieee80211_hw *hw) * Called with ah->lock. */ int -ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan) +ath5k_chan_set(struct ath5k_hw *ah, struct cfg80211_chan_def *chandef) { ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "channel set, resetting (%u -> %u MHz)\n", - ah->curchan->center_freq, chan->center_freq); + ah->curchan->center_freq, chandef->chan->center_freq); + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_20_NOHT: + ah->ah_bwmode = AR5K_BWMODE_DEFAULT; + break; + case NL80211_CHAN_WIDTH_5: + ah->ah_bwmode = AR5K_BWMODE_5MHZ; + break; + case NL80211_CHAN_WIDTH_10: + ah->ah_bwmode = AR5K_BWMODE_10MHZ; + break; + default: + WARN_ON(1); + return -EINVAL; + } /* * To switch channels clear any pending DMA operations; @@ -455,7 +472,7 @@ ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan) * hardware at the new frequency, and then re-enable * the relevant bits of the h/w. */ - return ath5k_reset(ah, chan, true); + return ath5k_reset(ah, chandef->chan, true); } void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) @@ -2525,6 +2542,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) /* SW support for IBSS_RSN is provided by mac80211 */ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; + /* both antennas can be configured as RX or TX */ hw->wiphy->available_antennas_tx = 0x3; hw->wiphy->available_antennas_rx = 0x3; diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index ca9a83ceeee1..97469d0fbad7 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -101,7 +101,7 @@ void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable); void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, struct ieee80211_vif *vif); -int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan); +int ath5k_chan_set(struct ath5k_hw *ah, struct cfg80211_chan_def *chandef); void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 40825d43322e..4ee01f654235 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -202,7 +202,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&ah->lock); if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ret = ath5k_chan_set(ah, conf->chandef.chan); + ret = ath5k_chan_set(ah, &conf->chandef); if (ret < 0) goto unlock; } -- cgit v1.2.3 From d074e8d547853cc8b40cf93a460e8fbf9eaa3d00 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 14 Aug 2013 08:01:38 +0200 Subject: ath9k: enable CSA functionality in ath9k CSA is only enabled for one interface, but the same limitation applies for mac80211 too. It checks whether the beacon has been sent (different approaches for non-EDMA-enabled and EDMA-enabled devices), and completes the channel switch after that. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/beacon.c | 21 +++++++++++++++++++++ drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/main.c | 17 +++++++++++++++++ drivers/net/wireless/ath/ath9k/xmit.c | 2 ++ 5 files changed, 43 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index df1c4957e3f0..8519e75a2e79 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -420,6 +420,7 @@ 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); +bool ath9k_csa_is_finished(struct ath_softc *sc); /*******************/ /* Link Monitoring */ @@ -756,6 +757,7 @@ struct ath_softc { #endif struct ath_descdma txsdma; + struct ieee80211_vif *csa_vif; struct ath_ant_comb ant_comb; u8 ant_tx, ant_rx; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 1a17732bb089..b5c16b3a37b9 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -291,6 +291,23 @@ void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) (unsigned long long)tsfadjust, avp->av_bslot); } +bool ath9k_csa_is_finished(struct ath_softc *sc) +{ + struct ieee80211_vif *vif; + + vif = sc->csa_vif; + if (!vif || !vif->csa_active) + return false; + + if (!ieee80211_csa_is_complete(vif)) + return false; + + ieee80211_csa_finish(vif); + + sc->csa_vif = NULL; + return true; +} + void ath9k_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -336,6 +353,10 @@ void ath9k_beacon_tasklet(unsigned long data) return; } + /* EDMA devices check that in the tx completion function. */ + if (!edma && ath9k_csa_is_finished(sc)) + return; + slot = ath9k_beacon_choose_slot(sc); vif = sc->beacon.bslot[slot]; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 60bb4d6f1d82..abf1eb5d97ad 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -861,6 +861,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; + hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; #ifdef CONFIG_PM_SLEEP if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ba382a8c8b9a..ac9f18fa0729 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1032,6 +1032,9 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, if (ath9k_uses_beacons(vif->type)) ath9k_beacon_remove_slot(sc, vif); + if (sc->csa_vif == vif) + sc->csa_vif = NULL; + ath9k_ps_wakeup(sc); ath9k_calculate_summary_state(hw, NULL); ath9k_ps_restore(sc); @@ -2318,6 +2321,19 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) clear_bit(SC_OP_SCANNING, &sc->sc_flags); } +static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct ath_softc *sc = hw->priv; + + /* mac80211 does not support CSA in multi-if cases (yet) */ + if (WARN_ON(sc->csa_vif)) + return; + + sc->csa_vif = vif; +} + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2365,4 +2381,5 @@ struct ieee80211_ops ath9k_ops = { #endif .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, + .channel_switch_beacon = ath9k_channel_switch_beacon, }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 7223e303f3a1..35b515fe3ffa 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2559,6 +2559,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) if (ts.qid == sc->beacon.beaconq) { sc->beacon.tx_processed = true; sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); + + ath9k_csa_is_finished(sc); continue; } -- cgit v1.2.3 From ae1b1c5dcdef1ebd4b37a7d56ad767add757a660 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 16 Aug 2013 10:23:29 +0200 Subject: rt2x00: rt2800lib: introduce rt2800_get_txwi_rxwi_size helper The rt2800pci driver uses the same [RT]XWI size for all chipsets, however some chips requires different values. The size of the [RT]XWI structures is a constant value for a given chipset and it does not depend on the underlying interface. Add a helper function which returns the correct values for the actual chipset and use the new helper both in the rt2800usb and in the rt2800pci drivers. This ensures that both drivers are using the correct values. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 23 +++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.h | 4 ++++ drivers/net/wireless/rt2x00/rt2800pci.c | 11 ++++++++--- drivers/net/wireless/rt2x00/rt2800usb.c | 11 +---------- 4 files changed, 36 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index dedc3d4ae365..313da6ac2ee4 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -521,6 +521,29 @@ void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2800_disable_wpdma); +void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev, + unsigned short *txwi_size, + unsigned short *rxwi_size) +{ + switch (rt2x00dev->chip.rt) { + case RT3593: + *txwi_size = TXWI_DESC_SIZE_4WORDS; + *rxwi_size = RXWI_DESC_SIZE_5WORDS; + break; + + case RT5592: + *txwi_size = TXWI_DESC_SIZE_5WORDS; + *rxwi_size = RXWI_DESC_SIZE_6WORDS; + break; + + default: + *txwi_size = TXWI_DESC_SIZE_4WORDS; + *rxwi_size = RXWI_DESC_SIZE_4WORDS; + break; + } +} +EXPORT_SYMBOL_GPL(rt2800_get_txwi_rxwi_size); + static bool rt2800_check_firmware_crc(const u8 *data, const size_t len) { u16 fw_crc; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 6ec739466db4..a94ba447e63c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -226,4 +226,8 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev); +void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev, + unsigned short *txwi_size, + unsigned short *rxwi_size); + #endif /* RT2800LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 00055627eb8d..dcad90c80542 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1189,12 +1189,17 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { static void rt2800pci_queue_init(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; + unsigned short txwi_size, rxwi_size; + + rt2800_get_txwi_rxwi_size(rt2x00dev, &txwi_size, &rxwi_size); + switch (queue->qid) { case QID_RX: queue->limit = 128; queue->data_size = AGGREGATION_SIZE; queue->desc_size = RXD_DESC_SIZE; - queue->winfo_size = RXWI_DESC_SIZE_4WORDS; + queue->winfo_size = rxwi_size; queue->priv_size = sizeof(struct queue_entry_priv_mmio); break; @@ -1205,7 +1210,7 @@ static void rt2800pci_queue_init(struct data_queue *queue) queue->limit = 64; queue->data_size = AGGREGATION_SIZE; queue->desc_size = TXD_DESC_SIZE; - queue->winfo_size = TXWI_DESC_SIZE_4WORDS; + queue->winfo_size = txwi_size; queue->priv_size = sizeof(struct queue_entry_priv_mmio); break; @@ -1213,7 +1218,7 @@ static void rt2800pci_queue_init(struct data_queue *queue) queue->limit = 8; queue->data_size = 0; /* No DMA required for beacons */ queue->desc_size = TXD_DESC_SIZE; - queue->winfo_size = TXWI_DESC_SIZE_4WORDS; + queue->winfo_size = txwi_size; queue->priv_size = sizeof(struct queue_entry_priv_mmio); break; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index fc9efdfca8f2..338034e18243 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -854,16 +854,7 @@ static void rt2800usb_queue_init(struct data_queue *queue) struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; unsigned short txwi_size, rxwi_size; - if (rt2x00_rt(rt2x00dev, RT3593)) { - txwi_size = TXWI_DESC_SIZE_4WORDS; - rxwi_size = RXWI_DESC_SIZE_5WORDS; - } else if (rt2x00_rt(rt2x00dev, RT5592)) { - txwi_size = TXWI_DESC_SIZE_5WORDS; - rxwi_size = RXWI_DESC_SIZE_6WORDS; - } else { - txwi_size = TXWI_DESC_SIZE_4WORDS; - rxwi_size = RXWI_DESC_SIZE_4WORDS; - } + rt2800_get_txwi_rxwi_size(rt2x00dev, &txwi_size, &rxwi_size); switch (queue->qid) { case QID_RX: -- cgit v1.2.3 From 41caa760d6acaf47cbd44c3d78307fb9be089111 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 16 Aug 2013 10:23:30 +0200 Subject: rt2x00: rt2800pci: fix AUX_CTRL register setup for RT3090/3390/3593/5592 The 2011_1007_RT5390_RT5392_Linux_STA_V2.5.0.3_DPO driver enables PCIe wakeup for these chips as well. Do the same in rt2x00. References: rt28xx_init in common/rtmp_init_intf.c RTMPInitPCIeLinkCtrlValue in os/linux/rt_rbus_pci_drv.c Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index dcad90c80542..f8f2abbfbb65 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -507,9 +507,13 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); if (rt2x00_is_pcie(rt2x00dev) && - (rt2x00_rt(rt2x00dev, RT3572) || + (rt2x00_rt(rt2x00dev, RT3090) || + rt2x00_rt(rt2x00dev, RT3390) || + rt2x00_rt(rt2x00dev, RT3572) || + rt2x00_rt(rt2x00dev, RT3593) || rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392))) { + rt2x00_rt(rt2x00dev, RT5392) || + rt2x00_rt(rt2x00dev, RT5592))) { rt2x00mmio_register_read(rt2x00dev, AUX_CTRL, ®); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); -- cgit v1.2.3 From 91a3fa39ddf2f85a15cb20ccc3a54c1f0497af1e Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 17 Aug 2013 00:15:49 +0200 Subject: rt2x00: rt2800: rename HW_BEACON_OFFSET macro The name of the HW_BEACON_OFFSET macro is a bit confusing. It returns with one of the HW_BEACON_BASE* values, so rename the macro to HW_BEACON_BASE to reflect that. The patch contains no functional changes. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 2 +- drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index a3132414ac9f..6e69b961909f 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2019,7 +2019,7 @@ struct mac_iveiv_entry { #define HW_BEACON_BASE6 0x5dc0 #define HW_BEACON_BASE7 0x5bc0 -#define HW_BEACON_OFFSET(__index) \ +#define HW_BEACON_BASE(__index) \ (((__index) < 4) ? (HW_BEACON_BASE0 + (__index * 0x0200)) : \ (((__index) < 6) ? (HW_BEACON_BASE4 + ((__index - 4) * 0x0200)) : \ (HW_BEACON_BASE6 - ((__index - 6) * 0x0200)))) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 313da6ac2ee4..704fcfbca06b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -992,7 +992,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) return; } - beacon_base = HW_BEACON_OFFSET(entry->entry_idx); + beacon_base = HW_BEACON_BASE(entry->entry_idx); rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, entry->skb->len + padding_len); @@ -1042,7 +1042,7 @@ void rt2800_clear_beacon(struct queue_entry *entry) * Clear beacon. */ rt2800_clear_beacon_register(rt2x00dev, - HW_BEACON_OFFSET(entry->entry_idx)); + HW_BEACON_BASE(entry->entry_idx)); /* * Enabled beaconing again. -- cgit v1.2.3 From 77f7c0f3b8f2d464e841c5c35f3da8b4999a885c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 17 Aug 2013 00:15:50 +0200 Subject: rt2x00: rt2800lib: pass beacon index to rt2800_clear_beacon_register Instead of precomputing the beacon base in each caller, pass the beacon index to the 'rt2800_clear_beacon_register' function and compute the beacon base in there. This allows to simplify the caller functions a bit. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 704fcfbca06b..2f64034606b0 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1011,10 +1011,13 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) EXPORT_SYMBOL_GPL(rt2800_write_beacon); static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev, - unsigned int beacon_base) + unsigned int index) { int i; const int txwi_desc_size = rt2x00dev->bcn->winfo_size; + unsigned int beacon_base; + + beacon_base = HW_BEACON_BASE(index); /* * For the Beacon base registers we only need to clear @@ -1041,8 +1044,7 @@ void rt2800_clear_beacon(struct queue_entry *entry) /* * Clear beacon. */ - rt2800_clear_beacon_register(rt2x00dev, - HW_BEACON_BASE(entry->entry_idx)); + rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx); /* * Enabled beaconing again. @@ -4803,14 +4805,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) /* * Clear all beacons */ - rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE0); - rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE1); - rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE2); - rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE3); - rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE4); - rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE5); - rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE6); - rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE7); + for (i = 0; i < 8; i++) + rt2800_clear_beacon_register(rt2x00dev, i); if (rt2x00_is_usb(rt2x00dev)) { rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); -- cgit v1.2.3 From c1fada4e5e53d88a8edd3ff01cee9d316cbf6025 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 17 Aug 2013 14:09:28 +0200 Subject: rt2x00: rt2800lib: fix frequency offset boundary calculation The current code in the 'rt2800_adjust_freq_offset' function limits the device specific frequency offset value to FREQ_BOUND but ignores the fact that the uppermost bit is not part of the frequency offset value. As the result, the driver always uses the FREQ_BOUND value if the uppermost bit is set. Update the code to use the correct source value for calculating the boundary. Based on the DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: RTMPAdjustFrequencyOffset function in common/rt_rf.c Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 2f64034606b0..de2727774477 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2496,13 +2496,14 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev) { + u8 freq_offset; u8 rfcsr; + freq_offset = rt2x00_get_field8(rt2x00dev->freq_offset, RFCSR17_CODE); + freq_offset = min_t(u8, freq_offset, FREQ_OFFSET_BOUND); + rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); - if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND) - rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND); - else - rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, freq_offset); rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); } -- cgit v1.2.3 From 6af1bdccabe956a08a37f2ae049d37307ec0c91c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 17 Aug 2013 14:09:29 +0200 Subject: rt2x00: rt2800lib: optimize frequency offset adjustment Don't write the new value into the register if it is the same as the old value to avoid unncessary USB bus traffic with USB devices. The change also saves a few cycle on MMIO based devices. Based on the DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: RTMPAdjustFrequencyOffset function in common/rt_rf.c Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index de2727774477..3407ac911fd6 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2497,13 +2497,18 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev) { u8 freq_offset; - u8 rfcsr; + u8 rfcsr, prev_rfcsr; freq_offset = rt2x00_get_field8(rt2x00dev->freq_offset, RFCSR17_CODE); freq_offset = min_t(u8, freq_offset, FREQ_OFFSET_BOUND); rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + prev_rfcsr = rfcsr; + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, freq_offset); + if (rfcsr == prev_rfcsr) + return; + rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); } -- cgit v1.2.3 From 76773f301f2210dcc20c466aebda7118062673eb Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 17 Aug 2013 14:09:30 +0200 Subject: rt2x00: rt2800lib: use a MCU command for frequency adjustment on USB devices According to the Ralink driver, there is an MCU command which can be used to send the frequency offset value directly to the USB device without going through the RFCSR writing sequence. Based on the DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: RTMPAdjustFrequencyOffset function in common/rt_rf.c Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 1 + drivers/net/wireless/rt2x00/rt2800lib.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 6e69b961909f..e25e5bf34aa7 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2794,6 +2794,7 @@ enum rt2800_eeprom_word { #define MCU_RADAR 0x60 #define MCU_BOOT_SIGNAL 0x72 #define MCU_ANT_SELECT 0X73 +#define MCU_FREQ_OFFSET 0x74 #define MCU_BBP_SIGNAL 0x80 #define MCU_POWER_SAVE 0x83 #define MCU_BAND_SELECT 0x91 diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3407ac911fd6..bebc56f5b849 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2509,7 +2509,11 @@ static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev) if (rfcsr == prev_rfcsr) return; - rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); + if (rt2x00_is_usb(rt2x00dev)) + rt2800_mcu_request(rt2x00dev, MCU_FREQ_OFFSET, 0xff, + freq_offset, prev_rfcsr); + else + rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); } static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, -- cgit v1.2.3 From 8d38eca8e089179b6858ca5f3ea03f571a5892a5 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 17 Aug 2013 14:09:31 +0200 Subject: rt2x00: rt2800lib: use step-by-step frequency offset adjustment on MMIO devices According to the DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver, the RFCSR17 register can't be programmed in one step on devices which are using the frequency offset adjustment code. Update the code to use step-by-step adjustment. Reference: RT30xxWriteRFRegister function in common/rt_rf.c Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index bebc56f5b849..623ad9d21ee5 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2496,7 +2496,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev) { - u8 freq_offset; + u8 freq_offset, prev_freq_offset; u8 rfcsr, prev_rfcsr; freq_offset = rt2x00_get_field8(rt2x00dev->freq_offset, RFCSR17_CODE); @@ -2509,11 +2509,24 @@ static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev) if (rfcsr == prev_rfcsr) return; - if (rt2x00_is_usb(rt2x00dev)) + if (rt2x00_is_usb(rt2x00dev)) { rt2800_mcu_request(rt2x00dev, MCU_FREQ_OFFSET, 0xff, freq_offset, prev_rfcsr); - else + return; + } + + prev_freq_offset = rt2x00_get_field8(prev_rfcsr, RFCSR17_CODE); + while (prev_freq_offset != freq_offset) { + if (prev_freq_offset < freq_offset) + prev_freq_offset++; + else + prev_freq_offset--; + + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, prev_freq_offset); rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); + + usleep_range(1000, 1500); + } } static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, -- cgit v1.2.3 From 3f1b8739a498c7570ca2fae6c49fd1561ef2358c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 17 Aug 2013 14:09:32 +0200 Subject: rt2x00: rt2800lib: move rt2800_adjust_freq_offset function Move the rt2800_adjust_freq_offset function before the channel configuration functions to make it usable from those without a forward declaration. The patch contains no functional changes. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 73 +++++++++++++++++---------------- 1 file changed, 37 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 623ad9d21ee5..1b81fc933f28 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1875,6 +1875,43 @@ static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev, rt2x00dev->lna_gain = lna_gain; } +#define FREQ_OFFSET_BOUND 0x5f + +static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev) +{ + u8 freq_offset, prev_freq_offset; + u8 rfcsr, prev_rfcsr; + + freq_offset = rt2x00_get_field8(rt2x00dev->freq_offset, RFCSR17_CODE); + freq_offset = min_t(u8, freq_offset, FREQ_OFFSET_BOUND); + + rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + prev_rfcsr = rfcsr; + + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, freq_offset); + if (rfcsr == prev_rfcsr) + return; + + if (rt2x00_is_usb(rt2x00dev)) { + rt2800_mcu_request(rt2x00dev, MCU_FREQ_OFFSET, 0xff, + freq_offset, prev_rfcsr); + return; + } + + prev_freq_offset = rt2x00_get_field8(prev_rfcsr, RFCSR17_CODE); + while (prev_freq_offset != freq_offset) { + if (prev_freq_offset < freq_offset) + prev_freq_offset++; + else + prev_freq_offset--; + + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, prev_freq_offset); + rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); + + usleep_range(1000, 1500); + } +} + static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, struct rf_channel *rf, @@ -2492,42 +2529,6 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, #define POWER_BOUND 0x27 #define POWER_BOUND_5G 0x2b -#define FREQ_OFFSET_BOUND 0x5f - -static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev) -{ - u8 freq_offset, prev_freq_offset; - u8 rfcsr, prev_rfcsr; - - freq_offset = rt2x00_get_field8(rt2x00dev->freq_offset, RFCSR17_CODE); - freq_offset = min_t(u8, freq_offset, FREQ_OFFSET_BOUND); - - rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); - prev_rfcsr = rfcsr; - - rt2x00_set_field8(&rfcsr, RFCSR17_CODE, freq_offset); - if (rfcsr == prev_rfcsr) - return; - - if (rt2x00_is_usb(rt2x00dev)) { - rt2800_mcu_request(rt2x00dev, MCU_FREQ_OFFSET, 0xff, - freq_offset, prev_rfcsr); - return; - } - - prev_freq_offset = rt2x00_get_field8(prev_rfcsr, RFCSR17_CODE); - while (prev_freq_offset != freq_offset) { - if (prev_freq_offset < freq_offset) - prev_freq_offset++; - else - prev_freq_offset--; - - rt2x00_set_field8(&rfcsr, RFCSR17_CODE, prev_freq_offset); - rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); - - usleep_range(1000, 1500); - } -} static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, -- cgit v1.2.3 From e979a8ab204edbf7b0815162109ee9c85e4d7ea5 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 17 Aug 2013 14:09:33 +0200 Subject: rt2x00: rt2800lib: adjust frequency offset for RF3053 Along with other chipsets, the Ralink driver uses the frequency adjustment code for RF3053 as well. Remove the bogus place-holder comment from the RF3053 specific channel configuration function and call the frequency adjustment function instead Based on the DPO_RT5572_LinuxSTA_2.6.0.1_20120629 driver. Reference: RT3593_ChipSwitchChannel function in chips/rt3593.c Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 1b81fc933f28..aa6b6b022547 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2360,7 +2360,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - /* TODO: frequency calibration? */ + rt2800_adjust_freq_offset(rt2x00dev); if (conf_is_ht40(conf)) { txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw40, -- cgit v1.2.3 From fb5a2dcbbcf19f8ff7e5312b2340460bc03a4b89 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 19 Aug 2013 11:03:43 +0530 Subject: ath9k: Add support for AR9485 1.2 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 18 +++++++++--------- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 2 +- drivers/net/wireless/ath/ath9k/reg.h | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index d402cb32283f..738aa7e454d8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -153,7 +153,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) if (!ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, ar9340_1p0_radio_core_40M); - } else if (AR_SREV_9485_11(ah)) { + } else if (AR_SREV_9485_11_OR_LATER(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9485_1_1_mac_core); @@ -424,7 +424,7 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_lowest_ob_db_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1); else if (AR_SREV_9550(ah)) @@ -458,7 +458,7 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_high_ob_db_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_ob_db_tx_gain_1_1); else if (AR_SREV_9580(ah)) @@ -492,7 +492,7 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_low_ob_db_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_low_ob_db_tx_gain_1_1); else if (AR_SREV_9580(ah)) @@ -517,7 +517,7 @@ static void ar9003_tx_gain_table_mode3(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_high_power_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_power_tx_gain_1_1); else if (AR_SREV_9580(ah)) @@ -552,7 +552,7 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) static void ar9003_tx_gain_table_mode5(struct ath_hw *ah) { - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_green_ob_db_tx_gain_1_1); else if (AR_SREV_9340(ah)) @@ -571,7 +571,7 @@ static void ar9003_tx_gain_table_mode6(struct ath_hw *ah) if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_green_spur_ob_db_tx_gain_1_1); else if (AR_SREV_9580(ah)) @@ -611,7 +611,7 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9340Common_rx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485_common_rx_gain_1_1); else if (AR_SREV_9550(ah)) { @@ -644,7 +644,7 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9340Common_wo_xlna_rx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485Common_wo_xlna_rx_gain_1_1); else if (AR_SREV_9462_21(ah)) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 18a5aa4fe406..46b910a857d9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1449,7 +1449,7 @@ static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S; REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); - if (AR_SREV_9485_11(ah)) { + if (AR_SREV_9485_11_OR_LATER(ah)) { /* * Enable LNA diversity. */ diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 5af97442ac37..a13b2d143d9e 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -893,9 +893,9 @@ #define AR_SREV_9485(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) -#define AR_SREV_9485_11(_ah) \ - (AR_SREV_9485(_ah) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) +#define AR_SREV_9485_11_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9485_11)) #define AR_SREV_9485_OR_LATER(_ah) \ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485)) -- cgit v1.2.3 From e083a42ef616b6987c024cccfec72cec75a1f1f5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 19 Aug 2013 11:04:01 +0530 Subject: ath9k: Add antenna diversity tweak for CUS198 This improves RX diversity and performance for AR9485. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 5 +++++ drivers/net/wireless/ath/ath9k/ar9003_phy.h | 2 ++ drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 1 + 4 files changed, 9 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index abdc7ee87413..a6846abf4749 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3825,6 +3825,11 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan) else value = ar9003_hw_atten_chain_get_margin(ah, i, chan); + if (ah->config.alt_mingainidx) + REG_RMW_FIELD(ah, AR_PHY_EXT_ATTEN_CTL_0, + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, + value); + REG_RMW_FIELD(ah, ext_atten_reg[i], AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 23c019d0d9aa..6fd752321e36 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -148,6 +148,8 @@ #define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 #define AR_PHY_EXT_CCA_THRESH62 0x007F0000 #define AR_PHY_EXT_CCA_THRESH62_S 16 +#define AR_PHY_EXTCHN_PWRTHR1_ANT_DIV_ALT_ANT_MINGAINIDX 0x0000FF00 +#define AR_PHY_EXTCHN_PWRTHR1_ANT_DIV_ALT_ANT_MINGAINIDX_S 8 #define AR_PHY_EXT_MINCCA_PWR 0x01FF0000 #define AR_PHY_EXT_MINCCA_PWR_S 16 #define AR_PHY_EXT_CYCPWR_THR1 0x0000FE00L diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 64ff8e61c243..fa543a62e839 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -314,6 +314,7 @@ struct ath9k_ops_config { u32 xlna_gpio; u32 ant_ctrl_comm2g_switch_enable; bool xatten_margin_cfg; + bool alt_mingainidx; }; enum ath9k_int { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index abf1eb5d97ad..19b46c7e3616 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -534,6 +534,7 @@ static void ath9k_init_platform(struct ath_softc *sc) ATH9K_PCI_CUS230)) { ah->config.xlna_gpio = 9; ah->config.xatten_margin_cfg = true; + ah->config.alt_mingainidx = true; ah->config.ant_ctrl_comm2g_switch_enable = 0x000BBB88; sc->ant_comb.low_rssi_thresh = 20; sc->ant_comb.fast_div_bias = 3; -- cgit v1.2.3 From 1211c961170cedb21c30d5bb7e2033c8720b38db Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 19 Aug 2013 16:10:21 -0700 Subject: mwifiex: do not create AP and P2P interfaces upon driver loading Bug 60747 - 1286:2044 [Microsoft Surface Pro] Marvell 88W8797 wifi show 3 interface under network https://bugzilla.kernel.org/show_bug.cgi?id=60747 This issue was also reported previously by OLPC and some folks from the community. There are 3 network interfaces with different types being created when mwifiex driver is loaded: 1. mlan0 (infra. STA) 2. uap0 (AP) 3. p2p0 (P2P_CLIENT) The Network Manager attempts to use all 3 interfaces above without filtering the managed interface type. As the result, 3 identical interfaces are displayed under network manager. If user happens to click on an entry under which its interface is uap0 or p2p0, the association will fail. Work around it by removing the creation of AP and P2P interfaces at driver loading time. These interfaces can be added with 'iw' or other applications manually when they are needed. Signed-off-by: Bing Zhao Signed-off-by: Avinash Patil Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 3402bffdd016..fd778337deee 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -477,20 +477,6 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) dev_err(adapter->dev, "cannot create default STA interface\n"); goto err_add_intf; } - - /* Create AP interface by default */ - if (!mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", - NL80211_IFTYPE_AP, NULL, NULL)) { - dev_err(adapter->dev, "cannot create default AP interface\n"); - goto err_add_intf; - } - - /* Create P2P interface by default */ - if (!mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", - NL80211_IFTYPE_P2P_CLIENT, NULL, NULL)) { - dev_err(adapter->dev, "cannot create default P2P interface\n"); - goto err_add_intf; - } rtnl_unlock(); mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); -- cgit v1.2.3 From f4d907046c3918005a1e4df0990461183c06e1bc Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 20 Aug 2013 13:05:58 +0530 Subject: ath9k: Add one more PCI ID for CUS198 This is a AR9485/WB225 based card. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 76e8c359bbf8..32807987dd67 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -59,6 +59,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { PCI_VENDOR_ID_AZWAVE, 0x2126), .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x126A), + .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, /* PCI-E CUS230 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, -- cgit v1.2.3 From 02ab8567ef14001d0b2e655bb726f52083bdd101 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:35 +0200 Subject: brcmsmac: cosmetic change in phy_lcn.c Cleaning up some code fragments reducing indentation and uncluttering some lines. Apart from whitespace there are no actual code changes made. Cc: Jonas Gorski Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 213 ++++++++++----------- 1 file changed, 106 insertions(+), 107 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 3d6b16ce4687..e646ba0b03f5 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1137,8 +1137,9 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, gain0_15 = ((biq1 & 0xf) << 12) | ((tia & 0xf) << 8) | ((lna2 & 0x3) << 6) | - ((lna2 & - 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0); + ((lna2 & 0x3) << 4) | + ((lna1 & 0x3) << 2) | + ((lna1 & 0x3) << 0); mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); @@ -1368,126 +1369,124 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, goto cal_done; } - if (module == 1) { + WARN_ON(module != 1); + tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); - tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); - wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + for (i = 0; i < 11; i++) + values_to_save[i] = + read_radio_reg(pi, rxiq_cal_rf_reg[i]); + Core1TxControl_old = read_phy_reg(pi, 0x631); + + or_phy_reg(pi, 0x631, 0x0015); + + RFOverride0_old = read_phy_reg(pi, 0x44c); + RFOverrideVal0_old = read_phy_reg(pi, 0x44d); + rfoverride2_old = read_phy_reg(pi, 0x4b0); + rfoverride2val_old = read_phy_reg(pi, 0x4b1); + rfoverride3_old = read_phy_reg(pi, 0x4f9); + rfoverride3val_old = read_phy_reg(pi, 0x4fa); + rfoverride4_old = read_phy_reg(pi, 0x938); + rfoverride4val_old = read_phy_reg(pi, 0x939); + afectrlovr_old = read_phy_reg(pi, 0x43b); + afectrlovrval_old = read_phy_reg(pi, 0x43c); + old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); + old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); - for (i = 0; i < 11; i++) - values_to_save[i] = - read_radio_reg(pi, rxiq_cal_rf_reg[i]); - Core1TxControl_old = read_phy_reg(pi, 0x631); - - or_phy_reg(pi, 0x631, 0x0015); - - RFOverride0_old = read_phy_reg(pi, 0x44c); - RFOverrideVal0_old = read_phy_reg(pi, 0x44d); - rfoverride2_old = read_phy_reg(pi, 0x4b0); - rfoverride2val_old = read_phy_reg(pi, 0x4b1); - rfoverride3_old = read_phy_reg(pi, 0x4f9); - rfoverride3val_old = read_phy_reg(pi, 0x4fa); - rfoverride4_old = read_phy_reg(pi, 0x938); - rfoverride4val_old = read_phy_reg(pi, 0x939); - afectrlovr_old = read_phy_reg(pi, 0x43b); - afectrlovrval_old = read_phy_reg(pi, 0x43c); - old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); - old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); - - tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); - if (tx_gain_override_old) { - wlc_lcnphy_get_tx_gain(pi, &old_gains); - tx_gain_index_old = pi_lcn->lcnphy_current_index; - } + tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); + if (tx_gain_override_old) { + wlc_lcnphy_get_tx_gain(pi, &old_gains); + tx_gain_index_old = pi_lcn->lcnphy_current_index; + } - wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); - mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); - mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); + mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); - write_radio_reg(pi, RADIO_2064_REG116, 0x06); - write_radio_reg(pi, RADIO_2064_REG12C, 0x07); - write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); - write_radio_reg(pi, RADIO_2064_REG098, 0x03); - write_radio_reg(pi, RADIO_2064_REG00B, 0x7); - mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); - write_radio_reg(pi, RADIO_2064_REG01D, 0x01); - write_radio_reg(pi, RADIO_2064_REG114, 0x01); - write_radio_reg(pi, RADIO_2064_REG02E, 0x10); - write_radio_reg(pi, RADIO_2064_REG12A, 0x08); - - mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); - mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); - mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); - mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); - mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); - mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); - mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); - - mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); - - wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); - write_phy_reg(pi, 0x6da, 0xffff); - or_phy_reg(pi, 0x6db, 0x3); - wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); - wlc_lcnphy_rx_gain_override_enable(pi, true); - - tia_gain = 8; - rx_pwr_threshold = 950; - while (tia_gain > 0) { - tia_gain -= 1; - wlc_lcnphy_set_rx_gain_by_distribution(pi, - 0, 0, 2, 2, - (u16) - tia_gain, 1, 0); - udelay(500); + write_radio_reg(pi, RADIO_2064_REG116, 0x06); + write_radio_reg(pi, RADIO_2064_REG12C, 0x07); + write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); + write_radio_reg(pi, RADIO_2064_REG098, 0x03); + write_radio_reg(pi, RADIO_2064_REG00B, 0x7); + mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); + write_radio_reg(pi, RADIO_2064_REG01D, 0x01); + write_radio_reg(pi, RADIO_2064_REG114, 0x01); + write_radio_reg(pi, RADIO_2064_REG02E, 0x10); + write_radio_reg(pi, RADIO_2064_REG12A, 0x08); + + mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); + mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); - received_power = - wlc_lcnphy_measure_digital_power(pi, 2000); - if (received_power < rx_pwr_threshold) - break; - } - result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); + mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); - wlc_lcnphy_stop_tx_tone(pi); + wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); + write_phy_reg(pi, 0x6da, 0xffff); + or_phy_reg(pi, 0x6db, 0x3); + wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); + wlc_lcnphy_rx_gain_override_enable(pi, true); - write_phy_reg(pi, 0x631, Core1TxControl_old); + tia_gain = 8; + rx_pwr_threshold = 950; + while (tia_gain > 0) { + tia_gain -= 1; + wlc_lcnphy_set_rx_gain_by_distribution(pi, + 0, 0, 2, 2, + (u16) + tia_gain, 1, 0); + udelay(500); - write_phy_reg(pi, 0x44c, RFOverrideVal0_old); - write_phy_reg(pi, 0x44d, RFOverrideVal0_old); - write_phy_reg(pi, 0x4b0, rfoverride2_old); - write_phy_reg(pi, 0x4b1, rfoverride2val_old); - write_phy_reg(pi, 0x4f9, rfoverride3_old); - write_phy_reg(pi, 0x4fa, rfoverride3val_old); - write_phy_reg(pi, 0x938, rfoverride4_old); - write_phy_reg(pi, 0x939, rfoverride4val_old); - write_phy_reg(pi, 0x43b, afectrlovr_old); - write_phy_reg(pi, 0x43c, afectrlovrval_old); - write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); - write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); + received_power = + wlc_lcnphy_measure_digital_power(pi, 2000); + if (received_power < rx_pwr_threshold) + break; + } + result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); - wlc_lcnphy_clear_trsw_override(pi); + wlc_lcnphy_stop_tx_tone(pi); - mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); + write_phy_reg(pi, 0x631, Core1TxControl_old); + + write_phy_reg(pi, 0x44c, RFOverrideVal0_old); + write_phy_reg(pi, 0x44d, RFOverrideVal0_old); + write_phy_reg(pi, 0x4b0, rfoverride2_old); + write_phy_reg(pi, 0x4b1, rfoverride2val_old); + write_phy_reg(pi, 0x4f9, rfoverride3_old); + write_phy_reg(pi, 0x4fa, rfoverride3val_old); + write_phy_reg(pi, 0x938, rfoverride4_old); + write_phy_reg(pi, 0x939, rfoverride4val_old); + write_phy_reg(pi, 0x43b, afectrlovr_old); + write_phy_reg(pi, 0x43c, afectrlovrval_old); + write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); + write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); - for (i = 0; i < 11; i++) - write_radio_reg(pi, rxiq_cal_rf_reg[i], - values_to_save[i]); + wlc_lcnphy_clear_trsw_override(pi); - if (tx_gain_override_old) - wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); - else - wlc_lcnphy_disable_tx_gain_override(pi); + mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); - wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); - wlc_lcnphy_rx_gain_override_enable(pi, false); - } + for (i = 0; i < 11; i++) + write_radio_reg(pi, rxiq_cal_rf_reg[i], + values_to_save[i]); + + if (tx_gain_override_old) + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); + else + wlc_lcnphy_disable_tx_gain_override(pi); + + wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); + wlc_lcnphy_rx_gain_override_enable(pi, false); cal_done: kfree(ptr); -- cgit v1.2.3 From acf97e9b5a5246da1193cb564377a4e7793eb29e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:36 +0200 Subject: brcmsmac: change pa_gain for bcm4313 iPA The function wlc_lcnphy_load_tx_gain_table() has a target PA gain specified for the iPA variant of the bcm4313. This gain value is reduced to avoid PA distortion. The if-statement is removed because it was rather redundant in the first place. Please note that this patch does not provide full iPA support. Cc: Jonas Gorski Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index e646ba0b03f5..8dc5d0ff2dc9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -4282,13 +4282,10 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi, u16 pa_gain; u16 gm_gain; - if (CHSPEC_IS5G(pi->radio_chanspec)) - pa_gain = 0x70; - else - pa_gain = 0x70; - if (pi->sh->boardflags & BFL_FEM) pa_gain = 0x10; + else + pa_gain = 0x60; tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; tab.tbl_len = 1; -- cgit v1.2.3 From d6b81daaa2afaa17d39b34e36ca17bc6062b4bc5 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:37 +0200 Subject: brcmsmac: use ARRAY_SIZE in phytbl_lcn.c This patch converts all sizeof(x)/sizeof(x[0]) instances to ARRAY_SIZE macro in phytbl_lcn.c. The patch was made using spatch with ARRAY_SIZE.cocci (see [1]). [1] https://github.com/coccinelle/coccinelle/tree/master/demos/janitorings Cc: Jonas Gorski Tested-by: David Herrmann Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c | 117 ++++++++------------- 1 file changed, 44 insertions(+), 73 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c index 622c01ca72c5..deae3a749657 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -1507,117 +1507,103 @@ static const u32 dot11lcn_gain_tbl_5G[] = { const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[] = { {&dot11lcn_gain_tbl_rev0, - sizeof(dot11lcn_gain_tbl_rev0) / sizeof(dot11lcn_gain_tbl_rev0[0]), 18, + ARRAY_SIZE(dot11lcn_gain_tbl_rev0), 18, 0, 32} , {&dot11lcn_aux_gain_idx_tbl_rev0, - sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / - sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} + ARRAY_SIZE(dot11lcn_aux_gain_idx_tbl_rev0), 14, 0, 16} , {&dot11lcn_gain_idx_tbl_rev0, - sizeof(dot11lcn_gain_idx_tbl_rev0) / - sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} + ARRAY_SIZE(dot11lcn_gain_idx_tbl_rev0), 13, 0, 32} , }; static const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev1[] = { {&dot11lcn_gain_tbl_rev1, - sizeof(dot11lcn_gain_tbl_rev1) / sizeof(dot11lcn_gain_tbl_rev1[0]), 18, + ARRAY_SIZE(dot11lcn_gain_tbl_rev1), 18, 0, 32} , {&dot11lcn_aux_gain_idx_tbl_rev0, - sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / - sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} + ARRAY_SIZE(dot11lcn_aux_gain_idx_tbl_rev0), 14, 0, 16} , {&dot11lcn_gain_idx_tbl_rev0, - sizeof(dot11lcn_gain_idx_tbl_rev0) / - sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} + ARRAY_SIZE(dot11lcn_gain_idx_tbl_rev0), 13, 0, 32} , }; const struct phytbl_info dot11lcnphytbl_rx_gain_info_2G_rev2[] = { {&dot11lcn_gain_tbl_2G, - sizeof(dot11lcn_gain_tbl_2G) / sizeof(dot11lcn_gain_tbl_2G[0]), 18, 0, + ARRAY_SIZE(dot11lcn_gain_tbl_2G), 18, 0, 32} , {&dot11lcn_aux_gain_idx_tbl_2G, - sizeof(dot11lcn_aux_gain_idx_tbl_2G) / - sizeof(dot11lcn_aux_gain_idx_tbl_2G[0]), 14, 0, 16} + ARRAY_SIZE(dot11lcn_aux_gain_idx_tbl_2G), 14, 0, 16} , {&dot11lcn_gain_idx_tbl_2G, - sizeof(dot11lcn_gain_idx_tbl_2G) / sizeof(dot11lcn_gain_idx_tbl_2G[0]), + ARRAY_SIZE(dot11lcn_gain_idx_tbl_2G), 13, 0, 32} , {&dot11lcn_gain_val_tbl_2G, - sizeof(dot11lcn_gain_val_tbl_2G) / sizeof(dot11lcn_gain_val_tbl_2G[0]), + ARRAY_SIZE(dot11lcn_gain_val_tbl_2G), 17, 0, 8} }; const struct phytbl_info dot11lcnphytbl_rx_gain_info_5G_rev2[] = { {&dot11lcn_gain_tbl_5G, - sizeof(dot11lcn_gain_tbl_5G) / sizeof(dot11lcn_gain_tbl_5G[0]), 18, 0, + ARRAY_SIZE(dot11lcn_gain_tbl_5G), 18, 0, 32} , {&dot11lcn_aux_gain_idx_tbl_5G, - sizeof(dot11lcn_aux_gain_idx_tbl_5G) / - sizeof(dot11lcn_aux_gain_idx_tbl_5G[0]), 14, 0, 16} + ARRAY_SIZE(dot11lcn_aux_gain_idx_tbl_5G), 14, 0, 16} , {&dot11lcn_gain_idx_tbl_5G, - sizeof(dot11lcn_gain_idx_tbl_5G) / sizeof(dot11lcn_gain_idx_tbl_5G[0]), + ARRAY_SIZE(dot11lcn_gain_idx_tbl_5G), 13, 0, 32} , {&dot11lcn_gain_val_tbl_5G, - sizeof(dot11lcn_gain_val_tbl_5G) / sizeof(dot11lcn_gain_val_tbl_5G[0]), + ARRAY_SIZE(dot11lcn_gain_val_tbl_5G), 17, 0, 8} }; const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_2G_rev2[] = { {&dot11lcn_gain_tbl_extlna_2G, - sizeof(dot11lcn_gain_tbl_extlna_2G) / - sizeof(dot11lcn_gain_tbl_extlna_2G[0]), 18, 0, 32} + ARRAY_SIZE(dot11lcn_gain_tbl_extlna_2G), 18, 0, 32} , {&dot11lcn_aux_gain_idx_tbl_extlna_2G, - sizeof(dot11lcn_aux_gain_idx_tbl_extlna_2G) / - sizeof(dot11lcn_aux_gain_idx_tbl_extlna_2G[0]), 14, 0, 16} + ARRAY_SIZE(dot11lcn_aux_gain_idx_tbl_extlna_2G), 14, 0, 16} , {&dot11lcn_gain_idx_tbl_extlna_2G, - sizeof(dot11lcn_gain_idx_tbl_extlna_2G) / - sizeof(dot11lcn_gain_idx_tbl_extlna_2G[0]), 13, 0, 32} + ARRAY_SIZE(dot11lcn_gain_idx_tbl_extlna_2G), 13, 0, 32} , {&dot11lcn_gain_val_tbl_extlna_2G, - sizeof(dot11lcn_gain_val_tbl_extlna_2G) / - sizeof(dot11lcn_gain_val_tbl_extlna_2G[0]), 17, 0, 8} + ARRAY_SIZE(dot11lcn_gain_val_tbl_extlna_2G), 17, 0, 8} }; const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_5G_rev2[] = { {&dot11lcn_gain_tbl_5G, - sizeof(dot11lcn_gain_tbl_5G) / sizeof(dot11lcn_gain_tbl_5G[0]), 18, 0, + ARRAY_SIZE(dot11lcn_gain_tbl_5G), 18, 0, 32} , {&dot11lcn_aux_gain_idx_tbl_5G, - sizeof(dot11lcn_aux_gain_idx_tbl_5G) / - sizeof(dot11lcn_aux_gain_idx_tbl_5G[0]), 14, 0, 16} + ARRAY_SIZE(dot11lcn_aux_gain_idx_tbl_5G), 14, 0, 16} , {&dot11lcn_gain_idx_tbl_5G, - sizeof(dot11lcn_gain_idx_tbl_5G) / sizeof(dot11lcn_gain_idx_tbl_5G[0]), + ARRAY_SIZE(dot11lcn_gain_idx_tbl_5G), 13, 0, 32} , {&dot11lcn_gain_val_tbl_5G, - sizeof(dot11lcn_gain_val_tbl_5G) / sizeof(dot11lcn_gain_val_tbl_5G[0]), + ARRAY_SIZE(dot11lcn_gain_val_tbl_5G), 17, 0, 8} }; const u32 dot11lcnphytbl_rx_gain_info_sz_rev0 = - sizeof(dot11lcnphytbl_rx_gain_info_rev0) / - sizeof(dot11lcnphytbl_rx_gain_info_rev0[0]); + ARRAY_SIZE(dot11lcnphytbl_rx_gain_info_rev0); const u32 dot11lcnphytbl_rx_gain_info_2G_rev2_sz = - sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2) / - sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2[0]); + ARRAY_SIZE(dot11lcnphytbl_rx_gain_info_2G_rev2); const u32 dot11lcnphytbl_rx_gain_info_5G_rev2_sz = - sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2) / - sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2[0]); + ARRAY_SIZE(dot11lcnphytbl_rx_gain_info_5G_rev2); static const u16 dot11lcn_min_sig_sq_tbl_rev0[] = { 0x014d, @@ -2771,89 +2757,74 @@ static const u32 dot11lcn_papd_compdelta_tbl_rev0[] = { const struct phytbl_info dot11lcnphytbl_info_rev0[] = { {&dot11lcn_min_sig_sq_tbl_rev0, - sizeof(dot11lcn_min_sig_sq_tbl_rev0) / - sizeof(dot11lcn_min_sig_sq_tbl_rev0[0]), 2, 0, 16} + ARRAY_SIZE(dot11lcn_min_sig_sq_tbl_rev0), 2, 0, 16} , {&dot11lcn_noise_scale_tbl_rev0, - sizeof(dot11lcn_noise_scale_tbl_rev0) / - sizeof(dot11lcn_noise_scale_tbl_rev0[0]), 1, 0, 16} + ARRAY_SIZE(dot11lcn_noise_scale_tbl_rev0), 1, 0, 16} , {&dot11lcn_fltr_ctrl_tbl_rev0, - sizeof(dot11lcn_fltr_ctrl_tbl_rev0) / - sizeof(dot11lcn_fltr_ctrl_tbl_rev0[0]), 11, 0, 32} + ARRAY_SIZE(dot11lcn_fltr_ctrl_tbl_rev0), 11, 0, 32} , {&dot11lcn_ps_ctrl_tbl_rev0, - sizeof(dot11lcn_ps_ctrl_tbl_rev0) / - sizeof(dot11lcn_ps_ctrl_tbl_rev0[0]), 12, 0, 32} + ARRAY_SIZE(dot11lcn_ps_ctrl_tbl_rev0), 12, 0, 32} , {&dot11lcn_gain_idx_tbl_rev0, - sizeof(dot11lcn_gain_idx_tbl_rev0) / - sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} + ARRAY_SIZE(dot11lcn_gain_idx_tbl_rev0), 13, 0, 32} , {&dot11lcn_aux_gain_idx_tbl_rev0, - sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / - sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} + ARRAY_SIZE(dot11lcn_aux_gain_idx_tbl_rev0), 14, 0, 16} , {&dot11lcn_sw_ctrl_tbl_rev0, - sizeof(dot11lcn_sw_ctrl_tbl_rev0) / - sizeof(dot11lcn_sw_ctrl_tbl_rev0[0]), 15, 0, 16} + ARRAY_SIZE(dot11lcn_sw_ctrl_tbl_rev0), 15, 0, 16} , {&dot11lcn_nf_table_rev0, - sizeof(dot11lcn_nf_table_rev0) / sizeof(dot11lcn_nf_table_rev0[0]), 16, + ARRAY_SIZE(dot11lcn_nf_table_rev0), 16, 0, 8} , {&dot11lcn_gain_val_tbl_rev0, - sizeof(dot11lcn_gain_val_tbl_rev0) / - sizeof(dot11lcn_gain_val_tbl_rev0[0]), 17, 0, 8} + ARRAY_SIZE(dot11lcn_gain_val_tbl_rev0), 17, 0, 8} , {&dot11lcn_gain_tbl_rev0, - sizeof(dot11lcn_gain_tbl_rev0) / sizeof(dot11lcn_gain_tbl_rev0[0]), 18, + ARRAY_SIZE(dot11lcn_gain_tbl_rev0), 18, 0, 32} , {&dot11lcn_spur_tbl_rev0, - sizeof(dot11lcn_spur_tbl_rev0) / sizeof(dot11lcn_spur_tbl_rev0[0]), 20, + ARRAY_SIZE(dot11lcn_spur_tbl_rev0), 20, 0, 8} , {&dot11lcn_unsup_mcs_tbl_rev0, - sizeof(dot11lcn_unsup_mcs_tbl_rev0) / - sizeof(dot11lcn_unsup_mcs_tbl_rev0[0]), 23, 0, 16} + ARRAY_SIZE(dot11lcn_unsup_mcs_tbl_rev0), 23, 0, 16} , {&dot11lcn_iq_local_tbl_rev0, - sizeof(dot11lcn_iq_local_tbl_rev0) / - sizeof(dot11lcn_iq_local_tbl_rev0[0]), 0, 0, 16} + ARRAY_SIZE(dot11lcn_iq_local_tbl_rev0), 0, 0, 16} , {&dot11lcn_papd_compdelta_tbl_rev0, - sizeof(dot11lcn_papd_compdelta_tbl_rev0) / - sizeof(dot11lcn_papd_compdelta_tbl_rev0[0]), 24, 0, 32} + ARRAY_SIZE(dot11lcn_papd_compdelta_tbl_rev0), 24, 0, 32} , }; const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313 = { &dot11lcn_sw_ctrl_tbl_4313_rev0, - sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0) / - sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0[0]), 15, 0, 16 + ARRAY_SIZE(dot11lcn_sw_ctrl_tbl_4313_rev0), 15, 0, 16 }; const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa = { &dot11lcn_sw_ctrl_tbl_4313_epa_rev0, - sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0) / - sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0[0]), 15, 0, 16 + ARRAY_SIZE(dot11lcn_sw_ctrl_tbl_4313_epa_rev0), 15, 0, 16 }; const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa = { &dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo, - sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo) / - sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[0]), 15, 0, 16 + ARRAY_SIZE(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo), 15, 0, 16 }; const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250 = { &dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0, - sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0) / - sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[0]), 15, 0, 16 + ARRAY_SIZE(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0), 15, 0, 16 }; const u32 dot11lcnphytbl_info_sz_rev0 = - sizeof(dot11lcnphytbl_info_rev0) / sizeof(dot11lcnphytbl_info_rev0[0]); + ARRAY_SIZE(dot11lcnphytbl_info_rev0); const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_extPA_gaintable_rev0[128] = { -- cgit v1.2.3 From 67e39c5ae7369bad2a1c2d631e5b971be2e1edc1 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:38 +0200 Subject: brcmsmac: add debug info message providing phy and radio info For debug purposes it is good to have the phy and radio information available in the log. Only logged when driver is built when BRCMDBG or BRCM_TRACING kconfig are set. Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 7ca10bf4a4d3..c3c6123dc7dd 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -4652,7 +4652,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, wlc->band->phyrev = wlc_hw->band->phyrev; wlc->band->radioid = wlc_hw->band->radioid; wlc->band->radiorev = wlc_hw->band->radiorev; - + brcms_dbg_info(core, "wl%d: phy %u/%u radio %x/%u\n", unit, + wlc->band->phytype, wlc->band->phyrev, + wlc->band->radioid, wlc->band->radiorev); /* default contention windows size limits */ wlc_hw->band->CWmin = APHY_CWMIN; wlc_hw->band->CWmax = PHY_CWMAX; -- cgit v1.2.3 From ab9a50e387dce5f33a9d7efd64375456ac9d996e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:39 +0200 Subject: brcmsmac: update transmit gain table for lcn phy Update the transmit gain table for bcm4313 chip family. Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c | 216 ++++++++++----------- 1 file changed, 108 insertions(+), 108 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c index deae3a749657..efd5a58f4ce1 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -2959,134 +2959,134 @@ dot11lcnphy_2GHz_extPA_gaintable_rev0[128] = { }; const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_gaintable_rev0[128] = { - {7, 0, 31, 0, 72}, - {7, 0, 31, 0, 70}, - {7, 0, 31, 0, 68}, - {7, 0, 30, 0, 67}, - {7, 0, 29, 0, 68}, - {7, 0, 28, 0, 68}, - {7, 0, 27, 0, 69}, - {7, 0, 26, 0, 70}, - {7, 0, 25, 0, 70}, - {7, 0, 24, 0, 71}, - {7, 0, 23, 0, 72}, - {7, 0, 23, 0, 70}, - {7, 0, 22, 0, 71}, - {7, 0, 21, 0, 72}, - {7, 0, 21, 0, 70}, - {7, 0, 21, 0, 68}, - {7, 0, 21, 0, 66}, - {7, 0, 21, 0, 64}, - {7, 0, 21, 0, 63}, - {7, 0, 20, 0, 64}, - {7, 0, 19, 0, 65}, - {7, 0, 19, 0, 64}, - {7, 0, 18, 0, 65}, - {7, 0, 18, 0, 64}, - {7, 0, 17, 0, 65}, - {7, 0, 17, 0, 64}, - {7, 0, 16, 0, 65}, - {7, 0, 16, 0, 64}, - {7, 0, 16, 0, 62}, - {7, 0, 16, 0, 60}, - {7, 0, 16, 0, 58}, - {7, 0, 15, 0, 61}, - {7, 0, 15, 0, 59}, - {7, 0, 14, 0, 61}, - {7, 0, 14, 0, 60}, - {7, 0, 14, 0, 58}, - {7, 0, 13, 0, 60}, - {7, 0, 13, 0, 59}, - {7, 0, 12, 0, 62}, - {7, 0, 12, 0, 60}, - {7, 0, 12, 0, 58}, - {7, 0, 11, 0, 62}, - {7, 0, 11, 0, 60}, - {7, 0, 11, 0, 59}, - {7, 0, 11, 0, 57}, - {7, 0, 10, 0, 61}, - {7, 0, 10, 0, 59}, - {7, 0, 10, 0, 57}, - {7, 0, 9, 0, 62}, - {7, 0, 9, 0, 60}, - {7, 0, 9, 0, 58}, - {7, 0, 9, 0, 57}, - {7, 0, 8, 0, 62}, - {7, 0, 8, 0, 60}, - {7, 0, 8, 0, 58}, - {7, 0, 8, 0, 57}, - {7, 0, 8, 0, 55}, - {7, 0, 7, 0, 61}, + {15, 0, 31, 0, 72}, + {15, 0, 31, 0, 70}, + {15, 0, 31, 0, 68}, + {15, 0, 30, 0, 68}, + {15, 0, 29, 0, 69}, + {15, 0, 28, 0, 69}, + {15, 0, 27, 0, 70}, + {15, 0, 26, 0, 70}, + {15, 0, 25, 0, 71}, + {15, 0, 24, 0, 72}, + {15, 0, 23, 0, 73}, + {15, 0, 23, 0, 71}, + {15, 0, 22, 0, 72}, + {15, 0, 21, 0, 73}, + {15, 0, 21, 0, 71}, + {15, 0, 21, 0, 69}, + {15, 0, 21, 0, 67}, + {15, 0, 21, 0, 65}, + {15, 0, 21, 0, 63}, + {15, 0, 20, 0, 65}, + {15, 0, 19, 0, 66}, + {15, 0, 19, 0, 64}, + {15, 0, 18, 0, 66}, + {15, 0, 18, 0, 64}, + {15, 0, 17, 0, 66}, + {15, 0, 17, 0, 64}, + {15, 0, 16, 0, 66}, + {15, 0, 16, 0, 64}, + {15, 0, 16, 0, 62}, + {15, 0, 16, 0, 61}, + {15, 0, 16, 0, 59}, + {15, 0, 15, 0, 61}, + {15, 0, 15, 0, 59}, + {15, 0, 14, 0, 62}, + {15, 0, 14, 0, 60}, + {15, 0, 14, 0, 58}, + {15, 0, 13, 0, 61}, + {15, 0, 13, 0, 59}, + {15, 0, 12, 0, 62}, + {15, 0, 12, 0, 61}, + {15, 0, 12, 0, 59}, + {15, 0, 11, 0, 62}, + {15, 0, 11, 0, 61}, + {15, 0, 11, 0, 59}, + {15, 0, 11, 0, 57}, + {15, 0, 10, 0, 61}, + {15, 0, 10, 0, 59}, + {15, 0, 10, 0, 58}, + {15, 0, 9, 0, 62}, + {15, 0, 9, 0, 61}, + {15, 0, 9, 0, 59}, + {15, 0, 9, 0, 57}, + {15, 0, 8, 0, 62}, + {15, 0, 8, 0, 61}, + {15, 0, 8, 0, 59}, + {15, 0, 8, 0, 57}, + {15, 0, 8, 0, 56}, + {15, 0, 8, 0, 54}, + {15, 0, 8, 0, 53}, + {15, 0, 8, 0, 51}, + {15, 0, 8, 0, 50}, + {7, 0, 7, 0, 69}, + {7, 0, 7, 0, 67}, + {7, 0, 7, 0, 65}, + {7, 0, 7, 0, 64}, + {7, 0, 7, 0, 62}, {7, 0, 7, 0, 60}, {7, 0, 7, 0, 58}, - {7, 0, 7, 0, 56}, + {7, 0, 7, 0, 57}, {7, 0, 7, 0, 55}, {7, 0, 6, 0, 62}, - {7, 0, 6, 0, 60}, - {7, 0, 6, 0, 58}, + {7, 0, 6, 0, 61}, + {7, 0, 6, 0, 59}, {7, 0, 6, 0, 57}, - {7, 0, 6, 0, 55}, + {7, 0, 6, 0, 56}, {7, 0, 6, 0, 54}, - {7, 0, 6, 0, 52}, + {7, 0, 6, 0, 53}, {7, 0, 5, 0, 61}, - {7, 0, 5, 0, 59}, - {7, 0, 5, 0, 57}, + {7, 0, 5, 0, 60}, + {7, 0, 5, 0, 58}, {7, 0, 5, 0, 56}, - {7, 0, 5, 0, 54}, + {7, 0, 5, 0, 55}, {7, 0, 5, 0, 53}, - {7, 0, 5, 0, 51}, - {7, 0, 4, 0, 62}, - {7, 0, 4, 0, 60}, - {7, 0, 4, 0, 58}, + {7, 0, 5, 0, 52}, + {7, 0, 5, 0, 50}, + {7, 0, 5, 0, 49}, + {7, 0, 5, 0, 47}, {7, 0, 4, 0, 57}, - {7, 0, 4, 0, 55}, + {7, 0, 4, 0, 56}, {7, 0, 4, 0, 54}, - {7, 0, 4, 0, 52}, + {7, 0, 4, 0, 53}, {7, 0, 4, 0, 51}, - {7, 0, 4, 0, 49}, + {7, 0, 4, 0, 50}, {7, 0, 4, 0, 48}, + {7, 0, 4, 0, 47}, {7, 0, 4, 0, 46}, - {7, 0, 3, 0, 60}, - {7, 0, 3, 0, 58}, - {7, 0, 3, 0, 57}, - {7, 0, 3, 0, 55}, - {7, 0, 3, 0, 54}, - {7, 0, 3, 0, 52}, + {7, 0, 4, 0, 44}, + {7, 0, 4, 0, 43}, + {7, 0, 4, 0, 42}, + {7, 0, 4, 0, 41}, + {7, 0, 4, 0, 40}, {7, 0, 3, 0, 51}, - {7, 0, 3, 0, 49}, + {7, 0, 3, 0, 50}, {7, 0, 3, 0, 48}, + {7, 0, 3, 0, 47}, {7, 0, 3, 0, 46}, - {7, 0, 3, 0, 45}, {7, 0, 3, 0, 44}, {7, 0, 3, 0, 43}, + {7, 0, 3, 0, 42}, {7, 0, 3, 0, 41}, - {7, 0, 2, 0, 61}, - {7, 0, 2, 0, 59}, - {7, 0, 2, 0, 57}, - {7, 0, 2, 0, 56}, - {7, 0, 2, 0, 54}, - {7, 0, 2, 0, 53}, - {7, 0, 2, 0, 51}, - {7, 0, 2, 0, 50}, - {7, 0, 2, 0, 48}, - {7, 0, 2, 0, 47}, - {7, 0, 2, 0, 46}, - {7, 0, 2, 0, 44}, - {7, 0, 2, 0, 43}, - {7, 0, 2, 0, 42}, - {7, 0, 2, 0, 41}, - {7, 0, 2, 0, 39}, - {7, 0, 2, 0, 38}, - {7, 0, 2, 0, 37}, - {7, 0, 2, 0, 36}, - {7, 0, 2, 0, 35}, - {7, 0, 2, 0, 34}, - {7, 0, 2, 0, 33}, - {7, 0, 2, 0, 32}, - {7, 0, 1, 0, 63}, - {7, 0, 1, 0, 61}, - {7, 0, 1, 0, 59}, - {7, 0, 1, 0, 57}, + {3, 0, 3, 0, 56}, + {3, 0, 3, 0, 54}, + {3, 0, 3, 0, 53}, + {3, 0, 3, 0, 51}, + {3, 0, 3, 0, 50}, + {3, 0, 3, 0, 48}, + {3, 0, 3, 0, 47}, + {3, 0, 3, 0, 46}, + {3, 0, 3, 0, 44}, + {3, 0, 3, 0, 43}, + {3, 0, 3, 0, 42}, + {3, 0, 3, 0, 41}, + {3, 0, 3, 0, 39}, + {3, 0, 3, 0, 38}, + {3, 0, 3, 0, 37}, + {3, 0, 3, 0, 36}, + {3, 0, 3, 0, 35}, + {3, 0, 3, 0, 34}, }; const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_5GHz_gaintable_rev0[128] = { -- cgit v1.2.3 From 7de646854bb1405ccafaa5e3545df6657141f510 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:40 +0200 Subject: brcmsmac: change lcnphy receive i/q calibration routine The gain level control for the test tone has been changed. This calbration test tone is used to determine the i/q compensation. The i/q calibration routine has been reworked to accomodate this. Cc: Jonas Gorski Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 78 ++++++++++++++++------ 1 file changed, 58 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 8dc5d0ff2dc9..236e8d90a5bc 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1329,6 +1329,43 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples) return (iq_est.i_pwr + iq_est.q_pwr) / nsamples; } +static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain, + u16 tia_gain, u16 lna2_gain) +{ + u32 i_thresh_l, q_thresh_l; + u32 i_thresh_h, q_thresh_h; + struct lcnphy_iq_est iq_est_h, iq_est_l; + + wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain, + lna2_gain, 0); + + wlc_lcnphy_rx_gain_override_enable(pi, true); + wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0); + udelay(500); + write_radio_reg(pi, RADIO_2064_REG112, 0); + if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l)) + return false; + + wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0); + udelay(500); + write_radio_reg(pi, RADIO_2064_REG112, 0); + if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h)) + return false; + + i_thresh_l = (iq_est_l.i_pwr << 1); + i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr; + + q_thresh_l = (iq_est_l.q_pwr << 1); + q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr; + if ((iq_est_h.i_pwr > i_thresh_l) && + (iq_est_h.i_pwr < i_thresh_h) && + (iq_est_h.q_pwr > q_thresh_l) && + (iq_est_h.q_pwr < q_thresh_h)) + return true; + + return false; +} + static bool wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, const struct lcnphy_rx_iqcomp *iqcomp, @@ -1343,8 +1380,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old, rfoverride3_old, rfoverride3val_old, rfoverride4_old, rfoverride4val_old, afectrlovr_old, afectrlovrval_old; - int tia_gain; - u32 received_power, rx_pwr_threshold; + int tia_gain, lna2_gain, biq1_gain; + bool set_gain; u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl; u16 values_to_save[11]; s16 *ptr; @@ -1432,29 +1469,30 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); - wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); write_phy_reg(pi, 0x6da, 0xffff); or_phy_reg(pi, 0x6db, 0x3); - wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); - wlc_lcnphy_rx_gain_override_enable(pi, true); - - tia_gain = 8; - rx_pwr_threshold = 950; - while (tia_gain > 0) { - tia_gain -= 1; - wlc_lcnphy_set_rx_gain_by_distribution(pi, - 0, 0, 2, 2, - (u16) - tia_gain, 1, 0); - udelay(500); - received_power = - wlc_lcnphy_measure_digital_power(pi, 2000); - if (received_power < rx_pwr_threshold) - break; + wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); + for (lna2_gain = 3; lna2_gain >= 0; lna2_gain--) { + for (tia_gain = 4; tia_gain >= 0; tia_gain--) { + for (biq1_gain = 6; biq1_gain >= 0; biq1_gain--) { + set_gain = wlc_lcnphy_rx_iq_cal_gain(pi, + (u16) + biq1_gain, + (u16) + tia_gain, + (u16) + lna2_gain); + if (!set_gain) + continue; + + result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024); + goto stop_tone; + } + } } - result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); +stop_tone: wlc_lcnphy_stop_tx_tone(pi); write_phy_reg(pi, 0x631, Core1TxControl_old); -- cgit v1.2.3 From d50ec00160b1842d492c8b871bcd16301454cdcf Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:41 +0200 Subject: brcmsmac: fix TSSI idle estimation The baseband multiplier must be zero during TSSI idle estimation and restored afterwards. Reviewed-by: Pieter-Paul Giesberts Tested-by: David Herrmann Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 236e8d90a5bc..e08b73a9b417 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -2836,6 +2836,8 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) read_radio_reg(pi, RADIO_2064_REG007) & 1; u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10; u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; + u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi); + idleTssi = read_phy_reg(pi, 0x4ab); suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC)); @@ -2853,6 +2855,12 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4); mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2); wlc_lcnphy_tssi_setup(pi); + + mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0)); + mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6)); + + wlc_lcnphy_set_bbmult(pi, 0x0); + wlc_phy_do_dummy_tx(pi, true, OFF); idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) >> 0); @@ -2874,6 +2882,7 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); + wlc_lcnphy_set_bbmult(pi, SAVE_bbmult); wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old); wlc_lcnphy_set_tx_gain(pi, &old_gains); wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); -- cgit v1.2.3 From 3e72ef73c3414be5932ac75d0938747fb232d4ae Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:42 +0200 Subject: brcmsmac: avoid calling set_txpwr_by_index() twice For lcnphy revision 1 or when hardware supports i/q calibration the function wlc_lcnphy_set_txpwr_by_index() was called twice. Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index e08b73a9b417..caced820191d 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -3897,7 +3897,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) target_gains.pad_gain = 21; target_gains.dac_gain = 0; wlc_lcnphy_set_tx_gain(pi, &target_gains); - wlc_lcnphy_set_tx_pwr_by_index(pi, 16); if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { @@ -3908,6 +3907,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) lcnphy_recal ? LCNPHY_CAL_RECAL : LCNPHY_CAL_FULL), false); } else { + wlc_lcnphy_set_tx_pwr_by_index(pi, 16); wlc_lcnphy_tx_iqlo_soft_cal_full(pi); } -- cgit v1.2.3 From 02fcc7535e92031695c50eb518e56ea09fd3c6e2 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:43 +0200 Subject: brcmsmac: rework switch control table init including iPA BT-combo Rework the code path in lcnphy tbl_init() for switch control table programming. This also takes the iPA BT-combo card into account. Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 31 +++++----- .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c | 72 ++++++++++++++++++++++ .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h | 1 + 3 files changed, 89 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index caced820191d..08bcae4b8c28 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -4573,6 +4573,7 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) uint idx; u8 phybw40; struct phytbl_info tab; + const struct phytbl_info *tb; u32 val; phybw40 = CHSPEC_IS40(pi->radio_chanspec); @@ -4619,7 +4620,6 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) } if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { - const struct phytbl_info *tb; int l; if (CHSPEC_IS2G(pi->radio_chanspec)) { @@ -4640,21 +4640,22 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) wlc_lcnphy_write_table(pi, &tb[idx]); } - if ((pi->sh->boardflags & BFL_FEM) - && !(pi->sh->boardflags & BFL_FEM_BT)) - wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa); - else if (pi->sh->boardflags & BFL_FEM_BT) { - if (pi->sh->boardrev < 0x1250) - wlc_lcnphy_write_table( - pi, - &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa); + if (pi->sh->boardflags & BFL_FEM) { + if (pi->sh->boardflags & BFL_FEM_BT) { + if (pi->sh->boardrev < 0x1250) + tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa; + else + tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250; + } else { + tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa; + } + } else { + if (pi->sh->boardflags & BFL_FEM_BT) + tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa; else - wlc_lcnphy_write_table( - pi, - &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250); - } else - wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313); - + tb = &dot11lcn_sw_ctrl_tbl_info_4313; + } + wlc_lcnphy_write_table(pi, tb); wlc_lcnphy_load_rfpower(pi); wlc_lcnphy_clear_papd_comptable(pi); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c index efd5a58f4ce1..d7fa312214f3 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -2044,6 +2044,73 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = { 0x0005, }; +static const u16 dot11lcn_sw_ctrl_tbl_4313_ipa_rev0_combo[] = { + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, + 0x0005, + 0x0006, + 0x0009, + 0x000a, +}; + static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = { 0x0004, 0x0004, @@ -2808,6 +2875,11 @@ const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313 = { ARRAY_SIZE(dot11lcn_sw_ctrl_tbl_4313_rev0), 15, 0, 16 }; +const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa = { + &dot11lcn_sw_ctrl_tbl_4313_ipa_rev0_combo, + ARRAY_SIZE(dot11lcn_sw_ctrl_tbl_4313_ipa_rev0_combo), 15, 0, 16 +}; + const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa = { &dot11lcn_sw_ctrl_tbl_4313_epa_rev0, ARRAY_SIZE(dot11lcn_sw_ctrl_tbl_4313_epa_rev0), 15, 0, 16 diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h index 5f75e16bf5a7..489422a36085 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h @@ -20,6 +20,7 @@ extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[]; extern const u32 dot11lcnphytbl_rx_gain_info_sz_rev0; extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313; +extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa; extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa; extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa_combo; extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa; -- cgit v1.2.3 From 118e545a2cf34c8a660d050a72d8e711850f8f93 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:44 +0200 Subject: brcmsmac: correct phy registers for TSSI-based power control A number of additional phy registers needs to be programmed when using TSSI-based power control. Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 08bcae4b8c28..2917f5c9fc1e 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -2020,6 +2020,16 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos) } else { mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1); mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); + mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2); + mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4); + mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); + mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77); + mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1); + mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7); + mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1); + mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4); } } else { mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); @@ -2106,6 +2116,7 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi) (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); + mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0)); } static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) @@ -2218,6 +2229,10 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); + mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0); + mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); + wlc_lcnphy_pwrctrl_rssiparams(pi); } @@ -3096,6 +3111,11 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) wlc_lcnphy_write_table(pi, &tab); tab.tbl_offset++; } + mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0); + mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0); + mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8); + mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4); + mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2); mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); -- cgit v1.2.3 From d37c8f0826becb82be0ea06b074f775fb4f75730 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 20 Aug 2013 16:00:45 +0200 Subject: brcmsmac: reinitialize TSSI power control upon channel switch When changing channels the TSSI based power control needs to be reinitialized. Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 2917f5c9fc1e..8fb10485a74d 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -5019,6 +5019,8 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) wlc_lcnphy_load_tx_iir_filter(pi, true, 3); mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); + if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) + wlc_lcnphy_tssi_setup(pi); } void wlc_phy_detach_lcnphy(struct brcms_phy *pi) -- cgit v1.2.3 From 20c7d42a5005938ea6734ee0463f2031d843878f Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 21 Aug 2013 11:45:47 +0200 Subject: brcmsmac: add support for BCM4313 iPA variant This patch completes the changes needed for supporting the iPA variant cards of the BCM4313 wireless chipset. Tested-by: David Herrmann Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 73 ++++++++++++++++------ 1 file changed, 53 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 8fb10485a74d..b2d6d6da3daf 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1826,6 +1826,19 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel) write_radio_reg(pi, RADIO_2064_REG038, 3); write_radio_reg(pi, RADIO_2064_REG091, 7); } + + if (!(pi->sh->boardflags & BFL_FEM)) { + static const u8 reg038[14] = { + 0xd, 0xe, 0xd, 0xd, 0xd, 0xc, 0xa, + 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0 + }; + + write_radio_reg(pi, RADIO_2064_REG02A, 0xf); + write_radio_reg(pi, RADIO_2064_REG091, 0x3); + write_radio_reg(pi, RADIO_2064_REG038, 0x3); + + write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]); + } } static int @@ -2123,7 +2136,16 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) { struct phytbl_info tab; u32 rfseq, ind; + enum lcnphy_tssi_mode mode; + u8 tssi_sel; + if (pi->sh->boardflags & BFL_FEM) { + tssi_sel = 0x1; + mode = LCNPHY_TSSI_EXT; + } else { + tssi_sel = 0xe; + mode = LCNPHY_TSSI_POST_PA; + } tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; tab.tbl_ptr = &ind; @@ -2144,7 +2166,7 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); - wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); + wlc_lcnphy_set_tssi_mux(pi, mode); mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); @@ -2180,9 +2202,10 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0); if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { - mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe); + mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel); mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); } else { + mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1); mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3); } @@ -4358,8 +4381,11 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi, tab.tbl_len = 1; tab.tbl_ptr = &val; + /* fixed gm_gain value for iPA */ + gm_gain = 15; for (j = 0; j < 128; j++) { - gm_gain = gain_table[j].gm; + if (pi->sh->boardflags & BFL_FEM) + gm_gain = gain_table[j].gm; val = (((u32) pa_gain << 24) | (gain_table[j].pad << 16) | (gain_table[j].pga << 8) | gm_gain); @@ -4570,7 +4596,10 @@ static void wlc_radio_2064_init(struct brcms_phy *pi) write_phy_reg(pi, 0x4ea, 0x4688); - mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); + if (pi->sh->boardflags & BFL_FEM) + mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); + else + mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0); mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); @@ -4581,6 +4610,13 @@ static void wlc_radio_2064_init(struct brcms_phy *pi) wlc_lcnphy_rcal(pi); wlc_lcnphy_rc_cal(pi); + + if (!(pi->sh->boardflags & BFL_FEM)) { + write_radio_reg(pi, RADIO_2064_REG032, 0x6f); + write_radio_reg(pi, RADIO_2064_REG033, 0x19); + write_radio_reg(pi, RADIO_2064_REG039, 0xe); + } + } static void wlc_lcnphy_radio_init(struct brcms_phy *pi) @@ -4611,22 +4647,20 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) wlc_lcnphy_write_table(pi, &tab); } - tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; - tab.tbl_width = 16; - tab.tbl_ptr = &val; - tab.tbl_len = 1; - - val = 114; - tab.tbl_offset = 0; - wlc_lcnphy_write_table(pi, &tab); + if (!(pi->sh->boardflags & BFL_FEM)) { + tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; + tab.tbl_width = 16; + tab.tbl_ptr = &val; + tab.tbl_len = 1; - val = 130; - tab.tbl_offset = 1; - wlc_lcnphy_write_table(pi, &tab); + val = 150; + tab.tbl_offset = 0; + wlc_lcnphy_write_table(pi, &tab); - val = 6; - tab.tbl_offset = 8; - wlc_lcnphy_write_table(pi, &tab); + val = 220; + tab.tbl_offset = 1; + wlc_lcnphy_write_table(pi, &tab); + } if (CHSPEC_IS2G(pi->radio_chanspec)) { if (pi->sh->boardflags & BFL_FEM) @@ -5059,8 +5093,7 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi) if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) return false; - if ((pi->sh->boardflags & BFL_FEM) && - (LCNREV_IS(pi->pubpi.phy_rev, 1))) { + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { if (pi_lcn->lcnphy_tempsense_option == 3) { pi->hwpwrctrl = true; pi->hwpwrctrl_capable = true; -- cgit v1.2.3 From 1fb9026000e66ffe032b11ec724c1bc7d068198e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Aug 2013 11:24:01 +0200 Subject: mac80211: move setting WIPHY_FLAG_SUPPORTS_SCHED_SCAN into drivers mac80211 currently sets WIPHY_FLAG_SUPPORTS_SCHED_SCAN based on whether the start_sched_scan operation is supported or not, but that will not be correct for all drivers, we're adding scheduled scan to the iwlmvm driver but it depends on firmware support. Therefore, move setting WIPHY_FLAG_SUPPORTS_SCHED_SCAN into the drivers so that they can control it regardless of implementing the operation. This currently only affects the TI drivers since they're the only ones implementing scheduled scan (in a mac80211 driver.) Acked-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/ti/wlcore/main.c | 3 ++- net/mac80211/main.c | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d1b19c38a907..38995f90040d 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5623,7 +5623,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_remain_on_channel_duration = 5000; wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_SUPPORTS_SCHED_SCAN; /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 25eb35b01938..21d5d44444d0 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -892,9 +892,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (!local->ops->remain_on_channel) local->hw.wiphy->max_remain_on_channel_duration = 5000; - if (local->ops->sched_scan_start) - local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; - /* mac80211 based drivers don't support internal TDLS setup */ if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; -- cgit v1.2.3 From 19504cf5f35fbe85db811fce9f4392a0cbdada2f Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 15 Aug 2013 14:51:28 +0300 Subject: cfg80211: add flags to cfg80211_rx_mgmt() Add flags intended to report various auxiliary information and introduce the NL80211_RXMGMT_FLAG_ANSWERED flag to report that the frame was already answered by the device. Signed-off-by: Vladimir Kondratiev [REPLIED->ANSWERED, reword commit message] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/wmi.c | 7 +++---- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 4 ++-- drivers/net/wireless/mwifiex/util.c | 4 ++-- include/net/cfg80211.h | 3 ++- include/uapi/linux/nl80211.h | 16 ++++++++++++++++ net/mac80211/rx.c | 3 +-- net/wireless/mlme.c | 4 ++-- net/wireless/nl80211.c | 6 ++++-- net/wireless/nl80211.h | 2 +- 10 files changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 87aefb4c4c23..546d5da0b894 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -568,8 +568,8 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(&vif->wdev, freq, 0, - ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, + GFP_ATOMIC); return 0; } @@ -608,8 +608,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(&vif->wdev, freq, 0, - ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, GFP_ATOMIC); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index dc8059ad4bab..21c791ee8178 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -339,7 +339,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) } } else { cfg80211_rx_mgmt(wil->wdev, freq, signal, - (void *)rx_mgmt_frame, d_len, GFP_KERNEL); + (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL); } } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index 79555f006d53..d7a974532909 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -1430,7 +1430,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, IEEE80211_BAND_5GHZ); wdev = &ifp->vif->wdev; - cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, + cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); kfree(mgmt_frame); @@ -1895,7 +1895,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ); - cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, + cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n", diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index e57ac0dd3ab5..5d9e150f4111 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -171,8 +171,8 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, rx_pd->rx_pkt_length = cpu_to_le16(pkt_len); cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq, - CAL_RSSI(rx_pd->snr, rx_pd->nf), - skb->data, pkt_len, GFP_ATOMIC); + CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len, + 0, GFP_ATOMIC); return 0; } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9ab7a0690d93..d530c54a3662 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4056,6 +4056,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * @sig_dbm: signal strength in mBm, or 0 if unknown * @buf: Management frame (header + body) * @len: length of the frame data + * @flags: flags, as defined in enum nl80211_rxmgmt_flags * @gfp: context flags * * This function is called whenever an Action frame is received for a station @@ -4067,7 +4068,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * driver is responsible for rejecting the frame. */ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, - const u8 *buf, size_t len, gfp_t gfp); + const u8 *buf, size_t len, u32 flags, gfp_t gfp); /** * cfg80211_mgmt_tx_status - notification of TX status for management frame diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1f42bc3dcb9c..fde2c021b26d 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1493,6 +1493,9 @@ enum nl80211_commands { * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter * field in the probe response (%NL80211_ATTR_PROBE_RESP). * + * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32. + * As specified in the &enum nl80211_rxmgmt_flags. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1801,6 +1804,8 @@ enum nl80211_attrs { NL80211_ATTR_CSA_C_OFF_BEACON, NL80211_ATTR_CSA_C_OFF_PRESP, + NL80211_ATTR_RXMGMT_FLAGS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3901,4 +3906,15 @@ enum nl80211_crit_proto_id { /* maximum duration for critical protocol measures */ #define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */ +/** + * enum nl80211_rxmgmt_flags - flags for received management frame. + * + * Used by cfg80211_rx_mgmt() + * + * @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver. + */ +enum nl80211_rxmgmt_flags { + NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ffad155316a9..07901050812f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2678,8 +2678,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) sig = status->signal; if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig, - rx->skb->data, rx->skb->len, - GFP_ATOMIC)) { + rx->skb->data, rx->skb->len, 0, GFP_ATOMIC)) { if (rx->sta) rx->sta->rx_packets++; dev_kfree_skb(rx->skb); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index bfac5e186f57..8d49c1ce3dea 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -621,7 +621,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, } bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, - const u8 *buf, size_t len, gfp_t gfp) + const u8 *buf, size_t len, u32 flags, gfp_t gfp) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); @@ -664,7 +664,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, /* Indicate the received Action frame to user space */ if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, freq, sig_mbm, - buf, len, gfp)) + buf, len, flags, gfp)) continue; result = true; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 334697de5cc0..a51269d2d488 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10446,7 +10446,7 @@ EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u32 nlportid, int freq, int sig_dbm, - const u8 *buf, size_t len, gfp_t gfp) + const u8 *buf, size_t len, u32 flags, gfp_t gfp) { struct net_device *netdev = wdev->netdev; struct sk_buff *msg; @@ -10469,7 +10469,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || (sig_dbm && nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || - nla_put(msg, NL80211_ATTR_FRAME, len, buf)) + nla_put(msg, NL80211_ATTR_FRAME, len, buf) || + (flags && + nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags))) goto nla_put_failure; genlmsg_end(msg, hdr); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 44341bf53cfc..2c0f2b3c07cb 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -66,7 +66,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u32 nlpid, int freq, int sig_dbm, - const u8 *buf, size_t len, gfp_t gfp); + const u8 *buf, size_t len, u32 flags, gfp_t gfp); void nl80211_radar_notify(struct cfg80211_registered_device *rdev, -- cgit v1.2.3 From bcdd822007e44b1da1ad5a62f20b75ee7d8da608 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 26 Aug 2013 15:32:58 +0800 Subject: mac80211_hwsim: fix error return code in init_mac80211_hwsim() Fix to return -ENOMEM in the netdev alloc error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a0d2aacd5e09..2cd3f54e1efa 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2528,8 +2528,10 @@ static int __init init_mac80211_hwsim(void) } hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); - if (hwsim_mon == NULL) + if (hwsim_mon == NULL) { + err = -ENOMEM; goto failed; + } rtnl_lock(); -- cgit v1.2.3 From 21c6af6b69b609b7934caaccda1b4535dceb402c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 22 Aug 2013 20:53:21 +0200 Subject: rt2x00: rt2800lib: add rt2800_hw_beacon_base helper The HW_BEACON_BASE() macro returns the base address of a given beacon, however the returned values are not usable on all chipsets. On devices which have selectable shared memory parts, some beacon may be located in the high part of the shared memory. Instead of extending the already complicated macro, add a new helper function and use that to get the base address of a given beacon. The actual patch contains no functional changes, the helper function will be extended in a further patch to handle different chipsets' requirements. Signed-off-by: Gabor Juhos Acked-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index aa6b6b022547..38606e2f8a52 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -940,6 +940,12 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) } EXPORT_SYMBOL_GPL(rt2800_txdone_entry); +static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, + unsigned int index) +{ + return HW_BEACON_BASE(index); +} + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; @@ -992,7 +998,8 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) return; } - beacon_base = HW_BEACON_BASE(entry->entry_idx); + beacon_base = rt2800_hw_beacon_base(rt2x00dev, entry->entry_idx); + rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, entry->skb->len + padding_len); @@ -1017,7 +1024,7 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev, const int txwi_desc_size = rt2x00dev->bcn->winfo_size; unsigned int beacon_base; - beacon_base = HW_BEACON_BASE(index); + beacon_base = rt2800_hw_beacon_base(rt2x00dev, index); /* * For the Beacon base registers we only need to clear -- cgit v1.2.3 From 634b80595fef79071d82bc231b7f82c4f808a1e8 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 22 Aug 2013 20:53:22 +0200 Subject: rt2x00: rt2800lib: don't hardcode beacon offsets The values written into the BCN_OFFSET[01] registers are hardcoded in the rt2800_init_register function. Add a macro and a helper function to derive these values directly from the base address of a given beacon, and use the new function instead of the hardcoded numbers. The patch contains no functional changes. The programmed register values are the same before and after the patch. Signed-off-by: Gabor Juhos Acked-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 2 ++ drivers/net/wireless/rt2x00/rt2800lib.c | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index e25e5bf34aa7..fa33b5edf931 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2024,6 +2024,8 @@ struct mac_iveiv_entry { (((__index) < 6) ? (HW_BEACON_BASE4 + ((__index - 4) * 0x0200)) : \ (HW_BEACON_BASE6 - ((__index - 6) * 0x0200)))) +#define BEACON_BASE_TO_OFFSET(_base) (((_base) - 0x4000) / 64) + /* * BBP registers. * The wordsize of the BBP is 8 bits. diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 38606e2f8a52..20243dcd4a6c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -946,6 +946,12 @@ static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, return HW_BEACON_BASE(index); } +static inline u8 rt2800_get_beacon_offset(struct rt2x00_dev *rt2x00dev, + unsigned int index) +{ + return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index)); +} + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; @@ -4474,17 +4480,25 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) return ret; rt2800_register_read(rt2x00dev, BCN_OFFSET0, ®); - rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN0, + rt2800_get_beacon_offset(rt2x00dev, 0)); + rt2x00_set_field32(®, BCN_OFFSET0_BCN1, + rt2800_get_beacon_offset(rt2x00dev, 1)); + rt2x00_set_field32(®, BCN_OFFSET0_BCN2, + rt2800_get_beacon_offset(rt2x00dev, 2)); + rt2x00_set_field32(®, BCN_OFFSET0_BCN3, + rt2800_get_beacon_offset(rt2x00dev, 3)); rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg); rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®); - rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN4, + rt2800_get_beacon_offset(rt2x00dev, 4)); + rt2x00_set_field32(®, BCN_OFFSET1_BCN5, + rt2800_get_beacon_offset(rt2x00dev, 5)); + rt2x00_set_field32(®, BCN_OFFSET1_BCN6, + rt2800_get_beacon_offset(rt2x00dev, 6)); + rt2x00_set_field32(®, BCN_OFFSET1_BCN7, + rt2800_get_beacon_offset(rt2x00dev, 7)); rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg); rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); -- cgit v1.2.3 From aa51e598d04c6acf5477934cd6383f5a17ce9029 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 24 Aug 2013 00:32:31 +0200 Subject: brcmsmac: use bcma PCIe up and down functions replace the calls to bcma_core_pci_extend_L1timer() by calls to the newly introduced bcma_core_pci_ip() and bcma_core_pci_down() Signed-off-by: Hauke Mehrtens Cc: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/aiutils.c | 21 --------------------- drivers/net/wireless/brcm80211/brcmsmac/aiutils.h | 3 --- drivers/net/wireless/brcm80211/brcmsmac/main.c | 8 ++++---- 3 files changed, 4 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c index e4fd1ee3d690..53365977bfd6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c @@ -679,27 +679,6 @@ bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode) return mode == BCMA_CLKMODE_FAST; } -void ai_pci_up(struct si_pub *sih) -{ - struct si_info *sii; - - sii = container_of(sih, struct si_info, pub); - - if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) - bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], true); -} - -/* Unconfigure and/or apply various WARs when going down */ -void ai_pci_down(struct si_pub *sih) -{ - struct si_info *sii; - - sii = container_of(sih, struct si_info, pub); - - if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) - bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], false); -} - /* Enable BT-COEX & Ex-PA for 4313 */ void ai_epa_4313war(struct si_pub *sih) { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h index 89562c1fbf49..a8a267b5b87a 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h @@ -183,9 +183,6 @@ extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih); extern bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode); extern bool ai_deviceremoved(struct si_pub *sih); -extern void ai_pci_down(struct si_pub *sih); -extern void ai_pci_up(struct si_pub *sih); - /* Enable Ex-PA for 4313 */ extern void ai_epa_4313war(struct si_pub *sih); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index c3c6123dc7dd..4608e0eb1493 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -4669,7 +4669,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, brcms_c_coredisable(wlc_hw); /* Match driver "down" state */ - ai_pci_down(wlc_hw->sih); + bcma_core_pci_down(wlc_hw->d11core->bus); /* turn off pll and xtal to match driver "down" state */ brcms_b_xtal(wlc_hw, OFF); @@ -5012,12 +5012,12 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) */ if (brcms_b_radio_read_hwdisabled(wlc_hw)) { /* put SB PCI in down state again */ - ai_pci_down(wlc_hw->sih); + bcma_core_pci_down(wlc_hw->d11core->bus); brcms_b_xtal(wlc_hw, OFF); return -ENOMEDIUM; } - ai_pci_up(wlc_hw->sih); + bcma_core_pci_up(wlc_hw->d11core->bus); /* reset the d11 core */ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); @@ -5214,7 +5214,7 @@ static int brcms_b_down_finish(struct brcms_hardware *wlc_hw) /* turn off primary xtal and pll */ if (!wlc_hw->noreset) { - ai_pci_down(wlc_hw->sih); + bcma_core_pci_down(wlc_hw->d11core->bus); brcms_b_xtal(wlc_hw, OFF); } } -- cgit v1.2.3 From 50023008f63c162bdb4b688c65d826bad627120e Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 24 Aug 2013 00:32:34 +0200 Subject: b43: call PCIe up and down functions Tell the PCIe host core when the wifi is activated. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 0e933bb71543..ccd24f0acb8d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4645,6 +4645,19 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PSM_RUN, B43_MACCTL_PSM_JMP0); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_core_pci_down(dev->dev->bdev->bus); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + /* TODO */ + break; +#endif + } + b43_dma_free(dev); b43_pio_free(dev); b43_chip_exit(dev); @@ -4684,6 +4697,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) case B43_BUS_BCMA: bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0], dev->dev->bdev, true); + bcma_core_pci_up(dev->dev->bdev->bus); break; #endif #ifdef CONFIG_B43_SSB -- cgit v1.2.3 From 027d3307f44c6ddccb2194474a18ff71cbff0ad9 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 23 Aug 2013 16:48:21 -0700 Subject: mwifiex: fix driver unload problem for usb chipsets We have usb_deregister() call in our rmmod routine. deauth, shutdown etc. commands will be sent to FW later when bus driver calls disconnect handler. This mechanism works fine with SDIO and PCIe interfaces, but there is an issue with USB. USB bus driver returns all URBs submitted for receiving data and command response immediately after usb_deregister() with failure status. Hence we don't send deauth, shutdown etc. command to firmware. The problem is fixed by moving code from disconnect handler to rmmod routine for USB interface. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/usb.c | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index fca98b5d7de4..2472d4b7f00e 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -24,9 +24,9 @@ static const char usbdriver_name[] = "usb8797"; -static u8 user_rmmod; static struct mwifiex_if_ops usb_ops; static struct semaphore add_remove_card_sem; +static struct usb_card_rec *usb_card; static struct usb_device_id mwifiex_usb_table[] = { {USB_DEVICE(USB8797_VID, USB8797_PID_1)}, @@ -350,6 +350,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf, card->udev = udev; card->intf = intf; + usb_card = card; pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n", udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, @@ -532,7 +533,6 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; - int i; if (!card || !card->adapter) { pr_err("%s: card or card->adapter is NULL\n", __func__); @@ -543,27 +543,6 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) if (!adapter->priv_num) return; - /* In case driver is removed when asynchronous FW downloading is - * in progress - */ - wait_for_completion(&adapter->fw_load); - - if (user_rmmod) { -#ifdef CONFIG_PM - if (adapter->is_suspended) - mwifiex_usb_resume(intf); -#endif - for (i = 0; i < adapter->priv_num; i++) - if ((GET_BSS_ROLE(adapter->priv[i]) == - MWIFIEX_BSS_ROLE_STA) && - adapter->priv[i]->media_connected) - mwifiex_deauthenticate(adapter->priv[i], NULL); - - mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, - MWIFIEX_BSS_ROLE_ANY), - MWIFIEX_FUNC_SHUTDOWN); - } - mwifiex_usb_free(card); dev_dbg(adapter->dev, "%s: removing card\n", __func__); @@ -1032,8 +1011,29 @@ static void mwifiex_usb_cleanup_module(void) if (!down_interruptible(&add_remove_card_sem)) up(&add_remove_card_sem); - /* set the flag as user is removing this module */ - user_rmmod = 1; + if (usb_card) { + struct mwifiex_adapter *adapter = usb_card->adapter; + int i; + + /* In case driver is removed when asynchronous FW downloading is + * in progress + */ + wait_for_completion(&adapter->fw_load); + +#ifdef CONFIG_PM + if (adapter->is_suspended) + mwifiex_usb_resume(usb_card->intf); +#endif + for (i = 0; i < adapter->priv_num; i++) + if ((GET_BSS_ROLE(adapter->priv[i]) == + MWIFIEX_BSS_ROLE_STA) && + adapter->priv[i]->media_connected) + mwifiex_deauthenticate(adapter->priv[i], NULL); + + mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_FUNC_SHUTDOWN); + } usb_deregister(&mwifiex_usb_driver); } -- cgit v1.2.3 From 68f95b09c80af7a0b7a27a03227fa802d55f3616 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 23 Aug 2013 16:48:22 -0700 Subject: mwifiex: fix ext_capab IE structure definition EXT_CAPAB_IE format involves IEEE header followed by bytestream of capabilities. Current structure has incorrect member u8 for data; fix it by defining it as u8[0]. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n.c | 10 ++++++---- drivers/net/wireless/mwifiex/fw.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 41e9d25a2d8e..b579a2e54f4b 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -292,6 +292,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, struct mwifiex_ie_types_extcap *ext_cap; int ret_len = 0; struct ieee80211_supported_band *sband; + struct ieee_types_header *hdr; u8 radio_type; if (!buffer || !*buffer) @@ -388,17 +389,18 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, } if (bss_desc->bcn_ext_cap) { + hdr = (void *)bss_desc->bcn_ext_cap; ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); - ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap)); + ext_cap->header.len = cpu_to_le16(hdr->len); - memcpy((u8 *)ext_cap + sizeof(struct mwifiex_ie_types_header), + memcpy((u8 *)ext_cap->ext_capab, bss_desc->bcn_ext_cap + sizeof(struct ieee_types_header), le16_to_cpu(ext_cap->header.len)); - *buffer += sizeof(struct mwifiex_ie_types_extcap); - ret_len += sizeof(struct mwifiex_ie_types_extcap); + *buffer += sizeof(struct mwifiex_ie_types_extcap) + hdr->len; + ret_len += sizeof(struct mwifiex_ie_types_extcap) + hdr->len; } return ret_len; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index c9ad1c0d338d..f80f30b6160e 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -1330,7 +1330,7 @@ struct mwifiex_ie_types_2040bssco { struct mwifiex_ie_types_extcap { struct mwifiex_ie_types_header header; - u8 ext_cap; + u8 ext_capab[0]; } __packed; struct host_cmd_ds_mac_reg_access { -- cgit v1.2.3 From 587b36d3642bdc921f4d624a740b6d91f779324b Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 23 Aug 2013 16:48:23 -0700 Subject: mwifiex: drop gratuitous ARP frames This patch adds support for dropping gratuitous ARP frames which is requirement for WFA Hotspot2.0. Hotspot2.0 capability is enabled in driver if extended capabilities IE from BSS descriptor has 11u interworking enabled. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n.c | 6 ++++ drivers/net/wireless/mwifiex/cfg80211.c | 1 + drivers/net/wireless/mwifiex/decl.h | 9 ++++++ drivers/net/wireless/mwifiex/init.c | 1 + drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sta_rx.c | 49 +++++++++++++++++++++++++++++++++ 6 files changed, 67 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index b579a2e54f4b..0b803c05cab3 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -399,6 +399,12 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, bss_desc->bcn_ext_cap + sizeof(struct ieee_types_header), le16_to_cpu(ext_cap->header.len)); + if (hdr->len > 3 && + ext_cap->ext_capab[3] & WLAN_EXT_CAPA4_INTERWORKING_ENABLED) + priv->hs2_enabled = true; + else + priv->hs2_enabled = false; + *buffer += sizeof(struct mwifiex_ie_types_extcap) + hdr->len; ret_len += sizeof(struct mwifiex_ie_types_extcap) + hdr->len; } diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ca149aea1517..fbad00a5abc8 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1508,6 +1508,7 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, " reason code %d\n", priv->cfg_bssid, reason_code); memset(priv->cfg_bssid, 0, ETH_ALEN); + priv->hs2_enabled = false; return 0; } diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index a5993475daef..5c85d7803d00 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -152,4 +153,12 @@ struct mwifiex_types_wmm_info { u8 reserved; struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS]; } __packed; + +struct mwifiex_arp_eth_header { + struct arphdr hdr; + u8 ar_sha[ETH_ALEN]; + u8 ar_sip[4]; + u8 ar_tha[ETH_ALEN]; + u8 ar_tip[4]; +} __packed; #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e021a581a143..6499117fce43 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -136,6 +136,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->csa_chan = 0; priv->csa_expire_time = 0; priv->del_list_idx = 0; + priv->hs2_enabled = false; return mwifiex_add_bss_prio_tbl(priv); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d2e5ccd891da..7d4d13779625 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -516,6 +516,7 @@ struct mwifiex_private { u8 csa_chan; unsigned long csa_expire_time; u8 del_list_idx; + bool hs2_enabled; }; enum mwifiex_ba_status { diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index b5c109504393..bb22664923ef 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -17,6 +17,8 @@ * this warranty disclaimer. */ +#include +#include #include "decl.h" #include "ioctl.h" #include "util.h" @@ -25,6 +27,46 @@ #include "11n_aggr.h" #include "11n_rxreorder.h" +/* This function checks if a frame is IPv4 ARP or IPv6 Neighbour advertisement + * frame. If frame has both source and destination mac address as same, this + * function drops such gratuitous frames. + */ +static bool +mwifiex_discard_gratuitous_arp(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + const struct mwifiex_arp_eth_header *arp; + struct ethhdr *eth_hdr; + struct ipv6hdr *ipv6; + struct icmp6hdr *icmpv6; + + eth_hdr = (struct ethhdr *)skb->data; + switch (ntohs(eth_hdr->h_proto)) { + case ETH_P_ARP: + arp = (void *)(skb->data + sizeof(struct ethhdr)); + if (arp->hdr.ar_op == htons(ARPOP_REPLY) || + arp->hdr.ar_op == htons(ARPOP_REQUEST)) { + if (!memcmp(arp->ar_sip, arp->ar_tip, 4)) + return true; + } + break; + case ETH_P_IPV6: + ipv6 = (void *)(skb->data + sizeof(struct ethhdr)); + icmpv6 = (void *)(skb->data + sizeof(struct ethhdr) + + sizeof(struct ipv6hdr)); + if (NDISC_NEIGHBOUR_ADVERTISEMENT == icmpv6->icmp6_type) { + if (!memcmp(&ipv6->saddr, &ipv6->daddr, + sizeof(struct in6_addr))) + return true; + } + break; + default: + break; + } + + return false; +} + /* * This function processes the received packet and forwards it * to kernel/upper layer. @@ -90,6 +132,13 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, either the reconstructed EthII frame or the 802.2/llc/snap frame */ skb_pull(skb, hdr_chop); + if (priv->hs2_enabled && + mwifiex_discard_gratuitous_arp(priv, skb)) { + dev_dbg(priv->adapter->dev, "Bypassed Gratuitous ARP\n"); + dev_kfree_skb_any(skb); + return 0; + } + priv->rxpd_rate = local_rx_pd->rx_rate; priv->rxpd_htinfo = local_rx_pd->ht_info; -- cgit v1.2.3 From b380a43b52bee70f2e31ed573d33191efd82f5ae Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 25 Aug 2013 14:43:09 +0530 Subject: ath9k: Fix ASPM for AR9462 If the L1 entrance latency is not calibrated properly in the EEPROM in WB222 boards, there could be problems in connectivity. Check and correct the calibrated value if it doesn't match the optimal value for WB222, 4us. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/pci.c | 16 ++++++++++++++++ 3 files changed, 31 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 738aa7e454d8..582cddddddd7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -745,6 +745,20 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah) static void ar9003_hw_configpcipowersave(struct ath_hw *ah, bool power_off) { + /* + * Increase L1 Entry Latency. Some WB222 boards don't have + * this change in eeprom/OTP. + * + */ + if (AR_SREV_9462(ah)) { + u32 val = ah->config.aspm_l1_fix; + if ((val & 0xff000000) == 0x17000000) { + val &= 0x00ffffff; + val |= 0x27000000; + REG_WRITE(ah, 0x570c, val); + } + } + /* Nothing to do on restore for 11N */ if (!power_off /* !restore */) { /* set bit 19 to allow forcing of pcie core into L1 state */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index fa543a62e839..69a907b55a73 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -311,6 +311,7 @@ struct ath9k_ops_config { u16 ani_poll_interval; /* ANI poll interval in ms */ /* Platform specific config */ + u32 aspm_l1_fix; u32 xlna_gpio; u32 ant_ctrl_comm2g_switch_enable; bool xatten_margin_cfg; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 32807987dd67..e7996a64a49d 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -314,6 +314,22 @@ static void ath_pci_aspm_init(struct ath_common *common) return; } + /* + * 0x70c - Ack Frequency Register. + * + * Bits 27:29 - DEFAULT_L1_ENTRANCE_LATENCY. + * + * 000 : 1 us + * 001 : 2 us + * 010 : 4 us + * 011 : 8 us + * 100 : 16 us + * 101 : 32 us + * 110/111 : 64 us + */ + if (AR_SREV_9462(ah)) + pci_read_config_dword(pdev, 0x70c, &ah->config.aspm_l1_fix); + pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm); if (aspm & (PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1)) { ah->aspm_enabled = true; -- cgit v1.2.3 From 8aada63cc408874916a19341ba514f941096e424 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Sun, 25 Aug 2013 11:50:49 +0100 Subject: ath5k: debugfs: NULL-terminate strings Avoid processing garbage data by NULL terminating the strings. Signed-off-by: Djalal Harouni Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/debug.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 9d00dab666a8..b8d031ae63c2 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -245,9 +245,11 @@ static ssize_t write_file_beacon(struct file *file, struct ath5k_hw *ah = file->private_data; char buf[20]; - if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + count = min_t(size_t, count, sizeof(buf) - 1); + if (copy_from_user(buf, userbuf, count)) return -EFAULT; + buf[count] = '\0'; if (strncmp(buf, "disable", 7) == 0) { AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); pr_info("debugfs disable beacons\n"); @@ -345,9 +347,11 @@ static ssize_t write_file_debug(struct file *file, unsigned int i; char buf[20]; - if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + count = min_t(size_t, count, sizeof(buf) - 1); + if (copy_from_user(buf, userbuf, count)) return -EFAULT; + buf[count] = '\0'; for (i = 0; i < ARRAY_SIZE(dbg_info); i++) { if (strncmp(buf, dbg_info[i].name, strlen(dbg_info[i].name)) == 0) { @@ -448,9 +452,11 @@ static ssize_t write_file_antenna(struct file *file, unsigned int i; char buf[20]; - if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + count = min_t(size_t, count, sizeof(buf) - 1); + if (copy_from_user(buf, userbuf, count)) return -EFAULT; + buf[count] = '\0'; if (strncmp(buf, "diversity", 9) == 0) { ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); pr_info("debug: enable diversity\n"); @@ -619,9 +625,11 @@ static ssize_t write_file_frameerrors(struct file *file, struct ath5k_statistics *st = &ah->stats; char buf[20]; - if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + count = min_t(size_t, count, sizeof(buf) - 1); + if (copy_from_user(buf, userbuf, count)) return -EFAULT; + buf[count] = '\0'; if (strncmp(buf, "clear", 5) == 0) { st->rxerr_crc = 0; st->rxerr_phy = 0; @@ -766,9 +774,11 @@ static ssize_t write_file_ani(struct file *file, struct ath5k_hw *ah = file->private_data; char buf[20]; - if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + count = min_t(size_t, count, sizeof(buf) - 1); + if (copy_from_user(buf, userbuf, count)) return -EFAULT; + buf[count] = '\0'; if (strncmp(buf, "sens-low", 8) == 0) { ath5k_ani_init(ah, ATH5K_ANI_MODE_MANUAL_HIGH); } else if (strncmp(buf, "sens-high", 9) == 0) { @@ -862,9 +872,11 @@ static ssize_t write_file_queue(struct file *file, struct ath5k_hw *ah = file->private_data; char buf[20]; - if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + count = min_t(size_t, count, sizeof(buf) - 1); + if (copy_from_user(buf, userbuf, count)) return -EFAULT; + buf[count] = '\0'; if (strncmp(buf, "start", 5) == 0) ieee80211_wake_queues(ah->hw); else if (strncmp(buf, "stop", 4) == 0) -- cgit v1.2.3 From d1ae25a0174938f03e28dee8f3269a826fc1bec5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 25 Aug 2013 16:30:40 +0530 Subject: ath9k: Fix ASPM workaround usage The PCIE Workaround register (AR_WA/0x4004) is used to handle various hardware quirks. For AR9002 chips, AR_WA_D3_L1_DISABLE is used to prevent the HW from automatically entering L1 state when D3 is enforced. AR_WA_D3_L1_DISABLE has to be enabled for a few AR9280 based cards, mark them based on their PCI subdevice/subvendor IDs and enforce it in ar9002_hw_configpcipowersave(). Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_hw.c | 29 +++++++------------ drivers/net/wireless/ath/ath9k/ar9003_hw.c | 7 +---- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 1 - drivers/net/wireless/ath/ath9k/init.c | 5 ++++ drivers/net/wireless/ath/ath9k/pci.c | 46 ++++++++++++++++++++++++++++++ 6 files changed, 64 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 8dc2d089cdef..fb61b081d172 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -269,13 +269,12 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE) val |= AR_WA_D3_L1_DISABLE; } else { - if (((AR_SREV_9285(ah) || - AR_SREV_9271(ah) || - AR_SREV_9287(ah)) && - (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) || - (AR_SREV_9280(ah) && - (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) { - val |= AR_WA_D3_L1_DISABLE; + if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) { + if (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE) + val |= AR_WA_D3_L1_DISABLE; + } else if (AR_SREV_9280(ah)) { + if (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE) + val |= AR_WA_D3_L1_DISABLE; } } @@ -297,24 +296,18 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, } else { if (ah->config.pcie_waen) { val = ah->config.pcie_waen; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); + val &= (~AR_WA_D3_L1_DISABLE); } else { - if (AR_SREV_9285(ah) || - AR_SREV_9271(ah) || - AR_SREV_9287(ah)) { + if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) { val = AR9285_WA_DEFAULT; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); - } - else if (AR_SREV_9280(ah)) { + val &= (~AR_WA_D3_L1_DISABLE); + } else if (AR_SREV_9280(ah)) { /* * For AR9280 chips, bit 22 of 0x4004 * needs to be set. */ val = AR9280_WA_DEFAULT; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); + val &= (~AR_WA_D3_L1_DISABLE); } else { val = AR_WA_DEFAULT; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 582cddddddd7..608bb4824e2a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -763,12 +763,7 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, if (!power_off /* !restore */) { /* set bit 19 to allow forcing of pcie core into L1 state */ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - - /* Several PCIe massages to ensure proper behaviour */ - if (ah->config.pcie_waen) - REG_WRITE(ah, AR_WA, ah->config.pcie_waen); - else - REG_WRITE(ah, AR_WA, ah->WARegVal); + REG_WRITE(ah, AR_WA, ah->WARegVal); } /* diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8519e75a2e79..2ee35f677c0e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -631,6 +631,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); #define ATH9K_PCI_CUS217 0x0004 #define ATH9K_PCI_WOW 0x0008 #define ATH9K_PCI_BT_ANT_DIV 0x0010 +#define ATH9K_PCI_D3_L1_WAR 0x0020 /* * Default cache line size, in bytes. diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b3a6891fe3d7..2670bf6cb066 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -450,7 +450,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.ack_6mb = 0x0; ah->config.cwm_ignore_extcca = 0; ah->config.pcie_clock_req = 0; - ah->config.pcie_waen = 0; ah->config.analog_shiftreg = 1; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 19b46c7e3616..c9f787dea3f6 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -551,6 +551,11 @@ static void ath9k_init_platform(struct ath_softc *sc) pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV; ath_info(common, "Set BT/WLAN RX diversity capability\n"); } + + if (sc->driver_data & ATH9K_PCI_D3_L1_WAR) { + ah->config.pcie_waen = 0x0040473b; + ath_info(common, "Enable WAR for ASPM D3/L1\n"); + } } static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index e7996a64a49d..d089a7cf01c4 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -30,6 +30,52 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_AZWAVE, + 0x1C71), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_FOXCONN, + 0xE01F), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x11AD, /* LITEON */ + 0x6632), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x11AD, /* LITEON */ + 0x6642), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_QMI, + 0x0306), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x185F, /* WNC */ + 0x309D), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x147C), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x147D), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x1536), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + /* AR9285 card for Asus */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x002B, -- cgit v1.2.3 From d4c04ba141d4c5981aebc0aa0ecadc0f16f99387 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 26 Aug 2013 11:47:22 +0530 Subject: ath9k: Fix TX poll work locking There is no need to call ath_txq_unlock_complete() in the TX poll routine - frame completion is not done here, so use ath_txq_unlock(). Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index fff5d3ccc663..2f831db396ac 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -41,7 +41,7 @@ void ath_tx_complete_poll_work(struct work_struct *work) txq->axq_tx_inprogress = true; } } - ath_txq_unlock_complete(sc, txq); + ath_txq_unlock(sc, txq); } if (needreset) { -- cgit v1.2.3 From cfcd926ea2bc46aaca4e9ca3f0a3b8ac35b9d691 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Mon, 26 Aug 2013 09:18:06 +0200 Subject: mwifiex: add missing endian conversions Fixes multiple locations where a little endian host is assumed during ser/des of messages sent to/received from the chip. Signed-off-by: Tobias Waldekranz Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_aggr.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/sdio.c | 6 +++--- drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 8f9f54231a1c..f69d7e068e75 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -69,7 +69,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); /* Copy SNAP header */ - snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset); + snap.snap_type = le16_to_cpu(*(__le16 *) ((u8 *)skb_src->data + dt_offset)); dt_offset += sizeof(u16); memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 7d4d13779625..1d72f13adb9d 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1026,7 +1026,7 @@ mwifiex_netdev_get_priv(struct net_device *dev) */ static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb) { - return (*(u32 *)skb->data == PKT_TYPE_MGMT); + return (le32_to_cpu(*(__le32 *)skb->data) == PKT_TYPE_MGMT); } /* This function retrieves channel closed for operation by Channel diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 0e2070f72fed..1576104e3d95 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1062,7 +1062,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, case MWIFIEX_TYPE_EVENT: dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); - adapter->event_cause = *(u32 *) skb->data; + adapter->event_cause = le32_to_cpu(*(__le32 *) skb->data); if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) memcpy(adapter->event_body, @@ -1207,8 +1207,8 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { /* get curr PKT len & type */ - pkt_len = *(u16 *) &curr_ptr[0]; - pkt_type = *(u16 *) &curr_ptr[2]; + pkt_len = le16_to_cpu(*(__le16 *) &curr_ptr[0]); + pkt_type = le16_to_cpu(*(__le16 *) &curr_ptr[2]); /* copy pkt to deaggr buf */ skb_deaggr = card->mpa_rx.skb_arr[pind]; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 6a814eb2671a..58a6013712d2 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -280,7 +280,7 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, tlv_buf = ((u8 *)rate_cfg) + sizeof(struct host_cmd_ds_tx_rate_cfg); - tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16)); + tlv_buf_len = le16_to_cpu(*(__le16 *) (tlv_buf + sizeof(u16))); while (tlv_buf && tlv_buf_len > 0) { tlv = (*tlv_buf); -- cgit v1.2.3 From 58fe431342fdcf53fe93c4482351a9aa46762a11 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 26 Aug 2013 15:32:01 +0800 Subject: zd1201: fix error return code Fix to return -ENOMEM in the memory alloc error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: John W. Linville --- drivers/net/wireless/zd1201.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 4941f201d6c8..73aa7388dd2b 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -75,8 +75,10 @@ static int zd1201_fw_upload(struct usb_device *dev, int apfw) len = fw_entry->size; buf = kmalloc(1024, GFP_ATOMIC); - if (!buf) + if (!buf) { + err = -ENOMEM; goto exit; + } while (len > 0) { int translen = (len > 1024) ? 1024 : len; @@ -1762,8 +1764,10 @@ static int zd1201_probe(struct usb_interface *interface, zd->endp_out2 = 2; zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL); zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!zd->rx_urb || !zd->tx_urb) + if (!zd->rx_urb || !zd->tx_urb) { + err = -ENOMEM; goto err_zd; + } mdelay(100); err = zd1201_drvr_start(zd); -- cgit v1.2.3 From e5614a91be86b4b2d56f68c036fd7e81473b4016 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 26 Aug 2013 13:23:43 +0530 Subject: ath9k: Fix DEBUG_FS dependency for ath9k Reported-by: Johannes Berg Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index c91bc6111c23..7944c25c9a43 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -56,7 +56,7 @@ config ATH9K_AHB config ATH9K_DEBUGFS bool "Atheros ath9k debugging" - depends on ATH9K + depends on ATH9K && DEBUG_FS select MAC80211_DEBUGFS select RELAY ---help--- -- cgit v1.2.3 From 93ba2a856f75aead35a043f169a49ce398afe737 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 26 Aug 2013 13:53:30 +0200 Subject: Update e-mail address for Andrea Merello (resubmit) A lot of files contain reference to my old e-mail address. Now I'm going not to read mail from it anymore, so update it with my current address everywhere. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 6 +++--- drivers/net/wireless/rtl818x/rtl8180/grf5101.c | 2 +- drivers/net/wireless/rtl818x/rtl8180/grf5101.h | 2 +- drivers/net/wireless/rtl818x/rtl8180/max2820.c | 2 +- drivers/net/wireless/rtl818x/rtl8180/max2820.h | 2 +- drivers/net/wireless/rtl818x/rtl8180/rtl8225.c | 4 ++-- drivers/net/wireless/rtl818x/rtl8180/sa2400.c | 2 +- drivers/net/wireless/rtl818x/rtl8180/sa2400.h | 2 +- drivers/net/wireless/rtl818x/rtl8187/dev.c | 6 +++--- drivers/net/wireless/rtl818x/rtl8187/rtl8187.h | 4 ++-- drivers/net/wireless/rtl818x/rtl8187/rtl8225.c | 4 ++-- drivers/net/wireless/rtl818x/rtl8187/rtl8225.h | 4 ++-- drivers/net/wireless/rtl818x/rtl818x.h | 4 ++-- drivers/staging/rtl8187se/ieee80211/ieee80211.h | 2 +- drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c | 2 +- drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c | 2 +- drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c | 2 +- drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c | 2 +- drivers/staging/rtl8187se/r8180.h | 2 +- drivers/staging/rtl8187se/r8180_93cx6.h | 2 +- drivers/staging/rtl8187se/r8180_core.c | 4 ++-- drivers/staging/rtl8187se/r8180_hw.h | 2 +- drivers/staging/rtl8187se/r8180_rtl8225.h | 2 +- drivers/staging/rtl8187se/r8180_rtl8225z2.c | 2 +- drivers/staging/rtl8187se/r8180_wx.c | 2 +- drivers/staging/rtl8187se/r8180_wx.h | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_cam.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pci.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pci.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- drivers/staging/rtl8192e/rtllib_debug.h | 2 +- drivers/staging/rtl8192e/rtllib_rx.c | 2 +- drivers/staging/rtl8192e/rtllib_softmac.c | 2 +- drivers/staging/rtl8192e/rtllib_softmac_wx.c | 2 +- drivers/staging/rtl8192e/rtllib_tx.c | 2 +- drivers/staging/rtl8192u/authors | 2 +- drivers/staging/rtl8192u/ieee80211/ieee80211.h | 2 +- drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c | 2 +- drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c | 2 +- drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c | 2 +- drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c | 2 +- drivers/staging/rtl8192u/r8180_93cx6.c | 2 +- drivers/staging/rtl8192u/r8180_93cx6.h | 2 +- drivers/staging/rtl8192u/r8180_pm.c | 2 +- drivers/staging/rtl8192u/r8180_pm.h | 2 +- drivers/staging/rtl8192u/r8190_rtl8256.h | 2 +- drivers/staging/rtl8192u/r8192U.h | 2 +- drivers/staging/rtl8192u/r8192U_core.c | 2 +- drivers/staging/rtl8192u/r8192U_hw.h | 2 +- drivers/staging/rtl8192u/r8192U_wx.c | 2 +- drivers/staging/rtl8192u/r8192U_wx.h | 2 +- 61 files changed, 71 insertions(+), 71 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 91a04e2b8ece..fc207b268e4f 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -3,10 +3,10 @@ * Linux device driver for RTL8180 / RTL8185 * * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * * Thanks to Realtek for their support! * @@ -32,7 +32,7 @@ #include "grf5101.h" MODULE_AUTHOR("Michael Wu "); -MODULE_AUTHOR("Andrea Merello "); +MODULE_AUTHOR("Andrea Merello "); MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rtl818x/rtl8180/grf5101.c b/drivers/net/wireless/rtl818x/rtl8180/grf5101.c index 077ff92cc139..dc845693f321 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/grf5101.c +++ b/drivers/net/wireless/rtl818x/rtl8180/grf5101.c @@ -2,7 +2,7 @@ /* * Radio tuning for GCT GRF5101 on RTL8180 * - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Code from the BSD driver and the rtl8181 project have been * very useful to understand certain things diff --git a/drivers/net/wireless/rtl818x/rtl8180/grf5101.h b/drivers/net/wireless/rtl818x/rtl8180/grf5101.h index 76647111bcff..4d80a2785123 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/grf5101.h +++ b/drivers/net/wireless/rtl818x/rtl8180/grf5101.h @@ -4,7 +4,7 @@ /* * Radio tuning for GCT GRF5101 on RTL8180 * - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Code from the BSD driver and the rtl8181 project have been * very useful to understand certain things diff --git a/drivers/net/wireless/rtl818x/rtl8180/max2820.c b/drivers/net/wireless/rtl818x/rtl8180/max2820.c index 4715000c94dd..a63c443c3c6f 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/max2820.c +++ b/drivers/net/wireless/rtl818x/rtl8180/max2820.c @@ -1,7 +1,7 @@ /* * Radio tuning for Maxim max2820 on RTL8180 * - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Code from the BSD driver and the rtl8181 project have been * very useful to understand certain things diff --git a/drivers/net/wireless/rtl818x/rtl8180/max2820.h b/drivers/net/wireless/rtl818x/rtl8180/max2820.h index 61cf6d1e7d57..8e982b72b690 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/max2820.h +++ b/drivers/net/wireless/rtl818x/rtl8180/max2820.h @@ -4,7 +4,7 @@ /* * Radio tuning for Maxim max2820 on RTL8180 * - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Code from the BSD driver and the rtl8181 project have been * very useful to understand certain things diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c index cc2a5412c1f0..ee638d0749d6 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c @@ -3,10 +3,10 @@ * Radio tuning for RTL8225 on RTL8180 * * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Based on the r8180 driver, which is: - * Copyright 2005 Andrea Merello , et al. + * Copyright 2005 Andrea Merello , et al. * * Thanks to Realtek for their support! * diff --git a/drivers/net/wireless/rtl818x/rtl8180/sa2400.c b/drivers/net/wireless/rtl818x/rtl8180/sa2400.c index b3ec40f6bd23..7614d9ccc729 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/sa2400.c +++ b/drivers/net/wireless/rtl818x/rtl8180/sa2400.c @@ -2,7 +2,7 @@ /* * Radio tuning for Philips SA2400 on RTL8180 * - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Code from the BSD driver and the rtl8181 project have been * very useful to understand certain things diff --git a/drivers/net/wireless/rtl818x/rtl8180/sa2400.h b/drivers/net/wireless/rtl818x/rtl8180/sa2400.h index a4aaa0d413f1..fb0093f35148 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/sa2400.h +++ b/drivers/net/wireless/rtl818x/rtl8180/sa2400.h @@ -4,7 +4,7 @@ /* * Radio tuning for Philips SA2400 on RTL8180 * - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Code from the BSD driver and the rtl8181 project have been * very useful to understand certain things diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index f49220e234b0..841fb9dfc9da 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -2,10 +2,10 @@ * Linux device driver for RTL8187 * * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. + * Copyright 2005 Andrea Merello , et al. * * The driver was extended to the RTL8187B in 2008 by: * Herton Ronaldo Krzesinski @@ -37,7 +37,7 @@ #include "rfkill.h" MODULE_AUTHOR("Michael Wu "); -MODULE_AUTHOR("Andrea Merello "); +MODULE_AUTHOR("Andrea Merello "); MODULE_AUTHOR("Herton Ronaldo Krzesinski "); MODULE_AUTHOR("Hin-Tak Leung "); MODULE_AUTHOR("Larry Finger "); diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h index e19a20a8e955..56aee067f324 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h @@ -2,10 +2,10 @@ * Definitions for RTL8187 hardware * * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. + * Copyright 2005 Andrea Merello , et al. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c index f0bf35fedbaf..a26193a04447 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c @@ -2,10 +2,10 @@ * Radio tuning for RTL8225 on RTL8187 * * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. + * Copyright 2005 Andrea Merello , et al. * * Magic delays, register offsets, and phy value tables below are * taken from the original r8187 driver sources. Thanks to Realtek diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.h index 20c5b6ead0f6..141afb09a5b4 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/rtl8225.h +++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.h @@ -2,10 +2,10 @@ * Radio tuning definitions for RTL8225 on RTL8187 * * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. + * Copyright 2005 Andrea Merello , et al. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 1615f63b02f6..ce23dfd42381 100644 --- a/drivers/net/wireless/rtl818x/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -2,10 +2,10 @@ * Definitions for RTL818x hardware * * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello + * Copyright 2007 Andrea Merello * * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. + * Copyright 2005 Andrea Merello , et al. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h index 8fc9f588b056..7f015499cfae 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -14,7 +14,7 @@ * Copyright (c) 2004, Intel Corporation * * Modified for Realtek's wi-fi cards by Andrea Merello - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c index d5df0d691fcc..10b22100dd3a 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c @@ -14,7 +14,7 @@ ****************************************************************************** Few modifications for Realtek's Wi-Fi drivers by - Andrea Merello + Andrea Merello A special thanks goes to Realtek for their support ! diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index 00f9af06aca5..b65db542e1ab 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -1,5 +1,5 @@ /* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello + * Copyright (c) 2005 Andrea Merello * * Mostly extracted from the rtl8180-sa2400 driver for the * in-kernel generic ieee802.11 stack. diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c index d9add5305e29..e5282068e3de 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c @@ -1,5 +1,5 @@ /* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello + * Copyright (c) 2005 Andrea Merello * * Mostly extracted from the rtl8180-sa2400 driver for the * in-kernel generic ieee802.11 stack. diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index 89ed86ef0d15..b3466530cf94 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -25,7 +25,7 @@ ****************************************************************************** Few modifications for Realtek's Wi-Fi drivers by - Andrea Merello + Andrea Merello A special thanks goes to Realtek for their support ! diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h index edacc8001640..d052f4a9a839 100644 --- a/drivers/staging/rtl8187se/r8180.h +++ b/drivers/staging/rtl8187se/r8180.h @@ -1,6 +1,6 @@ /* This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004-2005 + Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part of the diff --git a/drivers/staging/rtl8187se/r8180_93cx6.h b/drivers/staging/rtl8187se/r8180_93cx6.h index 79e7391ac881..b52b5b0610ab 100644 --- a/drivers/staging/rtl8187se/r8180_93cx6.h +++ b/drivers/staging/rtl8187se/r8180_93cx6.h @@ -1,6 +1,6 @@ /* This is part of rtl8180 OpenSource driver - Copyright (C) Andrea Merello 2004-2005 + Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part of the official realtek driver diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index ca691550436a..fd2bfeadd54c 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -1,6 +1,6 @@ /* This is part of rtl818x pci OpenSource driver - v 0.1 - Copyright (C) Andrea Merello 2004-2005 + Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public License) Parts of this driver are based on the GPL part of the official @@ -70,7 +70,7 @@ static int hwwep; MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl); -MODULE_AUTHOR("Andrea Merello "); +MODULE_AUTHOR("Andrea Merello "); MODULE_DESCRIPTION("Linux driver for Realtek RTL8187SE WiFi cards"); module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR); diff --git a/drivers/staging/rtl8187se/r8180_hw.h b/drivers/staging/rtl8187se/r8180_hw.h index 533938123a97..92c05af557cf 100644 --- a/drivers/staging/rtl8187se/r8180_hw.h +++ b/drivers/staging/rtl8187se/r8180_hw.h @@ -1,6 +1,6 @@ /* This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004-2005 + Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part of the diff --git a/drivers/staging/rtl8187se/r8180_rtl8225.h b/drivers/staging/rtl8187se/r8180_rtl8225.h index c6f2128e755c..c94ca0794a5d 100644 --- a/drivers/staging/rtl8187se/r8180_rtl8225.h +++ b/drivers/staging/rtl8187se/r8180_rtl8225.h @@ -1,7 +1,7 @@ /* This is part of the rtl8180-sa2400 driver released under the GPL (See file COPYING for details). - Copyright (c) 2005 Andrea Merello + Copyright (c) 2005 Andrea Merello This files contains programming code for the rtl8225 radio frontend. diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c index c592f7936ddb..9ae96b7852f3 100644 --- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c +++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c @@ -1,7 +1,7 @@ /* * This is part of the rtl8180-sa2400 driver * released under the GPL (See file COPYING for details). - * Copyright (c) 2005 Andrea Merello + * Copyright (c) 2005 Andrea Merello * * This files contains programming code for the rtl8225 * radio frontend. diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c index 156b75882290..dab787542c45 100644 --- a/drivers/staging/rtl8187se/r8180_wx.c +++ b/drivers/staging/rtl8187se/r8180_wx.c @@ -2,7 +2,7 @@ This file contains wireless extension handlers. This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004-2005 + Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part diff --git a/drivers/staging/rtl8187se/r8180_wx.h b/drivers/staging/rtl8187se/r8180_wx.h index 408191403112..d471520ac772 100644 --- a/drivers/staging/rtl8187se/r8180_wx.h +++ b/drivers/staging/rtl8187se/r8180_wx.h @@ -1,6 +1,6 @@ /* This is part of rtl8180 OpenSource driver - v 0.3 - Copyright (C) Andrea Merello 2004 + Copyright (C) Andrea Merello 2004 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part of the official realtek driver diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 50c7bb773984..74fbd70d5838 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index b9b3b52f9120..dbe0e1c87056 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index baf3b6342e44..fa5603a562c3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h index fa607f98b172..7d075d3cbe62 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 2b6c61c5d3d8..8d45c8dbfa83 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 87d4d349c890..9de1dc3e584b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c index c1ccff4a8321..a6778e0853c7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h index 9452e1683a72..adea2b4c7a44 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c index 0cfb3ecaadee..529ea54d1683 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c index 5abbee37cdca..2ad92eee50c2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h index 28c7da677a80..356aec437963 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index c9a7c563b682..a8c2ade4f435 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index df79d6c4ca03..962f2e5b8bf8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 3485ef1dfab1..05ef49f24cd9 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -14,7 +14,7 @@ * Copyright (c) 2004, Intel Corporation * * Modified for Realtek's wi-fi cards by Andrea Merello - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/staging/rtl8192e/rtllib_debug.h b/drivers/staging/rtl8192e/rtllib_debug.h index 2bfc1155f505..c59f67b26363 100644 --- a/drivers/staging/rtl8192e/rtllib_debug.h +++ b/drivers/staging/rtl8192e/rtllib_debug.h @@ -2,7 +2,7 @@ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. * * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index e75364e3eb43..96aa3a2fb7e1 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -14,7 +14,7 @@ ****************************************************************************** Few modifications for Realtek's Wi-Fi drivers by - Andrea Merello + Andrea Merello A special thanks goes to Realtek for their support ! diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index aefffac556a6..0cbf6f5593a3 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -1,5 +1,5 @@ /* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello + * Copyright (c) 2005 Andrea Merello * * Mostly extracted from the rtl8180-sa2400 driver for the * in-kernel generic ieee802.11 stack. diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c index 740cf85e9d5b..e6af8cfab12b 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c +++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c @@ -1,5 +1,5 @@ /* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello + * Copyright (c) 2005 Andrea Merello * * Mostly extracted from the rtl8180-sa2400 driver for the * in-kernel generic ieee802.11 stack. diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index 759d7c7d78e5..1cc6a9d5e8a3 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -25,7 +25,7 @@ ****************************************************************************** Few modifications for Realtek's Wi-Fi drivers by - Andrea Merello + Andrea Merello A special thanks goes to Realtek for their support ! diff --git a/drivers/staging/rtl8192u/authors b/drivers/staging/rtl8192u/authors index b08bbae39e72..0fab11228b48 100644 --- a/drivers/staging/rtl8192u/authors +++ b/drivers/staging/rtl8192u/authors @@ -1 +1 @@ -Andrea Merello +Andrea Merello diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h index c9f3bb363be4..bc64f05a7e6a 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h @@ -14,7 +14,7 @@ * Copyright (c) 2004, Intel Corporation * * Modified for Realtek's wi-fi cards by Andrea Merello - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index a6b18409103b..59900bfa1c18 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -14,7 +14,7 @@ ****************************************************************************** Few modifications for Realtek's Wi-Fi drivers by - Andrea Merello + Andrea Merello A special thanks goes to Realtek for their support ! diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 8a0075db9253..5fd696926ee3 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -1,5 +1,5 @@ /* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello + * Copyright (c) 2005 Andrea Merello * * Mostly extracted from the rtl8180-sa2400 driver for the * in-kernel generic ieee802.11 stack. diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c index 60746b8b1eb0..7b7d929f1536 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c @@ -1,5 +1,5 @@ /* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello + * Copyright (c) 2005 Andrea Merello * * Mostly extracted from the rtl8180-sa2400 driver for the * in-kernel generic ieee802.11 stack. diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c index 995504207fc6..a7bcc64ff226 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c @@ -25,7 +25,7 @@ ****************************************************************************** Few modifications for Realtek's Wi-Fi drivers by - Andrea Merello + Andrea Merello A special thanks goes to Realtek for their support ! diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c index d2199986d132..c61729b727ef 100644 --- a/drivers/staging/rtl8192u/r8180_93cx6.c +++ b/drivers/staging/rtl8192u/r8180_93cx6.c @@ -3,7 +3,7 @@ memory is addressed by 16 bits words. This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004 + Copyright (C) Andrea Merello 2004 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part of the diff --git a/drivers/staging/rtl8192u/r8180_93cx6.h b/drivers/staging/rtl8192u/r8180_93cx6.h index 5cea51e1142e..ee55dbffe32c 100644 --- a/drivers/staging/rtl8192u/r8180_93cx6.h +++ b/drivers/staging/rtl8192u/r8180_93cx6.h @@ -1,6 +1,6 @@ /* This is part of rtl8187 OpenSource driver - Copyright (C) Andrea Merello 2004-2005 + Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part of the official realtek driver diff --git a/drivers/staging/rtl8192u/r8180_pm.c b/drivers/staging/rtl8192u/r8180_pm.c index 0c58d0ed502a..999968d41720 100644 --- a/drivers/staging/rtl8192u/r8180_pm.c +++ b/drivers/staging/rtl8192u/r8180_pm.c @@ -5,7 +5,7 @@ does not do anything useful. This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004 + Copyright (C) Andrea Merello 2004 Released under the terms of GPL (General Public Licence) */ diff --git a/drivers/staging/rtl8192u/r8180_pm.h b/drivers/staging/rtl8192u/r8180_pm.h index 52d6fba99deb..4be63da0b781 100644 --- a/drivers/staging/rtl8192u/r8180_pm.h +++ b/drivers/staging/rtl8192u/r8180_pm.h @@ -5,7 +5,7 @@ does not do anything useful. This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004 + Copyright (C) Andrea Merello 2004 Released under the terms of GPL (General Public Licence) */ diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.h b/drivers/staging/rtl8192u/r8190_rtl8256.h index b64dd662761a..592e7807fa42 100644 --- a/drivers/staging/rtl8192u/r8190_rtl8256.h +++ b/drivers/staging/rtl8192u/r8190_rtl8256.h @@ -1,7 +1,7 @@ /* This is part of the rtl8180-sa2400 driver released under the GPL (See file COPYING for details). - Copyright (c) 2005 Andrea Merello + Copyright (c) 2005 Andrea Merello This files contains programming code for the rtl8256 radio frontend. diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index 338e7bc237c3..b484ee128c13 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -1,6 +1,6 @@ /* * This is part of rtl8187 OpenSource driver. - * Copyright (C) Andrea Merello 2004-2005 + * Copyright (C) Andrea Merello 2004-2005 * Released under the terms of GPL (General Public Licence) * * Parts of this driver are based on the GPL part of the diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 14c14c24ac50..cd0946db025c 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -3,7 +3,7 @@ * Linux device driver for RTL8192U * * Based on the r8187 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. + * Copyright 2004-2005 Andrea Merello , et al. * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h index 7e612aa56fa4..dd07a735b537 100644 --- a/drivers/staging/rtl8192u/r8192U_hw.h +++ b/drivers/staging/rtl8192u/r8192U_hw.h @@ -1,6 +1,6 @@ /* This is part of rtl8187 OpenSource driver. - Copyright (C) Andrea Merello 2004-2005 + Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part of the diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c index 3e2576347d29..61f6620213e2 100644 --- a/drivers/staging/rtl8192u/r8192U_wx.c +++ b/drivers/staging/rtl8192u/r8192U_wx.c @@ -2,7 +2,7 @@ This file contains wireless extension handlers. This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004-2005 + Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part diff --git a/drivers/staging/rtl8192u/r8192U_wx.h b/drivers/staging/rtl8192u/r8192U_wx.h index 9f6b10505426..ae7a617740a3 100644 --- a/drivers/staging/rtl8192u/r8192U_wx.h +++ b/drivers/staging/rtl8192u/r8192U_wx.h @@ -1,6 +1,6 @@ /* This is part of rtl8180 OpenSource driver - v 0.3 - Copyright (C) Andrea Merello 2004 + Copyright (C) Andrea Merello 2004 Released under the terms of GPL (General Public Licence) Parts of this driver are based on the GPL part of the official realtek driver -- cgit v1.2.3 From 6e956da2027c767859128b9bfef085cf2a8e233b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 26 Aug 2013 15:18:53 +0200 Subject: rt2800: fix wrong TX power compensation We should not do temperature compensation on devices without EXTERNAL_TX_ALC bit set (called DynamicTxAgcControl on vendor driver). Such devices can have totally bogus TSSI parameters on the EEPROM, but still threaded by us as valid and result doing wrong TX power calculations. This fix inability to connect to AP on slightly longer distance on some Ralink chips/devices. Reported-and-tested-by: Fabien ADAM Cc: stable@vger.kernel.org Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 20243dcd4a6c..660d7d856186 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3407,6 +3407,13 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) u8 step; int i; + /* + * First check if temperature compensation is supported. + */ + rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + if (!rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC)) + return 0; + /* * Read TSSI boundaries for temperature compensation from * the EEPROM. -- cgit v1.2.3 From 53b2f828487ea7a3f6fa4007b629466fb0d14339 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Aug 2013 11:05:36 -0400 Subject: ath9k: ar9003_eeprom.c:3618 fix variable name typo drivers/net/wireless/ath/ath9k/ar9003_eeprom.c: In function 'ar9003_hw_ant_ctrl_apply': >> drivers/net/wireless/ath/ath9k/ar9003_eeprom.c:3618: warning: 'regval' is used uninitialized in this function It seems obvious that 'regval' should have been 'value'... Reported-by: Fengguang Wu Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index a6846abf4749..f4864807e15b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3615,8 +3615,8 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); if (AR_SREV_9485(ah) && common->bt_ant_diversity) { - regval &= ~AR_SWITCH_TABLE_COM2_ALL; - regval |= ah->config.ant_ctrl_comm2g_switch_enable; + value &= ~AR_SWITCH_TABLE_COM2_ALL; + value |= ah->config.ant_ctrl_comm2g_switch_enable; } REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); -- cgit v1.2.3 From a16b635f24a72b798da41fa0814d59018a89c860 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 26 Aug 2013 14:57:34 -0700 Subject: mwifiex: break a long line into two lines It exceeded 80 characters. Split it into two lines. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_aggr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index f69d7e068e75..21c688264708 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -69,7 +69,8 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); /* Copy SNAP header */ - snap.snap_type = le16_to_cpu(*(__le16 *) ((u8 *)skb_src->data + dt_offset)); + snap.snap_type = + le16_to_cpu(*(__le16 *) ((u8 *)skb_src->data + dt_offset)); dt_offset += sizeof(u16); memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); -- cgit v1.2.3 From 65c1a4de59b0d417d68c04d5ee033058a9e7a83a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 27 Aug 2013 11:34:26 +0530 Subject: ath9k: Remove unused ANI commands Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 3 --- drivers/net/wireless/ath/ath9k/ani.h | 13 ++++--------- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 2 -- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 2 -- drivers/net/wireless/ath/ath9k/hw.c | 2 -- 5 files changed, 4 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 4994bea809eb..be466b0ef7a7 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -319,9 +319,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) ah->ani_function = 0; } - /* always allow mode (on/off) to be controlled */ - ah->ani_function |= ATH9K_ANI_MODE; - ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL, aniState->ofdmNoiseImmunityLevel); cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL, diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index b54a3fb01883..21e7b83c3f6a 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -48,15 +48,10 @@ /* values here are relative to the INI */ enum ath9k_ani_cmd { - ATH9K_ANI_PRESENT = 0x1, - ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4, - ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8, - ATH9K_ANI_FIRSTEP_LEVEL = 0x10, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20, - ATH9K_ANI_MODE = 0x40, - ATH9K_ANI_PHYERR_RESET = 0x80, - ATH9K_ANI_MRC_CCK = 0x100, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x1, + ATH9K_ANI_FIRSTEP_LEVEL = 0x2, + ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x4, + ATH9K_ANI_MRC_CCK = 0x8, ATH9K_ANI_ALL = 0xfff }; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 1576d58291d4..08656473c63e 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -1160,8 +1160,6 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, */ WARN_ON(1); break; - case ATH9K_ANI_PRESENT: - break; default: ath_dbg(common, ANI, "invalid cmd %u\n", cmd); return false; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 46b910a857d9..e897648d3233 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1193,8 +1193,6 @@ skip_ws_det: } break; } - case ATH9K_ANI_PRESENT: - break; default: ath_dbg(common, ANI, "invalid cmd %u\n", cmd); return false; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2670bf6cb066..ec47c506f175 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -655,8 +655,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_cal_settings(ah); ah->ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_20_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah)) - ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; if (!AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_MRC_CCK; -- cgit v1.2.3 From 27251e0087598befb39599eb3dd2a3c59bce2fb9 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 27 Aug 2013 11:34:39 +0530 Subject: ath9k: Enable D3/L1 ASPM fix for AR9462 AR9462 requires this HW fix for ASPM to work properly. Also, since WARegVal is used only for the AR8003 family, use AR_SREV_9300_20_OR_LATER. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ec47c506f175..ecc6ec4a1edb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -574,18 +574,17 @@ static int __ath9k_hw_init(struct ath_hw *ah) * We need to do this to avoid RMW of this register. We cannot * read the reg when chip is asleep. */ - ah->WARegVal = REG_READ(ah, AR_WA); - ah->WARegVal |= (AR_WA_D3_L1_DISABLE | - AR_WA_ASPM_TIMER_BASED_DISABLE); + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->WARegVal = REG_READ(ah, AR_WA); + ah->WARegVal |= (AR_WA_D3_L1_DISABLE | + AR_WA_ASPM_TIMER_BASED_DISABLE); + } if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { ath_err(common, "Couldn't reset chip\n"); return -EIO; } - if (AR_SREV_9462(ah)) - ah->WARegVal &= ~AR_WA_D3_L1_DISABLE; - if (AR_SREV_9565(ah)) { ah->WARegVal |= AR_WA_BIT22; REG_WRITE(ah, AR_WA, ah->WARegVal); -- cgit v1.2.3 From 708ff0835343c0696e69888943be05efd12fe7c6 Mon Sep 17 00:00:00 2001 From: Masami Ichikawa Date: Wed, 28 Aug 2013 00:37:23 +0900 Subject: rt2800usb: Add WLI-UC-G300HP's Product ID. Support Bufallo WLI-UC-G300HP. Signed-off-by: Masami Ichikawa Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 338034e18243..96961b9a395c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -971,6 +971,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0411, 0x016f) }, { USB_DEVICE(0x0411, 0x01a2) }, { USB_DEVICE(0x0411, 0x01ee) }, + { USB_DEVICE(0x0411, 0x01a8) }, /* Corega */ { USB_DEVICE(0x07aa, 0x002f) }, { USB_DEVICE(0x07aa, 0x003c) }, -- cgit v1.2.3 From 7f190230baac602f3f2be8e143c1c7c5aad15b1e Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Tue, 27 Aug 2013 20:17:12 -0400 Subject: cw1200: Display the correct default reference clock. This is purely a cosmetic bug. Signed-off-by: Solomon Peachy Signed-off-by: John W. Linville --- drivers/net/wireless/cw1200/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c index 3724e739cbf4..090f01577dd2 100644 --- a/drivers/net/wireless/cw1200/main.c +++ b/drivers/net/wireless/cw1200/main.c @@ -507,7 +507,7 @@ u32 cw1200_dpll_from_clk(u16 clk_khz) case 0xCB20: /* 52000 KHz */ return 0x07627091; default: - pr_err("Unknown Refclk freq (0x%04x), using 2600KHz\n", + pr_err("Unknown Refclk freq (0x%04x), using 26000KHz\n", clk_khz); return 0x0EC4F121; } -- cgit v1.2.3 From 076f0d20b636ef0e701e21e701c0631b5757b732 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Tue, 27 Aug 2013 20:17:13 -0400 Subject: cw1200: When debug is enabled, display all wakeup conditions for the wait_event_interruptible_timeout() call. When trying to debug an interrupt delivery problem I noticed that not all of the wakeup conditions on the worker thread were included in the debug message. This patch rectifies that. Signed-off-by: Solomon Peachy Signed-off-by: John W. Linville --- drivers/net/wireless/cw1200/bh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/cw1200/bh.c b/drivers/net/wireless/cw1200/bh.c index c1ec2a4dd8c0..92d299aa257c 100644 --- a/drivers/net/wireless/cw1200/bh.c +++ b/drivers/net/wireless/cw1200/bh.c @@ -465,8 +465,8 @@ static int cw1200_bh(void *arg) (rx || tx || term || suspend || priv->bh_error); }), status); - pr_debug("[BH] - rx: %d, tx: %d, term: %d, suspend: %d, status: %ld\n", - rx, tx, term, suspend, status); + pr_debug("[BH] - rx: %d, tx: %d, term: %d, bh_err: %d, suspend: %d, status: %ld\n", + rx, tx, term, suspend, priv->bh_error, status); /* Did an error occur? */ if ((status < 0 && status != -ERESTARTSYS) || -- cgit v1.2.3 From ede23fa8161c1a04aa1b3bf5447812ca14b3fef1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 26 Aug 2013 22:45:23 -0700 Subject: drivers:net: Convert dma_alloc_coherent(...__GFP_ZERO) to dma_zalloc_coherent __GFP_ZERO is an uncommon flag and perhaps is better not used. static inline dma_zalloc_coherent exists so convert the uses of dma_alloc_coherent with __GFP_ZERO to the more common kernel style with zalloc. Remove memset from the static inline dma_zalloc_coherent and add just one use of __GFP_ZERO instead. Trivially reduces the size of the existing uses of dma_zalloc_coherent. Realign arguments as appropriate. Signed-off-by: Joe Perches Acked-by: Neil Horman Acked-by: Jesse Brandeburg Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/aeroflex/greth.c | 12 ++++----- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 6 ++--- drivers/net/ethernet/broadcom/bnx2.c | 5 ++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 5 ++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 3 +-- drivers/net/ethernet/broadcom/tg3.c | 23 ++++++++--------- drivers/net/ethernet/emulex/benet/be_main.c | 18 +++++++------- drivers/net/ethernet/faraday/ftgmac100.c | 7 +++--- drivers/net/ethernet/faraday/ftmac100.c | 8 +++--- drivers/net/ethernet/ibm/emac/mal.c | 4 +-- drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 8 +++--- drivers/net/ethernet/intel/ixgb/ixgb_main.c | 4 +-- drivers/net/ethernet/marvell/pxa168_eth.c | 19 +++++++------- drivers/net/ethernet/myricom/myri10ge/myri10ge.c | 6 ++--- .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 16 ++++++------ drivers/net/ethernet/pasemi/pasemi_mac.c | 7 +++--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 29 +++++++++++----------- drivers/net/ethernet/sfc/nic.c | 5 ++-- drivers/net/ethernet/sgi/meth.c | 5 ++-- drivers/net/ethernet/tundra/tsi108_eth.c | 8 +++--- drivers/net/ethernet/xilinx/ll_temac_main.c | 12 ++++----- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 14 +++++------ drivers/net/fddi/defxx.c | 6 ++--- drivers/net/irda/ali-ircc.c | 8 +++--- drivers/net/irda/nsc-ircc.c | 8 +++--- drivers/net/irda/smsc-ircc2.c | 8 +++--- drivers/net/irda/via-ircc.c | 8 +++--- drivers/net/irda/w83977af_ir.c | 8 +++--- drivers/net/wireless/b43/dma.c | 6 ++--- drivers/net/wireless/b43legacy/dma.c | 7 +++--- include/linux/dma-mapping.h | 5 ++-- 31 files changed, 135 insertions(+), 153 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index 7ff4b30d55ea..e06694555144 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c @@ -1464,18 +1464,18 @@ static int greth_of_probe(struct platform_device *ofdev) } /* Allocate TX descriptor ring in coherent memory */ - greth->tx_bd_base = dma_alloc_coherent(greth->dev, 1024, - &greth->tx_bd_base_phys, - GFP_KERNEL | __GFP_ZERO); + greth->tx_bd_base = dma_zalloc_coherent(greth->dev, 1024, + &greth->tx_bd_base_phys, + GFP_KERNEL); if (!greth->tx_bd_base) { err = -ENOMEM; goto error3; } /* Allocate RX descriptor ring in coherent memory */ - greth->rx_bd_base = dma_alloc_coherent(greth->dev, 1024, - &greth->rx_bd_base_phys, - GFP_KERNEL | __GFP_ZERO); + greth->rx_bd_base = dma_zalloc_coherent(greth->dev, 1024, + &greth->rx_bd_base_phys, + GFP_KERNEL); if (!greth->rx_bd_base) { err = -ENOMEM; goto error4; diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 190219e02400..98b68703c53d 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -948,8 +948,7 @@ static int bcm_enet_open(struct net_device *dev) /* allocate rx dma ring */ size = priv->rx_ring_size * sizeof(struct bcm_enet_desc); - p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, - GFP_KERNEL | __GFP_ZERO); + p = dma_zalloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); if (!p) { ret = -ENOMEM; goto out_freeirq_tx; @@ -960,8 +959,7 @@ static int bcm_enet_open(struct net_device *dev) /* allocate tx dma ring */ size = priv->tx_ring_size * sizeof(struct bcm_enet_desc); - p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, - GFP_KERNEL | __GFP_ZERO); + p = dma_zalloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); if (!p) { ret = -ENOMEM; goto out_free_rx_ring; diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 4148058cef81..e838a3f74b69 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -853,9 +853,8 @@ bnx2_alloc_mem(struct bnx2 *bp) bp->status_stats_size = status_blk_size + sizeof(struct statistics_block); - status_blk = dma_alloc_coherent(&bp->pdev->dev, bp->status_stats_size, - &bp->status_blk_mapping, - GFP_KERNEL | __GFP_ZERO); + status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size, + &bp->status_blk_mapping, GFP_KERNEL); if (status_blk == NULL) goto alloc_mem_err; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 12202f81735c..3e77a1b1a44a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -2069,9 +2069,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, bool is_pf); -#define BNX2X_ILT_ZALLOC(x, y, size) \ - x = dma_alloc_coherent(&bp->pdev->dev, size, y, \ - GFP_KERNEL | __GFP_ZERO) +#define BNX2X_ILT_ZALLOC(x, y, size) \ + x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL) #define BNX2X_ILT_FREE(x, y, size) \ do { \ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 38be494ffa6e..affb7646241e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -51,8 +51,7 @@ extern int int_mode; #define BNX2X_PCI_ALLOC(x, y, size) \ do { \ - x = dma_alloc_coherent(&bp->pdev->dev, size, y, \ - GFP_KERNEL | __GFP_ZERO); \ + x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ if (x == NULL) \ goto alloc_mem_err; \ DP(NETIF_MSG_HW, "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n", \ diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 95b8995187d7..2e55ee29cf13 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8591,10 +8591,10 @@ static int tg3_mem_rx_acquire(struct tg3 *tp) if (!i && tg3_flag(tp, ENABLE_RSS)) continue; - tnapi->rx_rcb = dma_alloc_coherent(&tp->pdev->dev, - TG3_RX_RCB_RING_BYTES(tp), - &tnapi->rx_rcb_mapping, - GFP_KERNEL | __GFP_ZERO); + tnapi->rx_rcb = dma_zalloc_coherent(&tp->pdev->dev, + TG3_RX_RCB_RING_BYTES(tp), + &tnapi->rx_rcb_mapping, + GFP_KERNEL); if (!tnapi->rx_rcb) goto err_out; } @@ -8643,10 +8643,9 @@ static int tg3_alloc_consistent(struct tg3 *tp) { int i; - tp->hw_stats = dma_alloc_coherent(&tp->pdev->dev, - sizeof(struct tg3_hw_stats), - &tp->stats_mapping, - GFP_KERNEL | __GFP_ZERO); + tp->hw_stats = dma_zalloc_coherent(&tp->pdev->dev, + sizeof(struct tg3_hw_stats), + &tp->stats_mapping, GFP_KERNEL); if (!tp->hw_stats) goto err_out; @@ -8654,10 +8653,10 @@ static int tg3_alloc_consistent(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[i]; struct tg3_hw_status *sblk; - tnapi->hw_status = dma_alloc_coherent(&tp->pdev->dev, - TG3_HW_STATUS_SIZE, - &tnapi->status_mapping, - GFP_KERNEL | __GFP_ZERO); + tnapi->hw_status = dma_zalloc_coherent(&tp->pdev->dev, + TG3_HW_STATUS_SIZE, + &tnapi->status_mapping, + GFP_KERNEL); if (!tnapi->hw_status) goto err_out; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 50116f8ed576..39e0a7697a81 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -145,8 +145,8 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, q->len = len; q->entry_size = entry_size; mem->size = len * entry_size; - mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma, - GFP_KERNEL | __GFP_ZERO); + mem->va = dma_zalloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma, + GFP_KERNEL); if (!mem->va) return -ENOMEM; return 0; @@ -2642,8 +2642,8 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) memset(mac, 0, ETH_ALEN); cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); - cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_KERNEL | __GFP_ZERO); + cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_KERNEL); if (cmd.va == NULL) return -1; @@ -3946,9 +3946,9 @@ static int be_ctrl_init(struct be_adapter *adapter) memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); rx_filter->size = sizeof(struct be_cmd_req_rx_filter); - rx_filter->va = dma_alloc_coherent(&adapter->pdev->dev, rx_filter->size, - &rx_filter->dma, - GFP_KERNEL | __GFP_ZERO); + rx_filter->va = dma_zalloc_coherent(&adapter->pdev->dev, + rx_filter->size, &rx_filter->dma, + GFP_KERNEL); if (rx_filter->va == NULL) { status = -ENOMEM; goto free_mbox; @@ -3994,8 +3994,8 @@ static int be_stats_init(struct be_adapter *adapter) /* BE3 and Skyhawk */ cmd->size = sizeof(struct be_cmd_req_get_stats_v1); - cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, - GFP_KERNEL | __GFP_ZERO); + cmd->va = dma_zalloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, + GFP_KERNEL); if (cmd->va == NULL) return -1; return 0; diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 934e1ae279f0..212f44b3a773 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -778,10 +778,9 @@ static int ftgmac100_alloc_buffers(struct ftgmac100 *priv) { int i; - priv->descs = dma_alloc_coherent(priv->dev, - sizeof(struct ftgmac100_descs), - &priv->descs_dma_addr, - GFP_KERNEL | __GFP_ZERO); + priv->descs = dma_zalloc_coherent(priv->dev, + sizeof(struct ftgmac100_descs), + &priv->descs_dma_addr, GFP_KERNEL); if (!priv->descs) return -ENOMEM; diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index 4658f4cc1969..8be5b40c0a12 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -732,10 +732,10 @@ static int ftmac100_alloc_buffers(struct ftmac100 *priv) { int i; - priv->descs = dma_alloc_coherent(priv->dev, - sizeof(struct ftmac100_descs), - &priv->descs_dma_addr, - GFP_KERNEL | __GFP_ZERO); + priv->descs = dma_zalloc_coherent(priv->dev, + sizeof(struct ftmac100_descs), + &priv->descs_dma_addr, + GFP_KERNEL); if (!priv->descs) return -ENOMEM; diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c index 856ea66c9223..dac564c25440 100644 --- a/drivers/net/ethernet/ibm/emac/mal.c +++ b/drivers/net/ethernet/ibm/emac/mal.c @@ -637,8 +637,8 @@ static int mal_probe(struct platform_device *ofdev) bd_size = sizeof(struct mal_descriptor) * (NUM_TX_BUFF * mal->num_tx_chans + NUM_RX_BUFF * mal->num_rx_chans); - mal->bd_virt = dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma, - GFP_KERNEL | __GFP_ZERO); + mal->bd_virt = dma_zalloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma, + GFP_KERNEL); if (mal->bd_virt == NULL) { err = -ENOMEM; goto fail_unmap; diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index 82a967c95598..73a8aeefb92a 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -1019,8 +1019,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) txdr->size = txdr->count * sizeof(struct e1000_tx_desc); txdr->size = ALIGN(txdr->size, 4096); - txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma, - GFP_KERNEL | __GFP_ZERO); + txdr->desc = dma_zalloc_coherent(&pdev->dev, txdr->size, &txdr->dma, + GFP_KERNEL); if (!txdr->desc) { ret_val = 2; goto err_nomem; @@ -1077,8 +1077,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) } rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); - rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, - GFP_KERNEL | __GFP_ZERO); + rxdr->desc = dma_zalloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, + GFP_KERNEL); if (!rxdr->desc) { ret_val = 6; goto err_nomem; diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index fce3e92f9d11..9f6b236828e6 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -718,8 +718,8 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter) txdr->size = txdr->count * sizeof(struct ixgb_tx_desc); txdr->size = ALIGN(txdr->size, 4096); - txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma, - GFP_KERNEL | __GFP_ZERO); + txdr->desc = dma_zalloc_coherent(&pdev->dev, txdr->size, &txdr->dma, + GFP_KERNEL); if (!txdr->desc) { vfree(txdr->buffer_info); return -ENOMEM; diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index db481477bcc5..3e69febe377e 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -583,10 +583,9 @@ static int init_hash_table(struct pxa168_eth_private *pep) * table is full. */ if (pep->htpr == NULL) { - pep->htpr = dma_alloc_coherent(pep->dev->dev.parent, - HASH_ADDR_TABLE_SIZE, - &pep->htpr_dma, - GFP_KERNEL | __GFP_ZERO); + pep->htpr = dma_zalloc_coherent(pep->dev->dev.parent, + HASH_ADDR_TABLE_SIZE, + &pep->htpr_dma, GFP_KERNEL); if (pep->htpr == NULL) return -ENOMEM; } else { @@ -1024,9 +1023,9 @@ static int rxq_init(struct net_device *dev) pep->rx_desc_count = 0; size = pep->rx_ring_size * sizeof(struct rx_desc); pep->rx_desc_area_size = size; - pep->p_rx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size, - &pep->rx_desc_dma, - GFP_KERNEL | __GFP_ZERO); + pep->p_rx_desc_area = dma_zalloc_coherent(pep->dev->dev.parent, size, + &pep->rx_desc_dma, + GFP_KERNEL); if (!pep->p_rx_desc_area) goto out; @@ -1085,9 +1084,9 @@ static int txq_init(struct net_device *dev) pep->tx_desc_count = 0; size = pep->tx_ring_size * sizeof(struct tx_desc); pep->tx_desc_area_size = size; - pep->p_tx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size, - &pep->tx_desc_dma, - GFP_KERNEL | __GFP_ZERO); + pep->p_tx_desc_area = dma_zalloc_coherent(pep->dev->dev.parent, size, + &pep->tx_desc_dma, + GFP_KERNEL); if (!pep->p_tx_desc_area) goto out; /* Initialize the next_desc_ptr links in the Tx descriptors ring */ diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 50a1d4a04eb0..149355b52ad0 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -3783,9 +3783,9 @@ static int myri10ge_alloc_slices(struct myri10ge_priv *mgp) for (i = 0; i < mgp->num_slices; i++) { ss = &mgp->ss[i]; bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry); - ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes, - &ss->rx_done.bus, - GFP_KERNEL | __GFP_ZERO); + ss->rx_done.entry = dma_zalloc_coherent(&pdev->dev, bytes, + &ss->rx_done.bus, + GFP_KERNEL); if (ss->rx_done.entry == NULL) goto abort; bytes = sizeof(*ss->fw_stats); diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index e19f1be60d5e..5a0f04c2c813 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -1491,9 +1491,9 @@ pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter, bufsz = adapter->rx_buffer_len; size = rx_ring->count * bufsz + PCH_GBE_RESERVE_MEMORY; - rx_ring->rx_buff_pool = dma_alloc_coherent(&pdev->dev, size, - &rx_ring->rx_buff_pool_logic, - GFP_KERNEL | __GFP_ZERO); + rx_ring->rx_buff_pool = + dma_zalloc_coherent(&pdev->dev, size, + &rx_ring->rx_buff_pool_logic, GFP_KERNEL); if (!rx_ring->rx_buff_pool) return -ENOMEM; @@ -1807,9 +1807,8 @@ int pch_gbe_setup_tx_resources(struct pch_gbe_adapter *adapter, tx_ring->size = tx_ring->count * (int)sizeof(struct pch_gbe_tx_desc); - tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size, - &tx_ring->dma, - GFP_KERNEL | __GFP_ZERO); + tx_ring->desc = dma_zalloc_coherent(&pdev->dev, tx_ring->size, + &tx_ring->dma, GFP_KERNEL); if (!tx_ring->desc) { vfree(tx_ring->buffer_info); return -ENOMEM; @@ -1852,9 +1851,8 @@ int pch_gbe_setup_rx_resources(struct pch_gbe_adapter *adapter, return -ENOMEM; rx_ring->size = rx_ring->count * (int)sizeof(struct pch_gbe_rx_desc); - rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size, - &rx_ring->dma, - GFP_KERNEL | __GFP_ZERO); + rx_ring->desc = dma_zalloc_coherent(&pdev->dev, rx_ring->size, + &rx_ring->dma, GFP_KERNEL); if (!rx_ring->desc) { vfree(rx_ring->buffer_info); return -ENOMEM; diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index f21ae7b6c766..c498181a9aa8 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -440,10 +440,9 @@ static int pasemi_mac_setup_rx_resources(const struct net_device *dev) if (pasemi_dma_alloc_ring(&ring->chan, RX_RING_SIZE)) goto out_ring_desc; - ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(u64), - &ring->buf_dma, - GFP_KERNEL | __GFP_ZERO); + ring->buffers = dma_zalloc_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(u64), + &ring->buf_dma, GFP_KERNEL); if (!ring->buffers) goto out_ring_desc; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index bf3b17eaf8b8..86850dd633a1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -448,14 +448,14 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter, *(tx_ring->hw_consumer) = 0; rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); - rq_addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size, - &rq_phys_addr, GFP_KERNEL | __GFP_ZERO); + rq_addr = dma_zalloc_coherent(&adapter->pdev->dev, rq_size, + &rq_phys_addr, GFP_KERNEL); if (!rq_addr) return -ENOMEM; rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx); - rsp_addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size, - &rsp_phys_addr, GFP_KERNEL | __GFP_ZERO); + rsp_addr = dma_zalloc_coherent(&adapter->pdev->dev, rsp_size, + &rsp_phys_addr, GFP_KERNEL); if (!rsp_addr) { err = -ENOMEM; goto out_free_rq; @@ -865,8 +865,8 @@ int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args cmd; size_t nic_size = sizeof(struct qlcnic_info_le); - nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, - &nic_dma_t, GFP_KERNEL | __GFP_ZERO); + nic_info_addr = dma_zalloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; @@ -919,8 +919,8 @@ int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter, if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) return err; - nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, - &nic_dma_t, GFP_KERNEL | __GFP_ZERO); + nic_info_addr = dma_zalloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; @@ -972,9 +972,8 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter, size_t npar_size = sizeof(struct qlcnic_pci_info_le); size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC; - pci_info_addr = dma_alloc_coherent(&adapter->pdev->dev, pci_size, - &pci_info_dma_t, - GFP_KERNEL | __GFP_ZERO); + pci_info_addr = dma_zalloc_coherent(&adapter->pdev->dev, pci_size, + &pci_info_dma_t, GFP_KERNEL); if (!pci_info_addr) return -ENOMEM; @@ -1074,8 +1073,8 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, return -EIO; } - stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, - &stats_dma_t, GFP_KERNEL | __GFP_ZERO); + stats_addr = dma_zalloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); if (!stats_addr) return -ENOMEM; @@ -1130,8 +1129,8 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter, if (mac_stats == NULL) return -ENOMEM; - stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, - &stats_dma_t, GFP_KERNEL | __GFP_ZERO); + stats_addr = dma_zalloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); if (!stats_addr) return -ENOMEM; diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index b9b127743a07..78d413312052 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -33,9 +33,8 @@ int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, unsigned int len, gfp_t gfp_flags) { - buffer->addr = dma_alloc_coherent(&efx->pci_dev->dev, len, - &buffer->dma_addr, - gfp_flags | __GFP_ZERO); + buffer->addr = dma_zalloc_coherent(&efx->pci_dev->dev, len, + &buffer->dma_addr, gfp_flags); if (!buffer->addr) return -ENOMEM; buffer->len = len; diff --git a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c index 9f5f35e041ac..770036bc2d87 100644 --- a/drivers/net/ethernet/sgi/meth.c +++ b/drivers/net/ethernet/sgi/meth.c @@ -212,9 +212,8 @@ static void meth_check_link(struct net_device *dev) static int meth_init_tx_ring(struct meth_private *priv) { /* Init TX ring */ - priv->tx_ring = dma_alloc_coherent(NULL, TX_RING_BUFFER_SIZE, - &priv->tx_ring_dma, - GFP_ATOMIC | __GFP_ZERO); + priv->tx_ring = dma_zalloc_coherent(NULL, TX_RING_BUFFER_SIZE, + &priv->tx_ring_dma, GFP_ATOMIC); if (!priv->tx_ring) return -ENOMEM; diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c index 01bdc6ca0755..f2e76c9d736c 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.c +++ b/drivers/net/ethernet/tundra/tsi108_eth.c @@ -1308,13 +1308,13 @@ static int tsi108_open(struct net_device *dev) data->id, dev->irq, dev->name); } - data->rxring = dma_alloc_coherent(NULL, rxring_size, &data->rxdma, - GFP_KERNEL | __GFP_ZERO); + data->rxring = dma_zalloc_coherent(NULL, rxring_size, &data->rxdma, + GFP_KERNEL); if (!data->rxring) return -ENOMEM; - data->txring = dma_alloc_coherent(NULL, txring_size, &data->txdma, - GFP_KERNEL | __GFP_ZERO); + data->txring = dma_zalloc_coherent(NULL, txring_size, &data->txdma, + GFP_KERNEL); if (!data->txring) { pci_free_consistent(0, rxring_size, data->rxring, data->rxdma); return -ENOMEM; diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 58eb4488beff..b88121f240ca 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -243,15 +243,15 @@ static int temac_dma_bd_init(struct net_device *ndev) /* allocate the tx and rx ring buffer descriptors. */ /* returns a virtual address and a physical address. */ - lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->tx_bd_v) * TX_BD_NUM, - &lp->tx_bd_p, GFP_KERNEL | __GFP_ZERO); + lp->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent, + sizeof(*lp->tx_bd_v) * TX_BD_NUM, + &lp->tx_bd_p, GFP_KERNEL); if (!lp->tx_bd_v) goto out; - lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * RX_BD_NUM, - &lp->rx_bd_p, GFP_KERNEL | __GFP_ZERO); + lp->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent, + sizeof(*lp->rx_bd_v) * RX_BD_NUM, + &lp->rx_bd_p, GFP_KERNEL); if (!lp->rx_bd_v) goto out; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index fb7d1c28a2ea..b2ff038d6d20 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -201,17 +201,15 @@ static int axienet_dma_bd_init(struct net_device *ndev) /* * Allocate the Tx and Rx buffer descriptors. */ - lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->tx_bd_v) * TX_BD_NUM, - &lp->tx_bd_p, - GFP_KERNEL | __GFP_ZERO); + lp->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent, + sizeof(*lp->tx_bd_v) * TX_BD_NUM, + &lp->tx_bd_p, GFP_KERNEL); if (!lp->tx_bd_v) goto out; - lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * RX_BD_NUM, - &lp->rx_bd_p, - GFP_KERNEL | __GFP_ZERO); + lp->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent, + sizeof(*lp->rx_bd_v) * RX_BD_NUM, + &lp->rx_bd_p, GFP_KERNEL); if (!lp->rx_bd_v) goto out; diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 4c8ddc944d51..0b40e1c46f07 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -1068,9 +1068,9 @@ static int dfx_driver_init(struct net_device *dev, const char *print_name, #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); - bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size, - &bp->kmalloced_dma, - GFP_ATOMIC | __GFP_ZERO); + bp->kmalloced = top_v = dma_zalloc_coherent(bp->bus_dev, alloc_size, + &bp->kmalloced_dma, + GFP_ATOMIC); if (top_v == NULL) return DFX_K_FAILURE; diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 3adb43ce138f..7bbd318bc93e 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -351,16 +351,16 @@ static int ali_ircc_open(int i, chipio_t *info) /* Allocate memory if needed */ self->rx_buff.head = - dma_alloc_coherent(NULL, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(NULL, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) { err = -ENOMEM; goto err_out2; } self->tx_buff.head = - dma_alloc_coherent(NULL, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(NULL, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) { err = -ENOMEM; goto err_out3; diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 9cf836b57c49..ceeb53737f86 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -430,8 +430,8 @@ static int __init nsc_ircc_open(chipio_t *info) /* Allocate memory if needed */ self->rx_buff.head = - dma_alloc_coherent(NULL, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(NULL, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) { err = -ENOMEM; goto out2; @@ -439,8 +439,8 @@ static int __init nsc_ircc_open(chipio_t *info) } self->tx_buff.head = - dma_alloc_coherent(NULL, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(NULL, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) { err = -ENOMEM; goto out3; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index aa05dad75335..0dcdf1592f6b 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -562,14 +562,14 @@ static int smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE; self->rx_buff.head = - dma_alloc_coherent(NULL, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(NULL, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) goto err_out2; self->tx_buff.head = - dma_alloc_coherent(NULL, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(NULL, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) goto err_out3; diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 2dcc60fb37f1..9abaec27f962 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -361,16 +361,16 @@ static int via_ircc_open(struct pci_dev *pdev, chipio_t *info, unsigned int id) /* Allocate memory if needed */ self->rx_buff.head = - dma_alloc_coherent(&pdev->dev, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(&pdev->dev, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) { err = -ENOMEM; goto err_out2; } self->tx_buff.head = - dma_alloc_coherent(&pdev->dev, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(&pdev->dev, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) { err = -ENOMEM; goto err_out3; diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index bb8857a158a6..e641bb240362 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -215,16 +215,16 @@ static int w83977af_open(int i, unsigned int iobase, unsigned int irq, /* Allocate memory if needed */ self->rx_buff.head = - dma_alloc_coherent(NULL, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(NULL, self->rx_buff.truesize, + &self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) { err = -ENOMEM; goto err_out1; } self->tx_buff.head = - dma_alloc_coherent(NULL, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO); + dma_zalloc_coherent(NULL, self->tx_buff.truesize, + &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) { err = -ENOMEM; goto err_out2; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index f7c70b3a6ea9..c51d2dc489e4 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -431,9 +431,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring) u16 ring_mem_size = (ring->type == B43_DMA_64BIT) ? B43_DMA64_RINGMEMSIZE : B43_DMA32_RINGMEMSIZE; - ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev, - ring_mem_size, &(ring->dmabase), - GFP_KERNEL | __GFP_ZERO); + ring->descbase = dma_zalloc_coherent(ring->dev->dev->dma_dev, + ring_mem_size, &(ring->dmabase), + GFP_KERNEL); if (!ring->descbase) return -ENOMEM; diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index faeafe219c57..42eb26c99e11 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -331,10 +331,9 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring, static int alloc_ringmemory(struct b43legacy_dmaring *ring) { /* GFP flags must match the flags in free_ringmemory()! */ - ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev, - B43legacy_DMA_RINGMEMSIZE, - &(ring->dmabase), - GFP_KERNEL | __GFP_ZERO); + ring->descbase = dma_zalloc_coherent(ring->dev->dev->dma_dev, + B43legacy_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); if (!ring->descbase) return -ENOMEM; diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 94af41858513..3a8d0a2af607 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -132,9 +132,8 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask) static inline void *dma_zalloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { - void *ret = dma_alloc_coherent(dev, size, dma_handle, flag); - if (ret) - memset(ret, 0, size); + void *ret = dma_alloc_coherent(dev, size, dma_handle, + flag | __GFP_ZERO); return ret; } -- cgit v1.2.3 From 252352cb5eece744456863c264bc02a43f4d2366 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 30 Aug 2013 18:08:49 +0200 Subject: net: airo: inherit addr_assign_type along with dev_addr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A device inheriting a random or set address should reflect this in its addr_assign_type. Acked-by: John W. Linville Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/wireless/airo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index d0adbaf86186..7fe19648f10e 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2693,7 +2693,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, dev->base_addr = ethdev->base_addr; dev->wireless_data = ethdev->wireless_data; SET_NETDEV_DEV(dev, ethdev->dev.parent); - memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); + eth_hw_addr_inherit(dev, ethdev); err = register_netdev(dev); if (err<0) { free_netdev(dev); -- cgit v1.2.3 From db181347e838ec87e31e2488697b6f0eea418e5a Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 30 Aug 2013 18:08:50 +0200 Subject: net: hostap: inherit addr_assign_type along with dev_addr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A device inheriting a random or set address should reflect this in its addr_assign_type. Cc: Jouni Malinen Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/wireless/hostap/hostap_hw.c | 2 +- drivers/net/wireless/hostap/hostap_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 6307a4e36c85..c275dc1623fe 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -1425,7 +1425,7 @@ static int prism2_hw_init2(struct net_device *dev, int initial) } list_for_each(ptr, &local->hostap_interfaces) { iface = list_entry(ptr, struct hostap_interface, list); - memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN); + eth_hw_addr_inherit(iface->dev, dev); } } else if (local->fw_ap) prism2_check_sta_fw_version(local); diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index e4f56ad26cd8..a1257c92afc4 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -66,7 +66,7 @@ struct net_device * hostap_add_interface(struct local_info *local, list_add(&iface->list, &local->hostap_interfaces); mdev = local->dev; - memcpy(dev->dev_addr, mdev->dev_addr, ETH_ALEN); + eth_hw_addr_inherit(dev, mdev); dev->base_addr = mdev->base_addr; dev->irq = mdev->irq; dev->mem_start = mdev->mem_start; -- cgit v1.2.3 From d32a96e26acce17c565480363a1078f0c9e677f1 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 30 Aug 2013 18:08:51 +0200 Subject: net: libertas: inherit addr_assign_type along with dev_addr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A device inheriting a random or set address should reflect this in its addr_assign_type. Acked-by: John W. Linville Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index efae07e05c80..6fef746345bc 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -1017,7 +1017,7 @@ static int lbs_add_mesh(struct lbs_private *priv) mesh_dev->netdev_ops = &mesh_netdev_ops; mesh_dev->ethtool_ops = &lbs_ethtool_ops; - memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN); + eth_hw_addr_inherit(mesh_dev, priv->dev); SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); -- cgit v1.2.3 From 7367d0b573d149550d2ae25c402984b98f8f422e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 1 Sep 2013 11:51:23 -0700 Subject: drivers/net: Convert uses of compare_ether_addr to ether_addr_equal Use the new bool function ether_addr_equal to add some clarity and reduce the likelihood for misuse of compare_ether_addr for sorting. Done via cocci script: (and a little typing) $ cat compare_ether_addr.cocci @@ expression a,b; @@ - !compare_ether_addr(a, b) + ether_addr_equal(a, b) @@ expression a,b; @@ - compare_ether_addr(a, b) + !ether_addr_equal(a, b) @@ expression a,b; @@ - !ether_addr_equal(a, b) == 0 + ether_addr_equal(a, b) @@ expression a,b; @@ - !ether_addr_equal(a, b) != 0 + !ether_addr_equal(a, b) @@ expression a,b; @@ - ether_addr_equal(a, b) == 0 + !ether_addr_equal(a, b) @@ expression a,b; @@ - ether_addr_equal(a, b) != 0 + ether_addr_equal(a, b) @@ expression a,b; @@ - !!ether_addr_equal(a, b) + ether_addr_equal(a, b) Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 4 ++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 4 ++-- drivers/net/ethernet/tile/tilegx.c | 2 +- drivers/net/usb/qmi_wwan.c | 2 +- drivers/net/vxlan.c | 7 +++---- drivers/net/wireless/ath/carl9170/rx.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 4 ++-- drivers/net/wireless/rtlwifi/base.c | 2 +- drivers/net/wireless/rtlwifi/ps.c | 2 +- drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 9 +++++---- drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 20 ++++++++++---------- 11 files changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 1f5166ad6bb5..59a62bbfb371 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -488,8 +488,8 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, * source pruning. */ if ((skb->pkt_type & (PACKET_BROADCAST | PACKET_MULTICAST)) && - !(compare_ether_addr(adapter->netdev->dev_addr, - eth_hdr(skb)->h_source))) { + ether_addr_equal(adapter->netdev->dev_addr, + eth_hdr(skb)->h_source)) { dev_kfree_skb_irq(skb); goto next_desc; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index a9bc651e9ffa..330d9a8774ad 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -1652,14 +1652,14 @@ int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) if (!is_valid_ether_addr(mac) || vf >= num_vfs) return -EINVAL; - if (!compare_ether_addr(adapter->mac_addr, mac)) { + if (ether_addr_equal(adapter->mac_addr, mac)) { netdev_err(netdev, "MAC address is already in use by the PF\n"); return -EINVAL; } for (i = 0; i < num_vfs; i++) { vf_info = &sriov->vf_info[i]; - if (!compare_ether_addr(vf_info->vp->mac, mac)) { + if (ether_addr_equal(vf_info->vp->mac, mac)) { netdev_err(netdev, "MAC address is already in use by VF %d\n", i); diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 5d2a719fc688..949076f4e6ae 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -544,7 +544,7 @@ static inline bool filter_packet(struct net_device *dev, void *buf) /* Filter out packets that aren't for us. */ if (!(dev->flags & IFF_PROMISC) && !is_multicast_ether_addr(buf) && - compare_ether_addr(dev->dev_addr, buf) != 0) + !ether_addr_equal(dev->dev_addr, buf)) return true; return false; diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 606eba2872bd..3a8131582e75 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -323,7 +323,7 @@ next_desc: /* Never use the same address on both ends of the link, even * if the buggy firmware told us to. */ - if (!compare_ether_addr(dev->net->dev_addr, default_modem_addr)) + if (ether_addr_equal(dev->net->dev_addr, default_modem_addr)) eth_hw_addr_random(dev->net); /* make MAC addr easily distinguishable from an IP header */ diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 6b560f373fc3..8f6d6c1153ce 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -478,7 +478,7 @@ static struct vxlan_fdb *__vxlan_find_mac(struct vxlan_dev *vxlan, struct vxlan_fdb *f; hlist_for_each_entry_rcu(f, head, hlist) { - if (compare_ether_addr(mac, f->eth_addr) == 0) + if (ether_addr_equal(mac, f->eth_addr)) return f; } @@ -1049,8 +1049,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, skb->protocol = eth_type_trans(skb, vxlan->dev); /* Ignore packet loops (and multicast echo) */ - if (compare_ether_addr(eth_hdr(skb)->h_source, - vxlan->dev->dev_addr) == 0) + if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) goto drop; /* Re-examine inner Ethernet packet */ @@ -1320,7 +1319,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) if (n) { bool diff; - diff = compare_ether_addr(eth_hdr(skb)->h_dest, n->ha) != 0; + diff = !ether_addr_equal(eth_hdr(skb)->h_dest, n->ha); if (diff) { memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, dev->addr_len); diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 4684dd989496..e935f61c7fad 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -602,8 +602,8 @@ static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len) if (bar->start_seq_num == entry_bar->start_seq_num && TID_CHECK(bar->control, entry_bar->control) && - compare_ether_addr(bar->ra, entry_bar->ta) == 0 && - compare_ether_addr(bar->ta, entry_bar->ra) == 0) { + ether_addr_equal(bar->ra, entry_bar->ta) && + ether_addr_equal(bar->ta, entry_bar->ra)) { struct ieee80211_tx_info *tx_info; tx_info = IEEE80211_SKB_CB(entry_skb); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b16521e6bf4a..712eea9d398f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -566,10 +566,10 @@ static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev, #undef TID_CHECK - if (compare_ether_addr(ba->ra, entry->ta)) + if (!ether_addr_equal(ba->ra, entry->ta)) continue; - if (compare_ether_addr(ba->ta, entry->ra)) + if (!ether_addr_equal(ba->ta, entry->ra)) continue; /* Mark BAR since we received the according BA */ diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 7651f5acc14b..8bb4a9a01a18 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -1304,7 +1304,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) return; /* and only beacons from the associated BSSID, please */ - if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) return; rtlpriv->link_info.bcn_rx_inperiod++; diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index f646b7585d9b..0d81f766fd0f 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -923,7 +923,7 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) return; /* and only beacons from the associated BSSID, please */ - if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) return; /* check if this really is a beacon */ diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c index a8871d66d56a..68685a898257 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c @@ -305,13 +305,14 @@ static void _rtl88ee_translate_rx_signal_stuff(struct ieee80211_hw *hw, psaddr = ieee80211_get_SA(hdr); memcpy(pstatus->psaddr, psaddr, ETH_ALEN); - addr = (!compare_ether_addr(mac->bssid, (ufc & IEEE80211_FCTL_TODS) ? - hdr->addr1 : (ufc & IEEE80211_FCTL_FROMDS) ? - hdr->addr2 : hdr->addr3)); + addr = ether_addr_equal(mac->bssid, + (ufc & IEEE80211_FCTL_TODS) ? hdr->addr1 : + (ufc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : + hdr->addr3); match_bssid = ((IEEE80211_FTYPE_CTL != type) && (!pstatus->hwerror) && (!pstatus->crc) && (!pstatus->icv)) && addr; - addr = (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + addr = ether_addr_equal(praddr, rtlefuse->dev_addr); packet_toself = match_bssid && addr; if (ieee80211_is_beacon(fc)) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index c72758d8f4ed..bcd82a1020a5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -255,16 +255,16 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw, type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; - packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && - (!compare_ether_addr(mac->bssid, - (le16_to_cpu(fc) & IEEE80211_FCTL_TODS) ? - hdr->addr1 : (le16_to_cpu(fc) & - IEEE80211_FCTL_FROMDS) ? - hdr->addr2 : hdr->addr3)) && (!pstatus->hwerror) && - (!pstatus->crc) && (!pstatus->icv)); - - packet_toself = packet_matchbssid && - (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + packet_matchbssid = + ((IEEE80211_FTYPE_CTL != type) && + ether_addr_equal(mac->bssid, + (le16_to_cpu(fc) & IEEE80211_FCTL_TODS) ? hdr->addr1 : + (le16_to_cpu(fc) & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : + hdr->addr3) && + (!pstatus->hwerror) && (!pstatus->crc) && (!pstatus->icv)); + + packet_toself = (packet_matchbssid && + ether_addr_equal(praddr, rtlefuse->dev_addr)); if (ieee80211_is_beacon(fc)) packet_beacon = true; -- cgit v1.2.3