Skip to content

Commit 400f6eb

Browse files
jmberg-intelKalle Valo
authored andcommitted
wifi: iwlwifi: pcie: don't synchronize IRQs from IRQ
On older devices (before unified image!) we can end up calling stop_device from an rfkill interrupt. However, in stop_device we attempt to synchronize IRQs, which then of course deadlocks. Avoid this by checking the context, if running from the IRQ thread then don't synchronize. This wouldn't be correct on a new device since RSS is supported, but older devices only have a single interrupt/queue. Fixes: 37fb29b ("wifi: iwlwifi: pcie: synchronize IRQs before NAPI") Reviewed-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://msgid.link/20231215111335.59aab00baed7.Iadfe154d6248e7f9dfd69522e5429dbbd72925d7@changeid
1 parent 3c2a8eb commit 400f6eb

3 files changed

Lines changed: 15 additions & 14 deletions

File tree

drivers/net/wireless/intel/iwlwifi/pcie/internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
770770
}
771771
}
772772

773-
void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans);
773+
void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans, bool from_irq);
774774

775775
static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
776776
{
@@ -817,7 +817,7 @@ static inline bool iwl_pcie_dbg_on(struct iwl_trans *trans)
817817
return (trans->dbg.dest_tlv || iwl_trans_dbg_ini_valid(trans));
818818
}
819819

820-
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state);
820+
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq);
821821
void iwl_trans_pcie_dump_regs(struct iwl_trans *trans);
822822

823823
#ifdef CONFIG_IWLWIFI_DEBUGFS

drivers/net/wireless/intel/iwlwifi/pcie/rx.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,7 +1783,7 @@ static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans)
17831783
return inta;
17841784
}
17851785

1786-
void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans)
1786+
void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans, bool from_irq)
17871787
{
17881788
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
17891789
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
@@ -1807,7 +1807,7 @@ void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans)
18071807
isr_stats->rfkill++;
18081808

18091809
if (prev != report)
1810-
iwl_trans_pcie_rf_kill(trans, report);
1810+
iwl_trans_pcie_rf_kill(trans, report, from_irq);
18111811
mutex_unlock(&trans_pcie->mutex);
18121812

18131813
if (hw_rfkill) {
@@ -1947,7 +1947,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
19471947

19481948
/* HW RF KILL switch toggled */
19491949
if (inta & CSR_INT_BIT_RF_KILL) {
1950-
iwl_pcie_handle_rfkill_irq(trans);
1950+
iwl_pcie_handle_rfkill_irq(trans, true);
19511951
handled |= CSR_INT_BIT_RF_KILL;
19521952
}
19531953

@@ -2370,7 +2370,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
23702370

23712371
/* HW RF KILL switch toggled */
23722372
if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL)
2373-
iwl_pcie_handle_rfkill_irq(trans);
2373+
iwl_pcie_handle_rfkill_irq(trans, true);
23742374

23752375
if (inta_hw & MSIX_HW_INT_CAUSES_REG_HW_ERR) {
23762376
IWL_ERR(trans,

drivers/net/wireless/intel/iwlwifi/pcie/trans.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,7 @@ bool iwl_pcie_check_hw_rf_kill(struct iwl_trans *trans)
10821082
report = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
10831083

10841084
if (prev != report)
1085-
iwl_trans_pcie_rf_kill(trans, report);
1085+
iwl_trans_pcie_rf_kill(trans, report, false);
10861086

10871087
return hw_rfkill;
10881088
}
@@ -1237,7 +1237,7 @@ static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
12371237
trans_pcie->hw_mask = trans_pcie->hw_init_mask;
12381238
}
12391239

1240-
static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans)
1240+
static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool from_irq)
12411241
{
12421242
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
12431243

@@ -1264,7 +1264,8 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans)
12641264
if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
12651265
IWL_DEBUG_INFO(trans,
12661266
"DEVICE_ENABLED bit was set and is now cleared\n");
1267-
iwl_pcie_synchronize_irqs(trans);
1267+
if (!from_irq)
1268+
iwl_pcie_synchronize_irqs(trans);
12681269
iwl_pcie_rx_napi_sync(trans);
12691270
iwl_pcie_tx_stop(trans);
12701271
iwl_pcie_rx_stop(trans);
@@ -1454,7 +1455,7 @@ void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans,
14541455
clear_bit(STATUS_RFKILL_OPMODE, &trans->status);
14551456
}
14561457
if (hw_rfkill != was_in_rfkill)
1457-
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
1458+
iwl_trans_pcie_rf_kill(trans, hw_rfkill, false);
14581459
}
14591460

14601461
static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
@@ -1469,12 +1470,12 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
14691470
mutex_lock(&trans_pcie->mutex);
14701471
trans_pcie->opmode_down = true;
14711472
was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
1472-
_iwl_trans_pcie_stop_device(trans);
1473+
_iwl_trans_pcie_stop_device(trans, false);
14731474
iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill);
14741475
mutex_unlock(&trans_pcie->mutex);
14751476
}
14761477

1477-
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
1478+
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq)
14781479
{
14791480
struct iwl_trans_pcie __maybe_unused *trans_pcie =
14801481
IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1487,7 +1488,7 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
14871488
if (trans->trans_cfg->gen2)
14881489
_iwl_trans_pcie_gen2_stop_device(trans);
14891490
else
1490-
_iwl_trans_pcie_stop_device(trans);
1491+
_iwl_trans_pcie_stop_device(trans, from_irq);
14911492
}
14921493
}
14931494

@@ -2887,7 +2888,7 @@ static ssize_t iwl_dbgfs_rfkill_write(struct file *file,
28872888
IWL_WARN(trans, "changing debug rfkill %d->%d\n",
28882889
trans_pcie->debug_rfkill, new_value);
28892890
trans_pcie->debug_rfkill = new_value;
2890-
iwl_pcie_handle_rfkill_irq(trans);
2891+
iwl_pcie_handle_rfkill_irq(trans, false);
28912892

28922893
return count;
28932894
}

0 commit comments

Comments
 (0)