2013-03-01 19:30:19

by John W. Linville

[permalink] [raw]
Subject: pull request: wireless 2013-03-01

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
[email protected] might be all we have. Be ready.


2013-03-01 19:37:57

by John W. Linville

[permalink] [raw]
Subject: Re: pull request: wireless 2013-03-01

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
> [email protected] might be all we have. Be ready.

--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.


Attachments:
(No filename) (35.23 kB)
(No filename) (836.00 B)
Download all attachments

2013-03-01 20:57:30

by David Miller

[permalink] [raw]
Subject: Re: pull request: wireless 2013-03-01

From: "John W. Linville" <[email protected]>
Date: Fri, 1 Mar 2013 14:23:33 -0500

> 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!

Pulled, thanks John.