|
@@ -27,6 +27,9 @@
|
|
|
#include "hif_io32.h"
|
|
|
#include "qdf_platform.h"
|
|
|
|
|
|
+/* Ring index for WBM2SW2 release ring */
|
|
|
+#define HAL_IPA_TX_COMP_RING_IDX 2
|
|
|
+
|
|
|
/* calculate the register address offset from bar0 of shadow register x */
|
|
|
#if defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490)
|
|
|
#define SHADOW_REGISTER_START_ADDRESS_OFFSET 0x000008FC
|
|
@@ -597,6 +600,135 @@ uint32_t hal_read32_mb_cmem(struct hal_soc *hal_soc, uint32_t offset)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+#ifdef GENERIC_SHADOW_REGISTER_ACCESS_ENABLE
|
|
|
+/* To check shadow config index range between 0..31 */
|
|
|
+#define HAL_SHADOW_REG_INDEX_LOW 32
|
|
|
+/* To check shadow config index range between 32..39 */
|
|
|
+#define HAL_SHADOW_REG_INDEX_HIGH 40
|
|
|
+/* Dirty bit reg offsets corresponding to shadow config index */
|
|
|
+#define HAL_SHADOW_REG_DIRTY_BIT_DATA_LOW_OFFSET 0x30C8
|
|
|
+#define HAL_SHADOW_REG_DIRTY_BIT_DATA_HIGH_OFFSET 0x30C4
|
|
|
+/* PCIE_PCIE_TOP base addr offset */
|
|
|
+#define HAL_PCIE_PCIE_TOP_WRAPPER 0x01E00000
|
|
|
+/* Max retry attempts to read the dirty bit reg */
|
|
|
+#ifdef HAL_CONFIG_SLUB_DEBUG_ON
|
|
|
+#define HAL_SHADOW_DIRTY_BIT_POLL_MAX 10000
|
|
|
+#else
|
|
|
+#define HAL_SHADOW_DIRTY_BIT_POLL_MAX 2000
|
|
|
+#endif
|
|
|
+/* Delay in usecs for polling dirty bit reg */
|
|
|
+#define HAL_SHADOW_DIRTY_BIT_POLL_DELAY 5
|
|
|
+
|
|
|
+/**
|
|
|
+ * hal_poll_dirty_bit_reg() - Poll dirty register bit to confirm
|
|
|
+ * write was successful
|
|
|
+ * @hal_soc: hal soc handle
|
|
|
+ * @shadow_config_index: index of shadow reg used to confirm
|
|
|
+ * write
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static inline QDF_STATUS hal_poll_dirty_bit_reg(struct hal_soc *hal,
|
|
|
+ int shadow_config_index)
|
|
|
+{
|
|
|
+ uint32_t read_value = 0;
|
|
|
+ int retry_cnt = 0;
|
|
|
+ uint32_t reg_offset = 0;
|
|
|
+
|
|
|
+ if (shadow_config_index > 0 &&
|
|
|
+ shadow_config_index < HAL_SHADOW_REG_INDEX_LOW) {
|
|
|
+ reg_offset =
|
|
|
+ HAL_SHADOW_REG_DIRTY_BIT_DATA_LOW_OFFSET;
|
|
|
+ } else if (shadow_config_index >= HAL_SHADOW_REG_INDEX_LOW &&
|
|
|
+ shadow_config_index < HAL_SHADOW_REG_INDEX_HIGH) {
|
|
|
+ reg_offset =
|
|
|
+ HAL_SHADOW_REG_DIRTY_BIT_DATA_HIGH_OFFSET;
|
|
|
+ } else {
|
|
|
+ hal_err("Invalid shadow_config_index = %d",
|
|
|
+ shadow_config_index);
|
|
|
+ return QDF_STATUS_E_INVAL;
|
|
|
+ }
|
|
|
+ while (retry_cnt < HAL_SHADOW_DIRTY_BIT_POLL_MAX) {
|
|
|
+ read_value = hal_read32_mb(
|
|
|
+ hal, HAL_PCIE_PCIE_TOP_WRAPPER + reg_offset);
|
|
|
+ /* Check if dirty bit corresponding to shadow_index is set */
|
|
|
+ if (read_value & BIT(shadow_config_index)) {
|
|
|
+ /* Dirty reg bit not reset */
|
|
|
+ qdf_udelay(HAL_SHADOW_DIRTY_BIT_POLL_DELAY);
|
|
|
+ retry_cnt++;
|
|
|
+ } else {
|
|
|
+ hal_debug("Shadow write: offset 0x%x read val 0x%x",
|
|
|
+ reg_offset, read_value);
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return QDF_STATUS_E_TIMEOUT;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hal_write32_mb_shadow_confirm() - write to shadow reg and
|
|
|
+ * poll dirty register bit to confirm write
|
|
|
+ * @hal_soc: hal soc handle
|
|
|
+ * @reg_offset: target reg offset address from BAR
|
|
|
+ * @value: value to write
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static inline QDF_STATUS hal_write32_mb_shadow_confirm(
|
|
|
+ struct hal_soc *hal,
|
|
|
+ uint32_t reg_offset,
|
|
|
+ uint32_t value)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ QDF_STATUS ret;
|
|
|
+ uint32_t shadow_reg_offset;
|
|
|
+ uint32_t read_value;
|
|
|
+ int shadow_config_index;
|
|
|
+ bool is_reg_offset_present = false;
|
|
|
+
|
|
|
+ for (i = 0; i < MAX_GENERIC_SHADOW_REG; i++) {
|
|
|
+ /* Found the shadow config for the reg_offset */
|
|
|
+ struct shadow_reg_config *hal_shadow_reg_list =
|
|
|
+ &hal->list_shadow_reg_config[i];
|
|
|
+ if (hal_shadow_reg_list->target_register ==
|
|
|
+ reg_offset) {
|
|
|
+ shadow_config_index =
|
|
|
+ hal_shadow_reg_list->shadow_config_index;
|
|
|
+ shadow_reg_offset =
|
|
|
+ SHADOW_REGISTER(shadow_config_index);
|
|
|
+ hal_write32_mb_confirm(
|
|
|
+ hal, shadow_reg_offset, value);
|
|
|
+ is_reg_offset_present = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ ret = QDF_STATUS_E_FAILURE;
|
|
|
+ }
|
|
|
+ if (is_reg_offset_present) {
|
|
|
+ ret = hal_poll_dirty_bit_reg(hal, shadow_config_index);
|
|
|
+ read_value = hal_read32_mb(hal, reg_offset);
|
|
|
+ hal_info("Shadow retry:reg 0x%x val 0x%x readval 0x%x ret %d",
|
|
|
+ reg_offset, value, read_value, ret);
|
|
|
+ if (QDF_IS_STATUS_ERROR(ret)) {
|
|
|
+ HAL_STATS_INC(hal, shadow_reg_write_fail, 1);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ HAL_STATS_INC(hal, shadow_reg_write_succ, 1);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+#else /* GENERIC_SHADOW_REGISTER_ACCESS_ENABLE */
|
|
|
+
|
|
|
+static inline QDF_STATUS hal_write32_mb_shadow_confirm(
|
|
|
+ struct hal_soc *hal_soc,
|
|
|
+ uint32_t offset,
|
|
|
+ uint32_t value)
|
|
|
+{
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* GENERIC_SHADOW_REGISTER_ACCESS_ENABLE */
|
|
|
+
|
|
|
/* Max times allowed for register writing retry */
|
|
|
#define HAL_REG_WRITE_RETRY_MAX 5
|
|
|
/* Delay milliseconds for each time retry */
|
|
@@ -624,6 +756,7 @@ static inline void hal_write32_mb_confirm_retry(struct hal_soc *hal_soc,
|
|
|
{
|
|
|
uint8_t retry_cnt = 0;
|
|
|
uint32_t read_value;
|
|
|
+ QDF_STATUS ret;
|
|
|
|
|
|
while (retry_cnt <= HAL_REG_WRITE_RETRY_MAX) {
|
|
|
hal_write32_mb_confirm(hal_soc, offset, value);
|
|
@@ -638,8 +771,12 @@ static inline void hal_write32_mb_confirm_retry(struct hal_soc *hal_soc,
|
|
|
retry_cnt++;
|
|
|
}
|
|
|
|
|
|
- if (retry_cnt > HAL_REG_WRITE_RETRY_MAX && recovery)
|
|
|
- qdf_trigger_self_recovery(NULL, QDF_HAL_REG_WRITE_FAILURE);
|
|
|
+ if (retry_cnt > HAL_REG_WRITE_RETRY_MAX) {
|
|
|
+ ret = hal_write32_mb_shadow_confirm(hal_soc, offset, value);
|
|
|
+ if (QDF_IS_STATUS_ERROR(ret) && recovery)
|
|
|
+ qdf_trigger_self_recovery(
|
|
|
+ NULL, QDF_HAL_REG_WRITE_FAILURE);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#ifdef FEATURE_HAL_DELAYED_REG_WRITE
|
|
@@ -889,12 +1026,13 @@ struct hal_srng_params {
|
|
|
uint32_t prefetch_timer;
|
|
|
};
|
|
|
|
|
|
-/* hal_construct_shadow_config() - initialize the shadow registers for dp rings
|
|
|
+/* hal_construct_srng_shadow_regs() - initialize the shadow
|
|
|
+ * registers for srngs
|
|
|
* @hal_soc: hal handle
|
|
|
*
|
|
|
* Return: QDF_STATUS_OK on success
|
|
|
*/
|
|
|
-extern QDF_STATUS hal_construct_shadow_config(void *hal_soc);
|
|
|
+QDF_STATUS hal_construct_srng_shadow_regs(void *hal_soc);
|
|
|
|
|
|
/* hal_set_one_shadow_config() - add a config for the specified ring
|
|
|
* @hal_soc: hal handle
|
|
@@ -911,8 +1049,8 @@ extern QDF_STATUS hal_construct_shadow_config(void *hal_soc);
|
|
|
*
|
|
|
* Return: QDF_STATUS_OK on success
|
|
|
*/
|
|
|
-extern QDF_STATUS hal_set_one_shadow_config(void *hal_soc, int ring_type,
|
|
|
- int ring_num);
|
|
|
+QDF_STATUS hal_set_one_shadow_config(void *hal_soc, int ring_type,
|
|
|
+ int ring_num);
|
|
|
/**
|
|
|
* hal_get_shadow_config() - retrieve the config table
|
|
|
* @hal_soc: hal handle
|
|
@@ -1012,10 +1150,13 @@ extern void hal_srng_dst_set_hp_paddr(struct hal_srng *sring, uint64_t paddr);
|
|
|
|
|
|
/**
|
|
|
* hal_srng_dst_init_hp() - Initilaize head pointer with cached head pointer
|
|
|
+ * @hal_soc: hal_soc handle
|
|
|
* @srng: sring pointer
|
|
|
* @vaddr: virtual address
|
|
|
*/
|
|
|
-extern void hal_srng_dst_init_hp(struct hal_srng *srng, uint32_t *vaddr);
|
|
|
+void hal_srng_dst_init_hp(struct hal_soc_handle *hal_soc,
|
|
|
+ struct hal_srng *srng,
|
|
|
+ uint32_t *vaddr);
|
|
|
|
|
|
/**
|
|
|
* hal_srng_cleanup - Deinitialize HW SRNG ring.
|
|
@@ -2415,4 +2556,59 @@ static inline void hal_reo_set_err_dst_remap(hal_soc_handle_t hal_soc_hdl)
|
|
|
if (hal_soc->ops->hal_reo_set_err_dst_remap)
|
|
|
hal_soc->ops->hal_reo_set_err_dst_remap(hal_soc);
|
|
|
}
|
|
|
+
|
|
|
+#ifdef GENERIC_SHADOW_REGISTER_ACCESS_ENABLE
|
|
|
+
|
|
|
+/**
|
|
|
+ * hal_set_one_target_reg_config() - Populate the target reg
|
|
|
+ * offset in hal_soc for one non srng related register at the
|
|
|
+ * given list index
|
|
|
+ * @hal_soc: hal handle
|
|
|
+ * @target_reg_offset: target register offset
|
|
|
+ * @list_index: index in hal list for shadow regs
|
|
|
+ *
|
|
|
+ * Return: none
|
|
|
+ */
|
|
|
+void hal_set_one_target_reg_config(struct hal_soc *hal,
|
|
|
+ uint32_t target_reg_offset,
|
|
|
+ int list_index);
|
|
|
+
|
|
|
+/**
|
|
|
+ * hal_set_shadow_regs() - Populate register offset for
|
|
|
+ * registers that need to be populated in list_shadow_reg_config
|
|
|
+ * in order to be sent to FW. These reg offsets will be mapped
|
|
|
+ * to shadow registers.
|
|
|
+ * @hal_soc: hal handle
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_OK on success
|
|
|
+ */
|
|
|
+QDF_STATUS hal_set_shadow_regs(void *hal_soc);
|
|
|
+
|
|
|
+/**
|
|
|
+ * hal_construct_shadow_regs() - initialize the shadow registers
|
|
|
+ * for non-srng related register configs
|
|
|
+ * @hal_soc: hal handle
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_OK on success
|
|
|
+ */
|
|
|
+QDF_STATUS hal_construct_shadow_regs(void *hal_soc);
|
|
|
+
|
|
|
+#else /* GENERIC_SHADOW_REGISTER_ACCESS_ENABLE */
|
|
|
+static inline void hal_set_one_target_reg_config(
|
|
|
+ struct hal_soc *hal,
|
|
|
+ uint32_t target_reg_offset,
|
|
|
+ int list_index)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static inline QDF_STATUS hal_set_shadow_regs(void *hal_soc)
|
|
|
+{
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+static inline QDF_STATUS hal_construct_shadow_regs(void *hal_soc)
|
|
|
+{
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+}
|
|
|
+#endif /* GENERIC_SHADOW_REGISTER_ACCESS_ENABLE */
|
|
|
#endif /* _HAL_APIH_ */
|