Re: pull request: wireless 2013-03-01

From: John W. Linville
Date: Fri Mar 01 2013 - 14:38:01 EST


Ooops! Forgot signature...

On Fri, Mar 01, 2013 at 02:23:32PM -0500, John W. Linville wrote:
> Dave,
>
> This is another flurry of fixes intended for the 3.9 stream...
>
> A mac80211 pull from Johannes:
>
> "Seth fixes a stupid bug I introduced into one of his earlier patches,
> Chun-Yeow fixes mesh forwarding and Felix fixes monitor mode. I myself
> fixed a small locking issue and, the biggest change here, removed some
> nl80211 information with which sometimes the per wiphy information was
> getting too large for the typical 4k-minus-overhead. In my -next tree I
> have a patch to allow splitting that and add back the information
> removed now."
>
> An iwlwifi pull from Johannes:
>
> "I have a fix for a pretty important bug regarding DMA mapping, that
> could cause the DMA engine to overwrite data we wanted to send to it, so
> that the next time we send it it would be bad. This particularly affects
> calibration results. Other than that, three little fixes for the MVM
> driver."
>
> But wait, there's more!
>
> Avinash Patil fixes an incorrectly timed delay in mwifiex.
>
> Bing Zhao prevents a crash in SD8688 caused by failing to properly
> set a flag before issuing a command.
>
> Felix Fietkau is the big here this time, providing a trio of minor
> ath9k fixes and correcting the advertised interface combinations for
> rt2x00 when mesh support is disabled.
>
> Finally, Hauke Mehrtens gives us a patch that correctlin initializes
> a spin lock in the bcma code.
>
> Please let me know if there are problems!
>
> Thanks,
>
> John
>
> ---
>
> The following changes since commit 32fcafbcd1c9f6c7013016a22a5369b4acb93577:
>
> net/phy: micrel: Disable asymmetric pause for KSZ9021 (2013-02-28 15:37:30 -0500)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git for-davem
>
> for you to fetch changes up to 98b7ff9a4977e4f4f451c30288b197ad79e5ab7f:
>
> Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem (2013-03-01 13:52:03 -0500)
>
> ----------------------------------------------------------------
>
> Avinash Patil (1):
> mwifiex: correct sleep delay counter
>
> Bing Zhao (1):
> libertas: fix crash for SD8688
>
> Chun-Yeow Yeoh (1):
> mac80211: fix the problem of forwarding from DS to DS in Mesh
>
> Dor Shaish (1):
> iwlwifi: mvm: Remove testing of static PIC in PhyDB
>
> Felix Fietkau (6):
> mac80211: fix idle handling in monitor mode
> mac80211: fix monitor mode channel reporting
> ath9k: fix RSSI dummy marker value
> ath9k_htc: fix signal strength handling issues
> ath9k_hw: improve reset reliability after errors
> rt2x00: error in configurations with mesh support disabled
>
> Hauke Mehrtens (1):
> bcma: init spin lock
>
> Johannes Berg (6):
> mac80211: fix tim_lock locking
> nl80211: remove radar information
> nl80211: remove TCP WoWLAN information
> iwlwifi: always copy first 16 bytes of commands
> iwlwifi: mvm: fix AP/GO mode station removal
> iwlwifi: fix wakeup status query and packet reporting
>
> John W. Linville (2):
> Merge branch 'for-john' of git://git.kernel.org/.../iwlwifi/iwlwifi-fixes
> Merge branch 'master' of git://git.kernel.org/.../linville/wireless into for-davem
>
> Seth Forshee (1):
> mac80211: Ensure off-channel frames don't get queued
>
> drivers/bcma/driver_pci_host.c | 2 +
> drivers/net/wireless/ath/ath9k/common.h | 2 +-
> drivers/net/wireless/ath/ath9k/htc.h | 1 +
> drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 18 +++--
> drivers/net/wireless/ath/ath9k/hw.c | 4 +-
> drivers/net/wireless/iwlwifi/iwl-devtrace.h | 10 +--
> drivers/net/wireless/iwlwifi/iwl-phy-db.c | 16 ----
> drivers/net/wireless/iwlwifi/mvm/d3.c | 104 +++++++++++++++++++-------
> drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 +++--
> drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 +
> drivers/net/wireless/iwlwifi/pcie/internal.h | 9 +++
> drivers/net/wireless/iwlwifi/pcie/tx.c | 75 ++++++++++++++-----
> drivers/net/wireless/libertas/if_sdio.c | 6 +-
> drivers/net/wireless/mwifiex/pcie.c | 2 +-
> drivers/net/wireless/rt2x00/rt2x00dev.c | 8 +-
> net/mac80211/cfg.c | 12 ++-
> net/mac80211/iface.c | 2 +-
> net/mac80211/tx.c | 77 ++++++++++++-------
> net/wireless/nl80211.c | 61 +--------------
> 19 files changed, 258 insertions(+), 174 deletions(-)
>
> diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c
> index d3bde6c..30629a3 100644
> --- a/drivers/bcma/driver_pci_host.c
> +++ b/drivers/bcma/driver_pci_host.c
> @@ -404,6 +404,8 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
> return;
> }
>
> + spin_lock_init(&pc_host->cfgspace_lock);
> +
> pc->host_controller = pc_host;
> pc_host->pci_controller.io_resource = &pc_host->io_resource;
> pc_host->pci_controller.mem_resource = &pc_host->mem_resource;
> diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
> index 5f845be..050ca4a 100644
> --- a/drivers/net/wireless/ath/ath9k/common.h
> +++ b/drivers/net/wireless/ath/ath9k/common.h
> @@ -27,7 +27,7 @@
> #define WME_MAX_BA WME_BA_BMP_SIZE
> #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
>
> -#define ATH_RSSI_DUMMY_MARKER 0x127
> +#define ATH_RSSI_DUMMY_MARKER 127
> #define ATH_RSSI_LPF_LEN 10
> #define RSSI_LPF_THRESHOLD -20
> #define ATH_RSSI_EP_MULTIPLIER (1<<7)
> diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
> index 96bfb18..d3b099d 100644
> --- a/drivers/net/wireless/ath/ath9k/htc.h
> +++ b/drivers/net/wireless/ath/ath9k/htc.h
> @@ -22,6 +22,7 @@
> #include <linux/firmware.h>
> #include <linux/skbuff.h>
> #include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> #include <linux/leds.h>
> #include <linux/slab.h>
> #include <net/mac80211.h>
> diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
> index 3ad1fd0..bd8251c 100644
> --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
> +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
> @@ -1067,15 +1067,19 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
>
> last_rssi = priv->rx.last_rssi;
>
> - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
> - rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi,
> - ATH_RSSI_EP_MULTIPLIER);
> + if (ieee80211_is_beacon(hdr->frame_control) &&
> + !is_zero_ether_addr(common->curbssid) &&
> + ether_addr_equal(hdr->addr3, common->curbssid)) {
> + s8 rssi = rxbuf->rxstatus.rs_rssi;
>
> - if (rxbuf->rxstatus.rs_rssi < 0)
> - rxbuf->rxstatus.rs_rssi = 0;
> + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
> + rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
>
> - if (ieee80211_is_beacon(fc))
> - priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
> + if (rssi < 0)
> + rssi = 0;
> +
> + priv->ah->stats.avgbrssi = rssi;
> + }
>
> rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
> rx_status->band = hw->conf.channel->band;
> diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
> index 2a2ae40..07e2526 100644
> --- a/drivers/net/wireless/ath/ath9k/hw.c
> +++ b/drivers/net/wireless/ath/ath9k/hw.c
> @@ -1463,7 +1463,9 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,
> reset_type = ATH9K_RESET_POWER_ON;
> else
> reset_type = ATH9K_RESET_COLD;
> - }
> + } else if (ah->chip_fullsleep || REG_READ(ah, AR_Q_TXE) ||
> + (REG_READ(ah, AR_CR) & AR_CR_RXE))
> + reset_type = ATH9K_RESET_COLD;
>
> if (!ath9k_hw_set_reset_reg(ah, reset_type))
> return false;
> diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
> index 9a0f45e..10f0179 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
> @@ -349,25 +349,23 @@ TRACE_EVENT(iwlwifi_dev_rx_data,
> TRACE_EVENT(iwlwifi_dev_hcmd,
> TP_PROTO(const struct device *dev,
> struct iwl_host_cmd *cmd, u16 total_size,
> - const void *hdr, size_t hdr_len),
> - TP_ARGS(dev, cmd, total_size, hdr, hdr_len),
> + struct iwl_cmd_header *hdr),
> + TP_ARGS(dev, cmd, total_size, hdr),
> TP_STRUCT__entry(
> DEV_ENTRY
> __dynamic_array(u8, hcmd, total_size)
> __field(u32, flags)
> ),
> TP_fast_assign(
> - int i, offset = hdr_len;
> + int i, offset = sizeof(*hdr);
>
> DEV_ASSIGN;
> __entry->flags = cmd->flags;
> - memcpy(__get_dynamic_array(hcmd), hdr, hdr_len);
> + memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr));
>
> for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
> if (!cmd->len[i])
> continue;
> - if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
> - continue;
> memcpy((u8 *)__get_dynamic_array(hcmd) + offset,
> cmd->data[i], cmd->len[i]);
> offset += cmd->len[i];
> diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
> index 14fc8d3..3392011 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
> @@ -136,12 +136,6 @@ struct iwl_calib_res_notif_phy_db {
> u8 data[];
> } __packed;
>
> -#define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587)
> -static inline void iwl_phy_db_test_pic(__le32 pic)
> -{
> - WARN_ON(IWL_PHY_DB_STATIC_PIC != pic);
> -}
> -
> struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
> {
> struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db),
> @@ -260,11 +254,6 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
> (size - CHANNEL_NUM_SIZE) / phy_db->channel_num;
> }
>
> - /* Test PIC */
> - if (type != IWL_PHY_DB_CFG)
> - iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) +
> - (size / sizeof(__le32)) - 1));
> -
> IWL_DEBUG_INFO(phy_db->trans,
> "%s(%d): [PHYDB]SET: Type %d , Size: %d\n",
> __func__, __LINE__, type, size);
> @@ -372,11 +361,6 @@ int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db,
> *size = entry->size;
> }
>
> - /* Test PIC */
> - if (type != IWL_PHY_DB_CFG)
> - iwl_phy_db_test_pic(*(((__le32 *)*data) +
> - (*size / sizeof(__le32)) - 1));
> -
> IWL_DEBUG_INFO(phy_db->trans,
> "%s(%d): [PHYDB] GET: Type %d , Size: %d\n",
> __func__, __LINE__, type, *size);
> diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
> index c64d864..994c8c2 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/d3.c
> +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
> @@ -61,6 +61,7 @@
> *
> *****************************************************************************/
>
> +#include <linux/etherdevice.h>
> #include <net/cfg80211.h>
> #include <net/ipv6.h>
> #include "iwl-modparams.h"
> @@ -192,6 +193,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
> sizeof(wkc), &wkc);
> data->error = ret != 0;
>
> + mvm->ptk_ivlen = key->iv_len;
> + mvm->ptk_icvlen = key->icv_len;
> + mvm->gtk_ivlen = key->iv_len;
> + mvm->gtk_icvlen = key->icv_len;
> +
> /* don't upload key again */
> goto out_unlock;
> }
> @@ -304,9 +310,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
> */
> if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
> key->hw_key_idx = 0;
> + mvm->ptk_ivlen = key->iv_len;
> + mvm->ptk_icvlen = key->icv_len;
> } else {
> data->gtk_key_idx++;
> key->hw_key_idx = data->gtk_key_idx;
> + mvm->gtk_ivlen = key->iv_len;
> + mvm->gtk_icvlen = key->icv_len;
> }
>
> ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
> @@ -649,6 +659,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
> /* We reprogram keys and shouldn't allocate new key indices */
> memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
>
> + mvm->ptk_ivlen = 0;
> + mvm->ptk_icvlen = 0;
> + mvm->ptk_ivlen = 0;
> + mvm->ptk_icvlen = 0;
> +
> /*
> * The D3 firmware still hardcodes the AP station ID for the
> * BSS we're associated with as 0. As a result, we have to move
> @@ -783,7 +798,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
> struct iwl_wowlan_status *status;
> u32 reasons;
> int ret, len;
> - bool pkt8023 = false;
> struct sk_buff *pkt = NULL;
>
> iwl_trans_read_mem_bytes(mvm->trans, base,
> @@ -824,7 +838,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
> status = (void *)cmd.resp_pkt->data;
>
> if (len - sizeof(struct iwl_cmd_header) !=
> - sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) {
> + sizeof(*status) +
> + ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
> IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
> goto out;
> }
> @@ -836,61 +851,96 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
> goto report;
> }
>
> - if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) {
> + if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET)
> wakeup.magic_pkt = true;
> - pkt8023 = true;
> - }
>
> - if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) {
> + if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)
> wakeup.pattern_idx =
> le16_to_cpu(status->pattern_number);
> - pkt8023 = true;
> - }
>
> if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
> IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
> wakeup.disconnect = true;
>
> - if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) {
> + if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)
> wakeup.gtk_rekey_failure = true;
> - pkt8023 = true;
> - }
>
> - if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) {
> + if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
> wakeup.rfkill_release = true;
> - pkt8023 = true;
> - }
>
> - if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) {
> + if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST)
> wakeup.eap_identity_req = true;
> - pkt8023 = true;
> - }
>
> - if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) {
> + if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)
> wakeup.four_way_handshake = true;
> - pkt8023 = true;
> - }
>
> if (status->wake_packet_bufsize) {
> - u32 pktsize = le32_to_cpu(status->wake_packet_bufsize);
> - u32 pktlen = le32_to_cpu(status->wake_packet_length);
> + int pktsize = le32_to_cpu(status->wake_packet_bufsize);
> + int pktlen = le32_to_cpu(status->wake_packet_length);
> + const u8 *pktdata = status->wake_packet;
> + struct ieee80211_hdr *hdr = (void *)pktdata;
> + int truncated = pktlen - pktsize;
> +
> + /* this would be a firmware bug */
> + if (WARN_ON_ONCE(truncated < 0))
> + truncated = 0;
> +
> + if (ieee80211_is_data(hdr->frame_control)) {
> + int hdrlen = ieee80211_hdrlen(hdr->frame_control);
> + int ivlen = 0, icvlen = 4; /* also FCS */
>
> - if (pkt8023) {
> pkt = alloc_skb(pktsize, GFP_KERNEL);
> if (!pkt)
> goto report;
> - memcpy(skb_put(pkt, pktsize), status->wake_packet,
> - pktsize);
> +
> + memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen);
> + pktdata += hdrlen;
> + pktsize -= hdrlen;
> +
> + if (ieee80211_has_protected(hdr->frame_control)) {
> + if (is_multicast_ether_addr(hdr->addr1)) {
> + ivlen = mvm->gtk_ivlen;
> + icvlen += mvm->gtk_icvlen;
> + } else {
> + ivlen = mvm->ptk_ivlen;
> + icvlen += mvm->ptk_icvlen;
> + }
> + }
> +
> + /* if truncated, FCS/ICV is (partially) gone */
> + if (truncated >= icvlen) {
> + icvlen = 0;
> + truncated -= icvlen;
> + } else {
> + icvlen -= truncated;
> + truncated = 0;
> + }
> +
> + pktsize -= ivlen + icvlen;
> + pktdata += ivlen;
> +
> + memcpy(skb_put(pkt, pktsize), pktdata, pktsize);
> +
> if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))
> goto report;
> wakeup.packet = pkt->data;
> wakeup.packet_present_len = pkt->len;
> - wakeup.packet_len = pkt->len - (pktlen - pktsize);
> + wakeup.packet_len = pkt->len - truncated;
> wakeup.packet_80211 = false;
> } else {
> + int fcslen = 4;
> +
> + if (truncated >= 4) {
> + truncated -= 4;
> + fcslen = 0;
> + } else {
> + fcslen -= truncated;
> + truncated = 0;
> + }
> + pktsize -= fcslen;
> wakeup.packet = status->wake_packet;
> wakeup.packet_present_len = pktsize;
> - wakeup.packet_len = pktlen;
> + wakeup.packet_len = pktlen - truncated;
> wakeup.packet_80211 = true;
> }
> }
> diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> index e8264e1..7e169b0 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> @@ -557,11 +557,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
> return ret;
> }
>
> -static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
> - struct ieee80211_vif *vif)
> +static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
> + struct ieee80211_vif *vif)
> {
> - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
> - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
> u32 tfd_msk = 0, ac;
>
> for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
> @@ -594,12 +592,21 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
> */
> flush_work(&mvm->sta_drained_wk);
> }
> +}
> +
> +static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif)
> +{
> + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
> + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
> +
> + iwl_mvm_prepare_mac_removal(mvm, vif);
>
> mutex_lock(&mvm->mutex);
>
> /*
> * For AP/GO interface, the tear down of the resources allocated to the
> - * interface should be handled as part of the bss_info_changed flow.
> + * interface is be handled as part of the stop_ap flow.
> */
> if (vif->type == NL80211_IFTYPE_AP) {
> iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
> @@ -763,6 +770,8 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
> struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
> struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
>
> + iwl_mvm_prepare_mac_removal(mvm, vif);
> +
> mutex_lock(&mvm->mutex);
>
> mvmvif->ap_active = false;
> diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
> index 4e339cc..537711b 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
> +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
> @@ -327,6 +327,10 @@ struct iwl_mvm {
> struct led_classdev led;
>
> struct ieee80211_vif *p2p_device_vif;
> +
> +#ifdef CONFIG_PM_SLEEP
> + int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
> +#endif
> };
>
> /* Extract MVM priv from op_mode and _hw */
> diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
> index aa2a39a..3d62e80 100644
> --- a/drivers/net/wireless/iwlwifi/pcie/internal.h
> +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
> @@ -182,6 +182,15 @@ struct iwl_queue {
> #define TFD_TX_CMD_SLOTS 256
> #define TFD_CMD_SLOTS 32
>
> +/*
> + * The FH will write back to the first TB only, so we need
> + * to copy some data into the buffer regardless of whether
> + * it should be mapped or not. This indicates how much to
> + * copy, even for HCMDs it must be big enough to fit the
> + * DRAM scratch from the TX cmd, at least 16 bytes.
> + */
> +#define IWL_HCMD_MIN_COPY_SIZE 16
> +
> struct iwl_pcie_txq_entry {
> struct iwl_device_cmd *cmd;
> struct iwl_device_cmd *copy_cmd;
> diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
> index 8e9e321..8b625a7 100644
> --- a/drivers/net/wireless/iwlwifi/pcie/tx.c
> +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
> @@ -1152,10 +1152,12 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
> void *dup_buf = NULL;
> dma_addr_t phys_addr;
> int idx;
> - u16 copy_size, cmd_size;
> + u16 copy_size, cmd_size, dma_size;
> bool had_nocopy = false;
> int i;
> u32 cmd_pos;
> + const u8 *cmddata[IWL_MAX_CMD_TFDS];
> + u16 cmdlen[IWL_MAX_CMD_TFDS];
>
> copy_size = sizeof(out_cmd->hdr);
> cmd_size = sizeof(out_cmd->hdr);
> @@ -1164,8 +1166,23 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
> BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
>
> for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
> + cmddata[i] = cmd->data[i];
> + cmdlen[i] = cmd->len[i];
> +
> if (!cmd->len[i])
> continue;
> +
> + /* need at least IWL_HCMD_MIN_COPY_SIZE copied */
> + if (copy_size < IWL_HCMD_MIN_COPY_SIZE) {
> + int copy = IWL_HCMD_MIN_COPY_SIZE - copy_size;
> +
> + if (copy > cmdlen[i])
> + copy = cmdlen[i];
> + cmdlen[i] -= copy;
> + cmddata[i] += copy;
> + copy_size += copy;
> + }
> +
> if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
> had_nocopy = true;
> if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) {
> @@ -1185,7 +1202,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
> goto free_dup_buf;
> }
>
> - dup_buf = kmemdup(cmd->data[i], cmd->len[i],
> + dup_buf = kmemdup(cmddata[i], cmdlen[i],
> GFP_ATOMIC);
> if (!dup_buf)
> return -ENOMEM;
> @@ -1195,7 +1212,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
> idx = -EINVAL;
> goto free_dup_buf;
> }
> - copy_size += cmd->len[i];
> + copy_size += cmdlen[i];
> }
> cmd_size += cmd->len[i];
> }
> @@ -1242,14 +1259,31 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
>
> /* and copy the data that needs to be copied */
> cmd_pos = offsetof(struct iwl_device_cmd, payload);
> + copy_size = sizeof(out_cmd->hdr);
> for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
> - if (!cmd->len[i])
> + int copy = 0;
> +
> + if (!cmd->len)
> continue;
> - if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |
> - IWL_HCMD_DFL_DUP))
> - break;
> - memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]);
> - cmd_pos += cmd->len[i];
> +
> + /* need at least IWL_HCMD_MIN_COPY_SIZE copied */
> + if (copy_size < IWL_HCMD_MIN_COPY_SIZE) {
> + copy = IWL_HCMD_MIN_COPY_SIZE - copy_size;
> +
> + if (copy > cmd->len[i])
> + copy = cmd->len[i];
> + }
> +
> + /* copy everything if not nocopy/dup */
> + if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |
> + IWL_HCMD_DFL_DUP)))
> + copy = cmd->len[i];
> +
> + if (copy) {
> + memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy);
> + cmd_pos += copy;
> + copy_size += copy;
> + }
> }
>
> WARN_ON_ONCE(txq->entries[idx].copy_cmd);
> @@ -1275,7 +1309,14 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
> out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
> cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);
>
> - phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
> + /*
> + * If the entire command is smaller than IWL_HCMD_MIN_COPY_SIZE, we must
> + * still map at least that many bytes for the hardware to write back to.
> + * We have enough space, so that's not a problem.
> + */
> + dma_size = max_t(u16, copy_size, IWL_HCMD_MIN_COPY_SIZE);
> +
> + phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, dma_size,
> DMA_BIDIRECTIONAL);
> if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
> idx = -ENOMEM;
> @@ -1283,14 +1324,15 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
> }
>
> dma_unmap_addr_set(out_meta, mapping, phys_addr);
> - dma_unmap_len_set(out_meta, len, copy_size);
> + dma_unmap_len_set(out_meta, len, dma_size);
>
> iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1);
>
> + /* map the remaining (adjusted) nocopy/dup fragments */
> for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
> - const void *data = cmd->data[i];
> + const void *data = cmddata[i];
>
> - if (!cmd->len[i])
> + if (!cmdlen[i])
> continue;
> if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |
> IWL_HCMD_DFL_DUP)))
> @@ -1298,7 +1340,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
> if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP)
> data = dup_buf;
> phys_addr = dma_map_single(trans->dev, (void *)data,
> - cmd->len[i], DMA_BIDIRECTIONAL);
> + cmdlen[i], DMA_BIDIRECTIONAL);
> if (dma_mapping_error(trans->dev, phys_addr)) {
> iwl_pcie_tfd_unmap(trans, out_meta,
> &txq->tfds[q->write_ptr],
> @@ -1307,7 +1349,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
> goto out;
> }
>
> - iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0);
> + iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0);
> }
>
> out_meta->flags = cmd->flags;
> @@ -1317,8 +1359,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
>
> txq->need_update = 1;
>
> - trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size,
> - &out_cmd->hdr, copy_size);
> + trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);
>
> /* start timer if queue currently empty */
> if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
> diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
> index 739309e..4557833 100644
> --- a/drivers/net/wireless/libertas/if_sdio.c
> +++ b/drivers/net/wireless/libertas/if_sdio.c
> @@ -825,6 +825,11 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)
>
> sdio_release_host(func);
>
> + /* Set fw_ready before queuing any commands so that
> + * lbs_thread won't block from sending them to firmware.
> + */
> + priv->fw_ready = 1;
> +
> /*
> * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
> */
> @@ -839,7 +844,6 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)
> netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
> }
>
> - priv->fw_ready = 1;
> wake_up(&card->pwron_waitq);
>
> if (!card->started) {
> diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
> index 35c7972..5c395e2 100644
> --- a/drivers/net/wireless/mwifiex/pcie.c
> +++ b/drivers/net/wireless/mwifiex/pcie.c
> @@ -302,7 +302,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
> i++;
> usleep_range(10, 20);
> /* 50ms max wait */
> - if (i == 50000)
> + if (i == 5000)
> break;
> }
>
> diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
> index 1031db6..189744d 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00dev.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
> @@ -1236,8 +1236,10 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)
> */
> if_limit = &rt2x00dev->if_limits_ap;
> if_limit->max = rt2x00dev->ops->max_ap_intf;
> - if_limit->types = BIT(NL80211_IFTYPE_AP) |
> - BIT(NL80211_IFTYPE_MESH_POINT);
> + if_limit->types = BIT(NL80211_IFTYPE_AP);
> +#ifdef CONFIG_MAC80211_MESH
> + if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT);
> +#endif
>
> /*
> * Build up AP interface combinations structure.
> @@ -1309,7 +1311,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
> rt2x00dev->hw->wiphy->interface_modes |=
> BIT(NL80211_IFTYPE_ADHOC) |
> BIT(NL80211_IFTYPE_AP) |
> +#ifdef CONFIG_MAC80211_MESH
> BIT(NL80211_IFTYPE_MESH_POINT) |
> +#endif
> BIT(NL80211_IFTYPE_WDS);
>
> rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
> index 09d96a8..808f5fc 100644
> --- a/net/mac80211/cfg.c
> +++ b/net/mac80211/cfg.c
> @@ -3285,13 +3285,19 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
> struct cfg80211_chan_def *chandef)
> {
> struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
> + struct ieee80211_local *local = wiphy_priv(wiphy);
> struct ieee80211_chanctx_conf *chanctx_conf;
> int ret = -ENODATA;
>
> rcu_read_lock();
> - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
> - if (chanctx_conf) {
> - *chandef = chanctx_conf->def;
> + if (local->use_chanctx) {
> + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
> + if (chanctx_conf) {
> + *chandef = chanctx_conf->def;
> + ret = 0;
> + }
> + } else if (local->open_count == local->monitors) {
> + *chandef = local->monitor_chandef;
> ret = 0;
> }
> rcu_read_unlock();
> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
> index 2c059e5..640afab 100644
> --- a/net/mac80211/iface.c
> +++ b/net/mac80211/iface.c
> @@ -107,7 +107,7 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
>
> lockdep_assert_held(&local->mtx);
>
> - active = !list_empty(&local->chanctx_list);
> + active = !list_empty(&local->chanctx_list) || local->monitors;
>
> if (!local->ops->remain_on_channel) {
> list_for_each_entry(roc, &local->roc_list, list) {
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 5b9602b..c592a41 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -1231,34 +1231,40 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
> if (local->queue_stop_reasons[q] ||
> (!txpending && !skb_queue_empty(&local->pending[q]))) {
> if (unlikely(info->flags &
> - IEEE80211_TX_INTFL_OFFCHAN_TX_OK &&
> - local->queue_stop_reasons[q] &
> - ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL))) {
> + IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) {
> + if (local->queue_stop_reasons[q] &
> + ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL)) {
> + /*
> + * Drop off-channel frames if queues
> + * are stopped for any reason other
> + * than off-channel operation. Never
> + * queue them.
> + */
> + spin_unlock_irqrestore(
> + &local->queue_stop_reason_lock,
> + flags);
> + ieee80211_purge_tx_queue(&local->hw,
> + skbs);
> + return true;
> + }
> + } else {
> +
> /*
> - * Drop off-channel frames if queues are stopped
> - * for any reason other than off-channel
> - * operation. Never queue them.
> + * Since queue is stopped, queue up frames for
> + * later transmission from the tx-pending
> + * tasklet when the queue is woken again.
> */
> - spin_unlock_irqrestore(
> - &local->queue_stop_reason_lock, flags);
> - ieee80211_purge_tx_queue(&local->hw, skbs);
> - return true;
> + if (txpending)
> + skb_queue_splice_init(skbs,
> + &local->pending[q]);
> + else
> + skb_queue_splice_tail_init(skbs,
> + &local->pending[q]);
> +
> + spin_unlock_irqrestore(&local->queue_stop_reason_lock,
> + flags);
> + return false;
> }
> -
> - /*
> - * Since queue is stopped, queue up frames for later
> - * transmission from the tx-pending tasklet when the
> - * queue is woken again.
> - */
> - if (txpending)
> - skb_queue_splice_init(skbs, &local->pending[q]);
> - else
> - skb_queue_splice_tail_init(skbs,
> - &local->pending[q]);
> -
> - spin_unlock_irqrestore(&local->queue_stop_reason_lock,
> - flags);
> - return false;
> }
> spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
>
> @@ -1844,9 +1850,24 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
> }
>
> if (!is_multicast_ether_addr(skb->data)) {
> + struct sta_info *next_hop;
> + bool mpp_lookup = true;
> +
> mpath = mesh_path_lookup(sdata, skb->data);
> - if (!mpath)
> + if (mpath) {
> + mpp_lookup = false;
> + next_hop = rcu_dereference(mpath->next_hop);
> + if (!next_hop ||
> + !(mpath->flags & (MESH_PATH_ACTIVE |
> + MESH_PATH_RESOLVING)))
> + mpp_lookup = true;
> + }
> +
> + if (mpp_lookup)
> mppath = mpp_path_lookup(sdata, skb->data);
> +
> + if (mppath && mpath)
> + mesh_path_del(mpath->sdata, mpath->dst);
> }
>
> /*
> @@ -2360,9 +2381,9 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
> if (local->tim_in_locked_section) {
> __ieee80211_beacon_add_tim(sdata, ps, skb);
> } else {
> - spin_lock(&local->tim_lock);
> + spin_lock_bh(&local->tim_lock);
> __ieee80211_beacon_add_tim(sdata, ps, skb);
> - spin_unlock(&local->tim_lock);
> + spin_unlock_bh(&local->tim_lock);
> }
>
> return 0;
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index 35545cc..e652d05 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -554,16 +554,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
> if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
> nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
> goto nla_put_failure;
> - if (chan->flags & IEEE80211_CHAN_RADAR) {
> - u32 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
> - if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
> - goto nla_put_failure;
> - if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
> - chan->dfs_state))
> - goto nla_put_failure;
> - if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time))
> - goto nla_put_failure;
> - }
> + if ((chan->flags & IEEE80211_CHAN_RADAR) &&
> + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
> + goto nla_put_failure;
> if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
> nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
> goto nla_put_failure;
> @@ -900,9 +893,6 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
> nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
> c->max_interfaces))
> goto nla_put_failure;
> - if (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
> - c->radar_detect_widths))
> - goto nla_put_failure;
>
> nla_nest_end(msg, nl_combi);
> }
> @@ -914,48 +904,6 @@ nla_put_failure:
> return -ENOBUFS;
> }
>
> -#ifdef CONFIG_PM
> -static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
> - struct sk_buff *msg)
> -{
> - const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp;
> - struct nlattr *nl_tcp;
> -
> - if (!tcp)
> - return 0;
> -
> - nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
> - if (!nl_tcp)
> - return -ENOBUFS;
> -
> - if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
> - tcp->data_payload_max))
> - return -ENOBUFS;
> -
> - if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
> - tcp->data_payload_max))
> - return -ENOBUFS;
> -
> - if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
> - return -ENOBUFS;
> -
> - if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
> - sizeof(*tcp->tok), tcp->tok))
> - return -ENOBUFS;
> -
> - if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
> - tcp->data_interval_max))
> - return -ENOBUFS;
> -
> - if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
> - tcp->wake_payload_max))
> - return -ENOBUFS;
> -
> - nla_nest_end(msg, nl_tcp);
> - return 0;
> -}
> -#endif
> -
> static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags,
> struct cfg80211_registered_device *dev)
> {
> @@ -1330,9 +1278,6 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag
> goto nla_put_failure;
> }
>
> - if (nl80211_send_wowlan_tcp_caps(dev, msg))
> - goto nla_put_failure;
> -
> nla_nest_end(msg, nl_wowlan);
> }
> #endif
> --
> John W. Linville Someday the world will need a hero, and you
> linville@xxxxxxxxxxxxx might be all we have. Be ready.

--
John W. Linville Someday the world will need a hero, and you
linville@xxxxxxxxxxxxx might be all we have. Be ready.

Attachment: pgp00000.pgp
Description: PGP signature