diff mbox series

iwlwifi: Avoid use of non-existent queues

Message ID 20200320014839.4864-1-mark.asselstine@windriver.com (mailing list archive)
State Superseded
Delegated to: Luca Coelho
Headers show
Series iwlwifi: Avoid use of non-existent queues | expand

Commit Message

Mark Asselstine March 20, 2020, 1:48 a.m. UTC
From: Mark Asselstine <asselsm@gmail.com>

In iwl_pcie_tx_alloc() we only allocate 'num_of_queues' queues to
iwl_trans_pcie.txq[] yet queue_info[] always has IWL_MAX_HW_QUEUES
(ie. 32) entries. This gives us a range of queues from 0 to 31,
however, on some devices we have a num_of_queues of 31 or even 20,
thus a range of 0 to num_of_queues - 1 (or 0 - 30 on 8000 series
devices).

We need to therefor make some of the entries in queue_info[]
unavailable to functions like iwl_mvm_find_free_queue() which
otherwise will return invalid queue indexes.

Without this we get the following Oops:

  kernel: BUG: kernel NULL pointer dereference, address: 00000000000000d8
  kernel: #PF: supervisor write access in kernel mode
  kernel: #PF: error_code(0x0002) - not-present page
  kernel: PGD 0 P4D 0
  kernel: Oops: 0002 [#1] SMP PTI
  kernel: CPU: 0 PID: 2086 Comm: kworker/0:0 Not tainted 5.6.0-0.rc4.git0.1.fc33.x86_64+debug #1
  kernel: Hardware name: LENOVO 10A8S08P00/SHARKBAY, BIOS FBKTDBAUS 12/24/2019
  kernel: Workqueue: events iwl_mvm_add_new_dqa_stream_wk [iwlmvm]
  kernel: RIP: 0010:iwl_trans_pcie_txq_enable+0x4d/0x460 [iwlwifi]
  kernel: Code: bc c7 80 19 00 00 66 89 14 24 f0 48 0f ab 87 80 29 00 00 73 0d 80 3d af 37
  04 00 00 0f 84 c6 03 00 00 44 89 c7 e8 03 42 b0 d0 <49> 89 87 d8 00 00 00 4d 85 f6 0f 84
  d1 02 00 00 41 0f b6 06 89 44
  kernel: RSP: 0018:ffffac44c081fd08 EFLAGS: 00010202
  kernel: RAX: 0000000000002710 RBX: 0000000000000000 RCX: 0000000000000000
  kernel: RDX: 3ffffffffffffffe RSI: 000000000000001f RDI: 0000000000002710
  kernel: RBP: ffff8ee008040028 R08: 0000000000002710 R09: 0000000000000001
  kernel: R10: 0000000000000000 R11: 0000000000000000 R12: 000000000000001f
  kernel: R13: ffff8ee00567b3e8 R14: 0000000000000000 R15: 0000000000000000
  kernel: FS:  0000000000000000(0000) GS:ffff8ee00e800000(0000) knlGS:0000000000000000
  kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  kernel: CR2: 00000000000000d8 CR3: 0000000040612003 CR4: 00000000001606f0
  kernel: Call Trace:
  kernel:  iwl_mvm_enable_txq+0x1d8/0x2b0 [iwlmvm]
  kernel:  iwl_mvm_add_new_dqa_stream_wk+0x203/0x910 [iwlmvm]
  kernel:  process_one_work+0x25d/0x570
  kernel:  worker_thread+0x55/0x3d0
  kernel:  ? process_one_work+0x570/0x570
  kernel:  kthread+0x120/0x140
  kernel:  ? __kthread_bind_mask+0x60/0x60
  kernel:  ret_from_fork+0x3a/0x50

which logging shows happens when a queue index of 31 (txq_id) is used
for trans_pcie->txq[txq_id].

Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=206765
Reported-by: Gabriel Ramirez <gabriello.ramirez@gmail.com>
Signed-off-by: Mark Asselstine <asselsm@gmail.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 54c094e88474..bb6234b13014 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -310,7 +310,7 @@  static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
 	struct iwl_notification_wait alive_wait;
 	struct iwl_mvm_alive_data alive_data = {};
 	const struct fw_img *fw;
-	int ret;
+	int i, ret;
 	enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img;
 	static const u16 alive_cmd[] = { MVM_ALIVE };
 	bool run_in_rfkill =
@@ -413,6 +413,16 @@  static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
 	mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].tid_bitmap =
 		BIT(IWL_MAX_TID_COUNT + 2);
 
+	/*
+	 * Similarly prevent use of non-existing queues. The range
+	 * is from 0 - (num_of_queues-1) or 0 - (IWL_MAX_HW_QUEUES-1)
+	 * whichever is smaller. So we need to disable any queues
+	 * from num_of_queues to IWL_MAX_HW_QUEUES.
+	 */
+	for (i = mvm->trans->trans_cfg->base_params->num_of_queues;
+	     i < IWL_MAX_HW_QUEUES; i++)
+		mvm->queue_info[i].tid_bitmap = BIT(IWL_MAX_TID_COUNT + 2);
+
 	set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 	iwl_fw_set_dbg_rec_on(&mvm->fwrt);