wifi: ath12k: reset REOQ LUT addresses before firmware stop

During module removal, REOQ LUT cleanup writes 0 to the REOQ/ML-REOQ
LUT address registers. That cleanup runs from ath12k_core_stop(),
after ath12k_qmi_firmware_stop() has already stopped the
firmware (mode OFF), so the register writes can hit an invalid target
access.

Move the REOQ LUT register reset before ath12k_qmi_firmware_stop(),
so the registers are cleared before stopping the firmware,
while register access is still valid.

Additionally, handle the error path where firmware-ready setup fails
after LUT programming but before core_stop() is reached, ensuring the
registers are properly reset in that case as well.

On the crash-recovery path, ath12k_core_reconfigure_on_crash() calls
ath12k_core_qmi_firmware_ready(), which re-enters ath12k_dp_setup()
and ath12k_dp_reoq_lut_setup(), so the LUT registers are reprogrammed
before use and stale values do not persist across recovery.

There is a brief window between the crash and when the LUT registers
are reprogrammed during recovery, during which the registers still hold
the freed DMA memory addresses. This is safe because the device is
non-functional in that window and will not initiate any DMA access
until firmware is restarted and the registers are reprogrammed.

No functional issue has been observed so far due to this sequence.
However, this change proactively avoids potential issues such as
invalid register accesses after firmware stop during module
removal and error handling.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Co-developed-by: P Praneesh <praneesh.p@oss.qualcomm.com>
Signed-off-by: P Praneesh <praneesh.p@oss.qualcomm.com>
Signed-off-by: Aishwarya R <aishwarya.r@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Link: https://patch.msgid.link/20260619120751.363340-1-aishwarya.r@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
Aishwarya R
2026-06-19 17:37:51 +05:30
committed by Jeff Johnson
parent c2d60ab8e3
commit fe2b006c15
3 changed files with 17 additions and 3 deletions

View File

@@ -708,8 +708,10 @@ static void ath12k_core_stop(struct ath12k_base *ab)
ath12k_core_to_group_ref_put(ab);
if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags)) {
ath12k_dp_reoq_lut_addr_reset(ath12k_ab_to_dp(ab));
ath12k_qmi_firmware_stop(ab);
}
ath12k_acpi_stop(ab);
@@ -1371,6 +1373,7 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
goto exit;
err_deinit:
ath12k_dp_reoq_lut_addr_reset(ath12k_ab_to_dp(ab));
ath12k_dp_cmn_device_deinit(ath12k_ab_to_dp(ab));
mutex_unlock(&ab->core_lock);
mutex_unlock(&ag->mutex);

View File

@@ -1097,7 +1097,6 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
return;
if (dp->reoq_lut.vaddr_unaligned) {
ath12k_hal_write_reoq_lut_addr(ab, 0);
dma_free_coherent(ab->dev, dp->reoq_lut.size,
dp->reoq_lut.vaddr_unaligned,
dp->reoq_lut.paddr_unaligned);
@@ -1105,7 +1104,6 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
}
if (dp->ml_reoq_lut.vaddr_unaligned) {
ath12k_hal_write_ml_reoq_lut_addr(ab, 0);
dma_free_coherent(ab->dev, dp->ml_reoq_lut.size,
dp->ml_reoq_lut.vaddr_unaligned,
dp->ml_reoq_lut.paddr_unaligned);
@@ -1568,6 +1566,7 @@ static int ath12k_dp_setup(struct ath12k_base *ab)
ath12k_dp_rx_free(ab);
fail_cmn_reoq_cleanup:
ath12k_dp_reoq_lut_addr_reset(dp);
ath12k_dp_reoq_lut_cleanup(ab);
fail_cmn_srng_cleanup:
@@ -1627,3 +1626,14 @@ void ath12k_dp_cmn_hw_group_assign(struct ath12k_dp *dp,
dp->device_id = ab->device_id;
dp_hw_grp->dp[dp->device_id] = dp;
}
void ath12k_dp_reoq_lut_addr_reset(struct ath12k_dp *dp)
{
struct ath12k_base *ab = dp->ab;
if (dp->reoq_lut.vaddr_unaligned)
ath12k_hal_write_reoq_lut_addr(ab, 0);
if (dp->ml_reoq_lut.vaddr_unaligned)
ath12k_hal_write_ml_reoq_lut_addr(ab, 0);
}

View File

@@ -701,4 +701,5 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_dp *dp,
u32 cookie);
struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_dp *dp,
u32 desc_id);
void ath12k_dp_reoq_lut_addr_reset(struct ath12k_dp *dp);
#endif