iwlwifi: mvm: set the tx cmd tid for BAR frame correctly
authorEyal Shapira <eyal@wizery.com>
Wed, 31 Dec 2014 16:34:56 +0000 (18:34 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 13 Jan 2015 06:53:23 +0000 (08:53 +0200)
BAR tx cmd tid was set to non qos (8). This is wrong as BAR
should be sent with the tid of the BA session.
This led to a corruption in the firmware. The visible
effect of this from the driver side is the BA notification
that comes back after the BAR. It was botched and led to the
WARNING below.

------------[ cut here ]------------
WARNING: CPU: 2 PID: 17707 at /home/tester/workspace_hostap/iwlwifi/drivers/net/wireless/iwlwifi/mvm/tx.c:976 iwl_mvm_rx_ba_notif+0x4ba/0x4d0 [iwlmvm]()
Q 4500, tid 8, flow 65535
Modules linked in: iwlmvm(O) mac80211(O) iwlwifi(O) cfg80211(O) compat(O) netconsole configfs ctr ccm arc4 autofs4 microcode bnep rfcomm snd_hda_codec_hdmi snd_hda_codec_idt snd_hda_codec_generic snd_hda_intel joydev snd_hda_codec uvcvideo videobuf2_core snd_hwdep videodev snd_pcm videobuf2_vmalloc videobuf2_memops i915 snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device drm_kms_helper dell_wmi dell_laptop drm btusb bluetooth snd psmouse i2c_algo_bit sparse_keymap wmi soundcore 6lowpan_iphc dcdbas serio_raw video lpc_ich ppdev mac_hid parport_pc nfsd nfs_acl auth_rpcgss nfs fscache binfmt_misc lockd sunrpc lp parport msdos sdhci_pci sdhci mmc_core ahci libahci e1000e ptp pps_core [last unloaded: compat]
CPU: 2 PID: 17707 Comm: irq/46-iwlwifi Tainted: G        W  O 3.14.17-patched #4
Hardware name: Dell Inc. Latitude E6430/0CPWYR, BIOS A09 12/13/2012
 00000000 00000000 ebd49d6c c1616221 f985dbdc ebd49d9c c1044e44 f9861df4
 ebd49dc8 0000452b f985dbdc 000003d0 f98395da f98395da ebd49f10 eaf3d8a4
 0000ffff ebd49db4 c1044f03 00000009 ebd49dac f9861df4 ebd49dc8 ebd49e64
Call Trace:
 [<c1616221>] dump_stack+0x41/0x52
 [<c1044e44>] warn_slowpath_common+0x84/0xa0
 [<f98395da>] ? iwl_mvm_rx_ba_notif+0x4ba/0x4d0 [iwlmvm]
 [<f98395da>] ? iwl_mvm_rx_ba_notif+0x4ba/0x4d0 [iwlmvm]
 [<c1044f03>] warn_slowpath_fmt+0x33/0x40
 [<f98395da>] iwl_mvm_rx_ba_notif+0x4ba/0x4d0 [iwlmvm]
 [<c10e3952>] ? ring_buffer_unlock_commit+0xa2/0xd0
 [<c10e9767>] ? trace_buffer_unlock_commit+0x37/0x50
 [<f98568a3>] ? iwl_tm_mvm_send_rx+0x53/0x90 [iwlmvm]
 [<f98327a8>] iwl_mvm_rx_dispatch+0x108/0x130 [iwlmvm]
 [<f9eac7e7>] iwl_pcie_irq_handler+0xf17/0x15b0 [iwlwifi]
 [<c10994c1>] irq_thread_fn+0x21/0x50
 [<c109926c>] irq_thread+0xec/0x110
 [<c10994a0>] ? irq_thread_dtor+0xb0/0xb0
 [<c10993f0>] ? irq_finalize_oneshot.part.34+0xc0/0xc0
 [<c1099180>] ? wake_threads_waitq+0x40/0x40
 [<c1062fdb>] kthread+0x9b/0xb0
 [<c1627137>] ret_from_kernel_thread+0x1b/0x28
 [<c1062f40>] ? flush_kthread_worker+0x90/0x90
---[ end trace 5e0f67374816db17 ]---

Signed-off-by: Eyal Shapira <eyalx.shapira@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/mvm/tx.c

index 4333306ccdee75a02952288196897d63a349b6b0..c59d07567d9041688401c0345376e9dc52de3157 100644 (file)
@@ -90,8 +90,6 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
 
        if (ieee80211_is_probe_resp(fc))
                tx_flags |= TX_CMD_FLG_TSF;
-       else if (ieee80211_is_back_req(fc))
-               tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
 
        if (ieee80211_has_morefrags(fc))
                tx_flags |= TX_CMD_FLG_MORE_FRAG;
@@ -100,6 +98,15 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
                u8 *qc = ieee80211_get_qos_ctl(hdr);
                tx_cmd->tid_tspec = qc[0] & 0xf;
                tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
+       } else if (ieee80211_is_back_req(fc)) {
+               struct ieee80211_bar *bar = (void *)skb->data;
+               u16 control = le16_to_cpu(bar->control);
+
+               tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
+               tx_cmd->tid_tspec = (control &
+                                    IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
+                       IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
+               WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT);
        } else {
                tx_cmd->tid_tspec = IWL_TID_NON_QOS;
                if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)