diff options
author | David S. Miller <davem@davemloft.net> | 2009-08-21 01:56:56 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-21 01:56:56 -0700 |
commit | f8f2109d4f6c525f893f6f2901ae62372e83245e (patch) | |
tree | e20b095973d45eb2360ffa157ad161536c2ddbe9 | |
parent | bb81b2ddfa194b6d12761a350b5b5985cecae0a9 (diff) | |
parent | a2c3f6567c9ac327f1ef1272551f3a7595ec885e (diff) | |
download | blackbird-op-linux-f8f2109d4f6c525f893f6f2901ae62372e83245e.tar.gz blackbird-op-linux-f8f2109d4f6c525f893f6f2901ae62372e83245e.zip |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
99 files changed, 2790 insertions, 2170 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 866253d7abd7..9b55c661c3fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3272,6 +3272,12 @@ S: Supported F: drivers/net/mv643xx_eth.* F: include/linux/mv643xx.h +MARVELL MWL8K WIRELESS DRIVER +M: Lennert Buytenhek <buytenh@marvell.com> +L: linux-wireless@vger.kernel.org +S: Supported +F: drivers/net/wireless/mwl8k.c + MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER M: Nicolas Pitre <nico@cam.org> S: Maintained diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 5695911bc602..b80f514877d8 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1328,16 +1328,39 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev, } } +static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + unsigned int bit_nr, i; + u32 mc_filter[2]; + + mc_filter[1] = mc_filter[0] = 0; + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + + bit_nr &= 0x3F; + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + mclist = mclist->next; + } + + return mc_filter[0] | ((u64)(mc_filter[1]) << 32); +} + static void adm8211_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; struct adm8211_priv *priv = dev->priv; - unsigned int bit_nr, new_flags; + unsigned int new_flags; u32 mc_filter[2]; - int i; + + mc_filter[0] = multicast; + mc_filter[1] = multicast >> 32; new_flags = 0; @@ -1346,23 +1369,13 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev, priv->nar |= ADM8211_NAR_PR; priv->nar &= ~ADM8211_NAR_MM; mc_filter[1] = mc_filter[0] = ~0; - } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { + } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) { new_flags |= FIF_ALLMULTI; priv->nar &= ~ADM8211_NAR_PR; priv->nar |= ADM8211_NAR_MM; mc_filter[1] = mc_filter[0] = ~0; } else { priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); - mc_filter[1] = mc_filter[0] = 0; - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - - bit_nr &= 0x3F; - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - mclist = mclist->next; - } } ADM8211_IDLE_RX(); @@ -1757,6 +1770,7 @@ static const struct ieee80211_ops adm8211_ops = { .remove_interface = adm8211_remove_interface, .config = adm8211_config, .bss_info_changed = adm8211_bss_info_changed, + .prepare_multicast = adm8211_prepare_multicast, .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, .get_tx_stats = adm8211_get_tx_stats, diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 7218dbabad3e..8e1a55dec351 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1950,9 +1950,8 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed) { struct at76_priv *priv = hw->priv; - at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d", - __func__, hw->conf.channel->hw_value, - hw->conf.radio_enabled); + at76_dbg(DBG_MAC80211, "%s(): channel %d", + __func__, hw->conf.channel->hw_value); at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:"); mutex_lock(&priv->mtx); @@ -1997,15 +1996,14 @@ static void at76_bss_info_changed(struct ieee80211_hw *hw, /* must be atomic */ static void at76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total_flags, u64 multicast) { struct at76_priv *priv = hw->priv; int flags; at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x " - "total_flags=0x%08x mc_count=%d", - __func__, changed_flags, *total_flags, mc_count); + "total_flags=0x%08x", + __func__, changed_flags, *total_flags); flags = changed_flags & AT76_SUPPORTED_FILTERS; *total_flags = AT76_SUPPORTED_FILTERS; diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index e6c3ee3e0581..ce407248d7d8 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -157,6 +157,7 @@ struct ar9170_sta_tid { struct ar9170 { struct ieee80211_hw *hw; + struct ath_common common; struct mutex mutex; enum ar9170_device_state state; unsigned long bad_hw_nagger; @@ -184,10 +185,8 @@ struct ar9170 { bool disable_offload; /* filter settings */ - struct work_struct filter_config_work; - u64 cur_mc_hash, want_mc_hash; - u32 cur_filter, want_filter; - unsigned long filter_changed; + u64 cur_mc_hash; + u32 cur_filter; unsigned int filter_state; bool sniffer_enabled; @@ -222,7 +221,6 @@ struct ar9170 { /* EEPROM */ struct ar9170_eeprom eeprom; - struct ath_regulatory regulatory; /* tx queues - as seen by hw - */ struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; @@ -261,10 +259,6 @@ struct ar9170_tx_info { #define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) #define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) -#define AR9170_FILTER_CHANGED_MODE BIT(0) -#define AR9170_FILTER_CHANGED_MULTICAST BIT(1) -#define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) - /* exported interface */ void *ar9170_alloc(size_t priv_size); int ar9170_register(struct ar9170 *ar, struct device *pdev); @@ -278,8 +272,8 @@ int ar9170_nag_limiter(struct ar9170 *ar); int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int ar9170_init_mac(struct ar9170 *ar); int ar9170_set_qos(struct ar9170 *ar); -int ar9170_update_multicast(struct ar9170 *ar); -int ar9170_update_frame_filter(struct ar9170 *ar); +int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast); +int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter); int ar9170_set_operating_mode(struct ar9170 *ar); int ar9170_set_beacon_timers(struct ar9170 *ar); int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index d9f1f46de183..60049366e863 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -238,39 +238,31 @@ static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) return ar9170_regwrite_result(); } -int ar9170_update_multicast(struct ar9170 *ar) +int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) { int err; ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, - ar->want_mc_hash >> 32); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, - ar->want_mc_hash); - + ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); + ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); ar9170_regwrite_finish(); err = ar9170_regwrite_result(); - if (err) return err; - ar->cur_mc_hash = ar->want_mc_hash; - + ar->cur_mc_hash = mc_hash; return 0; } -int ar9170_update_frame_filter(struct ar9170 *ar) +int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter) { int err; - err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, - ar->want_filter); - + err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter); if (err) return err; - ar->cur_filter = ar->want_filter; - + ar->cur_filter = filter; return 0; } diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index ea8c9419336d..658b32312caf 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1232,8 +1232,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw) mutex_lock(&ar->mutex); - ar->filter_changed = 0; - /* reinitialize queues statistics */ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); for (i = 0; i < __AR9170_NUM_TXQ; i++) @@ -1296,7 +1294,6 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) #ifdef CONFIG_AR9170_LEDS cancel_delayed_work_sync(&ar->led_work); #endif - cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); @@ -1973,8 +1970,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, } ar->cur_filter = 0; - ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS; - err = ar9170_update_frame_filter(ar); + err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS); if (err) goto unlock; @@ -1992,8 +1988,7 @@ static void ar9170_op_remove_interface(struct ieee80211_hw *hw, mutex_lock(&ar->mutex); ar->vif = NULL; - ar->want_filter = 0; - ar9170_update_frame_filter(ar); + ar9170_update_frame_filter(ar, 0); ar9170_set_beacon_timers(ar); dev_kfree_skb(ar->beacon); ar->beacon = NULL; @@ -2065,48 +2060,37 @@ out: return err; } -static void ar9170_set_filters(struct work_struct *work) +static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, + struct dev_addr_list *mclist) { - struct ar9170 *ar = container_of(work, struct ar9170, - filter_config_work); - int err; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE, - &ar->filter_changed)) { - err = ar9170_set_operating_mode(ar); - if (err) - goto unlock; - } + u64 mchash; + int i; - if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST, - &ar->filter_changed)) { - err = ar9170_update_multicast(ar); - if (err) - goto unlock; - } + /* always get broadcast frames */ + mchash = 1ULL << (0xff >> 2); - if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, - &ar->filter_changed)) { - err = ar9170_update_frame_filter(ar); - if (err) - goto unlock; + for (i = 0; i < mc_count; i++) { + if (WARN_ON(!mclist)) + break; + mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); + mclist = mclist->next; } -unlock: - mutex_unlock(&ar->mutex); + return mchash; } static void ar9170_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct ar9170 *ar = hw->priv; + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return ; + + mutex_lock(&ar->mutex); + /* mask supported flags */ *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; @@ -2116,26 +2100,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, * then checking the error flags, later. */ - if (changed_flags & FIF_ALLMULTI) { - if (*new_flags & FIF_ALLMULTI) { - ar->want_mc_hash = ~0ULL; - } else { - u64 mchash; - int i; + if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) + multicast = ~0ULL; - /* always get broadcast frames */ - mchash = 1ULL << (0xff >> 2); - - for (i = 0; i < mc_count; i++) { - if (WARN_ON(!mclist)) - break; - mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); - mclist = mclist->next; - } - ar->want_mc_hash = mchash; - } - set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); - } + if (multicast != ar->cur_mc_hash) + ar9170_update_multicast(ar, multicast); if (changed_flags & FIF_CONTROL) { u32 filter = AR9170_MAC_REG_FTF_PSPOLL | @@ -2146,24 +2115,22 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, AR9170_MAC_REG_FTF_CFE_ACK; if (*new_flags & FIF_CONTROL) - ar->want_filter = ar->cur_filter | filter; + filter |= ar->cur_filter; else - ar->want_filter = ar->cur_filter & ~filter; + filter &= (~ar->cur_filter); - set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, - &ar->filter_changed); + ar9170_update_frame_filter(ar, filter); } if (changed_flags & FIF_PROMISC_IN_BSS) { ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - set_bit(AR9170_FILTER_CHANGED_MODE, - &ar->filter_changed); + ar9170_set_operating_mode(ar); } - if (likely(IS_STARTED(ar))) - ieee80211_queue_work(ar->hw, &ar->filter_config_work); + mutex_unlock(&ar->mutex); } + static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -2417,9 +2384,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, default: break; } - - if (IS_STARTED(ar) && ar->filter_changed) - ieee80211_queue_work(ar->hw, &ar->filter_config_work); } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -2543,6 +2507,7 @@ static const struct ieee80211_ops ar9170_ops = { .add_interface = ar9170_op_add_interface, .remove_interface = ar9170_op_remove_interface, .config = ar9170_op_config, + .prepare_multicast = ar9170_op_prepare_multicast, .configure_filter = ar9170_op_configure_filter, .conf_tx = ar9170_conf_tx, .bss_info_changed = ar9170_op_bss_info_changed, @@ -2589,7 +2554,6 @@ void *ar9170_alloc(size_t priv_size) skb_queue_head_init(&ar->tx_pending[i]); } ar9170_rx_reset_rx_mpdu(ar); - INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); INIT_LIST_HEAD(&ar->tx_ampdu_list); @@ -2634,6 +2598,7 @@ static int ar9170_read_eeprom(struct ar9170 *ar) { #define RW 8 /* number of words to read at once */ #define RB (sizeof(u32) * RW) + struct ath_regulatory *regulatory = &ar->common.regulatory; u8 *eeprom = (void *)&ar->eeprom; u8 *addr = ar->eeprom.mac_address; __le32 offsets[RW]; @@ -2700,8 +2665,8 @@ static int ar9170_read_eeprom(struct ar9170 *ar) else ar->hw->channel_change_time = 80 * 1000; - ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); - ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); + regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); + regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); /* second part of wiphy init */ SET_IEEE80211_PERM_ADDR(ar->hw, addr); @@ -2715,11 +2680,12 @@ static int ar9170_reg_notifier(struct wiphy *wiphy, struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ar9170 *ar = hw->priv; - return ath_reg_notifier_apply(wiphy, request, &ar->regulatory); + return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); } int ar9170_register(struct ar9170 *ar, struct device *pdev) { + struct ath_regulatory *regulatory = &ar->common.regulatory; int err; /* try to read EEPROM, init MAC addr */ @@ -2727,7 +2693,7 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) if (err) goto err_out; - err = ath_regd_init(&ar->regulatory, ar->hw->wiphy, + err = ath_regd_init(regulatory, ar->hw->wiphy, ar9170_reg_notifier); if (err) goto err_out; @@ -2736,8 +2702,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) if (err) goto err_out; - if (!ath_is_world_regd(&ar->regulatory)) - regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2); + if (!ath_is_world_regd(regulatory)) + regulatory_hint(ar->hw->wiphy, regulatory->alpha2); err = ar9170_init_leds(ar); if (err) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index e284cd3ac6d4..a63e90cbf9e5 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -19,8 +19,26 @@ #include <linux/skbuff.h> +struct reg_dmn_pair_mapping { + u16 regDmnEnum; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; +}; + +struct ath_regulatory { + char alpha2[2]; + u16 country_code; + u16 max_power_level; + u32 tp_scale; + u16 current_rd; + u16 current_rd_ext; + int16_t power_limit; + struct reg_dmn_pair_mapping *regpair; +}; + struct ath_common { u16 cachelsz; + struct ath_regulatory regulatory; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index c09402eea7f3..862762cea54c 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -27,8 +27,6 @@ #include <linux/types.h> #include <net/mac80211.h> -#include "../regd.h" - /* RX/TX descriptor hw structs * TODO: Driver part should only see sw structs */ #include "desc.h" @@ -1077,7 +1075,6 @@ struct ath5k_hw { int ah_gpio_npins; - struct ath_regulatory ah_regulatory; struct ath5k_capabilities ah_capabilities; struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2b3cf39dd4b1..5056410d788a 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -229,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static int ath5k_config(struct ieee80211_hw *hw, u32 changed); +static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mc_list); static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist); + u64 multicast); static int ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -260,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = { .add_interface = ath5k_add_interface, .remove_interface = ath5k_remove_interface, .config = ath5k_config, + .prepare_multicast = ath5k_prepare_multicast, .configure_filter = ath5k_configure_filter, .set_key = ath5k_set_key, .get_stats = ath5k_get_stats, @@ -715,9 +718,9 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath5k_softc *sc = hw->priv; - struct ath_regulatory *reg = &sc->ah->ah_regulatory; + struct ath_regulatory *regulatory = &sc->common.regulatory; - return ath_reg_notifier_apply(wiphy, request, reg); + return ath_reg_notifier_apply(wiphy, request, regulatory); } static int @@ -725,6 +728,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; + struct ath_regulatory *regulatory = &sc->common.regulatory; u8 mac[ETH_ALEN] = {}; int ret; @@ -814,9 +818,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) memset(sc->bssidmask, 0xff, ETH_ALEN); ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); - ah->ah_regulatory.current_rd = - ah->ah_capabilities.cap_eeprom.ee_regdomain; - ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier); + regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; + ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); if (ret) { ATH5K_ERR(sc, "can't initialize regulatory system\n"); goto err_queues; @@ -828,8 +831,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err_queues; } - if (!ath_is_world_regd(&sc->ah->ah_regulatory)) - regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2); + if (!ath_is_world_regd(regulatory)) + regulatory_hint(hw->wiphy, regulatory->alpha2); ath5k_init_leds(sc); @@ -2853,6 +2856,37 @@ unlock: return ret; } +static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + u32 mfilt[2], val; + int i; + u8 pos; + + mfilt[0] = 0; + mfilt[1] = 1; + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + /* calculate XOR of eight 6-bit values */ + val = get_unaligned_le32(mclist->dmi_addr + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = get_unaligned_le32(mclist->dmi_addr + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + /* XXX: we might be able to just do this instead, + * but not sure, needs testing, if we do use this we'd + * neet to inform below to not reset the mcast */ + /* ath5k_hw_set_mcast_filterindex(ah, + * mclist->dmi_addr[5]); */ + mclist = mclist->next; + } + + return ((u64)(mfilt[1]) << 32) | mfilt[0]; +} + #define SUPPORTED_FIF_FLAGS \ FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ @@ -2878,16 +2912,14 @@ unlock: static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - u32 mfilt[2], val, rfilt; - u8 pos; - int i; + u32 mfilt[2], rfilt; - mfilt[0] = 0; - mfilt[1] = 0; + mfilt[0] = multicast; + mfilt[1] = multicast >> 32; /* Only deal with supported flags */ changed_flags &= SUPPORTED_FIF_FLAGS; @@ -2913,24 +2945,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (*new_flags & FIF_ALLMULTI) { mfilt[0] = ~0; mfilt[1] = ~0; - } else { - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - /* calculate XOR of eight 6-bit values */ - val = get_unaligned_le32(mclist->dmi_addr + 0); - pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = get_unaligned_le32(mclist->dmi_addr + 3); - pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - pos &= 0x3f; - mfilt[pos / 32] |= (1 << (pos % 32)); - /* XXX: we might be able to just do this instead, - * but not sure, needs testing, if we do use this we'd - * neet to inform below to not reset the mcast */ - /* ath5k_hw_set_mcast_filterindex(ah, - * mclist->dmi_addr[5]); */ - mclist = mclist->next; - } } /* This is the best we can do */ diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 25a72a85aaa5..a28c42f32c9d 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -50,6 +50,8 @@ #include "ath5k.h" #include "debug.h" + +#include "../regd.h" #include "../ath.h" #define ATH_RXBUF 40 /* number of RX buffers */ @@ -200,4 +202,15 @@ struct ath5k_softc { #define ath5k_hw_hasveol(_ah) \ (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0) +static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) +{ + return &ah->ah_sc->common; +} + +static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah) +{ + return &(ath5k_hw_common(ah)->regulatory); + +} + #endif diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 298fcf015227..1a039f2bd732 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -2198,6 +2198,7 @@ static void ath5k_get_max_ctl_power(struct ath5k_hw *ah, struct ieee80211_channel *channel) { + struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; struct ath5k_edge_power *rep = ee->ee_ctl_pwr; u8 *ctl_val = ee->ee_ctl; @@ -2208,7 +2209,7 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, u8 ctl_idx = 0xFF; u32 target = channel->center_freq; - ctl_mode = ath_regd_get_band_ctl(&ah->ah_regulatory, channel->band); + ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band); switch (channel->hw_value & CHANNEL_MODES) { case CHANNEL_A: diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index f264097a2f4e..a7cbb07988cf 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -538,7 +538,6 @@ void ath9k_ani_reset(struct ath_hw *ah) } void ath9k_hw_ani_monitor(struct ath_hw *ah, - const struct ath9k_node_stats *stats, struct ath9k_channel *chan) { struct ar5416AniState *aniState; @@ -550,7 +549,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, return; aniState = ah->curani; - ah->stats.ast_nodestats = *stats; listenTime = ath9k_hw_ani_get_listen_time(ah); if (listenTime < 0) { @@ -693,8 +691,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, * any of the MIB counters overflow/trigger so don't assume we're * here because a PHY error counter triggered. */ -void ath9k_hw_procmibevent(struct ath_hw *ah, - const struct ath9k_node_stats *stats) +void ath9k_hw_procmibevent(struct ath_hw *ah) { u32 phyCnt1, phyCnt2; @@ -706,7 +703,6 @@ void ath9k_hw_procmibevent(struct ath_hw *ah, /* Clear the mib counters and save them in the stats */ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - ah->stats.ast_nodestats = *stats; if (!DO_ANI(ah)) return; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 119924511f85..4e1ab94a5153 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -18,15 +18,10 @@ #define ANI_H #define HAL_PROCESS_ANI 0x00000001 -#define ATH9K_RSSI_EP_MULTIPLIER (1<<7) #define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) -#define HAL_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -#define BEACON_RSSI(ahp) \ - HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi, \ - ATH9K_RSSI_EP_MULTIPLIER) +#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) #define ATH9K_ANI_OFDM_TRIG_HIGH 500 #define ATH9K_ANI_OFDM_TRIG_LOW 200 @@ -65,13 +60,6 @@ struct ath9k_mib_stats { u32 beacons; }; -struct ath9k_node_stats { - u32 ns_avgbrssi; - u32 ns_avgrssi; - u32 ns_avgtxrssi; - u32 ns_avgtxrate; -}; - struct ar5416AniState { struct ath9k_channel *c; u8 noiseImmunityLevel; @@ -115,21 +103,19 @@ struct ar5416Stats { u32 ast_ani_reset; u32 ast_ani_lzero; u32 ast_ani_lneg; + u32 avgbrssi; struct ath9k_mib_stats ast_mibstats; - struct ath9k_node_stats ast_nodestats; }; #define ah_mibStats stats.ast_mibstats void ath9k_ani_reset(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, - const struct ath9k_node_stats *stats, struct ath9k_channel *chan); void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, u32 *rxf_pcnt, u32 *txf_pcnt); -void ath9k_hw_procmibevent(struct ath_hw *ah, - const struct ath9k_node_stats *stats); +void ath9k_hw_procmibevent(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); void ath9k_hw_ani_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2fd663c01b8e..7705da1103f4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -454,7 +454,8 @@ struct ath_ani { /* LED Control */ /********************/ -#define ATH_LED_PIN 1 +#define ATH_LED_PIN_DEF 1 +#define ATH_LED_PIN_9287 8 #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ #define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ @@ -602,7 +603,6 @@ struct ath_softc { int beacon_interval; struct ath_ani ani; - struct ath9k_node_stats nodestats; #ifdef CONFIG_ATH9K_DEBUG struct ath9k_debug debug; #endif @@ -630,6 +630,16 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); +static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) +{ + return &ah->ah_sc->common; +} + +static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) +{ + return &(ath9k_hw_common(ah)->regulatory); +} + static inline void ath_read_cachesize(struct ath_softc *sc, int *csz) { sc->bus_ops->read_cachesize(sc, csz); diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 26d87527acbd..20f74b5b5703 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -729,26 +729,42 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) static void ath9k_olc_temp_compensation(struct ath_hw *ah) { u32 rddata, i; - int delta, currPDADC, regval; + int delta, currPDADC, regval, slope; rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); - currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); - if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) - delta = (currPDADC - ah->initPDADC + 4) / 8; - else - delta = (currPDADC - ah->initPDADC + 5) / 10; - if (delta != ah->PDADCdelta) { - ah->PDADCdelta = delta; - for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { - regval = ah->originalGain[i] - delta; - if (regval < 0) - regval = 0; + if (OLC_FOR_AR9287_10_LATER) { + if (ah->initPDADC == 0 || currPDADC == 0) { + return; + } else { + slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); + if (slope == 0) + delta = 0; + else + delta = ((currPDADC - ah->initPDADC)*4) / slope; + REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + } + } else { + if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) + delta = (currPDADC - ah->initPDADC + 4) / 8; + else + delta = (currPDADC - ah->initPDADC + 5) / 10; + + if (delta != ah->PDADCdelta) { + ah->PDADCdelta = delta; + for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { + regval = ah->originalGain[i] - delta; + if (regval < 0) + regval = 0; - REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, - AR_PHY_TX_GAIN, regval); + REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, + AR_PHY_TX_GAIN, regval); + } } } } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index d34dd23e806a..b8eca7be5f3a 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -508,6 +508,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); int i; int16_t twiceLargestAntenna; u16 twiceMinEdgePower; @@ -541,9 +542,9 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); @@ -707,6 +708,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, u8 twiceMaxRegulatoryPower, u8 powerLimit) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; struct modal_eep_4k_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; @@ -744,7 +746,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, else if (IS_CHAN_HT20(chan)) i = rateHt20_0; - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; if (AR_SREV_9280_10_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index aeb7f484b6e1..c20c21a79b21 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -374,7 +374,6 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, u8 *pCalChans, u16 availPiers, int8_t *pPwr) { - u8 pcdac, i = 0; u16 idxL = 0, idxR = 0, numPiers; bool match; struct chan_centers centers; @@ -392,17 +391,12 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, &idxL, &idxR); if (match) { - pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; - *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; + *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; } else { - pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; - *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + - pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + + (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; } - while ((pcdac > ah->originalGain[i]) && - (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) - i++; } static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, @@ -605,7 +599,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, { #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; @@ -638,9 +632,9 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); scaledPower = min(powerLimit, maxRegAllowedPower); @@ -837,7 +831,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, { #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 - + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; @@ -955,20 +949,20 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, i = rate6mb; if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = + regulatory->max_power_level = ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; else - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; switch (ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; case 2: - ah->regulatory.max_power_level += + regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; break; case 3: - ah->regulatory.max_power_level += + regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 5211ad94c8fb..ae7fb5dcb266 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -904,6 +904,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = @@ -953,9 +954,9 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); @@ -1163,6 +1164,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, u8 powerLimit) { #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; struct modal_eep_header *pModal = &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); @@ -1292,19 +1294,19 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, i = rateHt20_0; if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = + regulatory->max_power_level = ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; else - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; switch(ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; case 2: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; break; case 3: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9f1b34d9861a..4f3d5ea34812 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -439,8 +439,13 @@ static void ath9k_hw_init_config(struct ath_hw *ah) static void ath9k_hw_init_defaults(struct ath_hw *ah) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + + regulatory->country_code = CTRY_DEFAULT; + regulatory->power_limit = MAX_RATE_POWER; + regulatory->tp_scale = ATH9K_TP_SCALE_MAX; + ah->hw_version.magic = AR5416_MAGIC; - ah->regulatory.country_code = CTRY_DEFAULT; ah->hw_version.subvendorid = 0; ah->ah_flags = 0; @@ -449,8 +454,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) if (!AR_SREV_9100(ah)) ah->ah_flags = AH_USE_EEPROM; - ah->regulatory.power_limit = MAX_RATE_POWER; - ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; ah->atim_window = 0; ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; ah->beacon_interval = 100; @@ -1332,11 +1335,21 @@ static void ath9k_olc_init(struct ath_hw *ah) { u32 i; - for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) - ah->originalGain[i] = - MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), - AR_PHY_TX_GAIN); - ah->PDADCdelta = 0; + if (OLC_FOR_AR9287_10_LATER) { + REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, + AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0, + AR9287_AN_TXPC0_TXPCMODE, + AR9287_AN_TXPC0_TXPCMODE_S, + AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); + udelay(100); + } else { + for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) + ah->originalGain[i] = + MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), + AR_PHY_TX_GAIN); + ah->PDADCdelta = 0; + } } static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, @@ -1358,6 +1371,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); int i, regWrites = 0; struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; @@ -1464,11 +1478,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, ath9k_olc_init(ah); ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, @@ -1786,6 +1800,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ieee80211_channel *channel = chan->chan; u32 synthDelay, qnum; @@ -1818,11 +1833,11 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, } ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IS_CHAN_B(chan)) @@ -2382,7 +2397,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { /* Enable ASYNC FIFO */ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL); @@ -2468,7 +2483,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_user_settings(ah); - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { REG_WRITE(ah, AR_D_GBL_IFS_SIFS, AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR); REG_WRITE(ah, AR_D_GBL_IFS_SLOT, @@ -2484,7 +2499,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN, AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL); } - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { REG_SET_BIT(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_ENABLE_AGGWEP); } @@ -3063,7 +3078,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) if (ah->config.pcie_waen) { REG_WRITE(ah, AR_WA, ah->config.pcie_waen); } else { - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); /* * On AR9280 chips bit 22 of 0x4004 needs to be set to @@ -3470,27 +3485,29 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + u16 capField = 0, eeval; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); - ah->regulatory.current_rd = eeval; + regulatory->current_rd = eeval; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); if (AR_SREV_9285_10_OR_LATER(ah)) eeval |= AR9285_RDEXT_DEFAULT; - ah->regulatory.current_rd_ext = eeval; + regulatory->current_rd_ext = eeval; capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); if (ah->opmode != NL80211_IFTYPE_AP && ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { - if (ah->regulatory.current_rd == 0x64 || - ah->regulatory.current_rd == 0x65) - ah->regulatory.current_rd += 5; - else if (ah->regulatory.current_rd == 0x41) - ah->regulatory.current_rd = 0x43; + if (regulatory->current_rd == 0x64 || + regulatory->current_rd == 0x65) + regulatory->current_rd += 5; + else if (regulatory->current_rd == 0x41) + regulatory->current_rd = 0x43; DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "regdomain mapped to 0x%x\n", ah->regulatory.current_rd); + "regdomain mapped to 0x%x\n", regulatory->current_rd); } eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); @@ -3625,7 +3642,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { + if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { pCap->reg_cap = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | @@ -3654,6 +3671,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 *result) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); switch (type) { case ATH9K_CAP_CIPHER: switch (capability) { @@ -3702,13 +3720,13 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, case 0: return 0; case 1: - *result = ah->regulatory.power_limit; + *result = regulatory->power_limit; return 0; case 2: - *result = ah->regulatory.max_power_level; + *result = regulatory->max_power_level; return 0; case 3: - *result = ah->regulatory.tp_scale; + *result = regulatory->tp_scale; return 0; } return false; @@ -3946,17 +3964,18 @@ bool ath9k_hw_disable(struct ath_hw *ah) void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath9k_channel *chan = ah->curchan; struct ieee80211_channel *channel = chan->chan; - ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); + regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER); ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); } void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0336981a70ec..24b30631d93e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -396,7 +396,6 @@ struct ath_hw { struct ath9k_hw_version hw_version; struct ath9k_ops_config config; struct ath9k_hw_capabilities caps; - struct ath_regulatory regulatory; struct ath9k_channel channels[38]; struct ath9k_channel *curchan; @@ -522,6 +521,7 @@ struct ath_hw { u32 originalGain[22]; int initPDADC; int PDADCdelta; + u8 led_pin; struct ar5416IniArray iniModes; struct ar5416IniArray iniCommon; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fa4c6e74f977..9b9b4e8ee1ea 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -384,7 +384,7 @@ static void ath_ani_calibrate(unsigned long data) if (longcal || shortcal || aniflag) { /* Call ANI routine if necessary */ if (aniflag) - ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan); + ath9k_hw_ani_monitor(ah, ah->curchan); /* Perform calibration if necessary */ if (longcal || shortcal) { @@ -589,7 +589,7 @@ irqreturn_t ath_isr(int irq, void *dev) * it will clear whatever condition caused * the interrupt. */ - ath9k_hw_procmibevent(ah, &sc->nodestats); + ath9k_hw_procmibevent(ah); ath9k_hw_set_interrupts(ah, sc->imask); } @@ -940,10 +940,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_beacon_config(sc, vif); /* Reset rssi stats */ - sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; ath_start_ani(sc); } else { @@ -968,9 +965,9 @@ static void ath_led_blink_work(struct work_struct *work) if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); else - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); ieee80211_queue_delayed_work(sc->hw, @@ -1002,7 +999,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev, case LED_OFF: if (led->led_type == ATH_LED_ASSOC || led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (led->led_type == ATH_LED_RADIO)); sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; if (led->led_type == ATH_LED_RADIO) @@ -1017,7 +1014,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev, ieee80211_queue_delayed_work(sc->hw, &sc->ath_led_blink_work, 0); } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); sc->sc_flags |= SC_OP_LED_ON; } else { sc->led_on_cnt++; @@ -1062,7 +1059,7 @@ static void ath_deinit_leds(struct ath_softc *sc) ath_unregister_led(&sc->tx_led); ath_unregister_led(&sc->rx_led); ath_unregister_led(&sc->radio_led); - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); } static void ath_init_leds(struct ath_softc *sc) @@ -1070,11 +1067,16 @@ static void ath_init_leds(struct ath_softc *sc) char *trigger; int ret; + if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); /* LED off, active low */ - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); @@ -1153,9 +1155,9 @@ void ath_radio_enable(struct ath_softc *sc) ath9k_hw_set_interrupts(ah, sc->imask); /* Enable LED */ - ath9k_hw_cfg_output(ah, ATH_LED_PIN, + ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(ah, ah->led_pin, 0); ieee80211_wake_queues(sc->hw); ath9k_ps_restore(sc); @@ -1171,8 +1173,8 @@ void ath_radio_disable(struct ath_softc *sc) ieee80211_stop_queues(sc->hw); /* Disable LED */ - ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1); - ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN); + ath9k_hw_set_gpio(ah, ah->led_pin, 1); + ath9k_hw_cfg_gpio_input(ah, ah->led_pin); /* Disable interrupts */ ath9k_hw_set_interrupts(ah, 0); @@ -1288,7 +1290,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_regulatory *reg = &sc->sc_ah->regulatory; + struct ath_regulatory *reg = &sc->common.regulatory; return ath_reg_notifier_apply(wiphy, request, reg); } @@ -1581,12 +1583,12 @@ int ath_init_device(u16 devid, struct ath_softc *sc) ath_set_hw_capab(sc, hw); - error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, + error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy, ath9k_reg_notifier); if (error) return error; - reg = &sc->sc_ah->regulatory; + reg = &sc->common.regulatory; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); @@ -2100,6 +2102,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + mutex_lock(&sc->mutex); + aphy->state = ATH_WIPHY_INACTIVE; cancel_delayed_work_sync(&sc->ath_led_blink_work); @@ -2112,13 +2116,10 @@ static void ath9k_stop(struct ieee80211_hw *hw) if (sc->sc_flags & SC_OP_INVALID) { DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); + mutex_unlock(&sc->mutex); return; } - mutex_lock(&sc->mutex); - - cancel_delayed_work_sync(&sc->tx_complete_work); - if (ath9k_wiphy_started(sc)) { mutex_unlock(&sc->mutex); return; /* another wiphy still in use */ @@ -2389,8 +2390,7 @@ skip_chan_change: static void ath9k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, - struct dev_mc_list *mclist) + u64 multicast) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 616bdff2b6a1..685a8cebb468 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -236,7 +236,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); pci_save_state(pdev); pci_disable_device(pdev); @@ -269,9 +269,9 @@ static int ath_pci_resume(struct pci_dev *pdev) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); /* Enable LED */ - ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index e83cd4ab87f0..dfda6f444648 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -490,11 +490,18 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_TX_PWRCTRL9 0xa27C #define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 #define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 +#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 +#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31 #define AR_PHY_TX_GAIN_TBL1 0xa300 #define AR_PHY_TX_GAIN 0x0007F000 #define AR_PHY_TX_GAIN_S 12 +#define AR_PHY_CH0_TX_PWRCTRL11 0xa398 +#define AR_PHY_CH1_TX_PWRCTRL11 0xb398 +#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 +#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 + #define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 #define AR_PHY_MASK2_M_31_45 0xa3a4 #define AR_PHY_MASK2_M_16_30 0xa3a8 diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 61dbdd227444..7b62c220d5fd 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -222,7 +222,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, /* Update Beacon RSSI, this is used by ANI. */ if (ieee80211_is_beacon(fc)) - sc->nodestats.ns_avgbrssi = ds->ds_rxstat.rs_rssi; + sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi; rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->band = hw->conf.channel->band; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 13fd658b5d33..c9e1ac92d0e9 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -744,6 +744,7 @@ #define AR_SREV_VERSION_9287 0x180 #define AR_SREV_REVISION_9287_10 0 #define AR_SREV_REVISION_9287_11 1 +#define AR_SREV_REVISION_9287_12 2 #define AR_SREV_VERSION_9271 0x140 #define AR_SREV_REVISION_9271_10 0 #define AR_SREV_REVISION_9271_11 1 @@ -817,7 +818,13 @@ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11))) - +#define AR_SREV_9287_12(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_12)) +#define AR_SREV_9287_12_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12))) #define AR_SREV_9271(_ah) \ (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271) #define AR_SREV_9271_10(_ah) \ diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 07291ccb23f2..4d3c53674e5a 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -18,9 +18,10 @@ #define REGD_H #include <linux/nl80211.h> - #include <net/cfg80211.h> +#include "ath.h" + #define NO_CTL 0xff #define SD_NO_CTL 0xE0 #define NO_CTL 0xff @@ -47,29 +48,12 @@ #define CHANNEL_HALF_BW 10 #define CHANNEL_QUARTER_BW 5 -struct reg_dmn_pair_mapping { - u16 regDmnEnum; - u16 reg_5ghz_ctl; - u16 reg_2ghz_ctl; -}; - struct country_code_to_enum_rd { u16 countryCode; u16 regDmnEnum; const char *isoName; }; -struct ath_regulatory { - char alpha2[2]; - u16 country_code; - u16 max_power_level; - u32 tp_scale; - u16 current_rd; - u16 current_rd_ext; - int16_t power_limit; - struct reg_dmn_pair_mapping *regpair; -}; - enum CountryCode { CTRY_ALBANIA = 8, CTRY_ALGERIA = 12, diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 67f564e37225..237b1aadf9b6 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -80,16 +80,16 @@ config B43_NPHY SAY N. config B43_PHY_LP - bool "IEEE 802.11g LP-PHY support (BROKEN)" - depends on B43 && EXPERIMENTAL && BROKEN + bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)" + depends on B43 && EXPERIMENTAL ---help--- Support for the LP-PHY. - The LP-PHY is an IEEE 802.11g based PHY built into some notebooks - and embedded devices. - - THIS IS BROKEN AND DOES NOT WORK YET. + The LP-PHY is a low-power PHY built into some notebooks + and embedded devices. It supports 802.11a/g + (802.11a support is optional, and currently disabled). - SAY N. + This is heavily experimental, and probably will not work for you. + Say N unless you want to help debug the driver. # This config option automatically enables b43 LEDS support, # if it's possible. diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 41a0e9c2b339..289aaf6dfe79 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1188,7 +1188,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, info, cookie); + skb, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 22d0fbd83a62..976104f634a1 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -477,7 +477,7 @@ static void lo_measure_setup(struct b43_wldev *dev, } else b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); if (phy->rev >= 2) - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); b43_gphy_channel_switch(dev, 6, 0); b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 950beefbeaeb..f5bdf1cae1d1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -80,6 +80,10 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +static int modparam_hwtkip; +module_param_named(hwtkip, modparam_hwtkip, int, 0444); +MODULE_PARM_DESC(hwtkip, "Enable hardware tkip."); + static int modparam_qos = 1; module_param_named(qos, modparam_qos, int, 0444); MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); @@ -691,9 +695,9 @@ static void b43_synchronize_irq(struct b43_wldev *dev) } /* DummyTransmission function, as documented on - * http://bcm-specs.sipsolutions.net/DummyTransmission + * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission */ -void b43_dummy_transmission(struct b43_wldev *dev) +void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) { struct b43_wl *wl = dev->wl; struct b43_phy *phy = &dev->phy; @@ -707,19 +711,12 @@ void b43_dummy_transmission(struct b43_wldev *dev) 0x00000000, }; - switch (phy->type) { - case B43_PHYTYPE_A: + if (ofdm) { max_loop = 0x1E; buffer[0] = 0x000201CC; - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: + } else { max_loop = 0xFA; buffer[0] = 0x000B846E; - break; - default: - B43_WARN_ON(1); - return; } spin_lock_irq(&wl->irq_lock); @@ -728,20 +725,35 @@ void b43_dummy_transmission(struct b43_wldev *dev) for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); - /* Commit writes */ - b43_read32(dev, B43_MMIO_MACCTL); - b43_write16(dev, 0x0568, 0x0000); - b43_write16(dev, 0x07C0, 0x0000); - value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0); + if (dev->dev->id.revision < 11) + b43_write16(dev, 0x07C0, 0x0000); + else + b43_write16(dev, 0x07C0, 0x0100); + value = (ofdm ? 0x41 : 0x40); b43_write16(dev, 0x050C, value); + if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP)) + b43_write16(dev, 0x0514, 0x1A02); b43_write16(dev, 0x0508, 0x0000); b43_write16(dev, 0x050A, 0x0000); b43_write16(dev, 0x054C, 0x0000); b43_write16(dev, 0x056A, 0x0014); b43_write16(dev, 0x0568, 0x0826); b43_write16(dev, 0x0500, 0x0000); - b43_write16(dev, 0x0502, 0x0030); + if (!pa_on && (phy->type == B43_PHYTYPE_N)) { + //SPEC TODO + } + + switch (phy->type) { + case B43_PHYTYPE_N: + b43_write16(dev, 0x0502, 0x00D0); + break; + case B43_PHYTYPE_LP: + b43_write16(dev, 0x0502, 0x0050); + break; + default: + b43_write16(dev, 0x0502, 0x0030); + } if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0017); @@ -826,6 +838,85 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) (index * 2) + 1, addrtmp[1]); } +/* The ucode will use phase1 key with TEK key to decrypt rx packets. + * When a packet is received, the iv32 is checked. + * - if it doesn't the packet is returned without modification (and software + * decryption can be done). That's what happen when iv16 wrap. + * - if it does, the rc4 key is computed, and decryption is tried. + * Either it will success and B43_RX_MAC_DEC is returned, + * either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned + * and the packet is not usable (it got modified by the ucode). + * So in order to never have B43_RX_MAC_DECERR, we should provide + * a iv32 and phase1key that match. Because we drop packets in case of + * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all + * packets will be lost without higher layer knowing (ie no resync possible + * until next wrap). + * + * NOTE : this should support 50 key like RCMTA because + * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50 + */ +static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32, + u16 *phase1key) +{ + unsigned int i; + u32 offset; + u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; + + if (!modparam_hwtkip) + return; + + if (b43_new_kidx_api(dev)) + pairwise_keys_start = B43_NR_GROUP_KEYS; + + B43_WARN_ON(index < pairwise_keys_start); + /* We have four default TX keys and possibly four default RX keys. + * Physical mac 0 is mapped to physical key 4 or 8, depending + * on the firmware version. + * So we must adjust the index here. + */ + index -= pairwise_keys_start; + B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS); + + if (b43_debug(dev, B43_DBG_KEYS)) { + b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n", + index, iv32); + } + /* Write the key to the RX tkip shared mem */ + offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4); + for (i = 0; i < 10; i += 2) { + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, + phase1key ? phase1key[i / 2] : 0); + } + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32); + b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16); +} + +static void b43_op_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_key_conf *keyconf, const u8 *addr, + u32 iv32, u16 *phase1key) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + int index = keyconf->hw_key_idx; + + if (B43_WARN_ON(!modparam_hwtkip)) + return; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) + goto out_unlock; + + keymac_write(dev, index, NULL); /* First zero out mac to avoid race */ + + rx_tkip_phase1_write(dev, index, iv32, phase1key); + keymac_write(dev, index, addr); + +out_unlock: + mutex_unlock(&wl->mutex); +} + static void do_key_write(struct b43_wldev *dev, u8 index, u8 algorithm, const u8 *key, size_t key_len, const u8 *mac_addr) @@ -841,6 +932,19 @@ static void do_key_write(struct b43_wldev *dev, if (index >= pairwise_keys_start) keymac_write(dev, index, NULL); /* First zero out mac. */ + if (algorithm == B43_SEC_ALGO_TKIP) { + /* + * We should provide an initial iv32, phase1key pair. + * We could start with iv32=0 and compute the corresponding + * phase1key, but this means calling ieee80211_get_tkip_key + * with a fake skb (or export other tkip function). + * Because we are lazy we hope iv32 won't start with + * 0xffffffff and let's b43_op_update_tkip_key provide a + * correct pair. + */ + rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf); + } else if (index >= pairwise_keys_start) /* clear it */ + rx_tkip_phase1_write(dev, index, 0, NULL); if (key) memcpy(buf, key, key_len); key_write(dev, index, algorithm, buf); @@ -859,6 +963,15 @@ static int b43_key_write(struct b43_wldev *dev, int i; int pairwise_keys_start; + /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block: + * - Temporal Encryption Key (128 bits) + * - Temporal Authenticator Tx MIC Key (64 bits) + * - Temporal Authenticator Rx MIC Key (64 bits) + * + * Hardware only store TEK + */ + if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32) + key_len = 16; if (key_len > B43_SEC_KEYSIZE) return -EINVAL; for (i = 0; i < ARRAY_SIZE(dev->key); i++) { @@ -965,6 +1078,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev) printk(" Algo: %04X/%02X", algo, key->algorithm); if (index >= pairwise_keys_start) { + if (key->algorithm == B43_SEC_ALGO_TKIP) { + printk(" TKIP: "); + offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4); + for (i = 0; i < 14; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i); + printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF)); + } + } rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, ((index - pairwise_keys_start) * 2) + 0); rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, @@ -1947,8 +2068,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) filename = "ucode5"; else if ((rev >= 11) && (rev <= 12)) filename = "ucode11"; - else if (rev >= 13) + else if (rev == 13) filename = "ucode13"; + else if (rev == 14) + filename = "ucode14"; + else if (rev >= 15) + filename = "ucode15"; else goto err_no_ucode; err = b43_do_request_fw(ctx, filename, &fw->ucode); @@ -1996,6 +2121,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_initvals; break; + case B43_PHYTYPE_LP: + if (rev == 13) + filename = "lp0initvals13"; + else if (rev == 14) + filename = "lp0initvals14"; + else if (rev >= 15) + filename = "lp0initvals15"; + else + goto err_no_initvals; + break; default: goto err_no_initvals; } @@ -2030,6 +2165,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_initvals; break; + case B43_PHYTYPE_LP: + if (rev == 13) + filename = "lp0bsinitvals13"; + else if (rev == 14) + filename = "lp0bsinitvals14"; + else if (rev >= 15) + filename = "lp0bsinitvals15"; + else + goto err_no_initvals; + break; default: goto err_no_initvals; } @@ -2557,6 +2702,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev) case B43_PHYTYPE_A: case B43_PHYTYPE_G: case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); @@ -3587,8 +3733,10 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - if (algorithm == B43_SEC_ALGO_TKIP) { - /* FIXME: No TKIP hardware encryption for now. */ + if (algorithm == B43_SEC_ALGO_TKIP && + (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) || + !modparam_hwtkip)) { + /* We support only pairwise key */ err = -EOPNOTSUPP; goto out_unlock; } @@ -3618,6 +3766,8 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + if (algorithm == B43_SEC_ALGO_TKIP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; break; case DISABLE_KEY: { err = b43_key_clear(dev, key->hw_key_idx); @@ -3646,7 +3796,7 @@ out_unlock: static void b43_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *fflags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -3785,7 +3935,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) #endif #ifdef CONFIG_B43_PHY_LP case B43_PHYTYPE_LP: - if (phy_rev > 1) + if (phy_rev > 2) unsupported = 1; break; #endif @@ -3842,7 +3992,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) unsupported = 1; break; case B43_PHYTYPE_LP: - if (radio_ver != 0x2062) + if (radio_ver != 0x2062 && radio_ver != 0x2063) unsupported = 1; break; default: @@ -4345,6 +4495,7 @@ static const struct ieee80211_ops b43_hw_ops = { .bss_info_changed = b43_op_bss_info_changed, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, + .update_tkip_key = b43_op_update_tkip_key, .get_stats = b43_op_get_stats, .get_tx_stats = b43_op_get_tx_stats, .get_tsf = b43_op_get_tsf, @@ -4480,9 +4631,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) case B43_PHYTYPE_A: have_5ghz_phy = 1; break; + case B43_PHYTYPE_LP: //FIXME not always! +#if 0 //FIXME enabling 5GHz causes a NULL pointer dereference + have_5ghz_phy = 1; +#endif case B43_PHYTYPE_G: case B43_PHYTYPE_N: - case B43_PHYTYPE_LP: have_2ghz_phy = 1; break; default: @@ -4497,7 +4651,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } if (1 /* disable A-PHY */) { /* FIXME: For now we disable the A-PHY on multi-PHY devices. */ - if (dev->phy.type != B43_PHYTYPE_N) { + if (dev->phy.type != B43_PHYTYPE_N && + dev->phy.type != B43_PHYTYPE_LP) { have_2ghz_phy = 1; have_5ghz_phy = 0; } diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 950fb1b0546d..0406e06781d4 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -123,7 +123,7 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value u64 b43_hf_read(struct b43_wldev *dev); void b43_hf_write(struct b43_wldev *dev, u64 value); -void b43_dummy_transmission(struct b43_wldev *dev); +void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on); void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 5300232449f6..e47131216a67 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -333,7 +333,7 @@ static void b43_set_all_gains(struct b43_wldev *dev, b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp); b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp); } - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); } static void b43_set_original_gains(struct b43_wldev *dev) @@ -365,7 +365,7 @@ static void b43_set_original_gains(struct b43_wldev *dev) b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040); b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040); b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000); - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ @@ -1964,7 +1964,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) } b43_set_txpower_g(dev, &bbatt, &rfatt, 0); } - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); if (B43_DEBUG) { /* Current-Idle-TSSI sanity check. */ diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index cfb8337d3859..2d3a5d812c42 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -29,6 +29,25 @@ #include "tables_lpphy.h" +static inline u16 channel2freq_lp(u8 channel) +{ + if (channel < 14) + return (2407 + 5 * channel); + else if (channel == 14) + return 2484; + else if (channel < 184) + return (5000 + 5 * channel); + else + return (4000 + 5 * channel); +} + +static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 1; + return 36; +} + static int b43_lpphy_op_allocate(struct b43_wldev *dev) { struct b43_phy_lp *lpphy; @@ -142,10 +161,9 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) } } -static void lpphy_adjust_gain_table(struct b43_wldev *dev) +static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq) { struct b43_phy_lp *lpphy = dev->phy.lp; - u32 freq = dev->wl->hw->conf.channel->center_freq; u16 temp[3]; u16 isolation; @@ -170,6 +188,8 @@ static void lpphy_adjust_gain_table(struct b43_wldev *dev) static void lpphy_table_init(struct b43_wldev *dev) { + u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev)); + if (dev->phy.rev < 2) lpphy_rev0_1_table_init(dev); else @@ -178,14 +198,68 @@ static void lpphy_table_init(struct b43_wldev *dev) lpphy_init_tx_gain_table(dev); if (dev->phy.rev < 2) - lpphy_adjust_gain_table(dev); + lpphy_adjust_gain_table(dev, freq); } static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; + struct b43_phy_lp *lpphy = dev->phy.lp; u16 tmp, tmp2; + b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF); + b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0); + b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0); + b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800); + b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016); + b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400); + b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400); + b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100); + b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006); + b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC10, 0x0180); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3800); + b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005); + b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A); + b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3); + b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00); + b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB, + 0xFF00, lpphy->rx_pwr_offset); + if ((bus->sprom.boardflags_lo & B43_BFL_FEM) && + ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || + (bus->sprom.boardflags_hi & B43_BFH_PAREF))) { + /* TODO: + * Set the LDO voltage to 0x0028 - FIXME: What is this? + * Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage + * as arguments + * Call sb_pmu_paref_ldo_enable with argument TRUE + */ + if (dev->phy.rev == 0) { + b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, + 0xFFCF, 0x0010); + } + b43_lptab_write(dev, B43_LPTAB16(11, 7), 60); + } else { + //TODO: Call ssb_pmu_paref_ldo_enable with argument FALSE + b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, + 0xFFCF, 0x0020); + b43_lptab_write(dev, B43_LPTAB16(11, 7), 100); + } + tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000; + b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp); + if (bus->sprom.boardflags_hi & B43_BFH_RSSIINV) + b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA); + else + b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA); + b43_lptab_write(dev, B43_LPTAB16(11, 1), 24); + b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL, + 0xFFF9, (lpphy->bx_arch << 1)); if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) { b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A); @@ -235,7 +309,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700); } - if (dev->phy.rev == 1) { + if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_PAREF)) { b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3); @@ -247,6 +321,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); + //FIXME the Broadcom driver caches & delays this HF write! b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W); } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { @@ -364,7 +439,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9); b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF); b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500); - b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xF81F, 0xA0); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0); b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300); b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00); if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { @@ -385,7 +460,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12); b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000); - if ((bus->chip_id == 0x4325) && (bus->chip_rev == 1)) { + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); } @@ -396,6 +471,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6); b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00); b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1); + b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF); } else /* 5GHz */ b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40); @@ -435,8 +511,9 @@ struct b2062_freqdata { /* Initialize the 2062 radio. */ static void lpphy_2062_init(struct b43_wldev *dev) { + struct b43_phy_lp *lpphy = dev->phy.lp; struct ssb_bus *bus = dev->dev->bus; - u32 crystalfreq, pdiv, tmp, ref; + u32 crystalfreq, tmp, ref; unsigned int i; const struct b2062_freqdata *fd = NULL; @@ -460,10 +537,15 @@ static void lpphy_2062_init(struct b43_wldev *dev) b43_radio_write(dev, B2062_N_TX_CTL3, 0); b43_radio_write(dev, B2062_N_TX_CTL4, 0); b43_radio_write(dev, B2062_N_TX_CTL5, 0); + b43_radio_write(dev, B2062_N_TX_CTL6, 0); b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40); b43_radio_write(dev, B2062_N_PDN_CTL0, 0); b43_radio_write(dev, B2062_N_CALIB_TS, 0x10); b43_radio_write(dev, B2062_N_CALIB_TS, 0); + if (dev->phy.rev > 0) { + b43_radio_write(dev, B2062_S_BG_CTL1, + (b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80); + } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1); else @@ -475,23 +557,27 @@ static void lpphy_2062_init(struct b43_wldev *dev) B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)); B43_WARN_ON(crystalfreq == 0); - if (crystalfreq >= 30000000) { - pdiv = 1; + if (crystalfreq <= 30000000) { + lpphy->pdiv = 1; b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB); } else { - pdiv = 2; + lpphy->pdiv = 2; b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4); } - tmp = (800000000 * pdiv + crystalfreq) / (32000000 * pdiv); - tmp = (tmp - 1) & 0xFF; + tmp = (((800000000 * lpphy->pdiv + crystalfreq) / + (2 * crystalfreq)) - 8) & 0xFF; + b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp); + + tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) / + (32000000 * lpphy->pdiv)) - 1) & 0xFF; b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp); - tmp = (2 * crystalfreq + 1000000 * pdiv) / (2000000 * pdiv); - tmp = ((tmp & 0xFF) - 1) & 0xFFFF; + tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) / + (2000000 * lpphy->pdiv)) - 1) & 0xFF; b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp); - ref = (1000 * pdiv + 2 * crystalfreq) / (2000 * pdiv); + ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv); ref &= 0xFFFF; for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) { if (ref < freqdata_tab[i].freq) { @@ -523,9 +609,14 @@ static void lpphy_2063_init(struct b43_wldev *dev) b43_radio_write(dev, B2063_PA_SP7, 0); b43_radio_write(dev, B2063_TX_RF_SP6, 0x20); b43_radio_write(dev, B2063_TX_RF_SP9, 0x40); - b43_radio_write(dev, B2063_PA_SP3, 0xa0); - b43_radio_write(dev, B2063_PA_SP4, 0xa0); - b43_radio_write(dev, B2063_PA_SP2, 0x18); + if (dev->phy.rev == 2) { + b43_radio_write(dev, B2063_PA_SP3, 0xa0); + b43_radio_write(dev, B2063_PA_SP4, 0xa0); + b43_radio_write(dev, B2063_PA_SP2, 0x18); + } else { + b43_radio_write(dev, B2063_PA_SP3, 0x20); + b43_radio_write(dev, B2063_PA_SP2, 0x20); + } } struct lpphy_stx_table_entry { @@ -592,7 +683,7 @@ static void lpphy_radio_init(struct b43_wldev *dev) b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD); udelay(1); - if (dev->phy.rev < 2) { + if (dev->phy.radio_ver == 0x2062) { lpphy_2062_init(dev); } else { lpphy_2063_init(dev); @@ -609,11 +700,18 @@ struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; }; static void lpphy_set_rc_cap(struct b43_wldev *dev) { - u8 rc_cap = dev->phy.lp->rc_cap; + struct b43_phy_lp *lpphy = dev->phy.lp; + + u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1; + + if (dev->phy.rev == 1) //FIXME check channel 14! + rc_cap = max_t(u8, rc_cap + 5, 15); - b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, rc_cap-4, 0x80)); - b43_radio_write(dev, B2062_N_TX_CTL_A, ((rc_cap & 0x1F) >> 1) | 0x80); - b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80); + b43_radio_write(dev, B2062_N_RXBB_CALIB2, + max_t(u8, lpphy->rc_cap - 4, 0x80)); + b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80); + b43_radio_write(dev, B2062_S_RXG_CNT16, + ((lpphy->rc_cap & 0x1F) >> 2) | 0x80); } static u8 lpphy_get_bb_mult(struct b43_wldev *dev) @@ -626,9 +724,39 @@ static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult) b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8); } -static void lpphy_disable_crs(struct b43_wldev *dev) +static void lpphy_set_deaf(struct b43_wldev *dev, bool user) { + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (user) + lpphy->crs_usr_disable = 1; + else + lpphy->crs_sys_disable = 1; b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80); +} + +static void lpphy_clear_deaf(struct b43_wldev *dev, bool user) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (user) + lpphy->crs_usr_disable = 0; + else + lpphy->crs_sys_disable = 0; + + if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, + 0xFF1F, 0x60); + else + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, + 0xFF1F, 0x20); + } +} + +static void lpphy_disable_crs(struct b43_wldev *dev, bool user) +{ + lpphy_set_deaf(dev, user); b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB); @@ -656,12 +784,9 @@ static void lpphy_disable_crs(struct b43_wldev *dev) b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF); } -static void lpphy_restore_crs(struct b43_wldev *dev) +static void lpphy_restore_crs(struct b43_wldev *dev, bool user) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60); - else - b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20); + lpphy_clear_deaf(dev, user); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00); } @@ -707,10 +832,11 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev, b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xF800, rf_gain); } else { - pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F00; + pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x1FC0; + pa_gain <<= 2; b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, (gains.pga << 8) | gains.gm); - b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0x8000, gains.pad | pa_gain); b43_phy_write(dev, B43_PHY_OFDM(0xFC), (gains.pga << 8) | gains.gm); @@ -724,7 +850,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev, b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7); b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14); } - b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 4); + b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF, 1 << 6); } static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain) @@ -764,33 +890,33 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain) } } -static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) +static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF); if (dev->phy.rev >= 2) { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF); - if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) - return; - b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); - b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); + b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7); + } } else { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF); } } -static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) +static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); if (dev->phy.rev >= 2) { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100); - if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) - return; - b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); - b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x8); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); + b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8); + } } else { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200); } @@ -909,26 +1035,22 @@ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) { u32 quotient, remainder, rbit, roundup, tmp; - if (divisor == 0) { - quotient = 0; - remainder = 0; - } else { - quotient = dividend / divisor; - remainder = dividend % divisor; - } + if (divisor == 0) + return 0; + + quotient = dividend / divisor; + remainder = dividend % divisor; rbit = divisor & 0x1; roundup = (divisor >> 1) + rbit; - precision--; - while (precision != 0xFF) { + while (precision != 0) { tmp = remainder - roundup; quotient <<= 1; - remainder <<= 1; - if (remainder >= roundup) { + if (remainder >= roundup) remainder = (tmp << 1) + rbit; - quotient--; - } + else + remainder <<= 1; precision--; } @@ -992,9 +1114,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, struct b43_phy_lp *lpphy = dev->phy.lp; enum b43_lpphy_txpctl_mode oldmode; - oldmode = lpphy->txpctl_mode; lpphy_read_tx_pctl_mode_from_hardware(dev); - if (lpphy->txpctl_mode == mode) + oldmode = lpphy->txpctl_mode; + if (oldmode == mode) return; lpphy->txpctl_mode = mode; @@ -1022,28 +1144,37 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, lpphy_write_tx_pctl_mode_to_hardware(dev); } +static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel); + static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; struct lpphy_iq_est iq_est; struct lpphy_tx_gains tx_gains; - static const u32 ideal_pwr_table[22] = { + static const u32 ideal_pwr_table[21] = { 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64, 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35, 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088, - 0x0004c, 0x0002c, 0x0001a, 0xc0006, + 0x0004c, 0x0002c, 0x0001a, }; bool old_txg_ovr; u8 old_bbmult; u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval, - old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl; + old_rf2_ovr, old_rf2_ovrval, old_phy_ctl; + enum b43_lpphy_txpctl_mode old_txpctl; u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0; - int loopback, i, j, inner_sum; + int loopback, i, j, inner_sum, err; memset(&iq_est, 0, sizeof(iq_est)); - b43_switch_channel(dev, 7); - old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1; + err = b43_lpphy_op_switch_channel(dev, 7); + if (err) { + b43dbg(dev->wl, + "RC calib: Failed to switch to channel 7, error = %d", + err); + } + old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40); old_bbmult = lpphy_get_bb_mult(dev); if (old_txg_ovr) tx_gains = lpphy_get_tx_gains(dev); @@ -1054,11 +1185,11 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2); old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL); old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL); - old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) & - B43_LPPHY_TX_PWR_CTL_CMD_MODE; + lpphy_read_tx_pctl_mode_from_hardware(dev); + old_txpctl = lpphy->txpctl_mode; - lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); - lpphy_disable_crs(dev); + lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF); + lpphy_disable_crs(dev, true); loopback = lpphy_loopback(dev); if (loopback == -1) goto finish; @@ -1091,7 +1222,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) lpphy_stop_ddfs(dev); finish: - lpphy_restore_crs(dev); + lpphy_restore_crs(dev, true); b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval); b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr); b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval); @@ -1257,33 +1388,110 @@ static void lpphy_calibration(struct b43_wldev *dev) b43_mac_enable(dev); } -/* Initialize TX power control */ -static void lpphy_tx_pctl_init(struct b43_wldev *dev) +static void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode) { - if (0/*FIXME HWPCTL capable */) { - //TODO - } else { /* This device is only software TX power control capable. */ - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - //TODO + if (mode != TSSI_MUX_EXT) { + b43_radio_set(dev, B2063_PA_SP1, 0x2); + b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000); + b43_radio_write(dev, B2063_PA_CTL10, 0x51); + if (mode == TSSI_MUX_POSTPA) { + b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE); + b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7); } else { - //TODO + b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1); + b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL, + 0xFFC7, 0x20); } - //TODO set BB multiplier to 0x0096 + } else { + B43_WARN_ON(1); } } -static int b43_lpphy_op_init(struct b43_wldev *dev) +static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev) { - lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? - lpphy_baseband_init(dev); - lpphy_radio_init(dev); - lpphy_calibrate_rc(dev); - //TODO set channel - lpphy_tx_pctl_init(dev); - lpphy_calibration(dev); - //TODO ACI init + u16 tmp; + int i; - return 0; + //SPEC TODO Call LP PHY Clear TX Power offsets + for (i = 0; i < 64; i++) { + if (dev->phy.rev >= 2) + b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i); + else + b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i); + } + + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F); + if (dev->phy.rev < 2) { + b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF); + b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000); + } else { + b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE); + b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4); + b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10); + b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1); + lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA); + } + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000); + b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF); + b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD, + (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, + B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); + b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD, + (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, + B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW); + + if (dev->phy.rev < 2) { + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF); + } else { + lpphy_set_tx_power_by_index(dev, 0x7F); + } + + b43_dummy_transmission(dev, true, true); + + tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT); + if (tmp & 0x8000) { + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, + 0xFFC0, (tmp & 0xFF) - 32); + } + + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF); + + // (SPEC?) TODO Set "Target TX frequency" variable to 0 + // SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8! +} + +static void lpphy_tx_pctl_init_sw(struct b43_wldev *dev) +{ + struct lpphy_tx_gains gains; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + gains.gm = 4; + gains.pad = 12; + gains.pga = 12; + gains.dac = 0; + } else { + gains.gm = 7; + gains.pad = 14; + gains.pga = 15; + gains.dac = 0; + } + lpphy_set_tx_gains(dev, gains); + lpphy_set_bb_mult(dev, 150); +} + +/* Initialize TX power control */ +static void lpphy_tx_pctl_init(struct b43_wldev *dev) +{ + if (0/*FIXME HWPCTL capable */) { + lpphy_tx_pctl_init_hw(dev); + } else { /* This device is only software TX power control capable. */ + lpphy_tx_pctl_init_sw(dev); + } } static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) @@ -1328,18 +1536,668 @@ static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, //TODO } +struct b206x_channel { + u8 channel; + u16 freq; + u8 data[12]; +}; + +static const struct b206x_channel b2062_chantbl[] = { + { .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22, + .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77, + .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77, + .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66, + .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66, + .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55, + .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55, + .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44, + .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44, + .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44, + .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, +}; + +static const struct b206x_channel b2063_chantbl[] = { + { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05, + .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05, + .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04, + .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03, + .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03, + .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02, + .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, +}; + +static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF); + udelay(20); + if (bus->chip_id == 0x5354) { + b43_radio_write(dev, B2062_N_COMM1, 4); + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4); + } else { + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0); + } + udelay(5); +} + +static void lpphy_b2062_vco_calib(struct b43_wldev *dev) +{ + b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x42); + b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x62); + udelay(200); +} + +static int lpphy_b2062_tune(struct b43_wldev *dev, + unsigned int channel) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + struct ssb_bus *bus = dev->dev->bus; + const struct b206x_channel *chandata = NULL; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + int i, err = 0; + + for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) { + if (b2062_chantbl[i].channel == channel) { + chandata = &b2062_chantbl[i]; + break; + } + } + + if (B43_WARN_ON(!chandata)) + return -EINVAL; + + b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04); + b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]); + b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]); + b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]); + b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]); + b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]); + b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]); + b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]); + b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]); + b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]); + + tmp1 = crystal_freq / 1000; + tmp2 = lpphy->pdiv * 1000; + b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC); + b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07); + lpphy_b2062_reset_pll_bias(dev); + tmp3 = tmp2 * channel2freq_lp(channel); + if (channel2freq_lp(channel) < 4000) + tmp3 *= 2; + tmp4 = 48 * tmp1; + tmp6 = tmp3 / tmp4; + tmp7 = tmp3 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4)); + tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19); + tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1); + b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16); + b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF); + + lpphy_b2062_vco_calib(dev); + if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) { + b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC); + b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0); + lpphy_b2062_reset_pll_bias(dev); + lpphy_b2062_vco_calib(dev); + if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) + err = -EIO; + } + + b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04); + return err; +} + + +/* This was previously called lpphy_japan_filter */ +static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter! + + if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific? + b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9); + if ((dev->phy.rev == 1) && (lpphy->rc_cap)) + lpphy_set_rc_cap(dev); + } else { + b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F); + } +} + +static void lpphy_b2063_vco_calib(struct b43_wldev *dev) +{ + u16 tmp; + + b43_phy_mask(dev, B2063_PLL_SP1, ~0x40); + tmp = b43_phy_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8; + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7); + udelay(300); + b43_phy_set(dev, B2063_PLL_SP1, 0x40); +} + +static int lpphy_b2063_tune(struct b43_wldev *dev, + unsigned int channel) +{ + struct ssb_bus *bus = dev->dev->bus; + + static const struct b206x_channel *chandata = NULL; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count; + u16 old_comm15, scale; + u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + int i, div = (crystal_freq <= 26000000 ? 1 : 2); + + for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) { + if (b2063_chantbl[i].channel == channel) { + chandata = &b2063_chantbl[i]; + break; + } + } + + if (B43_WARN_ON(!chandata)) + return -EINVAL; + + b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]); + b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]); + b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]); + b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]); + b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]); + b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]); + b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]); + b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]); + b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]); + b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]); + b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]); + b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]); + + old_comm15 = b43_radio_read(dev, B2063_COMM15); + b43_radio_set(dev, B2063_COMM15, 0x1E); + + if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */ + vco_freq = chandata->freq << 1; + else + vco_freq = chandata->freq << 2; + + freqref = crystal_freq * 3; + val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16); + val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16); + val3 = lpphy_qdiv_roundup(vco_freq, 3, 16); + timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1; + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6, + 0xFFF8, timeout >> 2); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7, + 0xFF9F,timeout << 5); + + timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) + + 999999) / 1000000) + 1; + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref); + + count = lpphy_qdiv_roundup(val3, val2 + 16, 16); + count *= (timeout + 1) * (timeoutref + 1); + count--; + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7, + 0xF0, count >> 8); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF); + + tmp1 = ((val3 * 62500) / freqref) << 4; + tmp2 = ((val3 * 62500) % freqref) << 4; + while (tmp2 >= freqref) { + tmp1++; + tmp2 -= freqref; + } + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF); + + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63); + + tmp3 = ((41 * (val3 - 3000)) /1200) + 27; + tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16); + + if ((tmp4 + tmp3 - 1) / tmp3 > 60) { + scale = 1; + tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8; + } else { + scale = 0; + tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8; + } + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5); + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6); + + tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16); + tmp6 *= (tmp5 * 8) * (scale + 1); + if (tmp6 > 150) + tmp6 = 0; + + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6); + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5); + + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4); + if (crystal_freq > 26000000) + b43_phy_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2); + else + b43_phy_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD); + + if (val1 == 45) + b43_phy_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2); + else + b43_phy_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD); + + b43_phy_set(dev, B2063_PLL_SP2, 0x3); + udelay(1); + b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC); + lpphy_b2063_vco_calib(dev); + b43_radio_write(dev, B2063_COMM15, old_comm15); + + return 0; +} + static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { - //TODO + int err; + + b43_write16(dev, B43_MMIO_CHANNEL, new_channel); + + if (dev->phy.radio_ver == 0x2063) { + err = lpphy_b2063_tune(dev, new_channel); + if (err) + return err; + } else { + err = lpphy_b2062_tune(dev, new_channel); + if (err) + return err; + lpphy_set_analog_filter(dev, new_channel); + lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); + } + return 0; } -static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) +static int b43_lpphy_op_init(struct b43_wldev *dev) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - return 1; - return 36; + int err; + + lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? + lpphy_baseband_init(dev); + lpphy_radio_init(dev); + lpphy_calibrate_rc(dev); + err = b43_lpphy_op_switch_channel(dev, + b43_lpphy_op_get_default_chan(dev)); + if (err) { + b43dbg(dev->wl, "Switch to init channel failed, error = %d.\n", + err); + } + lpphy_tx_pctl_init(dev); + lpphy_calibration(dev); + //TODO ACI init + + return 0; } static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 0461d5b3144f..e158d1f66c0e 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -825,11 +825,11 @@ struct b43_phy_lp { enum b43_lpphy_txpctl_mode txpctl_mode; /* Transmit isolation medium band */ - u8 tx_isolation_med_band; /* FIXME initial value? */ + u8 tx_isolation_med_band; /* Transmit isolation low band */ - u8 tx_isolation_low_band; /* FIXME initial value? */ + u8 tx_isolation_low_band; /* Transmit isolation high band */ - u8 tx_isolation_hi_band; /* FIXME initial value? */ + u8 tx_isolation_hi_band; /* Max transmit power medium band */ u16 max_tx_pwr_med_band; @@ -848,7 +848,7 @@ struct b43_phy_lp { s16 txpa[3], txpal[3], txpah[3]; /* Receive power offset */ - u8 rx_pwr_offset; /* FIXME initial value? */ + u8 rx_pwr_offset; /* TSSI transmit count */ u16 tssi_tx_count; @@ -864,16 +864,16 @@ struct b43_phy_lp { s8 tx_pwr_idx_over; /* FIXME initial value? */ /* RSSI vf */ - u8 rssi_vf; /* FIXME initial value? */ + u8 rssi_vf; /* RSSI vc */ - u8 rssi_vc; /* FIXME initial value? */ + u8 rssi_vc; /* RSSI gs */ - u8 rssi_gs; /* FIXME initial value? */ + u8 rssi_gs; /* RC cap */ u8 rc_cap; /* FIXME initial value? */ /* BX arch */ - u8 bx_arch; /* FIXME initial value? */ + u8 bx_arch; /* Full calibration channel */ u8 full_calib_chan; /* FIXME initial value? */ @@ -884,8 +884,17 @@ struct b43_phy_lp { /* Used for "Save/Restore Dig Filt State" */ u16 dig_flt_state[9]; + + bool crs_usr_disable, crs_sys_disable; + + unsigned int pdiv; }; +enum tssi_mux_mode { + TSSI_MUX_PREPA, + TSSI_MUX_POSTPA, + TSSI_MUX_EXT, +}; struct b43_phy_operations; extern const struct b43_phy_operations b43_phyops_lp; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 73c047d8de40..3fd653c78b10 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -461,8 +461,8 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(q->dev); - err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, - skb->len, info, cookie); + err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb, + info, cookie); if (err) return err; diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 2721310acb2a..60d472f285af 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -2367,7 +2367,17 @@ static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, int offset, tmp = data.pad << 16; tmp |= data.pga << 8; tmp |= data.gm; - tmp |= 0x7f000000; + if (dev->phy.rev >= 3) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + tmp |= 0x10 << 24; + else + tmp |= 0x70 << 24; + } else { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + tmp |= 0x14 << 24; + else + tmp |= 0x7F << 24; + } b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + offset), tmp); tmp = data.bb_mult << 20; tmp |= data.dac << 28; diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index e1e20f69f6d7..97c79161c208 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -37,7 +37,7 @@ static void b43_wa_papd(struct b43_wldev *dev) backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0); b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7); b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0); - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, true, true); b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup); } @@ -628,7 +628,7 @@ void b43_wa_all(struct b43_wldev *dev) B43_WARN_ON(1); } b43_wa_boards_g(dev); - } else { /* No N PHY support so far */ + } else { /* No N PHY support so far, LP PHY is in phy_lp.c */ B43_WARN_ON(1); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 5280ebc8c6e9..e7075d2c7757 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -180,11 +180,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate) /* Generate a TX data header. */ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, + struct sk_buff *skb_frag, struct ieee80211_tx_info *info, u16 cookie) { + const unsigned char *fragment_data = skb_frag->data; + unsigned int fragment_len = skb_frag->len; struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = @@ -258,9 +259,26 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_hdrlen(fctl); - iv_len = min((size_t) info->control.hw_key->iv_len, - ARRAY_SIZE(txhdr->iv)); - memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + if (key->algorithm == B43_SEC_ALGO_TKIP) { + u16 phase1key[5]; + int i; + /* we give the phase1key and iv16 here, the key is stored in + * shm. With that the hardware can do phase 2 and encryption. + */ + ieee80211_get_tkip_key(info->control.hw_key, skb_frag, + IEEE80211_TKIP_P1_KEY, (u8*)phase1key); + /* phase1key is in host endian */ + for (i = 0; i < 5; i++) + phase1key[i] = cpu_to_le16(phase1key[i]); + + memcpy(txhdr->iv, phase1key, 10); + /* iv16 */ + memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); + } else { + iv_len = min((size_t) info->control.hw_key->iv_len, + ARRAY_SIZE(txhdr->iv)); + memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + } } if (b43_is_old_txhdr_format(dev)) { b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), @@ -655,6 +673,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) status.freq = chanid + 2400; break; case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: /* chanid is the SHM channel cookie. Which is the plain * channel number in b43. */ if (chanstat & B43_RX_CHAN_5GHZ) { diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 4fb2a190f7a7..3530de871873 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -176,8 +176,7 @@ size_t b43_txhdr_size(struct b43_wldev *dev) int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, + struct sk_buff *skb_frag, struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b1435594921a..b166a6f9f055 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2836,9 +2836,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *fflags, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *fflags,u64 multicast) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 742432388ca3..dee50ed0897d 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -185,7 +185,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); static int debug = 0; -static int mode = 0; +static int network_mode = 0; static int channel = 0; static int associate = 0; static int disable = 0; @@ -195,7 +195,7 @@ static struct ipw2100_fw ipw2100_firmware; #include <linux/moduleparam.h> module_param(debug, int, 0444); -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); module_param(channel, int, 0444); module_param(associate, int, 0444); module_param(disable, int, 0444); @@ -2844,7 +2844,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv) #ifdef CONFIG_IPW2100_DEBUG { - int i = txq->oldest; + i = txq->oldest; IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, &txq->drv[i], (u32) (txq->nic + i * sizeof(struct ipw2100_bd)), @@ -6076,7 +6076,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, priv->ieee->ieee802_1x = 1; /* Set module parameters */ - switch (mode) { + switch (network_mode) { case 1: priv->ieee->iw_mode = IW_MODE_ADHOC; break; @@ -8179,10 +8179,11 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) int rssi_qual; int tx_qual; int beacon_qual; + int quality; struct ipw2100_priv *priv = ieee80211_priv(dev); struct iw_statistics *wstats; - u32 rssi, quality, tx_retries, missed_beacons, tx_failures; + u32 rssi, tx_retries, missed_beacons, tx_failures; u32 ord_len = sizeof(u32); if (!priv) @@ -8265,7 +8266,8 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) beacon_qual = (20 - missed_beacons) * (PERFECT - VERY_GOOD) / 20 + VERY_GOOD; - quality = min(beacon_qual, min(tx_qual, rssi_qual)); + quality = min(tx_qual, rssi_qual); + quality = min(beacon_qual, quality); #ifdef CONFIG_IPW2100_DEBUG if (beacon_qual == quality) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 07f171c4d30e..8e18d5348350 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -83,13 +83,13 @@ MODULE_LICENSE("GPL"); static int cmdlog = 0; static int debug = 0; -static int channel = 0; -static int mode = 0; +static int default_channel = 0; +static int network_mode = 0; static u32 ipw_debug_level; static int associate; static int auto_create = 1; -static int led = 0; +static int led_support = 0; static int disable = 0; static int bt_coexist = 0; static int hwcrypto = 0; @@ -4265,9 +4265,10 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", signal_quality, rssi); - quality = min(beacon_quality, - min(rate_quality, - min(tx_quality, min(rx_quality, signal_quality)))); + quality = min(rx_quality, signal_quality); + quality = min(tx_quality, quality); + quality = min(rate_quality, quality); + quality = min(beacon_quality, quality); if (quality == beacon_quality) IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n", quality); @@ -4411,7 +4412,6 @@ static void ipw_rx_notification(struct ipw_priv *priv, { DECLARE_SSID_BUF(ssid); u16 size = le16_to_cpu(notif->size); - notif->size = le16_to_cpu(notif->size); IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size); @@ -6101,11 +6101,10 @@ static void ipw_debug_config(struct ipw_priv *priv) static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) { /* TODO: Verify that this works... */ - struct ipw_fixed_rate fr = { - .tx_rates = priv->rates_mask - }; + struct ipw_fixed_rate fr; u32 reg; u16 mask = 0; + u16 new_tx_rates = priv->rates_mask; /* Identify 'current FW band' and match it with the fixed * Tx rates */ @@ -6117,54 +6116,56 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; break; } - fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; + new_tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; break; default: /* 2.4Ghz or Mixed */ /* IEEE_B */ if (mode == IEEE_B) { - if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { + if (new_tx_rates & ~IEEE80211_CCK_RATES_MASK) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; } break; } /* IEEE_G */ - if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | + if (new_tx_rates & ~(IEEE80211_CCK_RATES_MASK | IEEE80211_OFDM_RATES_MASK)) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; break; } - if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_6MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; } - if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_9MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; } - if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_12MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; } - fr.tx_rates |= mask; + new_tx_rates |= mask; break; } + fr.tx_rates = cpu_to_le16(new_tx_rates); + reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE); ipw_write_reg32(priv, reg, *(u32 *) & fr); } @@ -7850,7 +7851,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, /* Convert signal to DBM */ ipw_rt->rt_dbmsignal = antsignal; - ipw_rt->rt_dbmnoise = frame->noise; + ipw_rt->rt_dbmnoise = (s8) le16_to_cpu(frame->noise); /* Convert the channel data and set the flags */ ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); @@ -7964,7 +7965,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, u16 channel = frame->received_channel; u8 phy_flags = frame->antennaAndPhy; s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM; - s8 noise = frame->noise; + s8 noise = (s8) le16_to_cpu(frame->noise); u8 rate = frame->rate; short len = le16_to_cpu(pkt->u.frame.length); struct sk_buff *skb; @@ -8335,7 +8336,7 @@ static void ipw_rx(struct ipw_priv *priv) .rssi = pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM, .signal = - le16_to_cpu(pkt->u.frame.rssi_dbm) - + pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM + 0x100, .noise = le16_to_cpu(pkt->u.frame.noise), @@ -8517,7 +8518,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) /* We default to disabling the LED code as right now it causes * too many systems to lock up... */ - if (!led) + if (!led_support) priv->config |= CFG_NO_LED; if (associate) @@ -8539,10 +8540,10 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) IPW_DEBUG_INFO("Radio disabled.\n"); } - if (channel != 0) { + if (default_channel != 0) { priv->config |= CFG_STATIC_CHANNEL; - priv->channel = channel; - IPW_DEBUG_INFO("Bind to static channel %d\n", channel); + priv->channel = default_channel; + IPW_DEBUG_INFO("Bind to static channel %d\n", default_channel); /* TODO: Validate that provided channel is in range */ } #ifdef CONFIG_IPW2200_QOS @@ -8550,7 +8551,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) burst_duration_CCK, burst_duration_OFDM); #endif /* CONFIG_IPW2200_QOS */ - switch (mode) { + switch (network_mode) { case 1: priv->ieee->iw_mode = IW_MODE_ADHOC; priv->net_dev->type = ARPHRD_ETHER; @@ -10181,7 +10182,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, #endif struct clx2_queue *q = &txq->q; u8 id, hdr_len, unicast; - u16 remaining_bytes; int fc; if (!(priv->status & STATUS_ASSOCIATED)) @@ -10220,7 +10220,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, tfd->u.data.cmd_id = DINO_CMD_TX; tfd->u.data.len = cpu_to_le16(txb->payload_size); - remaining_bytes = txb->payload_size; if (priv->assoc_request.ieee_mode == IPW_B_MODE) tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK; @@ -11946,13 +11945,13 @@ MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); -module_param(led, int, 0444); +module_param_named(led, led_support, int, 0444); MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)"); module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); -module_param(channel, int, 0444); +module_param_named(channel, default_channel, int, 0444); MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); #ifdef CONFIG_IPW2200_PROMISCUOUS @@ -11978,10 +11977,10 @@ MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value"); #endif /* CONFIG_IPW2200_QOS */ #ifdef CONFIG_IPW2200_MONITOR -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); #else -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 191718a0c545..a95caa014143 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -149,12 +149,15 @@ struct iwl_cfg iwl1000_bgn_cfg = { .ucode_api_min = IWL1000_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, .ops = &iwl1000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, + .ht_greenfield_support = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ba5ef832d770..e9a685d8e3a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -349,12 +349,13 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv, * *****************************************************************************/ -void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +void iwl3945_hw_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(struct iwl3945_notif_statistics), - le32_to_cpu(pkt->len)); + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); @@ -2889,7 +2890,8 @@ static struct iwl_cfg iwl3945_bg_cfg = { .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2902,7 +2904,8 @@ static struct iwl_cfg iwl3945_abg_cfg = { .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e427a8937ed8..6a13bfbc9d98 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2344,7 +2344,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 755c184b3ecb..1d539e3b8db1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -494,7 +494,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; - int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; + int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; int index; /* reduce the size of the length field itself */ @@ -1411,6 +1411,7 @@ static void iwl5150_temperature(struct iwl_priv *priv) vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; /* now vt hold the temperature in Kelvin */ priv->temperature = KELVIN_TO_CELSIUS(vt); + iwl_tt_handler(priv); } /* Calc max signal level (dBm) among 3 possible receivers */ @@ -1652,6 +1653,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1668,6 +1670,7 @@ struct iwl_cfg iwl5100_bg_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1684,6 +1687,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1700,6 +1704,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1716,6 +1721,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1732,6 +1738,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c3ec6c20cc94..383177db7de7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -161,7 +161,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -169,6 +169,9 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_HYBRID, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; /* @@ -181,7 +184,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -189,6 +192,9 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .valid_rx_ant = ANT_BC, .need_pll_cfg = false, .pa_type = IWL_PA_INTERNAL, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -198,7 +204,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -206,6 +212,9 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -215,7 +224,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -223,6 +232,9 @@ struct iwl_cfg iwl6000_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -232,7 +244,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -240,6 +252,9 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 21331552ff2c..fee110de5c6a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -332,6 +332,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, } else return MAX_TID_COUNT; + if (unlikely(tid >= TID_MAX_LOAD_COUNT)) + return MAX_TID_COUNT; + tl = &lq_data->load[tid]; curr_time -= curr_time % TID_ROUND_VALUE; @@ -654,19 +657,15 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, return 1; } -/* in 4965 we don't use greenfield at all */ -static inline u8 rs_use_green(struct iwl_priv *priv, - struct ieee80211_conf *conf) +/** + * Green-field mode is valid if the station supports it and + * there are no non-GF stations present in the BSS. + */ +static inline u8 rs_use_green(struct ieee80211_sta *sta, + struct iwl_ht_info *ht_conf) { - u8 is_green; - - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) - is_green = 0; - else - is_green = (conf_is_ht(conf) && - priv->current_ht_config.is_green_field && - !priv->current_ht_config.non_GF_STA_present); - return is_green; + return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && + !(ht_conf->non_GF_STA_present); } /** @@ -1222,18 +1221,6 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - rs_set_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); @@ -1288,18 +1275,6 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - rs_set_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); @@ -1347,18 +1322,6 @@ static int rs_switch_to_siso(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - if (is_green) tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ @@ -1527,6 +1490,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, 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 = tbl->action; @@ -1586,13 +1550,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, goto out; break; case IWL_SISO_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n"); @@ -1666,6 +1628,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, 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 = tbl->action; @@ -1726,13 +1689,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, break; case IWL_MIMO2_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n"); @@ -1808,6 +1769,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, 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 = tbl->action; @@ -1890,13 +1852,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, break; case IWL_MIMO3_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n"); @@ -2108,7 +2068,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (is_legacy(tbl->lq_type)) lq_sta->is_green = 0; else - lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config); is_green = lq_sta->is_green; /* current tx rate */ @@ -2466,7 +2426,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, int rate_idx; int i; u32 rate; - u8 use_green = rs_use_green(priv, conf); + u8 use_green = rs_use_green(sta, &priv->current_ht_config); u8 active_tbl = 0; u8 valid_tx_ant; @@ -2519,6 +2479,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = priv_sta; @@ -2551,7 +2512,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); sta_id = iwl_add_station(priv, hdr->addr1, - false, CMD_ASYNC, NULL); + false, CMD_ASYNC, ht_cap); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2620,6 +2581,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, int i, j; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct iwl_lq_sta *lq_sta = priv_sta; u16 mask_bit = 0; int count; @@ -2648,7 +2610,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); sta_id = iwl_add_station(priv, sta->addr, false, - CMD_ASYNC, NULL); + CMD_ASYNC, ht_cap); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2661,7 +2623,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->is_dup = 0; lq_sta->max_rate_idx = -1; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; - lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config); lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); lq_sta->active_rate_basic = priv->active_rate_basic; lq_sta->band = priv->band; @@ -2669,19 +2631,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1; - lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1; + lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1; - lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1; + lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1; - lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1; + 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; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 68d7719071f7..f4303843ff9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1156,6 +1156,7 @@ struct iwl_wep_cmd { #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) #define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_ANTENNA_POS 4 #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) @@ -3481,7 +3482,7 @@ struct iwl_wimax_coex_cmd { *****************************************************************************/ struct iwl_rx_packet { - __le32 len; + __le32 len_n_flags; struct iwl_cmd_header hdr; union { struct iwl3945_rx_frame rx_frame; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index af735128333a..f1f6dabd8fbd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -394,7 +394,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->ht_supported = true; - ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + if (priv->cfg->ht_greenfield_support) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & (WLAN_HT_CAP_SM_PS_DISABLED << 2)); @@ -1513,7 +1514,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error); void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 *filter_flags = &priv->staging_rxon.filter_flags; @@ -1579,6 +1580,12 @@ int iwl_setup_mac(struct iwl_priv *priv) /* Firmware does not support this */ hw->wiphy->disable_beacon_hints = true; + /* + * For now, disable PS by default because it affects + * RX performance significantly. + */ + hw->wiphy->ps_default = false; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; @@ -2293,10 +2300,11 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " - "notification for %s:\n", - le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + "notification for %s:\n", len, + get_cmd_string(pkt->hdr.cmd)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); @@ -2391,39 +2399,10 @@ static void iwl_ht_conf(struct iwl_priv *priv, } ht_conf = &sta->ht_cap; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= HT_SHORT_GI_20MHZ; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= HT_SHORT_GI_40MHZ; - - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); - - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); - - /* - * XXX: The HT configuration needs to be moved into iwl_mac_config() - * to be done there correctly. - */ - - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - if (conf_is_ht40_minus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; - else if (conf_is_ht40_plus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - - /* If no above or below channel supplied disable HT40 channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) - iwl_conf->supported_chan_width = 0; - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = @@ -2736,6 +2715,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; struct ieee80211_conf *conf = &hw->conf; + struct iwl_ht_info *ht_conf = &priv->current_ht_config; unsigned long flags = 0; int ret = 0; u16 ch; @@ -2777,10 +2757,32 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } - priv->current_ht_config.is_ht = conf_is_ht(conf); - spin_lock_irqsave(&priv->lock, flags); + /* Configure HT40 channels */ + ht_conf->is_ht = conf_is_ht(conf); + if (ht_conf->is_ht) { + if (conf_is_ht40_minus(conf)) { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_40MHZ; + } else if (conf_is_ht40_plus(conf)) { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_40MHZ; + } else { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_20MHZ; + } + } else + ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ; + /* Default to no protection. Protection mode will later be set + * from BSS config in iwl_ht_conf */ + ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 32750f4f1ce1..62d90364b61d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -209,6 +209,8 @@ struct iwl_mod_params { * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @pa_type: used by 6000 series only to identify the type of Power Amplifier + * @max_ll_items: max number of OTP blocks + * @shadow_ram_support: shadow support for OTP memory * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -247,6 +249,9 @@ struct iwl_cfg { bool need_pll_cfg; bool use_isr_legacy; enum iwl_pa_type pa_type; + const u16 max_ll_items; + const bool shadow_ram_support; + const bool ht_greenfield_support; }; /*************************** @@ -277,8 +282,7 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, void iwl_irq_handle_error(struct iwl_priv *priv); void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + unsigned int *total_flags, u64 multicast); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b96c3c9e92a9..0178734499f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -507,15 +507,9 @@ struct iwl_ht_info { u8 is_ht; u8 supported_chan_width; u8 sm_ps; - u8 is_green_field; - u8 sgf; /* HT_SHORT_GI_* short guard interval */ - u8 max_amsdu_size; - u8 ampdu_factor; - u8 mpdu_density; struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; - u8 tx_chan_width; u8 ht_protection; u8 non_GF_STA_present; }; @@ -732,9 +726,6 @@ struct iwl_dma_ptr { size_t size; }; -#define HT_SHORT_GI_20MHZ (1 << 0) -#define HT_SHORT_GI_40MHZ (1 << 1) - #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 @@ -888,6 +879,17 @@ enum iwl_nvm_type { NVM_DEVICE_TYPE_OTP, }; +/* + * Two types of OTP memory access modes + * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode, + * based on physical memory addressing + * IWL_OTP_ACCESS_RELATIVE - relative address mode, + * based on logical memory addressing + */ +enum iwl_access_mode { + IWL_OTP_ACCESS_ABSOLUTE, + IWL_OTP_ACCESS_RELATIVE, +}; /** * enum iwl_pa_type - Power Amplifier type diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 78c4a324a3b5..01b95e89009a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); +static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) +{ + u32 otpgp; + + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (mode == IWL_OTP_ACCESS_ABSOLUTE) + iwl_clear_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); + else + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); +} + static int iwlcore_get_nvm_type(struct iwl_priv *priv) { u32 otpgp; @@ -252,6 +265,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv) return ret; } +static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) +{ + int ret = 0; + u32 r; + u32 otpgp; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + return ret; + } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + /* check for ECC errors: */ + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { + /* stop in this case */ + /* set the uncorrectable OTP ECC bit for acknowledgement */ + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); + IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n"); + return -EINVAL; + } + if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { + /* continue in this case */ + /* set the correctable OTP ECC bit for acknowledgement */ + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); + IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); + } + *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); + return 0; +} + +/* + * iwl_is_otp_empty: check for empty OTP + */ +static bool iwl_is_otp_empty(struct iwl_priv *priv) +{ + u16 next_link_addr = 0, link_value; + bool is_empty = false; + + /* locate the beginning of OTP link list */ + if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) { + if (!link_value) { + IWL_ERR(priv, "OTP is empty\n"); + is_empty = true; + } + } else { + IWL_ERR(priv, "Unable to read first block of OTP list.\n"); + is_empty = true; + } + + return is_empty; +} + + +/* + * iwl_find_otp_image: find EEPROM image in OTP + * finding the OTP block that contains the EEPROM image. + * the last valid block on the link list (the block _before_ the last block) + * is the block we should read and used to configure the device. + * If all the available OTP blocks are full, the last block will be the block + * we should read and used to configure the device. + * only perform this operation if shadow RAM is disabled + */ +static int iwl_find_otp_image(struct iwl_priv *priv, + u16 *validblockaddr) +{ + u16 next_link_addr = 0, link_value = 0, valid_addr; + int ret = 0; + int usedblocks = 0; + + /* set addressing mode to absolute to traverse the link list */ + iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE); + + /* checking for empty OTP or error */ + if (iwl_is_otp_empty(priv)) + return -EINVAL; + + /* + * start traverse link list + * until reach the max number of OTP blocks + * different devices have different number of OTP blocks + */ + do { + /* save current valid block address + * check for more block on the link list + */ + valid_addr = next_link_addr; + next_link_addr = link_value; + IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", + usedblocks, next_link_addr); + if (iwl_read_otp_word(priv, next_link_addr, &link_value)) + return -EINVAL; + if (!link_value) { + /* + * reach the end of link list, + * set address point to the starting address + * of the image + */ + goto done; + } + /* more in the link list, continue */ + usedblocks++; + } while (usedblocks < priv->cfg->max_ll_items); + /* OTP full, use last block */ + IWL_DEBUG_INFO(priv, "OTP is full, use last block\n"); +done: + *validblockaddr = valid_addr; + /* skip first 2 bytes (link list pointer) */ + *validblockaddr += 2; + return ret; +} + /** * iwl_eeprom_init - read EEPROM contents * @@ -266,15 +397,14 @@ int iwl_eeprom_init(struct iwl_priv *priv) int sz; int ret; u16 addr; - u32 otpgp; + u16 validblockaddr = 0; + u16 cache_addr = 0; priv->nvm_device_type = iwlcore_get_nvm_type(priv); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) - priv->cfg->eeprom_size = - OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; + IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size); sz = priv->cfg->eeprom_size; priv->eeprom = kzalloc(sz, GFP_KERNEL); if (!priv->eeprom) { @@ -302,46 +432,31 @@ int iwl_eeprom_init(struct iwl_priv *priv) if (ret) { IWL_ERR(priv, "Failed to initialize OTP access.\n"); ret = -ENOENT; - goto err; + goto done; } _iwl_write32(priv, CSR_EEPROM_GP, iwl_read32(priv, CSR_EEPROM_GP) & ~CSR_EEPROM_GP_IF_OWNER_MSK); - /* clear */ - _iwl_write32(priv, CSR_OTP_GP_REG, - iwl_read32(priv, CSR_OTP_GP_REG) | + + iwl_set_bit(priv, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); - - for (addr = 0; addr < sz; addr += sizeof(u16)) { - u32 r; - - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { - IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + /* traversing the linked list if no shadow ram supported */ + if (!priv->cfg->shadow_ram_support) { + if (iwl_find_otp_image(priv, &validblockaddr)) { + ret = -ENOENT; goto done; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - /* check for ECC errors: */ - otpgp = iwl_read32(priv, CSR_OTP_GP_REG); - if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { - /* stop in this case */ - IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); + } + for (addr = validblockaddr; addr < validblockaddr + sz; + addr += sizeof(u16)) { + u16 eeprom_data; + + ret = iwl_read_otp_word(priv, addr, &eeprom_data); + if (ret) goto done; - } - if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { - /* continue in this case */ - _iwl_write32(priv, CSR_OTP_GP_REG, - iwl_read32(priv, CSR_OTP_GP_REG) | - CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); - IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); - } - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); + e[cache_addr / 2] = eeprom_data; + cache_addr += sizeof(u16); } } else { /* eeprom is an array of 16bit values */ @@ -484,14 +599,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl_set_ht40_chan_info - Copy ht40 channel info into driver's priv. + * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl_set_ht40_chan_info(struct iwl_priv *priv, +static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, const struct iwl_eeprom_channel *eeprom_ch, - u8 ht40_extension_channel) + u8 clear_ht40_extension_channel) { struct iwl_channel_info *ch_info; @@ -523,7 +638,7 @@ static int iwl_set_ht40_chan_info(struct iwl_priv *priv, ch_info->ht40_min_power = 0; ch_info->ht40_scan_power = eeprom_ch->max_power_avg; ch_info->ht40_flags = eeprom_ch->flags; - ch_info->ht40_extension_channel = ht40_extension_channel; + ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; return 0; } @@ -592,8 +707,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* First write that ht40 is not enabled, and then enable * one by one */ ch_info->ht40_extension_channel = - (IEEE80211_CHAN_NO_HT40PLUS | - IEEE80211_CHAN_NO_HT40MINUS); + IEEE80211_CHAN_NO_HT40; if (!(is_channel_valid(ch_info))) { IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " @@ -652,7 +766,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ for (band = 6; band <= 7; band++) { enum ieee80211_band ieeeband; - u8 ht40_extension_chan; iwl_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); @@ -663,28 +776,17 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { - - if ((band == 6) && - ((eeprom_ch_index[ch] == 5) || - (eeprom_ch_index[ch] == 6) || - (eeprom_ch_index[ch] == 7))) - /* both are allowed: above and below */ - ht40_extension_chan = 0; - else - ht40_extension_chan = - IEEE80211_CHAN_NO_HT40MINUS; - /* Set up driver's info for lower half */ - iwl_set_ht40_chan_info(priv, ieeeband, + iwl_mod_ht40_chan_info(priv, ieeeband, eeprom_ch_index[ch], - &(eeprom_ch_info[ch]), - ht40_extension_chan); + &eeprom_ch_info[ch], + IEEE80211_CHAN_NO_HT40PLUS); /* Set up driver's info for upper half */ - iwl_set_ht40_chan_info(priv, ieeeband, - (eeprom_ch_index[ch] + 4), - &(eeprom_ch_info[ch]), - IEEE80211_CHAN_NO_HT40PLUS); + iwl_mod_ht40_chan_info(priv, ieeeband, + eeprom_ch_index[ch] + 4, + &eeprom_ch_info[ch], + IEEE80211_CHAN_NO_HT40MINUS); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 05d4fc4451dc..ca7920a8f52f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -180,8 +180,14 @@ struct iwl_eeprom_channel { #define EEPROM_5050_EEPROM_VERSION (0x21E) /* OTP */ -#define OTP_LOWER_BLOCKS_TOTAL (3) -#define OTP_BLOCK_SIZE (0x400) +/* lower blocks contain EEPROM image and calibration data */ +#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ +/* high blocks contain PAPD data */ +#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */ +#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */ +#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ +#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ +#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 43b2fce4cbf0..353d9a2ddbca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -539,7 +539,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", - (int)sizeof(priv->statistics), pkt->len); + (int)sizeof(priv->statistics), + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); change = ((priv->statistics.general.temperature != pkt->u.stats.general.temperature) || @@ -853,61 +854,12 @@ static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) } static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, - int include_phy, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) + struct ieee80211_hdr *hdr, + u16 len, + u32 ampdu_status, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl_rx_phy_res *rx_start = (include_phy) ? - (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL; - struct ieee80211_hdr *hdr; - u16 len; - __le32 *rx_end; - unsigned int skblen; - u32 ampdu_status; - u32 ampdu_status_legacy; - - if (!include_phy && priv->last_phy_res[0]) - rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; - - if (!rx_start) { - IWL_ERR(priv, "MPDU frame without a PHY data\n"); - return; - } - if (include_phy) { - hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + - rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - - rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] + - sizeof(struct iwl_rx_phy_res) + - rx_start->cfg_phy_cnt + len); - - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - hdr = (struct ieee80211_hdr *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_start->byte_count = amsdu->byte_count; - rx_end = (__le32 *) (((u8 *) hdr) + len); - } - - ampdu_status = le32_to_cpu(*rx_end); - skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); - - if (!include_phy) { - /* New status scheme, need to translate */ - ampdu_status_legacy = ampdu_status; - ampdu_status = iwl_translate_rx_status(priv, ampdu_status); - } - - /* start from MAC */ - skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); - skb_put(rxb->skb, len); /* end where data ends */ - /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, @@ -915,13 +867,15 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, return; } - hdr = (struct ieee80211_hdr *)rxb->skb->data; - - /* in case of HW accelerated crypto and bad decryption, drop */ + /* In case of HW accelerated crypto and bad decryption, drop */ if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; + /* Resize SKB from mac header to end of packet */ + skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); + skb_put(rxb->skb, len); + iwl_update_stats(priv, false, hdr->frame_control, len); memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); @@ -955,25 +909,66 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - /* Use phy data (Rx signal strength, etc.) contained within - * this rx packet for legacy frames, - * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ - int include_phy = (pkt->hdr.cmd == REPLY_RX); - struct iwl_rx_phy_res *rx_start = (include_phy) ? - (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : - (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; - __le32 *rx_end; - unsigned int len = 0; + struct iwl_rx_phy_res *phy_res; + __le32 rx_pkt_status; + struct iwl4965_rx_mpdu_res_start *amsdu; + u32 len; + u32 ampdu_status; u16 fc; - u8 network_packet; - rx_status.mactime = le64_to_cpu(rx_start->timestamp); + /** + * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. + * REPLY_RX: physical layer info is in this buffer + * REPLY_RX_MPDU_CMD: physical layer info was sent in separate + * command and cached in priv->last_phy_res + * + * Here we set up local variables depending on which command is + * received. + */ + if (pkt->hdr.cmd == REPLY_RX) { + phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt); + + len = le16_to_cpu(phy_res->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt + len); + ampdu_status = le32_to_cpu(rx_pkt_status); + } else { + if (!priv->last_phy_res[0]) { + IWL_ERR(priv, "MPDU frame without cached PHY data\n"); + return; + } + phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; + amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); + len = le16_to_cpu(amsdu->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); + ampdu_status = iwl_translate_rx_status(priv, + le32_to_cpu(rx_pkt_status)); + } + + if ((unlikely(phy_res->cfg_phy_cnt > 20))) { + IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", + phy_res->cfg_phy_cnt); + return; + } + + if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || + !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", + le32_to_cpu(rx_pkt_status)); + return; + } + + /* rx_status carries information about the packet to mac80211 */ + rx_status.mactime = le64_to_cpu(phy_res->timestamp); rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); - rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); + rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; rx_status.rate_idx = - iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); + iwl_hwrate_to_plcp_idx(le32_to_cpu(phy_res->rate_n_flags)); if (rx_status.band == IEEE80211_BAND_5GHZ) rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; @@ -983,54 +978,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * this W/A doesn't propagate it to the mac80211 */ /*rx_status.flag |= RX_FLAG_TSFT;*/ - if ((unlikely(rx_start->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", - rx_start->cfg_phy_cnt); - return; - } - - if (!include_phy) { - if (priv->last_phy_res[0]) - rx_start = (struct iwl_rx_phy_res *) - &priv->last_phy_res[1]; - else - rx_start = NULL; - } - - if (!rx_start) { - IWL_ERR(priv, "MPDU frame without a PHY data\n"); - return; - } - - if (include_phy) { - header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] - + rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + - sizeof(struct iwl_rx_phy_res) + len); - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - header = (void *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_end = (__le32 *) (pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start) + len); - } - - if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || - !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { - IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", - le32_to_cpu(*rx_end)); - return; - } - - priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); + priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.signal = iwl_calc_rssi(priv, rx_start); + rx_status.signal = iwl_calc_rssi(priv, phy_res); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise @@ -1050,10 +1001,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (!iwl_is_associated(priv)) priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - /* Set "1" to report good data frames in groups of 100 */ #ifdef CONFIG_IWLWIFI_DEBUG + /* Set "1" to report good data frames in groups of 100 */ if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) - iwl_dbg_report_frame(priv, rx_start, len, header, 1); + iwl_dbg_report_frame(priv, phy_res, len, header, 1); #endif iwl_dbg_log_rx_data_frame(priv, len, header); IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", @@ -1073,18 +1024,18 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ - rx_status.antenna = le16_to_cpu(rx_start->phy_flags & - RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + rx_status.antenna = + le16_to_cpu(phy_res->phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK) + >> RX_RES_PHY_FLAGS_ANTENNA_POS; /* set the preamble flag if appropriate */ - if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) rx_status.flag |= RX_FLAG_SHORTPRE; - network_packet = iwl_is_network_packet(priv, header); - if (network_packet) { + if (iwl_is_network_packet(priv, header)) { priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; - priv->last_tsf = le64_to_cpu(rx_start->timestamp); + priv->last_tsf = le64_to_cpu(phy_res->timestamp); } fc = le16_to_cpu(header->frame_control); @@ -1096,8 +1047,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, header->addr2); /* fall through */ default: - iwl_pass_packet_to_mac80211(priv, include_phy, rxb, - &rx_status); + iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, + rxb, &rx_status); break; } diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9b76bd41f214..7686fc72eb89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -745,6 +745,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (unlikely(tid >= MAX_TID_COUNT)) + goto drop_unlock; seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & @@ -1238,6 +1240,9 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) return -EINVAL; } + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo_id = default_tid_to_tx_fifo[tid]; else diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e617411d0c5e..f339c5bd1fde 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -544,6 +544,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (unlikely(tid >= MAX_TID_COUNT)) + goto drop; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 385b50f4b105..81f86ef26990 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -45,9 +45,14 @@ static int get_common_rates(struct lbs_private *priv, u8 *card_rates = lbs_bg_rates; size_t num_card_rates = sizeof(lbs_bg_rates); int ret = 0, i, j; - u8 tmp[30]; + u8 *tmp; size_t tmp_size = 0; + tmp = kzalloc((ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1), + GFP_KERNEL); + if (!tmp) + return -1; + /* For each rate in card_rates that exists in rate1, copy to tmp */ for (i = 0; card_rates[i] && (i < num_card_rates); i++) { for (j = 0; rates[j] && (j < *rates_size); j++) { @@ -77,6 +82,7 @@ done: memset(rates, 0, *rates_size); *rates_size = min_t(int, tmp_size, *rates_size); memcpy(rates, tmp, *rates_size); + kfree(tmp); return ret; } diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 4872345a2f61..019431d2f8a9 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -366,15 +366,35 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) return 0; } +static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct lbtf_private *priv = hw->priv; + int i; + + if (!mc_count || mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) + return mc_count; + + priv->nr_of_multicastmacaddr = mc_count; + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + memcpy(&priv->multicastlist[i], mclist->da_addr, + ETH_ALEN); + mclist = mclist->next; + } + + return mc_count; +} + #define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI) static void lbtf_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct lbtf_private *priv = hw->priv; int old_mac_control = priv->mac_control; - int i; changed_flags &= SUPPORTED_FIF_FLAGS; *new_flags &= SUPPORTED_FIF_FLAGS; @@ -386,20 +406,12 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw, else priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; if (*new_flags & (FIF_ALLMULTI) || - mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { + multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) { priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else if (mc_count) { + } else if (multicast) { priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - priv->nr_of_multicastmacaddr = mc_count; - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - memcpy(&priv->multicastlist[i], mclist->da_addr, - ETH_ALEN); - mclist = mclist->next; - } lbtf_cmd_set_mac_multicast_addr(priv); } else { priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE | @@ -461,6 +473,7 @@ static const struct ieee80211_ops lbtf_ops = { .add_interface = lbtf_op_add_interface, .remove_interface = lbtf_op_remove_interface, .config = lbtf_op_config, + .prepare_multicast = lbtf_op_prepare_multicast, .configure_filter = lbtf_op_configure_filter, .bss_info_changed = lbtf_op_bss_info_changed, }; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 930f5c7da4a6..6f6cd43592c8 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -582,9 +582,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total_flags,u64 multicast) { struct mac80211_hwsim_data *data = hw->priv; diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8a6d3afe4122..41a708ce8730 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1,7 +1,8 @@ /* - * drivers/net/wireless/mwl8k.c driver for Marvell TOPDOG 802.11 Wireless cards + * drivers/net/wireless/mwl8k.c + * Driver for Marvell TOPDOG 802.11 Wireless cards * - * Copyright (C) 2008 Marvell Semiconductor Inc. + * Copyright (C) 2008-2009 Marvell Semiconductor Inc. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -24,7 +25,7 @@ #define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" #define MWL8K_NAME KBUILD_MODNAME -#define MWL8K_VERSION "0.9.1" +#define MWL8K_VERSION "0.10" MODULE_DESCRIPTION(MWL8K_DESC); MODULE_VERSION(MWL8K_VERSION); @@ -38,16 +39,14 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = { }; MODULE_DEVICE_TABLE(pci, mwl8k_table); -#define IEEE80211_ADDR_LEN ETH_ALEN - /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 -#define MWL8K_MODE_STA 0x0000005a -#define MWL8K_MODE_AP 0x000000a5 +#define MWL8K_MODE_STA 0x0000005a +#define MWL8K_MODE_AP 0x000000a5 #define MWL8K_HIU_INT_CODE 0x00000c14 -#define MWL8K_FWSTA_READY 0xf0f1f2f4 -#define MWL8K_FWAP_READY 0xf1f2f4a5 -#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005 +#define MWL8K_FWSTA_READY 0xf0f1f2f4 +#define MWL8K_FWAP_READY 0xf1f2f4a5 +#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005 #define MWL8K_HIU_SCRATCH 0x00000c40 /* Host->device communications */ @@ -56,11 +55,10 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_HIU_H2A_INTERRUPT_MASK 0x00000c20 #define MWL8K_HIU_H2A_INTERRUPT_CLEAR_SEL 0x00000c24 #define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28 -#define MWL8K_H2A_INT_DUMMY (1 << 20) -#define MWL8K_H2A_INT_RESET (1 << 15) -#define MWL8K_H2A_INT_PS (1 << 2) -#define MWL8K_H2A_INT_DOORBELL (1 << 1) -#define MWL8K_H2A_INT_PPA_READY (1 << 0) +#define MWL8K_H2A_INT_DUMMY (1 << 20) +#define MWL8K_H2A_INT_RESET (1 << 15) +#define MWL8K_H2A_INT_DOORBELL (1 << 1) +#define MWL8K_H2A_INT_PPA_READY (1 << 0) /* Device->host communications */ #define MWL8K_HIU_A2H_INTERRUPT_EVENTS 0x00000c2c @@ -68,16 +66,16 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_HIU_A2H_INTERRUPT_MASK 0x00000c34 #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c -#define MWL8K_A2H_INT_DUMMY (1 << 20) -#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) -#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) -#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) -#define MWL8K_A2H_INT_RADIO_ON (1 << 6) -#define MWL8K_A2H_INT_RADIO_OFF (1 << 5) -#define MWL8K_A2H_INT_MAC_EVENT (1 << 3) -#define MWL8K_A2H_INT_OPC_DONE (1 << 2) -#define MWL8K_A2H_INT_RX_READY (1 << 1) -#define MWL8K_A2H_INT_TX_DONE (1 << 0) +#define MWL8K_A2H_INT_DUMMY (1 << 20) +#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) +#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) +#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) +#define MWL8K_A2H_INT_RADIO_ON (1 << 6) +#define MWL8K_A2H_INT_RADIO_OFF (1 << 5) +#define MWL8K_A2H_INT_MAC_EVENT (1 << 3) +#define MWL8K_A2H_INT_OPC_DONE (1 << 2) +#define MWL8K_A2H_INT_RX_READY (1 << 1) +#define MWL8K_A2H_INT_TX_DONE (1 << 0) #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ MWL8K_A2H_INT_CHNL_SWITCHED | \ @@ -113,17 +111,6 @@ struct mwl8k_rx_queue { struct sk_buff **rx_skb; }; -struct mwl8k_skb { - /* - * The DMA engine requires a modification to the payload. - * If the skbuff is shared/cloned, it needs to be unshared. - * This method is used to ensure the stack always gets back - * the skbuff it sent for transmission. - */ - struct sk_buff *clone; - struct sk_buff *skb; -}; - struct mwl8k_tx_queue { /* hw transmits here */ int tx_head; @@ -134,7 +121,7 @@ struct mwl8k_tx_queue { struct ieee80211_tx_queue_stats tx_stats; struct mwl8k_tx_desc *tx_desc_area; dma_addr_t tx_desc_dma; - struct mwl8k_skb *tx_skb; + struct sk_buff **tx_skb; }; /* Pointers to the firmware data and meta information about it. */ @@ -152,19 +139,22 @@ struct mwl8k_priv { struct pci_dev *pdev; u8 name[16]; - /* firmware access lock */ - spinlock_t fw_lock; /* firmware files and meta data */ struct mwl8k_firmware fw; u32 part_num; + /* firmware access */ + struct mutex fw_mutex; + struct task_struct *fw_mutex_owner; + int fw_mutex_depth; + struct completion *tx_wait; + struct completion *hostcmd_wait; + /* lock held over TX and TX reap */ spinlock_t tx_lock; - u32 int_mask; struct ieee80211_vif *vif; - struct list_head vif_list; struct ieee80211_channel *current_channel; @@ -173,10 +163,8 @@ struct mwl8k_priv { dma_addr_t cookie_dma; u16 num_mcaddrs; - u16 region_code; u8 hw_rev; __le32 fw_rev; - u32 wep_enabled; /* * Running count of TX packets in flight, to avoid @@ -192,19 +180,13 @@ struct mwl8k_priv { struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; - /* RF preamble: Short, Long or Auto */ - u8 radio_preamble; - u8 radio_state; - - /* WMM MODE 1 for enabled; 0 for disabled */ - bool wmm_mode; - - /* Set if PHY config is in progress */ - bool inconfig; + bool radio_on; + bool radio_short_preamble; + bool wmm_enabled; /* XXX need to convert this to handle multiple interfaces */ bool capture_beacon; - u8 capture_bssid[IEEE80211_ADDR_LEN]; + u8 capture_bssid[ETH_ALEN]; struct sk_buff *beacon_skb; /* @@ -220,14 +202,10 @@ struct mwl8k_priv { /* Work thread to serialize configuration requests */ struct workqueue_struct *config_wq; - struct completion *hostcmd_wait; - struct completion *tx_wait; }; /* Per interface specific private data */ struct mwl8k_vif { - struct list_head node; - /* backpointer to parent config block */ struct mwl8k_priv *priv; @@ -235,8 +213,8 @@ struct mwl8k_vif { struct ieee80211_bss_conf bss_info; /* BSSID of AP or IBSS */ - u8 bssid[IEEE80211_ADDR_LEN]; - u8 mac_addr[IEEE80211_ADDR_LEN]; + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; /* * Subset of supported legacy rates. @@ -247,18 +225,11 @@ struct mwl8k_vif { /* number of supported legacy rates */ u8 legacy_nrates; - /* Number of supported MCS rates. Work in progress */ - u8 mcs_nrates; - /* Index into station database.Returned by update_sta_db call */ u8 peer_id; /* Non AMPDU sequence number assigned by driver */ u16 seqno; - - /* Note:There is no channel info, - * refer to the master channel info in priv - */ }; #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) @@ -292,28 +263,6 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 540, .hw_value = 108, }, }; -/* Radio settings */ -#define MWL8K_RADIO_FORCE 0x2 -#define MWL8K_RADIO_ENABLE 0x1 -#define MWL8K_RADIO_DISABLE 0x0 -#define MWL8K_RADIO_AUTO_PREAMBLE 0x0005 -#define MWL8K_RADIO_SHORT_PREAMBLE 0x0003 -#define MWL8K_RADIO_LONG_PREAMBLE 0x0001 - -/* WMM */ -#define MWL8K_WMM_ENABLE 1 -#define MWL8K_WMM_DISABLE 0 - -#define MWL8K_RADIO_DEFAULT_PREAMBLE MWL8K_RADIO_LONG_PREAMBLE - -/* Slot time */ - -/* Short Slot: 9us slot time */ -#define MWL8K_SHORT_SLOTTIME 1 - -/* Long slot: 20us slot time */ -#define MWL8K_LONG_SLOTTIME 0 - /* Set or get info from Firmware */ #define MWL8K_CMD_SET 0x0001 #define MWL8K_CMD_GET 0x0000 @@ -323,25 +272,23 @@ static const struct ieee80211_rate mwl8k_rates[] = { #define MWL8K_CMD_GET_HW_SPEC 0x0003 #define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 #define MWL8K_CMD_GET_STAT 0x0014 -#define MWL8K_CMD_RADIO_CONTROL 0x001C -#define MWL8K_CMD_RF_TX_POWER 0x001E +#define MWL8K_CMD_RADIO_CONTROL 0x001c +#define MWL8K_CMD_RF_TX_POWER 0x001e #define MWL8K_CMD_SET_PRE_SCAN 0x0107 #define MWL8K_CMD_SET_POST_SCAN 0x0108 -#define MWL8K_CMD_SET_RF_CHANNEL 0x010A +#define MWL8K_CMD_SET_RF_CHANNEL 0x010a +#define MWL8K_CMD_SET_AID 0x010d +#define MWL8K_CMD_SET_RATE 0x0110 +#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 +#define MWL8K_CMD_RTS_THRESHOLD 0x0113 #define MWL8K_CMD_SET_SLOT 0x0114 +#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 +#define MWL8K_CMD_SET_WMM_MODE 0x0123 #define MWL8K_CMD_MIMO_CONFIG 0x0125 +#define MWL8K_CMD_USE_FIXED_RATE 0x0126 #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 -#define MWL8K_CMD_SET_WMM_MODE 0x0123 -#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 -#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 -#define MWL8K_CMD_UPDATE_STADB 0x1123 #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 -#define MWL8K_CMD_SET_LINKADAPT_MODE 0x0129 -#define MWL8K_CMD_SET_AID 0x010d -#define MWL8K_CMD_SET_RATE 0x0110 -#define MWL8K_CMD_USE_FIXED_RATE 0x0126 -#define MWL8K_CMD_RTS_THRESHOLD 0x0113 -#define MWL8K_CMD_ENCRYPTION 0x1122 +#define MWL8K_CMD_UPDATE_STADB 0x1123 static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) { @@ -349,7 +296,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) snprintf(buf, bufsize, "%s", #x);\ return buf;\ } while (0) - switch (cmd & (~0x8000)) { + switch (cmd & ~0x8000) { MWL8K_CMDNAME(CODE_DNLD); MWL8K_CMDNAME(GET_HW_SPEC); MWL8K_CMDNAME(MAC_MULTICAST_ADR); @@ -359,20 +306,18 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(SET_PRE_SCAN); MWL8K_CMDNAME(SET_POST_SCAN); MWL8K_CMDNAME(SET_RF_CHANNEL); + MWL8K_CMDNAME(SET_AID); + MWL8K_CMDNAME(SET_RATE); + MWL8K_CMDNAME(SET_FINALIZE_JOIN); + MWL8K_CMDNAME(RTS_THRESHOLD); MWL8K_CMDNAME(SET_SLOT); + MWL8K_CMDNAME(SET_EDCA_PARAMS); + MWL8K_CMDNAME(SET_WMM_MODE); MWL8K_CMDNAME(MIMO_CONFIG); + MWL8K_CMDNAME(USE_FIXED_RATE); MWL8K_CMDNAME(ENABLE_SNIFFER); - MWL8K_CMDNAME(SET_WMM_MODE); - MWL8K_CMDNAME(SET_EDCA_PARAMS); - MWL8K_CMDNAME(SET_FINALIZE_JOIN); - MWL8K_CMDNAME(UPDATE_STADB); MWL8K_CMDNAME(SET_RATEADAPT_MODE); - MWL8K_CMDNAME(SET_LINKADAPT_MODE); - MWL8K_CMDNAME(SET_AID); - MWL8K_CMDNAME(SET_RATE); - MWL8K_CMDNAME(USE_FIXED_RATE); - MWL8K_CMDNAME(RTS_THRESHOLD); - MWL8K_CMDNAME(ENCRYPTION); + MWL8K_CMDNAME(UPDATE_STADB); default: snprintf(buf, bufsize, "0x%x", cmd); } @@ -466,7 +411,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) { void __iomem *regs = priv->regs; dma_addr_t dma_addr; - int rc; int loops; dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE); @@ -480,7 +424,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) iowrite32(MWL8K_H2A_INT_DUMMY, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); - rc = -ETIMEDOUT; loops = 1000; do { u32 int_code; @@ -488,7 +431,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) int_code = ioread32(regs + MWL8K_HIU_INT_CODE); if (int_code == MWL8K_INT_CODE_CMD_FINISHED) { iowrite32(0, regs + MWL8K_HIU_INT_CODE); - rc = 0; break; } @@ -497,26 +439,7 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE); - /* - * Clear 'command done' interrupt bit. - */ - loops = 1000; - do { - u32 status; - - status = ioread32(priv->regs + - MWL8K_HIU_A2H_INTERRUPT_STATUS); - if (status & MWL8K_A2H_INT_OPC_DONE) { - iowrite32(~MWL8K_A2H_INT_OPC_DONE, - priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - break; - } - - udelay(1); - } while (--loops); - - return rc; + return loops ? 0 : -ETIMEDOUT; } static int mwl8k_load_fw_image(struct mwl8k_priv *priv, @@ -681,11 +604,9 @@ struct ewc_ht_info { /* Peer Entry flags - used to define the type of the peer node */ #define MWL8K_PEER_TYPE_ACCESSPOINT 2 -#define MWL8K_PEER_TYPE_ADHOC_STATION 4 #define MWL8K_IEEE_LEGACY_DATA_RATES 12 #define MWL8K_MCS_BITMAP_SIZE 16 -#define pad_size 16 struct peer_capability_info { /* Peer type - AP vs. STA. */ @@ -707,7 +628,7 @@ struct peer_capability_info { /* HT rate table. Intersection of our rates and peer rates. */ __u8 ht_rates[MWL8K_MCS_BITMAP_SIZE]; - __u8 pad[pad_size]; + __u8 pad[16]; /* If set, interoperability mode, no proprietary extensions. */ __u8 interop; @@ -717,15 +638,6 @@ struct peer_capability_info { } __attribute__((packed)); /* Inline functions to manipulate QoS field in data descriptor. */ -static inline u16 mwl8k_qos_setbit_tid(u16 qos, u8 tid) -{ - u16 val_mask = 0x000f; - u16 qos_mask = ~val_mask; - - /* TID bits 0-3 */ - return (qos & qos_mask) | (tid & val_mask); -} - static inline u16 mwl8k_qos_setbit_eosp(u16 qos) { u16 val_mask = 1 << 4; @@ -769,12 +681,11 @@ struct mwl8k_dma_data { } __attribute__((packed)); /* Routines to add/remove DMA header from skb. */ -static inline int mwl8k_remove_dma_header(struct sk_buff *skb) +static inline void mwl8k_remove_dma_header(struct sk_buff *skb) { - struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data); + struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data; void *dst, *src = &tr->wh; - __le16 fc = tr->wh.frame_control; - int hdrlen = ieee80211_hdrlen(fc); + int hdrlen = ieee80211_hdrlen(tr->wh.frame_control); u16 space = sizeof(struct mwl8k_dma_data) - hdrlen; dst = (void *)tr + space; @@ -782,11 +693,9 @@ static inline int mwl8k_remove_dma_header(struct sk_buff *skb) memmove(dst, src, hdrlen); skb_pull(skb, space); } - - return 0; } -static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) +static inline void mwl8k_add_dma_header(struct sk_buff *skb) { struct ieee80211_hdr *wh; u32 hdrlen, pktlen; @@ -810,7 +719,7 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) memmove(&tr->wh, wh, hdrlen); /* Clear addr4 */ - memset(tr->wh.addr4, 0, IEEE80211_ADDR_LEN); + memset(tr->wh.addr4, 0, ETH_ALEN); /* * Firmware length is the length of the fully formed "802.11 @@ -818,17 +727,13 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) * This includes all crypto material including the MIC. */ tr->fwlen = cpu_to_le16(pktlen - hdrlen); - - return skb; } /* * Packet reception. */ -#define MWL8K_RX_CTRL_KEY_INDEX_MASK 0x30 #define MWL8K_RX_CTRL_OWNED_BY_HOST 0x02 -#define MWL8K_RX_CTRL_AMPDU 0x01 struct mwl8k_rx_desc { __le16 pkt_len; @@ -979,7 +884,7 @@ static inline void mwl8k_save_beacon(struct mwl8k_priv *priv, struct sk_buff *skb) { priv->capture_beacon = false; - memset(priv->capture_bssid, 0, IEEE80211_ADDR_LEN); + memset(priv->capture_bssid, 0, ETH_ALEN); /* * Use GFP_ATOMIC as rxq_process is called from @@ -1024,10 +929,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); skb_put(skb, le16_to_cpu(rx_desc->pkt_len)); - if (mwl8k_remove_dma_header(skb)) { - dev_kfree_skb(skb); - continue; - } + mwl8k_remove_dma_header(skb); wh = (struct ieee80211_hdr *)skb->data; @@ -1073,8 +975,6 @@ enum { /* Transmit packet ACK policy */ #define MWL8K_TXD_ACK_POLICY_NORMAL 0 -#define MWL8K_TXD_ACK_POLICY_NONE 1 -#define MWL8K_TXD_ACK_POLICY_NO_EXPLICIT 2 #define MWL8K_TXD_ACK_POLICY_BLOCKACK 3 #define GET_TXQ(_ac) (\ @@ -1083,20 +983,11 @@ enum { ((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \ MWL8K_WME_AC_BE) -#define MWL8K_TXD_STATUS_IDLE 0x00000000 -#define MWL8K_TXD_STATUS_USED 0x00000001 #define MWL8K_TXD_STATUS_OK 0x00000001 #define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 #define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 #define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008 -#define MWL8K_TXD_STATUS_BROADCAST_TX 0x00000010 -#define MWL8K_TXD_STATUS_FAILED_LINK_ERROR 0x00000020 -#define MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT 0x00000040 -#define MWL8K_TXD_STATUS_FAILED_AGING 0x00000080 -#define MWL8K_TXD_STATUS_HOST_CMD 0x40000000 #define MWL8K_TXD_STATUS_FW_OWNED 0x80000000 -#define MWL8K_TXD_SOFTSTALE 0x80 -#define MWL8K_TXD_SOFTSTALE_MGMT_RETRY 0x01 struct mwl8k_tx_desc { __le32 status; @@ -1105,7 +996,7 @@ struct mwl8k_tx_desc { __le16 qos_control; __le32 pkt_phys_addr; __le16 pkt_len; - __u8 dest_MAC_addr[IEEE80211_ADDR_LEN]; + __u8 dest_MAC_addr[ETH_ALEN]; __le32 next_tx_desc_phys_addr; __le32 reserved; __le16 rate_info; @@ -1122,8 +1013,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) int size; int i; - memset(&txq->tx_stats, 0, - sizeof(struct ieee80211_tx_queue_stats)); + memset(&txq->tx_stats, 0, sizeof(struct ieee80211_tx_queue_stats)); txq->tx_stats.limit = MWL8K_TX_DESCS; txq->tx_head = 0; txq->tx_tail = 0; @@ -1190,17 +1080,17 @@ struct mwl8k_txq_info { }; static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, - struct mwl8k_txq_info txinfo[], - u32 num_queues) + struct mwl8k_txq_info *txinfo) { int count, desc, status; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx_desc; int ndescs = 0; - memset(txinfo, 0, num_queues * sizeof(struct mwl8k_txq_info)); + memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info)); + spin_lock_bh(&priv->tx_lock); - for (count = 0; count < num_queues; count++) { + for (count = 0; count < MWL8K_TX_QUEUES; count++) { txq = priv->txq + count; txinfo[count].len = txq->tx_stats.len; txinfo[count].head = txq->tx_head; @@ -1223,34 +1113,34 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, return ndescs; } -static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) +/* + * Must be called with hw->fw_mutex held and tx queues stopped. + */ +static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) { - u32 count = 0; - unsigned long timeout = 0; struct mwl8k_priv *priv = hw->priv; DECLARE_COMPLETION_ONSTACK(cmd_wait); + u32 count; + unsigned long timeout; might_sleep(); - if (priv->tx_wait != NULL) - printk(KERN_ERR "WARNING Previous TXWaitEmpty instance\n"); - spin_lock_bh(&priv->tx_lock); count = mwl8k_txq_busy(priv); if (count) { priv->tx_wait = &cmd_wait; - if (priv->radio_state) + if (priv->radio_on) mwl8k_tx_start(priv); } spin_unlock_bh(&priv->tx_lock); if (count) { - struct mwl8k_txq_info txinfo[4]; + struct mwl8k_txq_info txinfo[MWL8K_TX_QUEUES]; int index; int newcount; timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(delay_ms)); + msecs_to_jiffies(5000)); if (timeout) return 0; @@ -1259,11 +1149,11 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) newcount = mwl8k_txq_busy(priv); spin_unlock_bh(&priv->tx_lock); - printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n", - __func__, __LINE__, delay_ms, count, newcount); + printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n", + __func__, __LINE__, count, newcount); - mwl8k_scan_tx_ring(priv, txinfo, 4); - for (index = 0 ; index < 4; index++) + mwl8k_scan_tx_ring(priv, txinfo); + for (index = 0; index < MWL8K_TX_QUEUES; index++) printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n", index, @@ -1273,18 +1163,17 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) txinfo[index].fw_owned, txinfo[index].drv_owned, txinfo[index].unused); + return -ETIMEDOUT; } return 0; } -#define MWL8K_TXD_OK (MWL8K_TXD_STATUS_OK | \ - MWL8K_TXD_STATUS_OK_RETRY | \ - MWL8K_TXD_STATUS_OK_MORE_RETRY) -#define MWL8K_TXD_SUCCESS(stat) ((stat) & MWL8K_TXD_OK) -#define MWL8K_TXD_FAIL_RETRY(stat) \ - ((stat) & (MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT)) +#define MWL8K_TXD_SUCCESS(status) \ + ((status) & (MWL8K_TXD_STATUS_OK | \ + MWL8K_TXD_STATUS_OK_RETRY | \ + MWL8K_TXD_STATUS_OK_MORE_RETRY)) static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) { @@ -1294,15 +1183,13 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) while (txq->tx_stats.len > 0) { int tx; - int rc; struct mwl8k_tx_desc *tx_desc; unsigned long addr; - size_t size; + int size; struct sk_buff *skb; struct ieee80211_tx_info *info; u32 status; - rc = 0; tx = txq->tx_head; tx_desc = txq->tx_desc_area + tx; @@ -1321,56 +1208,30 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) priv->pending_tx_pkts--; addr = le32_to_cpu(tx_desc->pkt_phys_addr); - size = (u32)(le16_to_cpu(tx_desc->pkt_len)); - skb = txq->tx_skb[tx].skb; - txq->tx_skb[tx].skb = NULL; + size = le16_to_cpu(tx_desc->pkt_len); + skb = txq->tx_skb[tx]; + txq->tx_skb[tx] = NULL; BUG_ON(skb == NULL); pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); - rc = mwl8k_remove_dma_header(skb); + mwl8k_remove_dma_header(skb); /* Mark descriptor as unused */ tx_desc->pkt_phys_addr = 0; tx_desc->pkt_len = 0; - if (txq->tx_skb[tx].clone) { - /* Replace with original skb - * before returning to stack - * as buffer has been cloned - */ - dev_kfree_skb(skb); - skb = txq->tx_skb[tx].clone; - txq->tx_skb[tx].clone = NULL; - } - - if (rc) { - /* Something has gone wrong here. - * Failed to remove DMA header. - * Print error message and drop packet. - */ - printk(KERN_ERR "%s: Error removing DMA header from " - "tx skb 0x%p.\n", priv->name, skb); - - dev_kfree_skb(skb); - continue; - } - info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); - - /* Convert firmware status stuff into tx_status */ - if (MWL8K_TXD_SUCCESS(status)) { - /* Transmit OK */ + if (MWL8K_TXD_SUCCESS(status)) info->flags |= IEEE80211_TX_STAT_ACK; - } ieee80211_tx_status_irqsafe(hw, skb); - wake = !priv->inconfig && priv->radio_state; + wake = 1; } - if (wake) + if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) ieee80211_wake_queue(hw, index); } @@ -1396,56 +1257,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) { struct mwl8k_priv *priv = hw->priv; struct ieee80211_tx_info *tx_info; + struct mwl8k_vif *mwl8k_vif; struct ieee80211_hdr *wh; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx; - struct mwl8k_dma_data *tr; - struct mwl8k_vif *mwl8k_vif; - struct sk_buff *org_skb = skb; dma_addr_t dma; - u16 qos = 0; - bool qosframe = false, ampduframe = false; - bool mcframe = false, eapolframe = false; - bool amsduframe = false; - __le16 fc; + u32 txstatus; + u8 txdatarate; + u16 qos; - txq = priv->txq + index; - tx = txq->tx_desc_area + txq->tx_tail; - - BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL); - - /* - * Append HW DMA header to start of packet. Drop packet if - * there is not enough space or a failure to unshare/unclone - * the skb. - */ - skb = mwl8k_add_dma_header(skb); + wh = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_data_qos(wh->frame_control)) + qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); + else + qos = 0; - if (skb == NULL) { - printk(KERN_DEBUG "%s: failed to prepend HW DMA " - "header, dropping TX frame.\n", priv->name); - dev_kfree_skb(org_skb); - return NETDEV_TX_OK; - } + mwl8k_add_dma_header(skb); + wh = &((struct mwl8k_dma_data *)skb->data)->wh; tx_info = IEEE80211_SKB_CB(skb); mwl8k_vif = MWL8K_VIF(tx_info->control.vif); - tr = (struct mwl8k_dma_data *)skb->data; - wh = &tr->wh; - fc = wh->frame_control; - qosframe = ieee80211_is_data_qos(fc); - mcframe = is_multicast_ether_addr(wh->addr1); - ampduframe = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { u16 seqno = mwl8k_vif->seqno; + wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); wh->seq_ctrl |= cpu_to_le16(seqno << 4); mwl8k_vif->seqno = seqno++ % 4096; } - if (qosframe) - qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); + /* Setup firmware control bit fields for each frame type. */ + txstatus = 0; + txdatarate = 0; + if (ieee80211_is_mgmt(wh->frame_control) || + ieee80211_is_ctl(wh->frame_control)) { + txdatarate = 0; + qos = mwl8k_qos_setbit_eosp(qos); + /* Set Queue size to unspecified */ + qos = mwl8k_qos_setbit_qlen(qos, 0xff); + } else if (ieee80211_is_data(wh->frame_control)) { + txdatarate = 1; + if (is_multicast_ether_addr(wh->addr1)) + txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX; + + /* Send pkt in an aggregate if AMPDU frame. */ + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + qos = mwl8k_qos_setbit_ack(qos, + MWL8K_TXD_ACK_POLICY_BLOCKACK); + else + qos = mwl8k_qos_setbit_ack(qos, + MWL8K_TXD_ACK_POLICY_NORMAL); + + if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + qos = mwl8k_qos_setbit_amsdu(qos); + } dma = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); @@ -1453,99 +1318,40 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (pci_dma_mapping_error(priv->pdev, dma)) { printk(KERN_DEBUG "%s: failed to dma map skb, " "dropping TX frame.\n", priv->name); - - if (org_skb != NULL) - dev_kfree_skb(org_skb); - if (skb != NULL) - dev_kfree_skb(skb); + dev_kfree_skb(skb); return NETDEV_TX_OK; } - /* Set desc header, cpu bit order. */ - tx->status = 0; - tx->data_rate = 0; - tx->tx_priority = index; - tx->qos_control = 0; - tx->rate_info = 0; - tx->peer_id = mwl8k_vif->peer_id; - - amsduframe = !!(qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); - - /* Setup firmware control bit fields for each frame type. */ - if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { - tx->data_rate = 0; - qos = mwl8k_qos_setbit_eosp(qos); - /* Set Queue size to unspecified */ - qos = mwl8k_qos_setbit_qlen(qos, 0xff); - } else if (ieee80211_is_data(fc)) { - tx->data_rate = 1; - if (mcframe) - tx->status |= MWL8K_TXD_STATUS_MULTICAST_TX; + spin_lock_bh(&priv->tx_lock); - /* - * Tell firmware to not send EAPOL pkts in an - * aggregate. Verify against mac80211 tx path. If - * stack turns off AMPDU for an EAPOL frame this - * check will be removed. - */ - if (eapolframe) { - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_NORMAL); - } else { - /* Send pkt in an aggregate if AMPDU frame. */ - if (ampduframe) - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_BLOCKACK); - else - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_NORMAL); + txq = priv->txq + index; - if (amsduframe) - qos = mwl8k_qos_setbit_amsdu(qos); - } - } + BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); + txq->tx_skb[txq->tx_tail] = skb; - /* Convert to little endian */ + tx = txq->tx_desc_area + txq->tx_tail; + tx->data_rate = txdatarate; + tx->tx_priority = index; tx->qos_control = cpu_to_le16(qos); - tx->status = cpu_to_le32(tx->status); tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); - - txq->tx_skb[txq->tx_tail].skb = skb; - txq->tx_skb[txq->tx_tail].clone = - skb == org_skb ? NULL : org_skb; - - spin_lock_bh(&priv->tx_lock); - - tx->status = cpu_to_le32(MWL8K_TXD_STATUS_OK | - MWL8K_TXD_STATUS_FW_OWNED); + tx->rate_info = 0; + tx->peer_id = mwl8k_vif->peer_id; wmb(); + tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); + + txq->tx_stats.count++; txq->tx_stats.len++; priv->pending_tx_pkts++; - txq->tx_stats.count++; - txq->tx_tail++; + txq->tx_tail++; if (txq->tx_tail == MWL8K_TX_DESCS) txq->tx_tail = 0; + if (txq->tx_head == txq->tx_tail) ieee80211_stop_queue(hw, index); - if (priv->inconfig) { - /* - * Silently queue packet when we are in the middle of - * a config cycle. Notify firmware only if we are - * waiting for TXQs to empty. If a packet is sent - * before .config() is complete, perhaps it is better - * to drop the packet, as the channel is being changed - * and the packet will end up on the wrong channel. - */ - printk(KERN_ERR "%s(): WARNING TX activity while " - "in config\n", __func__); - - if (priv->tx_wait != NULL) - mwl8k_tx_start(priv); - } else - mwl8k_tx_start(priv); + mwl8k_tx_start(priv); spin_unlock_bh(&priv->tx_lock); @@ -1554,6 +1360,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) /* + * Firmware access. + * + * We have the following requirements for issuing firmware commands: + * - Some commands require that the packet transmit path is idle when + * the command is issued. (For simplicity, we'll just quiesce the + * transmit path for every command.) + * - There are certain sequences of commands that need to be issued to + * the hardware sequentially, with no other intervening commands. + * + * This leads to an implementation of a "firmware lock" as a mutex that + * can be taken recursively, and which is taken by both the low-level + * command submission function (mwl8k_post_cmd) as well as any users of + * that function that require issuing of an atomic sequence of commands, + * and quiesces the transmit path whenever it's taken. + */ +static int mwl8k_fw_lock(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + + if (priv->fw_mutex_owner != current) { + int rc; + + mutex_lock(&priv->fw_mutex); + ieee80211_stop_queues(hw); + + rc = mwl8k_tx_wait_empty(hw); + if (rc) { + ieee80211_wake_queues(hw); + mutex_unlock(&priv->fw_mutex); + + return rc; + } + + priv->fw_mutex_owner = current; + } + + priv->fw_mutex_depth++; + + return 0; +} + +static void mwl8k_fw_unlock(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + + if (!--priv->fw_mutex_depth) { + ieee80211_wake_queues(hw); + priv->fw_mutex_owner = NULL; + mutex_unlock(&priv->fw_mutex); + } +} + + +/* * Command processing. */ @@ -1568,7 +1428,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) dma_addr_t dma_addr; unsigned int dma_size; int rc; - u16 __iomem *result; unsigned long timeout = 0; u8 buf[32]; @@ -1579,41 +1438,40 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) if (pci_dma_mapping_error(priv->pdev, dma_addr)) return -ENOMEM; - if (priv->hostcmd_wait != NULL) - printk(KERN_ERR "WARNING host command in progress\n"); + rc = mwl8k_fw_lock(hw); + if (rc) + return rc; - spin_lock_irq(&priv->fw_lock); priv->hostcmd_wait = &cmd_wait; iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); iowrite32(MWL8K_H2A_INT_DOORBELL, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); iowrite32(MWL8K_H2A_INT_DUMMY, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); - spin_unlock_irq(&priv->fw_lock); timeout = wait_for_completion_timeout(&cmd_wait, msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); + priv->hostcmd_wait = NULL; + + mwl8k_fw_unlock(hw); + pci_unmap_single(priv->pdev, dma_addr, dma_size, PCI_DMA_BIDIRECTIONAL); - result = &cmd->result; if (!timeout) { - spin_lock_irq(&priv->fw_lock); - priv->hostcmd_wait = NULL; - spin_unlock_irq(&priv->fw_lock); printk(KERN_ERR "%s: Command %s timeout after %u ms\n", priv->name, mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), MWL8K_CMD_TIMEOUT_MS); rc = -ETIMEDOUT; } else { - rc = *result ? -EINVAL : 0; + rc = cmd->result ? -EINVAL : 0; if (rc) printk(KERN_ERR "%s: Command %s error 0x%x\n", priv->name, mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), - *result); + cmd->result); } return rc; @@ -1627,7 +1485,7 @@ struct mwl8k_cmd_get_hw_spec { __u8 hw_rev; __u8 host_interface; __le16 num_mcaddrs; - __u8 perm_addr[IEEE80211_ADDR_LEN]; + __u8 perm_addr[ETH_ALEN]; __le16 region_code; __le32 fw_rev; __le32 ps_cookie; @@ -1671,7 +1529,6 @@ static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - priv->region_code = le16_to_cpu(cmd->region_code); } kfree(cmd); @@ -1685,41 +1542,44 @@ struct mwl8k_cmd_mac_multicast_adr { struct mwl8k_cmd_pkt header; __le16 action; __le16 numaddr; - __u8 addr[1][IEEE80211_ADDR_LEN]; + __u8 addr[0][ETH_ALEN]; }; #define MWL8K_ENABLE_RX_MULTICAST 0x000F -static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, - int mc_count, - struct dev_addr_list *mclist) + +static struct mwl8k_cmd_pkt * +__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) { + struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_mac_multicast_adr *cmd; - int index = 0; - int rc; - int size = sizeof(*cmd) + ((mc_count - 1) * IEEE80211_ADDR_LEN); - cmd = kzalloc(size, GFP_KERNEL); + int size; + int i; + + if (mc_count > priv->num_mcaddrs) + mc_count = priv->num_mcaddrs; + + size = sizeof(*cmd) + mc_count * ETH_ALEN; + + cmd = kzalloc(size, GFP_ATOMIC); if (cmd == NULL) - return -ENOMEM; + return NULL; cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); cmd->header.length = cpu_to_le16(size); cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); cmd->numaddr = cpu_to_le16(mc_count); - while ((index < mc_count) && mclist) { - if (mclist->da_addrlen != IEEE80211_ADDR_LEN) { - rc = -EINVAL; - goto mwl8k_cmd_mac_multicast_adr_exit; + + for (i = 0; i < mc_count && mclist; i++) { + if (mclist->da_addrlen != ETH_ALEN) { + kfree(cmd); + return NULL; } - memcpy(cmd->addr[index], mclist->da_addr, IEEE80211_ADDR_LEN); - index++; + memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN); mclist = mclist->next; } - rc = mwl8k_post_cmd(hw, &cmd->header); - -mwl8k_cmd_mac_multicast_adr_exit: - kfree(cmd); - return rc; + return &cmd->header; } /* @@ -1776,18 +1636,16 @@ struct mwl8k_cmd_802_11_radio_control { __le16 radio_on; } __attribute__((packed)); -static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable) +static int +mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_802_11_radio_control *cmd; int rc; - if (((enable & MWL8K_RADIO_ENABLE) == priv->radio_state) && - !(enable & MWL8K_RADIO_FORCE)) + if (enable == priv->radio_on && !force) return 0; - enable &= MWL8K_RADIO_ENABLE; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -1795,18 +1653,28 @@ static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable) cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->control = cpu_to_le16(priv->radio_preamble); + cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1); cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); if (!rc) - priv->radio_state = enable; + priv->radio_on = enable; return rc; } +static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw) +{ + return mwl8k_cmd_802_11_radio_control(hw, 0, 0); +} + +static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw) +{ + return mwl8k_cmd_802_11_radio_control(hw, 1, 0); +} + static int mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) { @@ -1816,12 +1684,9 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) return -EINVAL; priv = hw->priv; - priv->radio_preamble = (short_preamble ? - MWL8K_RADIO_SHORT_PREAMBLE : - MWL8K_RADIO_LONG_PREAMBLE); + priv->radio_short_preamble = short_preamble; - return mwl8k_cmd_802_11_radio_control(hw, - MWL8K_RADIO_ENABLE | MWL8K_RADIO_FORCE); + return mwl8k_cmd_802_11_radio_control(hw, 1, 1); } /* @@ -1889,11 +1754,11 @@ static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) struct mwl8k_cmd_set_post_scan { struct mwl8k_cmd_pkt header; __le32 isibss; - __u8 bssid[IEEE80211_ADDR_LEN]; + __u8 bssid[ETH_ALEN]; } __attribute__((packed)); static int -mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN]) +mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac) { struct mwl8k_cmd_set_post_scan *cmd; int rc; @@ -1905,7 +1770,7 @@ mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN]) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->isibss = 0; - memcpy(cmd->bssid, mac, IEEE80211_ADDR_LEN); + memcpy(cmd->bssid, mac, ETH_ALEN); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -1957,7 +1822,7 @@ struct mwl8k_cmd_set_slot { __u8 short_slot; } __attribute__((packed)); -static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time) +static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) { struct mwl8k_cmd_set_slot *cmd; int rc; @@ -1969,7 +1834,7 @@ static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->short_slot = slot_time == MWL8K_SHORT_SLOTTIME ? 1 : 0; + cmd->short_slot = short_slot_time; rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2027,7 +1892,7 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = enable ? cpu_to_le32((u32)MWL8K_CMD_SET) : 0; + cmd->action = cpu_to_le32(!!enable); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2036,7 +1901,7 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) } /* - * CMD_SET_RATE_ADAPT_MODE. + * CMD_SET_RATEADAPT_MODE. */ struct mwl8k_cmd_set_rate_adapt_mode { struct mwl8k_cmd_pkt header; @@ -2084,13 +1949,13 @@ static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = enable ? cpu_to_le16(MWL8K_CMD_SET) : 0; + cmd->action = cpu_to_le16(!!enable); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); if (!rc) - priv->wmm_mode = enable; + priv->wmm_enabled = enable; return rc; } @@ -2105,7 +1970,7 @@ struct mwl8k_cmd_rts_threshold { } __attribute__((packed)); static int mwl8k_rts_threshold(struct ieee80211_hw *hw, - u16 action, u16 *threshold) + u16 action, u16 threshold) { struct mwl8k_cmd_rts_threshold *cmd; int rc; @@ -2117,7 +1982,7 @@ static int mwl8k_rts_threshold(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(action); - cmd->threshold = cpu_to_le16(*threshold); + cmd->threshold = cpu_to_le16(threshold); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2150,7 +2015,6 @@ struct mwl8k_cmd_set_edca_params { __u8 txq; } __attribute__((packed)); -#define MWL8K_GET_EDCA_ALL 0 #define MWL8K_SET_EDCA_CW 0x01 #define MWL8K_SET_EDCA_TXOP 0x02 #define MWL8K_SET_EDCA_AIFS 0x04 @@ -2165,22 +2029,18 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, __u8 aifs, __u16 txop) { struct mwl8k_cmd_set_edca_params *cmd; - u32 log_cw_min, log_cw_max; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - log_cw_min = ilog2(cw_min+1); - log_cw_max = ilog2(cw_max+1); cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); cmd->txop = cpu_to_le16(txop); - cmd->log_cw_max = (u8)log_cw_max; - cmd->log_cw_min = (u8)log_cw_min; + cmd->log_cw_max = (u8)ilog2(cw_max + 1); + cmd->log_cw_min = (u8)ilog2(cw_min + 1); cmd->aifs = aifs; cmd->txq = qnum; @@ -2221,11 +2081,7 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - - if (dtim) - cmd->sleep_interval = cpu_to_le32(dtim); - else - cmd->sleep_interval = cpu_to_le32(1); + cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); hdrlen = ieee80211_hdrlen(payload->frame_control); @@ -2237,8 +2093,8 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, "sent to firmware. Sz=%u MAX=%u\n", __func__, payload_len, MWL8K_FJ_BEACON_MAXLEN); - payload_len = payload_len > MWL8K_FJ_BEACON_MAXLEN ? - MWL8K_FJ_BEACON_MAXLEN : payload_len; + if (payload_len > MWL8K_FJ_BEACON_MAXLEN) + payload_len = MWL8K_FJ_BEACON_MAXLEN; if (payload && payload_len) memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); @@ -2258,7 +2114,7 @@ struct mwl8k_cmd_update_sta_db { __le32 action; /* Peer MAC address */ - __u8 peer_addr[IEEE80211_ADDR_LEN]; + __u8 peer_addr[ETH_ALEN]; __le32 reserved; @@ -2286,7 +2142,7 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, cmd->action = cpu_to_le32(action); peer_info = &cmd->peer_info; - memcpy(cmd->peer_addr, mv_vif->bssid, IEEE80211_ADDR_LEN); + memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN); switch (action) { case MWL8K_STA_DB_ADD_ENTRY: @@ -2298,7 +2154,7 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, peer_info->amsdu_enabled = 0; rates = peer_info->legacy_rates; - for (count = 0 ; count < mv_vif->legacy_nrates; count++) + for (count = 0; count < mv_vif->legacy_nrates; count++) rates[count] = bitrates[count].hw_value; rc = mwl8k_post_cmd(hw, &cmd->header); @@ -2323,25 +2179,19 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, /* * CMD_SET_AID. */ -#define IEEE80211_OPMODE_DISABLED 0x00 -#define IEEE80211_OPMODE_NON_MEMBER_PROT_MODE 0x01 -#define IEEE80211_OPMODE_ONE_20MHZ_STA_PROT_MODE 0x02 -#define IEEE80211_OPMODE_HTMIXED_PROT_MODE 0x03 - #define MWL8K_RATE_INDEX_MAX_ARRAY 14 #define MWL8K_FRAME_PROT_DISABLED 0x00 #define MWL8K_FRAME_PROT_11G 0x07 #define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 #define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 -#define MWL8K_FRAME_PROT_MASK 0x07 struct mwl8k_cmd_update_set_aid { struct mwl8k_cmd_pkt header; __le16 aid; /* AP's MAC address (BSSID) */ - __u8 bssid[IEEE80211_ADDR_LEN]; + __u8 bssid[ETH_ALEN]; __le16 protection_mode; __u8 supp_rates[MWL8K_RATE_INDEX_MAX_ARRAY]; } __attribute__((packed)); @@ -2365,9 +2215,7 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->aid = cpu_to_le16(info->aid); - memcpy(cmd->bssid, mv_vif->bssid, IEEE80211_ADDR_LEN); - - prot_mode = MWL8K_FRAME_PROT_DISABLED; + memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); if (info->use_cts_prot) { prot_mode = MWL8K_FRAME_PROT_11G; @@ -2385,7 +2233,6 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, break; } } - cmd->protection_mode = cpu_to_le16(prot_mode); for (count = 0; count < mv_vif->legacy_nrates; count++) @@ -2439,10 +2286,6 @@ static int mwl8k_update_rateset(struct ieee80211_hw *hw, */ #define MWL8K_RATE_TABLE_SIZE 8 #define MWL8K_UCAST_RATE 0 -#define MWL8K_MCAST_RATE 1 -#define MWL8K_BCAST_RATE 2 - -#define MWL8K_USE_FIXED_RATE 0x0001 #define MWL8K_USE_AUTO_RATE 0x0002 struct mwl8k_rate_entry { @@ -2535,7 +2378,6 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - status &= priv->int_mask; if (!status) return IRQ_NONE; @@ -2548,17 +2390,14 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) } if (status & MWL8K_A2H_INT_OPC_DONE) { - if (priv->hostcmd_wait != NULL) { + if (priv->hostcmd_wait != NULL) complete(priv->hostcmd_wait); - priv->hostcmd_wait = NULL; - } } if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { - if (!priv->inconfig && - priv->radio_state && - mwl8k_txq_busy(priv)) - mwl8k_tx_start(priv); + if (!mutex_is_locked(&priv->fw_mutex) && + priv->radio_on && mwl8k_txq_busy(priv)) + mwl8k_tx_start(priv); } return IRQ_HANDLED; @@ -2586,365 +2425,68 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return rc; } -struct mwl8k_work_struct { - /* Initialized by mwl8k_queue_work(). */ - struct work_struct wt; - - /* Required field passed in to mwl8k_queue_work(). */ - struct ieee80211_hw *hw; - - /* Required field passed in to mwl8k_queue_work(). */ - int (*wfunc)(struct work_struct *w); - - /* Initialized by mwl8k_queue_work(). */ - struct completion *cmd_wait; - - /* Result code. */ - int rc; - - /* - * Optional field. Refer to explanation of MWL8K_WQ_XXX_XXX - * flags for explanation. Defaults to MWL8K_WQ_DEFAULT_OPTIONS. - */ - u32 options; - - /* Optional field. Defaults to MWL8K_CONFIG_TIMEOUT_MS. */ - unsigned long timeout_ms; - - /* Optional field. Defaults to MWL8K_WQ_TXWAIT_ATTEMPTS. */ - u32 txwait_attempts; - - /* Optional field. Defaults to MWL8K_TXWAIT_MS. */ - u32 tx_timeout_ms; - u32 step; -}; - -/* Flags controlling behavior of config queue requests */ - -/* Caller spins while waiting for completion. */ -#define MWL8K_WQ_SPIN 0x00000001 - -/* Wait for TX queues to empty before proceeding with configuration. */ -#define MWL8K_WQ_TX_WAIT_EMPTY 0x00000002 - -/* Queue request and return immediately. */ -#define MWL8K_WQ_POST_REQUEST 0x00000004 - -/* - * Caller sleeps and waits for task complete notification. - * Do not use in atomic context. - */ -#define MWL8K_WQ_SLEEP 0x00000008 - -/* Free work struct when task is done. */ -#define MWL8K_WQ_FREE_WORKSTRUCT 0x00000010 - -/* - * Config request is queued and returns to caller imediately. Use - * this in atomic context. Work struct is freed by mwl8k_queue_work() - * when this flag is set. - */ -#define MWL8K_WQ_QUEUE_ONLY (MWL8K_WQ_POST_REQUEST | \ - MWL8K_WQ_FREE_WORKSTRUCT) - -/* Default work queue behavior is to sleep and wait for tx completion. */ -#define MWL8K_WQ_DEFAULT_OPTIONS (MWL8K_WQ_SLEEP | MWL8K_WQ_TX_WAIT_EMPTY) - -/* - * Default config request timeout. Add adjustments to make sure the - * config thread waits long enough for both tx wait and cmd wait before - * timing out. - */ - -/* Time to wait for all TXQs to drain. TX Doorbell is pressed each time. */ -#define MWL8K_TXWAIT_TIMEOUT_MS 1000 - -/* Default number of TX wait attempts. */ -#define MWL8K_WQ_TXWAIT_ATTEMPTS 4 - -/* Total time to wait for TXQ to drain. */ -#define MWL8K_TXWAIT_MS (MWL8K_TXWAIT_TIMEOUT_MS * \ - MWL8K_WQ_TXWAIT_ATTEMPTS) - -/* Scheduling slop. */ -#define MWL8K_OS_SCHEDULE_OVERHEAD_MS 200 - -#define MWL8K_CONFIG_TIMEOUT_MS (MWL8K_CMD_TIMEOUT_MS + \ - MWL8K_TXWAIT_MS + \ - MWL8K_OS_SCHEDULE_OVERHEAD_MS) - -static void mwl8k_config_thread(struct work_struct *wt) -{ - struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt; - struct ieee80211_hw *hw = worker->hw; - struct mwl8k_priv *priv = hw->priv; - int rc = 0; - - spin_lock_irq(&priv->tx_lock); - priv->inconfig = true; - spin_unlock_irq(&priv->tx_lock); - - ieee80211_stop_queues(hw); - - /* - * Wait for host queues to drain before doing PHY - * reconfiguration. This avoids interrupting any in-flight - * DMA transfers to the hardware. - */ - if (worker->options & MWL8K_WQ_TX_WAIT_EMPTY) { - u32 timeout; - u32 time_remaining; - u32 iter; - u32 tx_wait_attempts = worker->txwait_attempts; - - time_remaining = worker->tx_timeout_ms; - if (!tx_wait_attempts) - tx_wait_attempts = 1; - - timeout = worker->tx_timeout_ms/tx_wait_attempts; - if (!timeout) - timeout = 1; - - iter = tx_wait_attempts; - do { - int wait_time; - - if (time_remaining > timeout) { - time_remaining -= timeout; - wait_time = timeout; - } else - wait_time = time_remaining; - - if (!wait_time) - wait_time = 1; - - rc = mwl8k_tx_wait_empty(hw, wait_time); - if (rc) - printk(KERN_ERR "%s() txwait timeout=%ums " - "Retry:%u/%u\n", __func__, timeout, - tx_wait_attempts - iter + 1, - tx_wait_attempts); - - } while (rc && --iter); - - rc = iter ? 0 : -ETIMEDOUT; - } - if (!rc) - rc = worker->wfunc(wt); - - spin_lock_irq(&priv->tx_lock); - priv->inconfig = false; - if (priv->pending_tx_pkts && priv->radio_state) - mwl8k_tx_start(priv); - spin_unlock_irq(&priv->tx_lock); - ieee80211_wake_queues(hw); - - worker->rc = rc; - if (worker->options & MWL8K_WQ_SLEEP) - complete(worker->cmd_wait); - - if (worker->options & MWL8K_WQ_FREE_WORKSTRUCT) - kfree(wt); -} - -static int mwl8k_queue_work(struct ieee80211_hw *hw, - struct mwl8k_work_struct *worker, - struct workqueue_struct *wqueue, - int (*wfunc)(struct work_struct *w)) -{ - unsigned long timeout = 0; - int rc = 0; - - DECLARE_COMPLETION_ONSTACK(cmd_wait); - - if (!worker->timeout_ms) - worker->timeout_ms = MWL8K_CONFIG_TIMEOUT_MS; - - if (!worker->options) - worker->options = MWL8K_WQ_DEFAULT_OPTIONS; - - if (!worker->txwait_attempts) - worker->txwait_attempts = MWL8K_WQ_TXWAIT_ATTEMPTS; - - if (!worker->tx_timeout_ms) - worker->tx_timeout_ms = MWL8K_TXWAIT_MS; - - worker->hw = hw; - worker->cmd_wait = &cmd_wait; - worker->rc = 1; - worker->wfunc = wfunc; - - INIT_WORK(&worker->wt, mwl8k_config_thread); - queue_work(wqueue, &worker->wt); - - if (worker->options & MWL8K_WQ_POST_REQUEST) { - rc = 0; - } else { - if (worker->options & MWL8K_WQ_SPIN) { - timeout = worker->timeout_ms; - while (timeout && (worker->rc > 0)) { - mdelay(1); - timeout--; - } - } else if (worker->options & MWL8K_WQ_SLEEP) - timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(worker->timeout_ms)); - - if (timeout) - rc = worker->rc; - else { - cancel_work_sync(&worker->wt); - rc = -ETIMEDOUT; - } - } - - return rc; -} - -struct mwl8k_start_worker { - struct mwl8k_work_struct header; -}; - -static int mwl8k_start_wt(struct work_struct *wt) -{ - struct mwl8k_start_worker *worker = (struct mwl8k_start_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - struct mwl8k_priv *priv = hw->priv; - int rc = 0; - - if (priv->vif != NULL) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Turn on radio */ - if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Purge TX/RX HW queues */ - if (mwl8k_cmd_set_pre_scan(hw)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - if (mwl8k_cmd_set_post_scan(hw, "\x00\x00\x00\x00\x00\x00")) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Enable firmware rate adaptation */ - if (mwl8k_cmd_setrateadaptmode(hw, 0)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Disable WMM. WMM gets enabled when stack sends WMM parms */ - if (mwl8k_set_wmm(hw, MWL8K_WMM_DISABLE)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Disable sniffer mode */ - if (mwl8k_enable_sniffer(hw, 0)) - rc = -EIO; - -mwl8k_start_exit: - return rc; -} - static int mwl8k_start(struct ieee80211_hw *hw) { - struct mwl8k_start_worker *worker; struct mwl8k_priv *priv = hw->priv; int rc; - /* Enable tx reclaim tasklet */ - tasklet_enable(&priv->tx_reclaim_task); - rc = request_irq(priv->pdev->irq, &mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { printk(KERN_ERR "%s: failed to register IRQ handler\n", priv->name); - rc = -EIO; - goto mwl8k_start_disable_tasklet; + return -EIO; } - /* Enable interrupts */ - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) { - rc = -ENOMEM; - goto mwl8k_start_disable_irq; - } + /* Enable tx reclaim tasklet */ + tasklet_enable(&priv->tx_reclaim_task); - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_start_wt); - kfree(worker); - if (!rc) - return rc; + /* Enable interrupts */ + iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); + rc = mwl8k_fw_lock(hw); + if (!rc) { + rc = mwl8k_cmd_802_11_radio_enable(hw); - rc = -EIO; + if (!rc) + rc = mwl8k_cmd_set_pre_scan(hw); -mwl8k_start_disable_irq: - spin_lock_irq(&priv->tx_lock); - iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); - free_irq(priv->pdev->irq, hw); + if (!rc) + rc = mwl8k_cmd_set_post_scan(hw, + "\x00\x00\x00\x00\x00\x00"); -mwl8k_start_disable_tasklet: - tasklet_disable(&priv->tx_reclaim_task); + if (!rc) + rc = mwl8k_cmd_setrateadaptmode(hw, 0); - return rc; -} + if (!rc) + rc = mwl8k_set_wmm(hw, 0); -struct mwl8k_stop_worker { - struct mwl8k_work_struct header; -}; + if (!rc) + rc = mwl8k_enable_sniffer(hw, 0); -static int mwl8k_stop_wt(struct work_struct *wt) -{ - struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - int rc; + mwl8k_fw_unlock(hw); + } - rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); + if (rc) { + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + free_irq(priv->pdev->irq, hw); + tasklet_disable(&priv->tx_reclaim_task); + } return rc; } static void mwl8k_stop(struct ieee80211_hw *hw) { - int rc; - struct mwl8k_stop_worker *worker; struct mwl8k_priv *priv = hw->priv; int i; - if (priv->vif != NULL) - return; + mwl8k_cmd_802_11_radio_disable(hw); ieee80211_stop_queues(hw); - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return; - - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_stop_wt); - kfree(worker); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); - /* Disable interrupts */ - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); /* Stop finalize join worker */ @@ -2978,8 +2520,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, /* * We only support managed interfaces for now. */ - if (conf->type != NL80211_IFTYPE_STATION && - conf->type != NL80211_IFTYPE_MONITOR) + if (conf->type != NL80211_IFTYPE_STATION) return -EINVAL; /* Clean out driver private area */ @@ -2987,13 +2528,13 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); /* Save the mac address */ - memcpy(mwl8k_vif->mac_addr, conf->mac_addr, IEEE80211_ADDR_LEN); + memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); /* Back pointer to parent config block */ mwl8k_vif->priv = priv; /* Setup initial PHY parameters */ - memcpy(mwl8k_vif->legacy_rates , + memcpy(mwl8k_vif->legacy_rates, priv->rates, sizeof(mwl8k_vif->legacy_rates)); mwl8k_vif->legacy_nrates = ARRAY_SIZE(priv->rates); @@ -3017,213 +2558,148 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, priv->vif = NULL; } -struct mwl8k_config_worker { - struct mwl8k_work_struct header; - u32 changed; -}; - -static int mwl8k_config_wt(struct work_struct *wt) +static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) { - struct mwl8k_config_worker *worker = - (struct mwl8k_config_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; struct ieee80211_conf *conf = &hw->conf; struct mwl8k_priv *priv = hw->priv; - int rc = 0; + int rc; - if (!conf->radio_enabled) { - mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); + if (conf->flags & IEEE80211_CONF_IDLE) { + mwl8k_cmd_802_11_radio_disable(hw); priv->current_channel = NULL; - rc = 0; - goto mwl8k_config_exit; + return 0; } - if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_fw_lock(hw); + if (rc) + return rc; - priv->current_channel = conf->channel; + rc = mwl8k_cmd_802_11_radio_enable(hw); + if (rc) + goto out; - if (mwl8k_cmd_set_rf_channel(hw, conf->channel)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_cmd_set_rf_channel(hw, conf->channel); + if (rc) + goto out; + + priv->current_channel = conf->channel; if (conf->power_level > 18) conf->power_level = 18; - if (mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level); + if (rc) + goto out; if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7)) rc = -EINVAL; -mwl8k_config_exit: +out: + mwl8k_fw_unlock(hw); + return rc; } -static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) +static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) { - int rc = 0; - struct mwl8k_config_worker *worker; struct mwl8k_priv *priv = hw->priv; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->changed = changed; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_config_wt); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out.\n", __func__); - rc = -EINVAL; - } - - kfree(worker); - - /* - * mac80211 will crash on anything other than -EINVAL on - * error. Looks like wireless extensions which calls mac80211 - * may be the actual culprit... - */ - return rc ? -EINVAL : 0; -} - -struct mwl8k_bss_info_changed_worker { - struct mwl8k_work_struct header; - struct ieee80211_vif *vif; - struct ieee80211_bss_conf *info; - u32 changed; -}; - -static int mwl8k_bss_info_changed_wt(struct work_struct *wt) -{ - struct mwl8k_bss_info_changed_worker *worker = - (struct mwl8k_bss_info_changed_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - struct ieee80211_vif *vif = worker->vif; - struct ieee80211_bss_conf *info = worker->info; - u32 changed; + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); int rc; - struct mwl8k_priv *priv = hw->priv; - struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); + if (changed & BSS_CHANGED_BSSID) + memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN); + + if ((changed & BSS_CHANGED_ASSOC) == 0) + return; - changed = worker->changed; priv->capture_beacon = false; + rc = mwl8k_fw_lock(hw); + if (!rc) + return; + if (info->assoc) { memcpy(&mwl8k_vif->bss_info, info, sizeof(struct ieee80211_bss_conf)); /* Install rates */ - if (mwl8k_update_rateset(hw, vif)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_update_rateset(hw, vif); + if (rc) + goto out; /* Turn on rate adaptation */ - if (mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, - MWL8K_UCAST_RATE, NULL)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, + MWL8K_UCAST_RATE, NULL); + if (rc) + goto out; /* Set radio preamble */ - if (mwl8k_set_radio_preamble(hw, - info->use_short_preamble)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble); + if (rc) + goto out; /* Set slot time */ - if (mwl8k_cmd_set_slot(hw, info->use_short_slot ? - MWL8K_SHORT_SLOTTIME : MWL8K_LONG_SLOTTIME)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_set_slot(hw, info->use_short_slot); + if (rc) + goto out; /* Update peer rate info */ - if (mwl8k_cmd_update_sta_db(hw, vif, - MWL8K_STA_DB_MODIFY_ENTRY)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_update_sta_db(hw, vif, + MWL8K_STA_DB_MODIFY_ENTRY); + if (rc) + goto out; /* Set AID */ - if (mwl8k_cmd_set_aid(hw, vif)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_set_aid(hw, vif); + if (rc) + goto out; /* * Finalize the join. Tell rx handler to process * next beacon from our BSSID. */ - memcpy(priv->capture_bssid, - mwl8k_vif->bssid, IEEE80211_ADDR_LEN); + memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); priv->capture_beacon = true; } else { - mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); + rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); memset(&mwl8k_vif->bss_info, 0, sizeof(struct ieee80211_bss_conf)); - memset(mwl8k_vif->bssid, 0, IEEE80211_ADDR_LEN); + memset(mwl8k_vif->bssid, 0, ETH_ALEN); } -mwl8k_bss_info_changed_exit: - rc = 0; - return rc; +out: + mwl8k_fw_unlock(hw); } -static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) +static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) { - struct mwl8k_bss_info_changed_worker *worker; - struct mwl8k_priv *priv = hw->priv; - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - int rc; - - if (changed & BSS_CHANGED_BSSID) - memcpy(mv_vif->bssid, info->bssid, IEEE80211_ADDR_LEN); - - if ((changed & BSS_CHANGED_ASSOC) == 0) - return; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return; + struct mwl8k_cmd_pkt *cmd; - worker->vif = vif; - worker->info = info; - worker->changed = changed; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, - mwl8k_bss_info_changed_wt); - kfree(worker); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); -} - -struct mwl8k_configure_filter_worker { - struct mwl8k_work_struct header; - unsigned int changed_flags; - unsigned int *total_flags; - int mc_count; - struct dev_addr_list *mclist; -}; + cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); -#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC + return (unsigned long)cmd; +} -static int mwl8k_configure_filter_wt(struct work_struct *wt) +static void mwl8k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) { - struct mwl8k_configure_filter_worker *worker = - (struct mwl8k_configure_filter_worker *)wt; + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_cmd_pkt *multicast_adr_cmd; - struct ieee80211_hw *hw = worker->header.hw; - unsigned int changed_flags = worker->changed_flags; - unsigned int *total_flags = worker->total_flags; - int mc_count = worker->mc_count; - struct dev_addr_list *mclist = worker->mclist; + /* Clear unsupported feature flags */ + *total_flags &= FIF_BCN_PRBRESP_PROMISC; - struct mwl8k_priv *priv = hw->priv; - int rc = 0; + if (mwl8k_fw_lock(hw)) + return; if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - rc = mwl8k_cmd_set_pre_scan(hw); + mwl8k_cmd_set_pre_scan(hw); else { u8 *bssid; @@ -3231,151 +2707,45 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) if (priv->vif != NULL) bssid = MWL8K_VIF(priv->vif)->bssid; - rc = mwl8k_cmd_set_post_scan(hw, bssid); + mwl8k_cmd_set_post_scan(hw, bssid); } } - if (rc) - goto mwl8k_configure_filter_exit; - if (mc_count) { - mc_count = mc_count < priv->num_mcaddrs ? - mc_count : priv->num_mcaddrs; - rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); - if (rc) - printk(KERN_ERR - "%s()Error setting multicast addresses\n", - __func__); + multicast_adr_cmd = (void *)(unsigned long)multicast; + if (multicast_adr_cmd != NULL) { + mwl8k_post_cmd(hw, multicast_adr_cmd); + kfree(multicast_adr_cmd); } -mwl8k_configure_filter_exit: - return rc; -} - -static void mwl8k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mclist) -{ - - struct mwl8k_configure_filter_worker *worker; - struct mwl8k_priv *priv = hw->priv; - - /* Clear unsupported feature flags */ - *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; - - if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS) && !mc_count) - return; - - worker = kzalloc(sizeof(*worker), GFP_ATOMIC); - if (worker == NULL) - return; - - worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY; - worker->changed_flags = changed_flags; - worker->total_flags = total_flags; - worker->mc_count = mc_count; - worker->mclist = mclist; - - mwl8k_queue_work(hw, &worker->header, priv->config_wq, - mwl8k_configure_filter_wt); -} - -struct mwl8k_set_rts_threshold_worker { - struct mwl8k_work_struct header; - u32 value; -}; - -static int mwl8k_set_rts_threshold_wt(struct work_struct *wt) -{ - struct mwl8k_set_rts_threshold_worker *worker = - (struct mwl8k_set_rts_threshold_worker *)wt; - - struct ieee80211_hw *hw = worker->header.hw; - u16 threshold = (u16)(worker->value); - int rc; - - rc = mwl8k_rts_threshold(hw, MWL8K_CMD_SET, &threshold); - - return rc; + mwl8k_fw_unlock(hw); } static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - int rc; - struct mwl8k_set_rts_threshold_worker *worker; - struct mwl8k_priv *priv = hw->priv; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->value = value; - - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, - mwl8k_set_rts_threshold_wt); - kfree(worker); - - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; - } - - return rc; -} - -struct mwl8k_conf_tx_worker { - struct mwl8k_work_struct header; - u16 queue; - const struct ieee80211_tx_queue_params *params; -}; - -static int mwl8k_conf_tx_wt(struct work_struct *wt) -{ - struct mwl8k_conf_tx_worker *worker = - (struct mwl8k_conf_tx_worker *)wt; - - struct ieee80211_hw *hw = worker->header.hw; - u16 queue = worker->queue; - const struct ieee80211_tx_queue_params *params = worker->params; - - struct mwl8k_priv *priv = hw->priv; - int rc = 0; - - if (priv->wmm_mode == MWL8K_WMM_DISABLE) - if (mwl8k_set_wmm(hw, MWL8K_WMM_ENABLE)) { - rc = -EINVAL; - goto mwl8k_conf_tx_exit; - } - - if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min, - params->cw_max, params->aifs, params->txop)) - rc = -EINVAL; -mwl8k_conf_tx_exit: - return rc; + return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value); } static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { - int rc; - struct mwl8k_conf_tx_worker *worker; struct mwl8k_priv *priv = hw->priv; + int rc; - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; + rc = mwl8k_fw_lock(hw); + if (!rc) { + if (!priv->wmm_enabled) + rc = mwl8k_set_wmm(hw, 1); - worker->queue = queue; - worker->params = params; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_conf_tx_wt); - kfree(worker); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; + if (!rc) + rc = mwl8k_set_edca_params(hw, queue, + params->cw_min, + params->cw_max, + params->aifs, + params->txop); + + mwl8k_fw_unlock(hw); } + return rc; } @@ -3393,44 +2763,14 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw, sizeof(struct ieee80211_tx_queue_stats)); } spin_unlock_bh(&priv->tx_lock); - return 0; -} - -struct mwl8k_get_stats_worker { - struct mwl8k_work_struct header; - struct ieee80211_low_level_stats *stats; -}; - -static int mwl8k_get_stats_wt(struct work_struct *wt) -{ - struct mwl8k_get_stats_worker *worker = - (struct mwl8k_get_stats_worker *)wt; - return mwl8k_cmd_802_11_get_stat(worker->header.hw, worker->stats); + return 0; } static int mwl8k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { - int rc; - struct mwl8k_get_stats_worker *worker; - struct mwl8k_priv *priv = hw->priv; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->stats = stats; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_get_stats_wt); - - kfree(worker); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; - } - - return rc; + return mwl8k_cmd_802_11_get_stat(hw, stats); } static const struct ieee80211_ops mwl8k_ops = { @@ -3441,6 +2781,7 @@ static const struct ieee80211_ops mwl8k_ops = { .remove_interface = mwl8k_remove_interface, .config = mwl8k_config, .bss_info_changed = mwl8k_bss_info_changed, + .prepare_multicast = mwl8k_prepare_multicast, .configure_filter = mwl8k_configure_filter, .set_rts_threshold = mwl8k_set_rts_threshold, .conf_tx = mwl8k_conf_tx, @@ -3458,12 +2799,9 @@ static void mwl8k_tx_reclaim_handler(unsigned long data) for (i = 0; i < MWL8K_TX_QUEUES; i++) mwl8k_txq_reclaim(hw, i, 0); - if (priv->tx_wait != NULL) { - int count = mwl8k_txq_busy(priv); - if (count == 0) { - complete(priv->tx_wait); - priv->tx_wait = NULL; - } + if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) { + complete(priv->tx_wait); + priv->tx_wait = NULL; } spin_unlock_bh(&priv->tx_lock); } @@ -3473,7 +2811,7 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, finalize_join_worker); struct sk_buff *skb = priv->beacon_skb; - u8 dtim = (MWL8K_VIF(priv->vif))->bss_info.dtim_period; + u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period; mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim); dev_kfree_skb(skb); @@ -3516,16 +2854,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv = hw->priv; priv->hw = hw; priv->pdev = pdev; - priv->hostcmd_wait = NULL; - priv->tx_wait = NULL; - priv->inconfig = false; - priv->wep_enabled = 0; - priv->wmm_mode = false; + priv->wmm_enabled = false; priv->pending_tx_pkts = 0; strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); - spin_lock_init(&priv->fw_lock); - SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); @@ -3557,17 +2889,16 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, hw->queues = MWL8K_TX_QUEUES; - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR); + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); /* Set rssi and noise values to dBm */ - hw->flags |= (IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM); + hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->vif_data_size = sizeof(struct mwl8k_vif); priv->vif = NULL; /* Set default radio state and preamble */ - priv->radio_preamble = MWL8K_RADIO_DEFAULT_PREAMBLE; - priv->radio_state = MWL8K_RADIO_DISABLE; + priv->radio_on = 0; + priv->radio_short_preamble = 0; /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); @@ -3592,6 +2923,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_iounmap; rxq_refill(hw, 0, INT_MAX); + mutex_init(&priv->fw_mutex); + priv->fw_mutex_owner = NULL; + priv->fw_mutex_depth = 0; + priv->tx_wait = NULL; + priv->hostcmd_wait = NULL; + spin_lock_init(&priv->tx_lock); for (i = 0; i < MWL8K_TX_QUEUES; i++) { @@ -3601,8 +2938,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - priv->int_mask = 0; - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); @@ -3639,9 +2975,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, * commands use interrupts and avoids polling. Disable * interrupts when done. */ - priv->int_mask |= MWL8K_A2H_EVENTS; - - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); /* Get config data, mac addrs etc */ rc = mwl8k_cmd_get_hw_spec(hw); @@ -3651,16 +2985,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } /* Turn radio off */ - rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); + rc = mwl8k_cmd_802_11_radio_disable(hw); if (rc) { printk(KERN_ERR "%s: Cannot disable\n", priv->name); goto err_stop_firmware; } /* Disable interrupts */ - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); rc = ieee80211_register_hw(hw); @@ -3684,9 +3016,7 @@ err_stop_firmware: mwl8k_release_firmware(priv); err_free_irq: - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); err_free_queues: diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 3e56f7643df5..7698fdd6a3a2 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1291,7 +1291,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - priv->ibss_port = val ; + priv->ibss_port = val; /* Actually update the mode we are using */ set_port_type(priv); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 4a741df9c081..4d486bf9f725 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -302,7 +302,7 @@ out: static void p54_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct p54_common *priv = dev->priv; @@ -575,6 +575,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + sizeof(struct p54_tx_data); + /* + * For now, disable PS by default because it affects + * link stability significantly. + */ + dev->wiphy->ps_default = false; + mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); init_completion(&priv->eeprom_comp); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 09a589432dab..b04f59bab3b0 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1874,7 +1874,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); if (!modparam_nohwcrypt) { __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3856f06fdca7..639dc6cc04b9 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1463,6 +1463,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) /* * ASIC will keep garbage value after boot, clear encryption keys. */ + for (i = 0; i < 4; i++) + rt2x00usb_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); + for (i = 0; i < 256; i++) { u32 wcid[2] = { 0xffffffff, 0x00ffffff }; rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), @@ -1472,10 +1476,6 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); } - for (i = 0; i < 16; i++) - rt2x00usb_register_write(rt2x00dev, - SHARED_KEY_MODE_ENTRY(i), 0); - /* * Clear all beacons * For the Beacon base registers we only need to clear @@ -1520,7 +1520,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, ®); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 3); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); @@ -1995,11 +1995,11 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? - txdesc->key_idx : 0xff); + (skbdesc->entry->entry_idx + 1) : 0xff); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, skb->len - txdesc->l2pad); rt2x00_set_field32(&word, TXWI_W1_PACKETID, - skbdesc->entry->entry_idx); + skbdesc->entry->queue->qid + 1); rt2x00_desc_write(txwi, 1, word); /* @@ -2163,8 +2163,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) + if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) { rxdesc->dev_flags |= RXDONE_L2PAD; + skbdesc->flags |= SKBDESC_L2_PADDED; + } if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) rxdesc->flags |= RX_FLAG_SHORT_GI; @@ -2632,7 +2634,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 2d9dc3783361..4d9991c9a51c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -36,6 +36,9 @@ * RF2750 2.4G/5G 1T2R * RF3020 2.4G 1T1R * RF2020 2.4G B/G + * RF3021 2.4G 1T2R + * RF3022 2.4G 2T2R + * RF3052 2.4G 2T2R */ #define RF2820 0x0001 #define RF2850 0x0002 @@ -43,6 +46,9 @@ #define RF2750 0x0004 #define RF3020 0x0005 #define RF2020 0x0006 +#define RF3021 0x0007 +#define RF3022 0x0008 +#define RF3052 0x0009 /* * RT2870 version @@ -1300,8 +1306,8 @@ * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry - * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry - * SHARED_KEY_MODE_BASE: 4-byte * 16-entry + * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry + * SHARED_KEY_MODE_BASE: 4 bits * 32-entry */ #define MAC_WCID_BASE 0x1800 #define PAIRWISE_KEY_TABLE_BASE 0x4000 diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 99e89596cef6..555a777db6df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -350,8 +350,6 @@ struct rt2x00_intf { */ unsigned int delayed_flags; #define DELAYED_UPDATE_BEACON 0x00000001 -#define DELAYED_CONFIG_ERP 0x00000002 -#define DELAYED_LED_ASSOC 0x00000004 /* * Software sequence counter, this is only required @@ -614,7 +612,6 @@ enum rt2x00_flags { DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_BEACON_GUARD, DRIVER_REQUIRE_ATIM_QUEUE, - DRIVER_REQUIRE_SCHEDULED, DRIVER_REQUIRE_DMA, DRIVER_REQUIRE_COPY_IV, DRIVER_REQUIRE_L2PAD, @@ -826,7 +823,6 @@ struct rt2x00_dev { * due to RTNL locking requirements. */ struct work_struct intf_work; - struct work_struct filter_work; /* * Data queue arrays for RX, TX and Beacon. @@ -978,7 +974,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + u64 multicast); int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); #ifdef CONFIG_RT2X00_LIB_CRYPTO diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b6676c6722fc..3f8c70ebe9ad 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -118,20 +118,11 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) rt2x00link_start_tuner(rt2x00dev); } -static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) -{ - struct rt2x00_dev *rt2x00dev = - container_of(work, struct rt2x00_dev, filter_work); - - rt2x00dev->ops->lib->config_filter(rt2x00dev, rt2x00dev->packet_filter); -} - static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); - struct ieee80211_bss_conf conf; int delayed_flags; /* @@ -141,7 +132,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, */ spin_lock(&intf->lock); - memcpy(&conf, &vif->bss_conf, sizeof(conf)); delayed_flags = intf->delayed_flags; intf->delayed_flags = 0; @@ -158,12 +148,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, if (delayed_flags & DELAYED_UPDATE_BEACON) rt2x00queue_update_beacon(rt2x00dev, vif, true); - - if (delayed_flags & DELAYED_CONFIG_ERP) - rt2x00lib_config_erp(rt2x00dev, intf, &conf); - - if (delayed_flags & DELAYED_LED_ASSOC) - rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); } static void rt2x00lib_intf_scheduled(struct work_struct *work) @@ -220,7 +204,8 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - u8 rate_idx, rate_flags; + u8 rate_idx, rate_flags, retry_rates; + unsigned int i; /* * Unmap the skb. @@ -259,16 +244,27 @@ void rt2x00lib_txdone(struct queue_entry *entry, rate_idx = skbdesc->tx_rate_idx; rate_flags = skbdesc->tx_rate_flags; + retry_rates = test_bit(TXDONE_FALLBACK, &txdesc->flags) ? + (txdesc->retry + 1) : 1; /* * Initialize TX status */ memset(&tx_info->status, 0, sizeof(tx_info->status)); tx_info->status.ack_signal = 0; - tx_info->status.rates[0].idx = rate_idx; - tx_info->status.rates[0].flags = rate_flags; - tx_info->status.rates[0].count = txdesc->retry + 1; - tx_info->status.rates[1].idx = -1; /* terminate */ + + /* + * Frame was send with retries, hardware tried + * different rates to send out the frame, at each + * retry it lowered the rate 1 step. + */ + for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) { + tx_info->status.rates[i].idx = rate_idx - i; + tx_info->status.rates[i].flags = rate_flags; + tx_info->status.rates[i].count = 1; + } + if (i < (IEEE80211_TX_MAX_RATES -1)) + tx_info->status.rates[i].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || @@ -847,7 +843,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) * Initialize configuration work. */ INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); - INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); /* * Allocate queue array. @@ -895,7 +890,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Stop all work. */ - cancel_work_sync(&rt2x00dev->filter_work); cancel_work_sync(&rt2x00dev->intf_work); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index cb7b6d459331..a91f316cd452 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -379,7 +379,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_config); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -430,10 +430,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, return; rt2x00dev->packet_filter = *total_flags; - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); - else - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->filter_work); + rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); @@ -639,23 +636,15 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, else rt2x00dev->intf_associated--; - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00leds_led_assoc(rt2x00dev, - !!rt2x00dev->intf_associated); - else - delayed |= DELAYED_LED_ASSOC; + rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); } /* * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. */ - if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); - else - delayed |= DELAYED_CONFIG_ERP; - } + if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) + rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); spin_lock(&intf->lock); if (delayed) { @@ -704,8 +693,8 @@ EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); - wiphy_rfkill_set_hw_state(hw->wiphy, blocked); + wiphy_rfkill_set_hw_state(hw->wiphy, !active); } EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 47d175a13790..a5591fb2b191 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -214,6 +214,7 @@ struct rxdone_entry_desc { * * @TXDONE_UNKNOWN: Hardware could not determine success of transmission. * @TXDONE_SUCCESS: Frame was successfully send + * @TXDONE_FALLBACK: Frame was successfully send using a fallback rate. * @TXDONE_FAILURE: Frame was not successfully send * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the * frame transmission failed due to excessive retries. @@ -221,6 +222,7 @@ struct rxdone_entry_desc { enum txdone_entry_desc_flags { TXDONE_UNKNOWN, TXDONE_SUCCESS, + TXDONE_FALLBACK, TXDONE_FAILURE, TXDONE_EXCESSIVE_RETRY, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4d94b65943f1..90e117263051 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2151,7 +2151,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 09f46abc730a..16429c49139c 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -728,10 +728,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, priv->rf->conf_erp(dev, info); } +static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count, + struct dev_addr_list *mc_list) +{ + return mc_count; +} + static void rtl8180_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) + u64 multicast) { struct rtl8180_priv *priv = dev->priv; @@ -741,7 +747,7 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev, priv->rx_conf ^= RTL818X_RX_CONF_CTRL; if (changed_flags & FIF_OTHER_BSS) priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) + if (*total_flags & FIF_ALLMULTI || multicast > 0) priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; else priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; @@ -768,6 +774,7 @@ static const struct ieee80211_ops rtl8180_ops = { .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, .bss_info_changed = rtl8180_bss_info_changed, + .prepare_multicast = rtl8180_prepare_multicast, .configure_filter = rtl8180_configure_filter, }; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 53f57dc52226..90f38357393c 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1192,10 +1192,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, info->use_short_preamble); } +static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev, + int mc_count, struct dev_addr_list *mc_list) +{ + return mc_count; +} + static void rtl8187_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) + u64 multicast) { struct rtl8187_priv *priv = dev->priv; @@ -1205,7 +1211,7 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, priv->rx_conf ^= RTL818X_RX_CONF_CTRL; if (changed_flags & FIF_OTHER_BSS) priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) + if (*total_flags & FIF_ALLMULTI || multicast > 0) priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; else priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; @@ -1268,6 +1274,7 @@ static const struct ieee80211_ops rtl8187_ops = { .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .bss_info_changed = rtl8187_bss_info_changed, + .prepare_multicast = rtl8187_prepare_multicast, .configure_filter = rtl8187_configure_filter, .conf_tx = rtl8187_conf_tx }; diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 592c3b5cc8f8..452d748e42c6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -465,6 +465,9 @@ int wl1251_boot(struct wl1251 *wl) int ret = 0, minor_minor_e2_ver; u32 tmp, boot_data; + /* halt embedded ARM CPU while loading firmware */ + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT); + ret = wl1251_boot_soft_reset(wl); if (ret < 0) goto out; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 7148934e464d..5809ef5b18f8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -652,9 +652,7 @@ out: static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total,u64 multicast) { struct wl1251 *wl = hw->priv; diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h index bdd561001dcb..06e1bd94a739 100644 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h @@ -245,8 +245,8 @@ enum wl12xx_acx_int_reg { ACX_REG_TABLE_LEN }; -#define ACX_SLV_SOFT_RESET_BIT BIT(1) -#define ACX_REG_EEPROM_START_BIT BIT(1) +#define ACX_SLV_SOFT_RESET_BIT BIT(0) +#define ACX_REG_EEPROM_START_BIT BIT(0) /* Command/Information Mailbox Pointers */ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 4102d590b798..d9169b47ac42 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -605,11 +605,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct wl1271 *wl = hw->priv; - DECLARE_MAC_BUF(mac); int ret = 0; - wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", - conf->type, print_mac(mac, conf->mac_addr)); + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + conf->type, conf->mac_addr); mutex_lock(&wl->mutex); @@ -793,9 +792,7 @@ out: static void wl1271_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total,u64 multicast) { struct wl1271 *wl = hw->priv; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 55b7fbdc85dc..6d666359a42f 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -796,18 +796,40 @@ static void set_rx_filter_handler(struct work_struct *work) dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); } +static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct zd_mac *mac = zd_hw_mac(hw); + struct zd_mc_hash hash; + int i; + + zd_mc_clear(&hash); + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr); + zd_mc_add_addr(&hash, mclist->dmi_addr); + mclist = mclist->next; + } + + return hash.low | ((u64)hash.high << 32); +} + #define SUPPORTED_FIF_FLAGS \ (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC) static void zd_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { - struct zd_mc_hash hash; + struct zd_mc_hash hash = { + .low = multicast, + .high = multicast >> 32, + }; struct zd_mac *mac = zd_hw_mac(hw); unsigned long flags; - int i; /* Only deal with supported flags */ changed_flags &= SUPPORTED_FIF_FLAGS; @@ -819,25 +841,16 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, if (!changed_flags) return; - if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { + if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) zd_mc_add_all(&hash); - } else { - zd_mc_clear(&hash); - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", - mclist->dmi_addr); - zd_mc_add_addr(&hash, mclist->dmi_addr); - mclist = mclist->next; - } - } spin_lock_irqsave(&mac->lock, flags); mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL); mac->pass_ctrl = !!(*new_flags & FIF_CONTROL); mac->multicast_hash = hash; spin_unlock_irqrestore(&mac->lock, flags); + + /* XXX: these can be called here now, can sleep now! */ queue_work(zd_workqueue, &mac->set_multicast_hash_work); if (changed_flags & FIF_CONTROL) @@ -940,6 +953,7 @@ static const struct ieee80211_ops zd_ops = { .add_interface = zd_op_add_interface, .remove_interface = zd_op_remove_interface, .config = zd_op_config, + .prepare_multicast = zd_op_prepare_multicast, .configure_filter = zd_op_configure_filter, .bss_info_changed = zd_op_bss_info_changed, .get_tsf = zd_op_get_tsf, diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 593fc618a2ea..f853d5600ca7 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -480,7 +480,7 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) /* extract the MAC address */ for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; + v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0b146bb2dd14..3d874c620219 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1325,6 +1325,8 @@ struct wireless_dev { struct mutex mtx; + struct work_struct cleanup_work; + /* currently used for IBSS and SME - might be rearranged later */ u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 76d43e12cc29..aac84d7bd46e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -583,7 +583,6 @@ enum ieee80211_conf_flags { /** * enum ieee80211_conf_changed - denotes which configuration changed * - * @_IEEE80211_CONF_CHANGE_RADIO_ENABLED: DEPRECATED * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed @@ -593,7 +592,6 @@ enum ieee80211_conf_flags { * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed */ enum ieee80211_conf_changed { - _IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), @@ -603,14 +601,6 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_IDLE = BIT(8), }; -static inline __deprecated enum ieee80211_conf_changed -__IEEE80211_CONF_CHANGE_RADIO_ENABLED(void) -{ - return _IEEE80211_CONF_CHANGE_RADIO_ENABLED; -} -#define IEEE80211_CONF_CHANGE_RADIO_ENABLED \ - __IEEE80211_CONF_CHANGE_RADIO_ENABLED() - /** * struct ieee80211_conf - configuration of the device * @@ -618,9 +608,6 @@ __IEEE80211_CONF_CHANGE_RADIO_ENABLED(void) * * @flags: configuration flags defined above * - * @radio_enabled: when zero, driver is required to switch off the radio. - * @beacon_int: DEPRECATED, DO NOT USE - * * @listen_interval: listen interval in units of beacon interval * @max_sleep_period: the maximum number of beacon intervals to sleep for * before checking the beacon for a TIM bit (managed mode only); this @@ -644,13 +631,11 @@ __IEEE80211_CONF_CHANGE_RADIO_ENABLED(void) * number of transmissions not the number of retries */ struct ieee80211_conf { - int __deprecated beacon_int; u32 flags; int power_level, dynamic_ps_timeout; int max_sleep_period; u16 listen_interval; - bool __deprecated radio_enabled; u8 long_frame_max_tx_count, short_frame_max_tx_count; @@ -1219,10 +1204,13 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * the driver's configure_filter() function which frames should be * passed to mac80211 and which should be filtered out. * - * The configure_filter() callback is invoked with the parameters - * @mc_count and @mc_list for the combined multicast address list - * of all virtual interfaces, @changed_flags telling which flags - * were changed and @total_flags with the new flag states. + * Before configure_filter() is invoked, the prepare_multicast() + * callback is invoked with the parameters @mc_count and @mc_list + * for the combined multicast address list of all virtual interfaces. + * It's use is optional, and it returns a u64 that is passed to + * configure_filter(). Additionally, configure_filter() has the + * arguments @changed_flags telling which flags were changed and + * @total_flags with the new flag states. * * If your device has no multicast address filters your driver will * need to check both the %FIF_ALLMULTI flag and the @mc_count @@ -1375,9 +1363,13 @@ enum ieee80211_ampdu_mlme_action { * for association indication. The @changed parameter indicates which * of the bss parameters has changed when a call is made. * + * @prepare_multicast: Prepare for multicast filter configuration. + * This callback is optional, and its return value is passed + * to configure_filter(). This callback must be atomic. + * * @configure_filter: Configure the device's RX filter. * See the section "Frame filtering" for more information. - * This callback must be implemented and atomic. + * This callback must be implemented. * * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit * must be set or cleared for a given STA. Must be atomic. @@ -1479,10 +1471,12 @@ struct ieee80211_ops { struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed); + u64 (*prepare_multicast)(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mc_list); void (*configure_filter)(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + u64 multicast); int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e9ec6cae2d39..61234e79022b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -116,6 +116,8 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); #ifdef CONFIG_MAC80211_MESH /* Mesh stats attributes */ +IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC); +IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); IEEE80211_IF_FILE(dropped_frames_no_route, @@ -205,6 +207,8 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) { sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", sdata->debugfsdir); + MESHSTATS_ADD(fwded_mcast); + MESHSTATS_ADD(fwded_unicast); MESHSTATS_ADD(fwded_frames); MESHSTATS_ADD(dropped_frames_ttl); MESHSTATS_ADD(dropped_frames_no_route); @@ -327,6 +331,8 @@ static void del_monitor_files(struct ieee80211_sub_if_data *sdata) static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) { + MESHSTATS_DEL(fwded_mcast); + MESHSTATS_DEL(fwded_unicast); MESHSTATS_DEL(fwded_frames); MESHSTATS_DEL(dropped_frames_ttl); MESHSTATS_DEL(dropped_frames_no_route); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4100c361a99d..d231c9323ad1 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -55,16 +55,32 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, trace_drv_bss_info_changed(local, vif, info, changed); } +static inline u64 drv_prepare_multicast(struct ieee80211_local *local, + int mc_count, + struct dev_addr_list *mc_list) +{ + u64 ret = 0; + + if (local->ops->prepare_multicast) + ret = local->ops->prepare_multicast(&local->hw, mc_count, + mc_list); + + trace_drv_prepare_multicast(local, mc_count, ret); + + return ret; +} + static inline void drv_configure_filter(struct ieee80211_local *local, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) + u64 multicast) { + might_sleep(); + local->ops->configure_filter(&local->hw, changed_flags, total_flags, - mc_count, mc_list); + multicast); trace_drv_configure_filter(local, changed_flags, total_flags, - mc_count); + multicast); } static inline int drv_set_tim(struct ieee80211_local *local, diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 5a10da2d70fd..37b9051afcf3 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -191,31 +191,55 @@ TRACE_EVENT(drv_bss_info_changed, ) ); +TRACE_EVENT(drv_prepare_multicast, + TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret), + + TP_ARGS(local, mc_count, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, mc_count) + __field(u64, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->mc_count = mc_count; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " prepare mc (%d): %llx", + LOCAL_PR_ARG, __entry->mc_count, + (unsigned long long) __entry->ret + ) +); + TRACE_EVENT(drv_configure_filter, TP_PROTO(struct ieee80211_local *local, unsigned int changed_flags, unsigned int *total_flags, - int mc_count), + u64 multicast), - TP_ARGS(local, changed_flags, total_flags, mc_count), + TP_ARGS(local, changed_flags, total_flags, multicast), TP_STRUCT__entry( LOCAL_ENTRY __field(unsigned int, changed) __field(unsigned int, total) - __field(int, mc) + __field(u64, multicast) ), TP_fast_assign( LOCAL_ASSIGN; __entry->changed = changed_flags; __entry->total = *total_flags; - __entry->mc = mc_count; + __entry->multicast = multicast; ), TP_printk( - LOCAL_PR_FMT " changed:%#x total:%#x mc:%d", - LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc + LOCAL_PR_FMT " changed:%#x total:%#x", + LOCAL_PR_ARG, __entry->changed, __entry->total ) ); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a6abc7dfd903..93e618a980d1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -212,7 +212,9 @@ struct ieee80211_if_vlan { }; struct mesh_stats { - __u32 fwded_frames; /* Mesh forwarded frames */ + __u32 fwded_mcast; /* Mesh forwarded multicast frames */ + __u32 fwded_unicast; /* Mesh forwarded unicast frames */ + __u32 fwded_frames; /* Mesh total forwarded frames */ __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ __u32 dropped_frames_no_route; /* Not transmitted, no route found */ atomic_t estab_plinks; @@ -506,6 +508,8 @@ struct ieee80211_sub_if_data { #ifdef CONFIG_MAC80211_MESH struct dentry *mesh_stats_dir; struct { + struct dentry *fwded_mcast; + struct dentry *fwded_unicast; struct dentry *fwded_frames; struct dentry *dropped_frames_ttl; struct dentry *dropped_frames_no_route; @@ -636,6 +640,9 @@ struct ieee80211_local { /* protects the aggregated multicast list and filter calls */ spinlock_t filter_lock; + /* used for uploading changed mc list */ + struct work_struct reconfig_filter; + /* aggregated multicast list */ struct dev_addr_list *mc_list; int mc_count; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e8fb03b91a44..b161301056df 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -227,9 +227,7 @@ static int ieee80211_open(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); break; default: conf.vif = &sdata->vif; @@ -241,17 +239,13 @@ static int ieee80211_open(struct net_device *dev) if (ieee80211_vif_is_mesh(&sdata->vif)) { local->fif_other_bss++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); ieee80211_start_mesh(sdata); } else if (sdata->vif.type == NL80211_IFTYPE_AP) { local->fif_pspoll++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); } changed |= ieee80211_reset_erp_info(sdata); @@ -404,10 +398,11 @@ static int ieee80211_stop(struct net_device *dev) spin_lock_bh(&local->filter_lock); __dev_addr_unsync(&local->mc_list, &local->mc_count, &dev->mc_list, &dev->mc_count); - ieee80211_configure_filter(local); spin_unlock_bh(&local->filter_lock); netif_addr_unlock_bh(dev); + ieee80211_configure_filter(local); + del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -458,9 +453,7 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss--; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); break; case NL80211_IFTYPE_STATION: del_timer_sync(&sdata->u.mgd.chswitch_timer); @@ -503,9 +496,7 @@ static int ieee80211_stop(struct net_device *dev) local->fif_other_bss--; atomic_dec(&local->iff_allmultis); - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); ieee80211_stop_mesh(sdata); } @@ -622,8 +613,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev) spin_lock_bh(&local->filter_lock); __dev_addr_sync(&local->mc_list, &local->mc_count, &dev->mc_list, &dev->mc_count); - ieee80211_configure_filter(local); spin_unlock_bh(&local->filter_lock); + ieee80211_queue_work(&local->hw, &local->reconfig_filter); } /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b03fd84777fa..dd3b0816614d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr { } __attribute__ ((packed)); -/* must be called under mdev tx lock */ void ieee80211_configure_filter(struct ieee80211_local *local) { + u64 mc; unsigned int changed_flags; unsigned int new_flags = 0; @@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (atomic_read(&local->iff_allmultis)) new_flags |= FIF_ALLMULTI; - if (local->monitors) + if (local->monitors || local->scanning) new_flags |= FIF_BCN_PRBRESP_PROMISC; if (local->fif_fcsfail) @@ -80,20 +80,30 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (local->fif_pspoll) new_flags |= FIF_PSPOLL; + spin_lock_bh(&local->filter_lock); changed_flags = local->filter_flags ^ new_flags; + mc = drv_prepare_multicast(local, local->mc_count, local->mc_list); + spin_unlock_bh(&local->filter_lock); + /* be a bit nasty */ new_flags |= (1<<31); - drv_configure_filter(local, changed_flags, &new_flags, - local->mc_count, - local->mc_list); + drv_configure_filter(local, changed_flags, &new_flags, mc); WARN_ON(new_flags & (1<<31)); local->filter_flags = new_flags & ~(1<<31); } +static void ieee80211_reconfig_filter(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, reconfig_filter); + + ieee80211_configure_filter(local); +} + int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan, *scan_chan; @@ -231,9 +241,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, drv_bss_info_changed(local, &sdata->vif, &sdata->vif.bss_conf, changed); - - /* DEPRECATED */ - local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -475,6 +482,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } rate_control_tx_status(local, sband, sta, skb); + if (ieee80211_vif_is_mesh(&sta->sdata->vif)) + ieee80211s_update_metric(local, sta, skb); } rcu_read_unlock(); @@ -677,7 +686,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.max_rates = 1; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; - local->hw.conf.radio_enabled = true; local->user_power_level = -1; INIT_LIST_HEAD(&local->interfaces); @@ -692,6 +700,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_WORK(&local->restart_work, ieee80211_restart_work); + INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); + INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); INIT_WORK(&local->dynamic_ps_disable_work, @@ -920,7 +930,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: - kfree(local->int_scan_req->channels); + kfree(local->int_scan_req); return result; } EXPORT_SYMBOL(ieee80211_register_hw); @@ -946,6 +956,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rtnl_unlock(); + cancel_work_sync(&local->reconfig_filter); + ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index eb23fc639b2b..dd1c19319f0a 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -226,6 +226,8 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); void ieee80211s_init(void); +void ieee80211s_update_metric(struct ieee80211_local *local, + struct sta_info *stainfo, struct sk_buff *skb); void ieee80211s_stop(void); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index ef1efd362691..e12a786e26b8 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -201,6 +201,24 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, return 0; } +void ieee80211s_update_metric(struct ieee80211_local *local, + struct sta_info *stainfo, struct sk_buff *skb) +{ + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + int failed; + + if (!ieee80211_is_data(hdr->frame_control)) + return; + + failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); + + /* moving average, scaled to 100 */ + stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); + if (stainfo->fail_avg > 95) + mesh_plink_broken(stainfo); +} + static u32 airtime_link_metric_get(struct ieee80211_local *local, struct sta_info *sta) { @@ -479,6 +497,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); + ifmsh->mshstats.fwded_mcast++; ifmsh->mshstats.fwded_frames++; } } @@ -537,6 +556,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); rcu_read_unlock(); + + sdata->u.mesh.mshstats.fwded_unicast++; sdata->u.mesh.mshstats.fwded_frames++; return; diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 007164919e02..7c5142988bbb 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -51,7 +51,6 @@ #include <linux/random.h> #include <linux/ieee80211.h> #include <net/mac80211.h> -#include "mesh.h" #include "rate.h" #include "rc80211_minstrel.h" @@ -156,16 +155,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, struct sk_buff *skb) { struct minstrel_sta_info *mi = priv_sta; - struct minstrel_priv *mp = (struct minstrel_priv *)priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *ar = info->status.rates; - struct ieee80211_local *local = hw_to_local(mp->hw); - struct sta_info *si; int i, ndx; int success; success = !!(info->flags & IEEE80211_TX_STAT_ACK); - si = sta_info_get(local, sta->addr); for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { if (ar[i].idx < 0) @@ -177,17 +172,8 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, mi->r[ndx].attempts += ar[i].count; - if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { + if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) mi->r[ndx].success += success; - if (si) { - si->fail_avg = (18050 - mi->r[ndx].probability) - / 180; - WARN_ON(si->fail_avg > 100); - if (si->fail_avg == 100 && - ieee80211_vif_is_mesh(&si->sdata->vif)) - mesh_plink_broken(si); - } - } } if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 8c053be9dc24..699d3ed869c4 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -169,19 +169,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, * still a good measurement and copy it. */ if (unlikely(spinfo->tx_num_xmit == 0)) pf = spinfo->last_pf; - else { - /* XXX: BAD HACK!!! */ - struct sta_info *si = container_of(sta, struct sta_info, sta); - + else pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; - if (ieee80211_vif_is_mesh(&si->sdata->vif) && pf == 100) - mesh_plink_broken(si); - pf <<= RC_PID_ARITH_SHIFT; - si->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9) - >> RC_PID_ARITH_SHIFT; - } - spinfo->tx_num_xmit = 0; spinfo->tx_num_failed = 0; @@ -311,7 +301,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, struct rc_pid_sta_info *spinfo = priv_sta; struct rc_pid_info *pinfo = priv; struct rc_pid_rateinfo *rinfo = pinfo->rinfo; - struct sta_info *si; int i, j, tmp; bool s; @@ -348,9 +337,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, } spinfo->txrate_idx = rate_lowest_index(sband, sta); - /* HACK */ - si = container_of(sta, struct sta_info, sta); - si->fail_avg = 0; } static void *rate_control_pid_alloc(struct ieee80211_hw *hw, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4cd9e45b1443..7065fd7e7ba2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1550,7 +1550,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->control.vif = &rx->sdata->vif; ieee80211_select_queue(local, fwd_skb); - if (!is_multicast_ether_addr(fwd_hdr->addr1)) { + if (is_multicast_ether_addr(fwd_hdr->addr1)) + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_mcast); + else { int err; /* * Save TA to addr1 to send TA a path error if a @@ -1564,6 +1567,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) * later to the pending skb queue. */ if (err) return RX_DROP_MONITOR; + + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_unicast); } IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, fwded_frames); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e091cbc3434f..1e04be6b9129 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -292,13 +292,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (was_hw_scan) goto done; - spin_lock_bh(&local->filter_lock); - local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; - drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mc_count, - local->mc_list); - spin_unlock_bh(&local->filter_lock); + ieee80211_configure_filter(local); drv_sw_scan_complete(local); @@ -376,13 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; - spin_lock_bh(&local->filter_lock); - local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; - drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mc_count, - local->mc_list); - spin_unlock_bh(&local->filter_lock); + ieee80211_configure_filter(local); /* TODO: start scan as soon as all nullfunc frames are ACKed */ ieee80211_queue_delayed_work(&local->hw, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e55d57f559ec..5eb306377c63 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1076,9 +1076,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* reconfigure hardware */ ieee80211_hw_config(local, ~0); - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { diff --git a/net/wireless/core.c b/net/wireless/core.c index bc99e4ec7463..154e1e294cb9 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -12,6 +12,7 @@ #include <linux/debugfs.h> #include <linux/notifier.h> #include <linux/device.h> +#include <linux/etherdevice.h> #include <linux/rtnetlink.h> #include <net/genetlink.h> #include <net/cfg80211.h> @@ -309,7 +310,8 @@ static void cfg80211_process_events(struct wireless_dev *wdev) switch (ev->type) { case EVENT_CONNECT_RESULT: __cfg80211_connect_result( - wdev->netdev, ev->cr.bssid, + wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ? + NULL : ev->cr.bssid, ev->cr.req_ie, ev->cr.req_ie_len, ev->cr.resp_ie, ev->cr.resp_ie_len, ev->cr.status, @@ -430,6 +432,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) INIT_WORK(&rdev->conn_work, cfg80211_conn_work); INIT_WORK(&rdev->event_work, cfg80211_event_work); + init_waitqueue_head(&rdev->dev_wait); + /* * Initialize wiphy parameters to IEEE 802.11 MIB default values. * Fragmentation and RTS threshold are disabled by default with the @@ -574,7 +578,23 @@ void wiphy_unregister(struct wiphy *wiphy) /* protect the device list */ mutex_lock(&cfg80211_mutex); + wait_event(rdev->dev_wait, ({ + int __count; + mutex_lock(&rdev->devlist_mtx); + __count = rdev->opencount; + mutex_unlock(&rdev->devlist_mtx); + __count == 0;})); + + mutex_lock(&rdev->devlist_mtx); BUG_ON(!list_empty(&rdev->netdev_list)); + mutex_unlock(&rdev->devlist_mtx); + + /* + * First remove the hardware from everywhere, this makes + * it impossible to find from userspace. + */ + cfg80211_debugfs_rdev_del(rdev); + list_del(&rdev->list); /* * Try to grab rdev->mtx. If a command is still in progress, @@ -582,21 +602,18 @@ void wiphy_unregister(struct wiphy *wiphy) * down the device already. We wait for this command to complete * before unlinking the item from the list. * Note: as codified by the BUG_ON above we cannot get here if - * a virtual interface is still associated. Hence, we can only - * get to lock contention here if userspace issues a command - * that identified the hardware by wiphy index. + * a virtual interface is still present. Hence, we can only get + * to lock contention here if userspace issues a command that + * identified the hardware by wiphy index. */ - mutex_lock(&rdev->mtx); - /* unlock again before freeing */ - mutex_unlock(&rdev->mtx); - - cfg80211_debugfs_rdev_del(rdev); + cfg80211_lock_rdev(rdev); + /* nothing */ + cfg80211_unlock_rdev(rdev); /* If this device got a regulatory hint tell core its * free to listen now to a new shiny device regulatory hint */ reg_device_remove(wiphy); - list_del(&rdev->list); cfg80211_rdev_list_generation++; device_del(&rdev->wiphy.dev); debugfs_remove(rdev->wiphy.debugfsdir); @@ -605,7 +622,6 @@ void wiphy_unregister(struct wiphy *wiphy) flush_work(&rdev->scan_done_wk); cancel_work_sync(&rdev->conn_work); - kfree(rdev->scan_req); flush_work(&rdev->event_work); } EXPORT_SYMBOL(wiphy_unregister); @@ -636,6 +652,31 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) } EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); +static void wdev_cleanup_work(struct work_struct *work) +{ + struct wireless_dev *wdev; + struct cfg80211_registered_device *rdev; + + wdev = container_of(work, struct wireless_dev, cleanup_work); + rdev = wiphy_to_dev(wdev->wiphy); + + cfg80211_lock_rdev(rdev); + + if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev); + } + + cfg80211_unlock_rdev(rdev); + + mutex_lock(&rdev->devlist_mtx); + rdev->opencount--; + mutex_unlock(&rdev->devlist_mtx); + wake_up(&rdev->dev_wait); + + dev_put(wdev->netdev); +} + static int cfg80211_netdev_notifier_call(struct notifier_block * nb, unsigned long state, void *ndev) @@ -653,7 +694,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, switch (state) { case NETDEV_REGISTER: + /* + * NB: cannot take rdev->mtx here because this may be + * called within code protected by it when interfaces + * are added with nl80211. + */ mutex_init(&wdev->mtx); + INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); INIT_LIST_HEAD(&wdev->event_list); spin_lock_init(&wdev->event_lock); mutex_lock(&rdev->devlist_mtx); @@ -708,8 +755,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, default: break; } + dev_hold(dev); + schedule_work(&wdev->cleanup_work); break; case NETDEV_UP: + /* + * If we have a really quick DOWN/UP succession we may + * have this work still pending ... cancel it and see + * if it was pending, in which case we need to account + * for some of the work it would have done. + */ + if (cancel_work_sync(&wdev->cleanup_work)) { + mutex_lock(&rdev->devlist_mtx); + rdev->opencount--; + mutex_unlock(&rdev->devlist_mtx); + dev_put(dev); + } #ifdef CONFIG_WIRELESS_EXT cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); @@ -725,18 +786,17 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } wdev_unlock(wdev); + rdev->opencount++; mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); #endif break; case NETDEV_UNREGISTER: - cfg80211_lock_rdev(rdev); - - if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { - rdev->scan_req->aborted = true; - ___cfg80211_scan_done(rdev); - } - + /* + * NB: cannot take rdev->mtx here because this may be + * called within code protected by it when interfaces + * are removed with nl80211. + */ mutex_lock(&rdev->devlist_mtx); /* * It is possible to get NETDEV_UNREGISTER @@ -749,13 +809,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, sysfs_remove_link(&dev->dev.kobj, "phy80211"); list_del_init(&wdev->list); rdev->devlist_generation++; - mutex_destroy(&wdev->mtx); #ifdef CONFIG_WIRELESS_EXT kfree(wdev->wext.keys); #endif } mutex_unlock(&rdev->devlist_mtx); - cfg80211_unlock_rdev(rdev); break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) diff --git a/net/wireless/core.h b/net/wireless/core.h index c603f5286326..f565432ae22f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -50,6 +50,8 @@ struct cfg80211_registered_device { struct mutex devlist_mtx; struct list_head netdev_list; int devlist_generation; + int opencount; /* also protected by devlist_mtx */ + wait_queue_head_t dev_wait; /* BSSes/scanning */ spinlock_t bss_lock; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index da64071ceb84..79d2eec54cec 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -96,6 +96,15 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) WARN_ON(!bss); } + if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { + /* + * This is for the userspace SME, the CONNECTING + * state will be changed to CONNECTED by + * __cfg80211_connect_result() below. + */ + wdev->sme_state = CFG80211_SME_CONNECTING; + } + /* this consumes one bss reference (unless bss is NULL) */ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, status_code, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8e2ef54ea714..4a8289f9b4f0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -351,15 +351,13 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; - if (wdev->sme_state == CFG80211_SME_CONNECTED) - nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, + if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING)) + return; + + nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid, req_ie, req_ie_len, - resp_ie, resp_ie_len, GFP_KERNEL); - else - nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, - bssid, req_ie, req_ie_len, - resp_ie, resp_ie_len, - status, GFP_KERNEL); + resp_ie, resp_ie_len, + status, GFP_KERNEL); #ifdef CONFIG_WIRELESS_EXT if (wextev) { @@ -392,18 +390,13 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, wdev->current_bss = NULL; } - if (status == WLAN_STATUS_SUCCESS && - wdev->sme_state == CFG80211_SME_IDLE) - goto success; - - if (wdev->sme_state != CFG80211_SME_CONNECTING) - return; - if (wdev->conn) wdev->conn->state = CFG80211_CONN_IDLE; if (status != WLAN_STATUS_SUCCESS) { wdev->sme_state = CFG80211_SME_IDLE; + if (wdev->conn) + kfree(wdev->conn->ie); kfree(wdev->conn); wdev->conn = NULL; kfree(wdev->connect_keys); @@ -412,7 +405,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, return; } - success: if (!bss) bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, wdev->ssid, wdev->ssid_len, @@ -458,7 +450,8 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, return; ev->type = EVENT_CONNECT_RESULT; - memcpy(ev->cr.bssid, bssid, ETH_ALEN); + if (bssid) + memcpy(ev->cr.bssid, bssid, ETH_ALEN); ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); ev->cr.req_ie_len = req_ie_len; memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); @@ -789,6 +782,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, } } if (err) { + kfree(wdev->conn->ie); kfree(wdev->conn); wdev->conn = NULL; wdev->sme_state = CFG80211_SME_IDLE; @@ -858,6 +852,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, (wdev->conn->state == CFG80211_CONN_SCANNING || wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { wdev->sme_state = CFG80211_SME_IDLE; + kfree(wdev->conn->ie); kfree(wdev->conn); wdev->conn = NULL; wdev->ssid_len = 0; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index c44917492210..c12029b1def0 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -771,6 +771,7 @@ int cfg80211_wext_siwfreq(struct net_device *dev, return err; } } +EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); int cfg80211_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, |