diff --git a/hal/wifi3.0/hal_api.h b/hal/wifi3.0/hal_api.h index 489f49c13032..06a707e96509 100644 --- a/hal/wifi3.0/hal_api.h +++ b/hal/wifi3.0/hal_api.h @@ -533,6 +533,51 @@ uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset) } #endif +/* Max times allowed for register writing retry */ +#define HAL_REG_WRITE_RETRY_MAX 5 +/* Delay milliseconds for each time retry */ +#define HAL_REG_WRITE_RETRY_DELAY 1 + +/** + * hal_write32_mb_confirm_retry() - write register with confirming and + do retry/recovery if writing failed + * @hal_soc: hal soc handle + * @offset: offset address from the BAR + * @value: value to write + * @recovery: is recovery needed or not. + * + * Write the register value with confirming and read it back, if + * read back value is not as expected, do retry for writing, if + * retry hit max times allowed but still fail, check if recovery + * needed. + * + * Return: None + */ +static inline void hal_write32_mb_confirm_retry(struct hal_soc *hal_soc, + uint32_t offset, + uint32_t value, + bool recovery) +{ + uint8_t retry_cnt = 0; + uint32_t read_value; + + while (retry_cnt <= HAL_REG_WRITE_RETRY_MAX) { + hal_write32_mb_confirm(hal_soc, offset, value); + read_value = hal_read32_mb(hal_soc, offset); + if (qdf_likely(read_value == value)) + break; + + /* write failed, do retry */ + hal_warn("Retry reg offset 0x%x, value 0x%x, read value 0x%x", + offset, value, read_value); + qdf_mdelay(HAL_REG_WRITE_RETRY_DELAY); + retry_cnt++; + } + + if (retry_cnt > HAL_REG_WRITE_RETRY_MAX && recovery) + qdf_trigger_self_recovery(NULL, QDF_HAL_REG_WRITE_FAILURE); +} + #ifdef FEATURE_HAL_DELAYED_REG_WRITE /** * hal_dump_reg_write_srng_stats() - dump SRNG reg write stats diff --git a/hal/wifi3.0/hal_hw_headers.h b/hal/wifi3.0/hal_hw_headers.h index 43cb81841905..49aff583a367 100644 --- a/hal/wifi3.0/hal_hw_headers.h +++ b/hal/wifi3.0/hal_hw_headers.h @@ -116,6 +116,9 @@ #define HAL_REG_WRITE_CONFIRM(_soc, _reg, _value) \ hal_write32_mb_confirm(_soc, (_reg), (_value)) +#define HAL_REG_WRITE_CONFIRM_RETRY(_soc, _reg, _value, _recovery) \ + hal_write32_mb_confirm_retry(_soc, (_reg), (_value), (_recovery)) + #define HAL_REG_READ(_soc, _offset) \ hal_read32_mb(_soc, (_offset)) diff --git a/hal/wifi3.0/hal_srng.c b/hal/wifi3.0/hal_srng.c index f6427486c09b..f242b0579a39 100644 --- a/hal/wifi3.0/hal_srng.c +++ b/hal/wifi3.0/hal_srng.c @@ -970,28 +970,32 @@ void hal_reo_read_write_ctrl_ix(hal_soc_handle_t hal_soc_hdl, bool read, reg_offset = HWIO_REO_R0_DESTINATION_RING_CTRL_IX_0_ADDR( SEQ_WCSS_UMAC_REO_REG_OFFSET); - HAL_REG_WRITE_CONFIRM(hal, reg_offset, *ix0); + HAL_REG_WRITE_CONFIRM_RETRY(hal, reg_offset, + *ix0, true); } if (ix1) { reg_offset = HWIO_REO_R0_DESTINATION_RING_CTRL_IX_1_ADDR( SEQ_WCSS_UMAC_REO_REG_OFFSET); - HAL_REG_WRITE(hal, reg_offset, *ix1); + HAL_REG_WRITE_CONFIRM_RETRY(hal, reg_offset, + *ix1, true); } if (ix2) { reg_offset = HWIO_REO_R0_DESTINATION_RING_CTRL_IX_2_ADDR( SEQ_WCSS_UMAC_REO_REG_OFFSET); - HAL_REG_WRITE_CONFIRM(hal, reg_offset, *ix2); + HAL_REG_WRITE_CONFIRM_RETRY(hal, reg_offset, + *ix2, true); } if (ix3) { reg_offset = HWIO_REO_R0_DESTINATION_RING_CTRL_IX_3_ADDR( SEQ_WCSS_UMAC_REO_REG_OFFSET); - HAL_REG_WRITE_CONFIRM(hal, reg_offset, *ix3); + HAL_REG_WRITE_CONFIRM_RETRY(hal, reg_offset, + *ix3, true); } } } diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h index a1b2518a1405..cfad243b11cc 100644 --- a/qdf/inc/qdf_types.h +++ b/qdf/inc/qdf_types.h @@ -1341,6 +1341,7 @@ enum qdf_suspend_type { * @QDF_VDEV_DELETE_RESPONSE_TIMED_OUT: Delete response timeout from FW * @QDF_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT: Peer delete all resp timeout * @QDF_WMI_BUF_SEQUENCE_MISMATCH: WMI Tx completion buffer sequence mismatch + * @QDF_HAL_REG_WRITE_FAILURE: HAL register writing failures */ enum qdf_hang_reason { QDF_REASON_UNSPECIFIED, @@ -1364,6 +1365,7 @@ enum qdf_hang_reason { QDF_VDEV_DELETE_RESPONSE_TIMED_OUT, QDF_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT, QDF_WMI_BUF_SEQUENCE_MISMATCH, + QDF_HAL_REG_WRITE_FAILURE, }; /**