diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index 1322acb42b..4dd81fffd0 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -63,7 +63,7 @@ jobs: # debug ls -la git log --pretty=oneline | head -n 10 - $ZEPHYR_BASE/scripts/ci/check_compliance.py -m Codeowners -m Devicetree -m Gitlint -m Identity -m Nits -m pylint -m checkpatch -m KconfigBasic -c origin/${BASE_REF}.. + $ZEPHYR_BASE/scripts/ci/check_compliance.py -m Codeowners -m Devicetree -m Gitlint -m Identity -m Nits -m pylint -m checkpatch -c origin/${BASE_REF}.. - name: Upload Results uses: actions/upload-artifact@master diff --git a/nrf_wifi/fw_bins/default/nrf70.bin b/nrf_wifi/fw_bins/default/nrf70.bin index 2a3f210217..901da75b52 100644 Binary files a/nrf_wifi/fw_bins/default/nrf70.bin and b/nrf_wifi/fw_bins/default/nrf70.bin differ diff --git a/nrf_wifi/fw_bins/radio_test/nrf70.bin b/nrf_wifi/fw_bins/radio_test/nrf70.bin index a3168e2559..100c6d65c6 100644 Binary files a/nrf_wifi/fw_bins/radio_test/nrf70.bin and b/nrf_wifi/fw_bins/radio_test/nrf70.bin differ diff --git a/nrf_wifi/fw_bins/scan_only/nrf70.bin b/nrf_wifi/fw_bins/scan_only/nrf70.bin index 8513073cb0..909aaf50f8 100644 Binary files a/nrf_wifi/fw_bins/scan_only/nrf70.bin and b/nrf_wifi/fw_bins/scan_only/nrf70.bin differ diff --git a/nrf_wifi/fw_if/umac_if/inc/default/fmac_api.h b/nrf_wifi/fw_if/umac_if/inc/default/fmac_api.h index f483fbc584..34eb6a4f37 100644 --- a/nrf_wifi/fw_if/umac_if/inc/default/fmac_api.h +++ b/nrf_wifi/fw_if/umac_if/inc/default/fmac_api.h @@ -1036,6 +1036,13 @@ bool nrf_wifi_util_is_rawpktmode_enabled(struct nrf_wifi_fmac_vif_ctx *vif); *@retval WIFI_NRF_STATUS_FAIL On failure */ enum nrf_wifi_status nrf_wifi_check_mode_validity(unsigned char mode); +#if defined(CONFIG_NRF_WIFI_RPU_RECOVERY) || defined(__DOXYGEN__) +/** @cond INTERNAL_HIDDEN */ +enum nrf_wifi_status nrf_wifi_fmac_rpu_recovery_callback(void *mac_dev_ctx, + void *event_data, + unsigned int len); +/** @endcond */ +#endif /* CONFIG_NRF_RPU_RECOVERY */ /** * @} */ diff --git a/nrf_wifi/fw_if/umac_if/inc/default/fmac_structs.h b/nrf_wifi/fw_if/umac_if/inc/default/fmac_structs.h index 1c42e55ea1..7e3a1e01f8 100644 --- a/nrf_wifi/fw_if/umac_if/inc/default/fmac_structs.h +++ b/nrf_wifi/fw_if/umac_if/inc/default/fmac_structs.h @@ -99,6 +99,11 @@ struct raw_rx_pkt_header { * the UMAC IF layer needs to invoke for various events. */ struct nrf_wifi_fmac_callbk_fns { + /** Callback function to be called when RPU recovery is required. */ + void (*rpu_recovery_callbk_fn)(void *os_vif_ctx, + void *event_data, + unsigned int event_len); + /** Callback function to be called when a scan is started. */ void (*scan_start_callbk_fn)(void *os_vif_ctx, struct nrf_wifi_umac_event_trigger_scan *scan_start_event, diff --git a/nrf_wifi/fw_if/umac_if/inc/fw/host_rpu_sys_if.h b/nrf_wifi/fw_if/umac_if/inc/fw/host_rpu_sys_if.h index f3c8b0c508..f20ab5c289 100644 --- a/nrf_wifi/fw_if/umac_if/inc/fw/host_rpu_sys_if.h +++ b/nrf_wifi/fw_if/umac_if/inc/fw/host_rpu_sys_if.h @@ -828,6 +828,30 @@ enum op_band { BAND_24G }; +/** + * @brief This enum defines keep alive state + * + */ +enum keep_alive_status { + /** Keep alive feature disabled */ + KEEP_ALIVE_DISABLED = 0, + /** Keep alive feature enabled */ + KEEP_ALIVE_ENABLED = 1 +}; + +/** + * @brief This enum specifies the type of frames used to retrieve buffered data + * from the AP in power save mode. + */ +enum data_retrieve_mechanism { + /** Retrieves data from the AP using a PS-Poll frame */ + PS_POLL_FRAME, + /** Retrieves data from the AP using a QoS Null frame */ + QOS_NULL_FRAME, + /** For future implementation. The RPU will decide which frame to use */ + AUTOMATIC +}; + #define TWT_EXTEND_SP_EDCA 0x1 #define DISABLE_DFS_CHANNELS 0x2 @@ -872,6 +896,20 @@ struct nrf_wifi_cmd_sys_init { * without receiving beacons before disconnection. */ unsigned int discon_timeout; + /** RPU uses QoS null frame or PS-Poll frame to retrieve buffered frames + * from the AP in power save @ref data_retrieve_mechanism. + */ + unsigned char ps_data_retrieval_mech; + /** The RPU uses this value to configure watchdog timer */ + unsigned int watchdog_timer_val; + /** The RPU uses this value to decide whether keep alive + * feature is enabled or not see enum keep_alive_status + */ + unsigned char keep_alive_enable; + /** The RPU uses this value(in seconds) for periodicity of the keep + * alive frame. + */ + unsigned int keep_alive_period; } __NRF_WIFI_PKD; /** diff --git a/nrf_wifi/fw_if/umac_if/inc/fw/lmac_if_common.h b/nrf_wifi/fw_if/umac_if/inc/fw/lmac_if_common.h index f3ddb04ad1..e903b96b65 100644 --- a/nrf_wifi/fw_if/umac_if/inc/fw/lmac_if_common.h +++ b/nrf_wifi/fw_if/umac_if/inc/fw/lmac_if_common.h @@ -19,7 +19,7 @@ #define RPU_MEM_LMAC_VER 0xB7000D54 #define RPU_MEM_LMAC_PATCH_BIN 0x80044000 -#define RPU_MEM_LMAC_PATCH_BIMG 0x8004B000 +#define RPU_MEM_LMAC_PATCH_BIMG 0x8004B400 #define NRF_WIFI_LMAC_VER(ver) ((ver & 0xFF000000) >> 24) #define NRF_WIFI_LMAC_VER_MAJ(ver) ((ver & 0x00FF0000) >> 16) diff --git a/nrf_wifi/fw_if/umac_if/src/cmd.c b/nrf_wifi/fw_if/umac_if/src/cmd.c index cb4847be75..063c520599 100644 --- a/nrf_wifi/fw_if/umac_if/src/cmd.c +++ b/nrf_wifi/fw_if/umac_if/src/cmd.c @@ -149,10 +149,30 @@ enum nrf_wifi_status umac_cmd_init(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx, umac_cmd_data->tcp_ip_checksum_offload = 1; #endif /* CONFIG_NRF700X_TCP_IP_CHECKSUM_OFFLOAD */ umac_cmd_data->discon_timeout = CONFIG_NRF_WIFI_AP_DEAD_DETECT_TIMEOUT; +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + umac_cmd_data->watchdog_timer_val = + (CONFIG_NRF_WIFI_RPU_RECOVERY_PS_ACTIVE_TIMEOUT_MS) / 1000; +#else + /* Disable watchdog */ + umac_cmd_data->watchdog_timer_val = 0xFFFFFF; +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv, "RPU LPM type: %s", umac_cmd_data->sys_params.sleep_enable == 2 ? "HW" : umac_cmd_data->sys_params.sleep_enable == 1 ? "SW" : "DISABLED"); +#ifdef CONFIG_NRF_WIFI_MGMT_BUFF_OFFLOAD + umac_cmd_data->mgmt_buff_offload = 1; + nrf_wifi_osal_log_info(fmac_dev_ctx->fpriv->opriv, + "Management buffer offload enabled\n"); +#endif /* CONFIG_NRF_WIFI_MGMT_BUFF_OFFLOAD */ +#ifdef CONFIG_NRF_WIFI_FEAT_KEEPALIVE + umac_cmd_data->keep_alive_enable = KEEP_ALIVE_ENABLED; + umac_cmd_data->keep_alive_period = CONFIG_NRF_WIFI_KEEPALIVE_PERIOD_S; + nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv, + "Keepalive enabled with period %d\n", + umac_cmd_data->keepalive_period); +#endif /* CONFIG_NRF_WIFI_FEAT_KEEPALIVE */ + #ifndef CONFIG_NRF700X_RADIO_TEST nrf_wifi_osal_mem_cpy(fmac_dev_ctx->fpriv->opriv, umac_cmd_data->rx_buf_pools, @@ -202,7 +222,13 @@ enum nrf_wifi_status umac_cmd_init(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx, umac_cmd_data->disable_beamforming = 1; } - status = nrf_wifi_hal_ctrl_cmd_send(fmac_dev_ctx->hal_dev_ctx, +#if defined(CONFIG_NRF_WIFI_QOS_NULL_BASED_RETRIEVAL) + umac_cmd_data->ps_data_retrieval_mech = QOS_NULL_FRAME; +#else + umac_cmd_data->ps_data_retrieval_mech = PS_POLL_FRAME; +#endif /* CONFIG_NRF_WIFI_QOS_NULL_BASED_RETRIEVAL */ + + status = nrf_wifi_hal_ctrl_cmd_send(fmac_dev_ctx->hal_dev_ctx, umac_cmd, (sizeof(*umac_cmd) + len)); diff --git a/nrf_wifi/fw_if/umac_if/src/default/fmac_api.c b/nrf_wifi/fw_if/umac_if/src/default/fmac_api.c index 40a34134d0..dc9ee7b8c0 100644 --- a/nrf_wifi/fw_if/umac_if/src/default/fmac_api.c +++ b/nrf_wifi/fw_if/umac_if/src/default/fmac_api.c @@ -433,13 +433,50 @@ enum nrf_wifi_status nrf_wifi_fmac_dev_init(struct nrf_wifi_fmac_dev_ctx *fmac_d void nrf_wifi_fmac_dev_deinit(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx) { - nrf_wifi_hal_lock_rx(fmac_dev_ctx->hal_dev_ctx); + nrf_wifi_hal_dev_deinit(fmac_dev_ctx->hal_dev_ctx); nrf_wifi_fmac_fw_deinit(fmac_dev_ctx); nrf_wifi_osal_mem_free(fmac_dev_ctx->fpriv->opriv, fmac_dev_ctx->tx_pwr_ceil_params); - nrf_wifi_hal_unlock_rx(fmac_dev_ctx->hal_dev_ctx); } +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY +enum nrf_wifi_status nrf_wifi_fmac_rpu_recovery_callback(void *mac_dev_ctx, + void *event_data, + unsigned int len) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + struct nrf_wifi_fmac_priv *fpriv = NULL; + struct nrf_wifi_fmac_priv_def *def_priv = NULL; + + fmac_dev_ctx = mac_dev_ctx; + if (!fmac_dev_ctx) { + nrf_wifi_osal_log_err(fpriv->opriv, + "%s: Invalid device context", + __func__); + goto out; + } + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + if (!def_dev_ctx) { + nrf_wifi_osal_log_err(fpriv->opriv, + "%s: Invalid device context", + __func__); + goto out; + } + fpriv = fmac_dev_ctx->fpriv; + def_priv = wifi_fmac_priv(fpriv); + + /* Here we only care about FMAC, so, just use VIF0 */ + def_priv->callbk_fns.rpu_recovery_callbk_fn(def_dev_ctx->vif_ctx[0], + event_data, len); + + status = NRF_WIFI_STATUS_SUCCESS; +out: + return status; +} +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ + struct nrf_wifi_fmac_priv *nrf_wifi_fmac_init(struct nrf_wifi_data_config_params *data_config, struct rx_buf_pool_params *rx_buf_pools, struct nrf_wifi_fmac_callbk_fns *callbk_fns) @@ -525,7 +562,12 @@ struct nrf_wifi_fmac_priv *nrf_wifi_fmac_init(struct nrf_wifi_data_config_params fpriv->hpriv = nrf_wifi_hal_init(opriv, &hal_cfg_params, - &nrf_wifi_fmac_event_callback); + &nrf_wifi_fmac_event_callback, +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + &nrf_wifi_fmac_rpu_recovery_callback); +#else + NULL); +#endif if (!fpriv->hpriv) { nrf_wifi_osal_log_err(opriv, diff --git a/nrf_wifi/fw_if/umac_if/src/event.c b/nrf_wifi/fw_if/umac_if/src/event.c index 41ca50ccc7..06dfbaaad4 100644 --- a/nrf_wifi/fw_if/umac_if/src/event.c +++ b/nrf_wifi/fw_if/umac_if/src/event.c @@ -194,10 +194,17 @@ static enum nrf_wifi_status umac_event_ctrl_process(struct nrf_wifi_fmac_dev_ctx callbk_fns = &def_priv->callbk_fns; #endif /* !CONFIG_NRF700X_RADIO_TEST */ +#ifdef CONFIG_NRF_WIFI_CMD_EVENT_LOG + nrf_wifi_osal_log_info(fmac_dev_ctx->fpriv->opriv, + "%s: Event %d received from UMAC\n", + __func__, + event_num); +#else nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv, "%s: Event %d received from UMAC", __func__, event_num); +#endif /* CONFIG_NRF_WIFI_CMD_EVENT_LOG */ switch (umac_hdr->cmd_evnt) { case NRF_WIFI_UMAC_EVENT_GET_REG: @@ -631,10 +638,17 @@ nrf_wifi_fmac_data_event_process(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx, event = ((struct nrf_wifi_umac_head *)umac_head)->cmd; +#ifdef CONFIG_NRF_WIFI_CMD_EVENT_LOG + nrf_wifi_osal_log_info(fmac_dev_ctx->fpriv->opriv, + "%s: Event %d received from UMAC\n", + __func__, + event); +#else nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv, "%s: Event %d received from UMAC", __func__, event); +#endif /* CONFIG_NRF_WIFI_CMD_EVENT_LOG */ switch (event) { case NRF_WIFI_CMD_RX_BUFF: @@ -1121,10 +1135,17 @@ enum nrf_wifi_status nrf_wifi_fmac_event_callback(void *mac_dev_ctx, umac_msg_len = rpu_msg->hdr.len; umac_msg_type = umac_hdr->cmd_evnt; +#ifdef CONFIG_NRF_WIFI_CMD_EVENT_LOG + nrf_wifi_osal_log_info(fmac_dev_ctx->fpriv->opriv, + "%s: Event type %d recd\n", + __func__, + rpu_msg->type); +#else nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv, "%s: Event type %d recd", __func__, rpu_msg->type); +#endif /* CONFIG_NRF_WIFI_CMD_EVENT_LOG */ switch (rpu_msg->type) { #ifndef CONFIG_NRF700X_RADIO_TEST diff --git a/nrf_wifi/fw_if/umac_if/src/radio_test/fmac_api.c b/nrf_wifi/fw_if/umac_if/src/radio_test/fmac_api.c index 6579460892..0c616b15b4 100644 --- a/nrf_wifi/fw_if/umac_if/src/radio_test/fmac_api.c +++ b/nrf_wifi/fw_if/umac_if/src/radio_test/fmac_api.c @@ -229,7 +229,8 @@ struct nrf_wifi_fmac_priv *nrf_wifi_fmac_init_rt(void) fpriv->hpriv = nrf_wifi_hal_init(opriv, &hal_cfg_params, - &nrf_wifi_fmac_event_callback); + &nrf_wifi_fmac_event_callback, + NULL); if (!fpriv->hpriv) { nrf_wifi_osal_log_err(opriv, diff --git a/nrf_wifi/fw_if/umac_if/src/rx.c b/nrf_wifi/fw_if/umac_if/src/rx.c index 01f6d3d468..cdb6c206cb 100644 --- a/nrf_wifi/fw_if/umac_if/src/rx.c +++ b/nrf_wifi/fw_if/umac_if/src/rx.c @@ -375,6 +375,9 @@ enum nrf_wifi_status nrf_wifi_fmac_rx_event_process(struct nrf_wifi_fmac_dev_ctx #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ nrf_wifi_osal_nbuf_free(fmac_dev_ctx->fpriv->opriv, nwb); +#ifdef CONFIG_NRF_WIFI_MGMT_BUFF_OFFLOAD + goto out; +#endif /* CONFIG_NRF_WIFI_MGMT_BUFF_OFFLOAD */ } #if defined(CONFIG_NRF700X_RAW_DATA_RX) || defined(CONFIG_NRF700X_PROMISC_DATA_RX) else if (config->rx_pkt_type == NRF_WIFI_RAW_RX_PKT) { diff --git a/nrf_wifi/fw_if/umac_if/src/tx.c b/nrf_wifi/fw_if/umac_if/src/tx.c index b0bf63b753..8335a73ba4 100644 --- a/nrf_wifi/fw_if/umac_if/src/tx.c +++ b/nrf_wifi/fw_if/umac_if/src/tx.c @@ -1452,6 +1452,14 @@ enum nrf_wifi_status nrf_wifi_fmac_rawtx_done_event_process( goto out; } + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + if (!def_dev_ctx || !def_dev_ctx->tx_config.tx_lock) { + /* This is a valid case when the TX_DONE event is received + * during the driver deinit, so, silently ignore the failure. + */ + return NRF_WIFI_STATUS_SUCCESS; + } + nrf_wifi_osal_spinlock_take(fmac_dev_ctx->fpriv->opriv, def_dev_ctx->tx_config.tx_lock); @@ -1790,6 +1798,12 @@ void tx_deinit(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx) for (i = 0; i < def_priv->num_tx_tokens; i++) { if (def_dev_ctx->tx_config.pkt_info_p) { + while (nrf_wifi_utils_q_len(fpriv->opriv, + def_dev_ctx->tx_config.pkt_info_p[i].pkt)) { + nrf_wifi_osal_nbuf_free(fpriv->opriv, + nrf_wifi_utils_q_dequeue(fpriv->opriv, + def_dev_ctx->tx_config.pkt_info_p[i].pkt)); + } nrf_wifi_utils_list_free(fpriv->opriv, def_dev_ctx->tx_config.pkt_info_p[i].pkt); } @@ -1800,6 +1814,12 @@ void tx_deinit(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx) for (i = 0; i < NRF_WIFI_FMAC_AC_MAX; i++) { for (j = 0; j < MAX_SW_PEERS; j++) { + while (nrf_wifi_utils_q_len(fpriv->opriv, + def_dev_ctx->tx_config.data_pending_txq[j][i])) { + nrf_wifi_osal_nbuf_free(fpriv->opriv, + nrf_wifi_utils_q_dequeue(fpriv->opriv, + def_dev_ctx->tx_config.data_pending_txq[j][i])); + } nrf_wifi_utils_q_free(fpriv->opriv, def_dev_ctx->tx_config.data_pending_txq[j][i]); } diff --git a/nrf_wifi/hw_if/hal/inc/fw/rpu_if.h b/nrf_wifi/hw_if/hal/inc/fw/rpu_if.h index 88e3ea83cf..0fa1dc69bf 100644 --- a/nrf_wifi/hw_if/hal/inc/fw/rpu_if.h +++ b/nrf_wifi/hw_if/hal/inc/fw/rpu_if.h @@ -101,6 +101,12 @@ struct rpu_mcu_boot_vectors { #define RPU_REG_BIT_MIPS_WATCHDOG_INT_STATUS 1 #define RPU_REG_MIPS_MCU_TIMER_CONTROL 0xA4000048 +#define RPU_REG_MIPS_MCU_TIMER 0xA400004C /* 24 bit timer@core clock ticks*/ +#define RPU_REG_MIPS_MCU_TIMER_RESET_VAL 0xFFFFFF + +#define RPU_REG_MIPS_MCU_UCCP_INT_CLEAR 0xA400000C +#define RPU_REG_BIT_MIPS_UCCP_INT_CLEAR 0 +#define RPU_REG_BIT_MIPS_WATCHDOG_INT_CLEAR 1 #define RPU_REG_MIPS_MCU_SYS_CORE_MEM_CTRL 0xA4000030 /* 13.1.10 */ #define RPU_REG_MIPS_MCU_SYS_CORE_MEM_WDATA 0xA4000034 /* 13.1.11 */ diff --git a/nrf_wifi/hw_if/hal/inc/hal_api.h b/nrf_wifi/hw_if/hal/inc/hal_api.h index 0604a3ec46..0fa58fc1e5 100644 --- a/nrf_wifi/hw_if/hal/inc/hal_api.h +++ b/nrf_wifi/hw_if/hal/inc/hal_api.h @@ -36,6 +36,8 @@ extern const struct nrf70_fw_addr_info nrf70_fw_addr_info[]; * @cfg_params: Parameters needed to configure the HAL for WLAN operation. * @intr_callbk_fn: Pointer to the callback function which the user of this * layer needs to implement to handle events from the RPU. + * @rpu_recovery_callbk_fn: Pointer to the callback function which the user of + * this layer needs to implement to handle RPU recovery. * * This API is used to initialize the HAL layer and is expected to be called * before using the HAL layer. This API returns a pointer to the HAL context @@ -48,7 +50,10 @@ nrf_wifi_hal_init(struct nrf_wifi_osal_priv *opriv, struct nrf_wifi_hal_cfg_params *cfg_params, enum nrf_wifi_status (*intr_callbk_fn)(void *mac_ctx, void *event_data, - unsigned int len)); + unsigned int len), + enum nrf_wifi_status (*rpu_recovery_callbk_fn)(void *mac_ctx, + void *event_data, + unsigned int len)); /** * nrf_wifi_hal_deinit() - Deinitialize the HAL layer. diff --git a/nrf_wifi/hw_if/hal/inc/hal_interrupt.h b/nrf_wifi/hw_if/hal/inc/hal_interrupt.h index c21e0e6781..849eef3617 100644 --- a/nrf_wifi/hw_if/hal/inc/hal_interrupt.h +++ b/nrf_wifi/hw_if/hal/inc/hal_interrupt.h @@ -43,6 +43,8 @@ enum nrf_wifi_status hal_rpu_irq_disable(struct nrf_wifi_hal_dev_ctx *hal_dev_ct /** * hal_rpu_irq_process() - Processes an interrupt from the RPU. * @hal_dev_ctx: Pointer to HAL context. + * @do_rpu_recovery: Pointer to a boolean variable that indicates if the RPU recovery + * is required. * * This function is an interrupt handler for the interrupts generated by the * RPU. This function does the following: @@ -57,5 +59,6 @@ enum nrf_wifi_status hal_rpu_irq_disable(struct nrf_wifi_hal_dev_ctx *hal_dev_ct * Pass : %NRF_WIFI_STATUS_SUCCESS * Error: %NRF_WIFI_STATUS_FAIL */ -enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx); +enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx, + bool *do_rpu_recovery); #endif /* __HAL_INTERRUPT_H__ */ diff --git a/nrf_wifi/hw_if/hal/inc/hal_structs.h b/nrf_wifi/hw_if/hal/inc/hal_structs.h index ba5076d680..ba81691d8c 100644 --- a/nrf_wifi/hw_if/hal/inc/hal_structs.h +++ b/nrf_wifi/hw_if/hal/inc/hal_structs.h @@ -126,6 +126,9 @@ struct nrf_wifi_hal_priv { enum nrf_wifi_status (*intr_callbk_fn)(void *mac_ctx, void *event_data, unsigned int len); + enum nrf_wifi_status (*rpu_recovery_callbk_fn)(void *mac_ctx, + void *event_data, + unsigned int len); struct nrf_wifi_hal_cfg_params cfg_params; unsigned long addr_pktram_base; }; @@ -223,6 +226,12 @@ struct nrf_wifi_hal_dev_ctx { unsigned long addr_rpu_pktram_base_rx; unsigned long addr_rpu_pktram_base_rx_pool[MAX_NUM_OF_RX_QUEUES]; unsigned long tx_frame_offset; +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + unsigned long last_wakeup_now_asserted_time_ms; + unsigned long last_wakeup_now_deasserted_time_ms; + unsigned long last_rpu_sleep_opp_time_ms; + bool is_wakup_now_asserted; +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ #ifdef CONFIG_NRF_WIFI_LOW_POWER enum RPU_PS_STATE rpu_ps_state; void *rpu_ps_timer; @@ -237,6 +246,8 @@ struct nrf_wifi_hal_dev_ctx { unsigned int event_data_pending; unsigned int event_resubmit; enum NRF_WIFI_HAL_STATUS hal_status; + void *recovery_tasklet; + void *lock_recovery; }; diff --git a/nrf_wifi/hw_if/hal/src/hal_api.c b/nrf_wifi/hw_if/hal/src/hal_api.c index ae44a90fd2..c886dc248a 100644 --- a/nrf_wifi/hw_if/hal/src/hal_api.c +++ b/nrf_wifi/hw_if/hal/src/hal_api.c @@ -66,6 +66,13 @@ unsigned long nrf_wifi_hal_buf_map_rx(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx, unsigned long bounce_buf_addr = 0; unsigned long rpu_addr = 0; + if (!hal_dev_ctx || !hal_dev_ctx->rx_buf_info[pool_id]) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "%s: Invalid parameters\n", + __func__); + goto out; + } + rx_buf_info = &hal_dev_ctx->rx_buf_info[pool_id][buf_id]; if (rx_buf_info->mapped) { @@ -300,6 +307,20 @@ unsigned long nrf_wifi_hal_buf_unmap_tx(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx #ifdef CONFIG_NRF_WIFI_LOW_POWER +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY +static void did_rpu_had_sleep_opp(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) +{ + unsigned int deassert_time_diff_ms = nrf_wifi_osal_time_elapsed_ms( + hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->last_wakeup_now_deasserted_time_ms); + + if (deassert_time_diff_ms > CONFIG_NRF_WIFI_RPU_MIN_TIME_TO_ENTER_SLEEP_MS) { + hal_dev_ctx->last_rpu_sleep_opp_time_ms = + hal_dev_ctx->last_wakeup_now_deasserted_time_ms; + } +} +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ + enum nrf_wifi_status hal_rpu_ps_wake(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) { unsigned int reg_val = 0; @@ -332,7 +353,11 @@ enum nrf_wifi_status hal_rpu_ps_wake(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) } nrf_wifi_bal_rpu_ps_wake(hal_dev_ctx->bal_dev_ctx); - +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + hal_dev_ctx->is_wakup_now_asserted = true; + hal_dev_ctx->last_wakeup_now_asserted_time_ms = + nrf_wifi_osal_time_get_curr_ms(hal_dev_ctx->hpriv->opriv); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ start_time_us = nrf_wifi_osal_time_get_curr_us(hal_dev_ctx->hpriv->opriv); rpu_ps_state_mask = ((1 << RPU_REG_BIT_PS_STATE) | @@ -372,9 +397,21 @@ enum nrf_wifi_status hal_rpu_ps_wake(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) RPU_PS_WAKE_TIMEOUT_S, reg_val, rpu_ps_state_mask); +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + nrf_wifi_osal_tasklet_schedule(hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->recovery_tasklet); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ goto out; } hal_dev_ctx->rpu_ps_state = RPU_PS_STATE_AWAKE; +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + did_rpu_had_sleep_opp(hal_dev_ctx); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_PS_STATE_DEBUG + nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv, + "%s: RPU PS state is AWAKE\n", + __func__); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_PS_STATE_DEBUG */ out: if (!hal_dev_ctx->irq_ctx) { @@ -398,9 +435,18 @@ static void hal_rpu_ps_sleep(unsigned long data) &flags); nrf_wifi_bal_rpu_ps_sleep(hal_dev_ctx->bal_dev_ctx); - +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + hal_dev_ctx->is_wakup_now_asserted = false; + hal_dev_ctx->last_wakeup_now_deasserted_time_ms = + nrf_wifi_osal_time_get_curr_ms(hal_dev_ctx->hpriv->opriv); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ hal_dev_ctx->rpu_ps_state = RPU_PS_STATE_ASLEEP; +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_PS_STATE_DEBUG + nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv, + "%s: RPU PS state is ASLEEP\n", + __func__); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_PS_STATE_DEBUG */ nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->hpriv->opriv, hal_dev_ctx->rpu_ps_lock, &flags); @@ -881,6 +927,17 @@ enum nrf_wifi_status nrf_wifi_hal_ctrl_cmd_send(struct nrf_wifi_hal_dev_ctx *hal { enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; +#ifdef CONFIG_NRF_WIFI_CMD_EVENT_LOG + nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv, + "%s: caller %p\n", + __func__, + __builtin_return_address(0)); +#else + nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv, + "%s: caller %p\n", + __func__, + __builtin_return_address(0)); +#endif nrf_wifi_osal_spinlock_take(hal_dev_ctx->hpriv->opriv, hal_dev_ctx->lock_hal); @@ -986,6 +1043,12 @@ static void event_tasklet_fn(unsigned long data) unsigned long flags = 0; hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)data; + if (!hal_dev_ctx) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "%s: Invalid hal_dev_ctx\n", + __func__); + return; + } nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->hpriv->opriv, hal_dev_ctx->lock_rx, @@ -1089,8 +1152,6 @@ void hal_rpu_eventq_drain(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) return; } - - void nrf_wifi_hal_proc_ctx_set(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx, enum RPU_PROC_TYPE proc) { @@ -1098,6 +1159,51 @@ void nrf_wifi_hal_proc_ctx_set(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx, } +static enum nrf_wifi_status hal_rpu_recovery(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + + if (!hal_dev_ctx->hpriv->rpu_recovery_callbk_fn) { + nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv, + "%s: RPU recovery callback not registered", + __func__); + goto out; + } + + status = hal_dev_ctx->hpriv->rpu_recovery_callbk_fn(hal_dev_ctx->mac_dev_ctx, NULL, 0); + if (status != NRF_WIFI_STATUS_SUCCESS) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "%s: RPU recovery failed", + __func__); + goto out; + } + +out: + return status; +} + +static void recovery_tasklet_fn(unsigned long data) +{ + struct nrf_wifi_hal_dev_ctx *hal_dev_ctx = NULL; + unsigned long flags = 0; + + hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)data; + if (!hal_dev_ctx) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "%s: Invalid hal_dev_ctx", + __func__); + return; + } + + nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->lock_recovery, + &flags); + hal_rpu_recovery(hal_dev_ctx); + nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->lock_recovery, + &flags); +} + struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpriv, void *mac_dev_ctx) { @@ -1182,6 +1288,29 @@ struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpri event_tasklet_fn, (unsigned long)hal_dev_ctx); + hal_dev_ctx->recovery_tasklet = nrf_wifi_osal_tasklet_alloc(hpriv->opriv, + NRF_WIFI_TASKLET_TYPE_BH); + if (!hal_dev_ctx->recovery_tasklet) { + nrf_wifi_osal_log_err(hpriv->opriv, + "%s: Unable to allocate recovery_tasklet", + __func__); + goto event_tasklet_free; + } + nrf_wifi_osal_tasklet_init(hpriv->opriv, + hal_dev_ctx->recovery_tasklet, + recovery_tasklet_fn, + (unsigned long)hal_dev_ctx); + + hal_dev_ctx->lock_recovery = nrf_wifi_osal_spinlock_alloc(hpriv->opriv); + if (!hal_dev_ctx->lock_recovery) { + nrf_wifi_osal_log_err(hpriv->opriv, + "%s: Unable to allocate recovery lock", + __func__); + goto recovery_tasklet_free; + } + + nrf_wifi_osal_spinlock_init(hpriv->opriv, + hal_dev_ctx->lock_recovery); #ifdef CONFIG_NRF_WIFI_LOW_POWER status = hal_rpu_ps_init(hal_dev_ctx); @@ -1189,7 +1318,7 @@ struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpri nrf_wifi_osal_log_err(hpriv->opriv, "%s: hal_rpu_ps_init failed", __func__); - goto tasklet_free; + goto lock_recovery_free; } #endif /* CONFIG_NRF_WIFI_LOW_POWER */ @@ -1200,7 +1329,7 @@ struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpri nrf_wifi_osal_log_err(hpriv->opriv, "%s: nrf_wifi_bal_dev_add failed", __func__); - goto tasklet_free; + goto lock_recovery_free; } status = hal_rpu_irq_enable(hal_dev_ctx); @@ -1274,7 +1403,13 @@ struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpri #endif /* !CONFIG_NRF700X_RADIO_TEST */ bal_dev_free: nrf_wifi_bal_dev_rem(hal_dev_ctx->bal_dev_ctx); -tasklet_free: +lock_recovery_free: + nrf_wifi_osal_spinlock_free(hpriv->opriv, + hal_dev_ctx->lock_recovery); +recovery_tasklet_free: + nrf_wifi_osal_tasklet_free(hpriv->opriv, + hal_dev_ctx->recovery_tasklet); +event_tasklet_free: nrf_wifi_osal_tasklet_free(hpriv->opriv, hal_dev_ctx->event_tasklet); lock_rx_free: @@ -1302,6 +1437,14 @@ void nrf_wifi_hal_dev_rem(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) { unsigned int i = 0; + + nrf_wifi_osal_tasklet_kill(hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->recovery_tasklet); + nrf_wifi_osal_tasklet_free(hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->recovery_tasklet); + nrf_wifi_osal_spinlock_free(hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->lock_recovery); + nrf_wifi_osal_tasklet_kill(hal_dev_ctx->hpriv->opriv, hal_dev_ctx->event_tasklet); @@ -1395,10 +1538,11 @@ enum nrf_wifi_status nrf_wifi_hal_dev_init(struct nrf_wifi_hal_dev_ctx *hal_dev_ void nrf_wifi_hal_dev_deinit(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) { + nrf_wifi_hal_disable(hal_dev_ctx); nrf_wifi_bal_dev_deinit(hal_dev_ctx->bal_dev_ctx); + hal_rpu_eventq_drain(hal_dev_ctx); } - void nrf_wifi_hal_lock_rx(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) { unsigned long flags = 0; @@ -1425,17 +1569,23 @@ enum nrf_wifi_status nrf_wifi_hal_irq_handler(void *data) #ifdef CONFIG_NRF_WIFI_LOW_POWER enum RPU_PS_STATE ps_state = RPU_PS_STATE_ASLEEP; #endif /* CONFIG_NRF_WIFI_LOW_POWER */ + bool do_rpu_recovery = false; hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)data; + if (!hal_dev_ctx) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "%s: Invalid hal_dev_ctx\n", + __func__); + goto out; + } nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->hpriv->opriv, hal_dev_ctx->lock_rx, &flags); if (hal_dev_ctx->hal_status != NRF_WIFI_HAL_STATUS_ENABLED) { - /* Ignore the interrupt if the HAL is not enabled */ status = NRF_WIFI_STATUS_SUCCESS; - goto out; + goto unlock; } #ifdef CONFIG_NRF_WIFI_LOW_POWER @@ -1447,7 +1597,7 @@ enum nrf_wifi_status nrf_wifi_hal_irq_handler(void *data) #endif /* CONFIG_NRF_WIFI_LOW_POWER_DBG */ #endif /* CONFIG_NRF_WIFI_LOW_POWER */ - status = hal_rpu_irq_process(hal_dev_ctx); + status = hal_rpu_irq_process(hal_dev_ctx, &do_rpu_recovery); #ifdef CONFIG_NRF_WIFI_LOW_POWER hal_rpu_ps_set_state(hal_dev_ctx, @@ -1458,16 +1608,23 @@ enum nrf_wifi_status nrf_wifi_hal_irq_handler(void *data) #endif /* CONFIG_NRF_WIFI_LOW_POWER */ if (status != NRF_WIFI_STATUS_SUCCESS) { - goto out; + goto unlock; + } + + if (do_rpu_recovery) { + nrf_wifi_osal_tasklet_schedule(hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->recovery_tasklet); + goto unlock; } nrf_wifi_osal_tasklet_schedule(hal_dev_ctx->hpriv->opriv, hal_dev_ctx->event_tasklet); -out: +unlock: nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->hpriv->opriv, hal_dev_ctx->lock_rx, &flags); +out: return status; } @@ -1671,7 +1828,10 @@ nrf_wifi_hal_init(struct nrf_wifi_osal_priv *opriv, struct nrf_wifi_hal_cfg_params *cfg_params, enum nrf_wifi_status (*intr_callbk_fn)(void *dev_ctx, void *event_data, - unsigned int len)) + unsigned int len), + enum nrf_wifi_status (*rpu_recovery_callbk_fn)(void *mac_ctx, + void *event_data, + unsigned int len)) { enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; struct nrf_wifi_hal_priv *hpriv = NULL; @@ -1695,6 +1855,7 @@ nrf_wifi_hal_init(struct nrf_wifi_osal_priv *opriv, sizeof(hpriv->cfg_params)); hpriv->intr_callbk_fn = intr_callbk_fn; + hpriv->rpu_recovery_callbk_fn = rpu_recovery_callbk_fn; status = pal_rpu_addr_offset_get(opriv, RPU_ADDR_PKTRAM_START, diff --git a/nrf_wifi/hw_if/hal/src/hal_interrupt.c b/nrf_wifi/hw_if/hal/src/hal_interrupt.c index 91771a5b0e..22419b7cd9 100644 --- a/nrf_wifi/hw_if/hal/src/hal_interrupt.c +++ b/nrf_wifi/hw_if/hal/src/hal_interrupt.c @@ -158,11 +158,10 @@ static bool hal_rpu_irq_wdog_chk(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) static enum nrf_wifi_status hal_rpu_irq_wdog_ack(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) { enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; - unsigned int val = 0; status = hal_rpu_reg_write(hal_dev_ctx, - RPU_REG_MIPS_MCU_TIMER_CONTROL, - val); + RPU_REG_MIPS_MCU_UCCP_INT_CLEAR, + 1 << RPU_REG_BIT_MIPS_WATCHDOG_INT_CLEAR); if (status != NRF_WIFI_STATUS_SUCCESS) { nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, @@ -176,6 +175,24 @@ static enum nrf_wifi_status hal_rpu_irq_wdog_ack(struct nrf_wifi_hal_dev_ctx *ha } +static enum nrf_wifi_status hal_rpu_irq_wdog_rearm(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + + status = hal_rpu_reg_write(hal_dev_ctx, + RPU_REG_MIPS_MCU_TIMER, + RPU_REG_MIPS_MCU_TIMER_RESET_VAL); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "%s: Rearming watchdog interrupt failed", + __func__); + goto out; + } +out: + return status; +} + static enum nrf_wifi_status hal_rpu_event_free(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx, unsigned int event_addr) @@ -388,8 +405,8 @@ static enum nrf_wifi_status hal_rpu_event_get(struct nrf_wifi_hal_dev_ctx *hal_d if (!event) { nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, - "%s: Unable to alloc HAL msg for event", - __func__); + "%s: Unable to alloc HAL msg for event, len %d\n", + __func__, hal_dev_ctx->event_data_len); nrf_wifi_osal_mem_free(hal_dev_ctx->hpriv->opriv, hal_dev_ctx->event_data); hal_dev_ctx->event_data = NULL; @@ -480,12 +497,90 @@ static unsigned int hal_rpu_event_get_all(struct nrf_wifi_hal_dev_ctx *hal_dev_c return num_events; } +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY +static inline bool is_rpu_recovery_needed(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) +{ + unsigned int rpu_sleep_opp_diff_ms = nrf_wifi_osal_time_elapsed_ms( + hal_dev_ctx->hpriv->opriv, + hal_dev_ctx->last_rpu_sleep_opp_time_ms); + +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG + nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv, + "RPU sleep opp diff: %d ms, last RPU sleep opp time: %lu", + rpu_sleep_opp_diff_ms, + hal_dev_ctx->last_rpu_sleep_opp_time_ms); +#else + nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv, + "RPU sleep opp diff: %d ms, last RPU sleep opp time: %lu", + rpu_sleep_opp_diff_ms, + hal_dev_ctx->last_rpu_sleep_opp_time_ms); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG */ + + if (rpu_sleep_opp_diff_ms >= CONFIG_NRF_WIFI_RPU_RECOVERY_PS_ACTIVE_TIMEOUT_MS) { + return false; + } + + return true; +} +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ -enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx) +static enum nrf_wifi_status hal_rpu_process_wdog(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx, + bool *do_rpu_recovery) { - enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; - unsigned int num_events = 0; + enum nrf_wifi_status nrf_wifi_status = NRF_WIFI_STATUS_FAIL; + bool rpu_recovery = false; + +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG + nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv, + "Processing watchdog interrupt"); +#else + nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv, + "Processing watchdog interrupt"); +#endif + +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + /* Check if host has asserted WAKEUP_NOW or if the RPU has been in + * PS_ACTIVE state for more than the timeout period + */ + if (!is_rpu_recovery_needed(hal_dev_ctx)) { +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG + nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv, + "Ignore watchdog interrupt, RPU recovery not needed"); +#else + nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv, + "Ignore watchdog interrupt, RPU recovery not needed"); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG */ + goto out; + } + + rpu_recovery = true; +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ + + if (!rpu_recovery) { + hal_rpu_irq_wdog_rearm(hal_dev_ctx); + goto out; + } +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG + nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv, + "RPU recovery needed"); +#else + nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv, + "RPU recovery needed"); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG */ +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ +out: + nrf_wifi_status = NRF_WIFI_STATUS_SUCCESS; + *do_rpu_recovery = rpu_recovery; + + return nrf_wifi_status; +} + +enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx, + bool *do_rpu_recovery) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; /* Get all the events in the queue. It is possible that there are no * events in the queue. This is a valid scenario as per our present @@ -498,29 +593,29 @@ enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ct * the interrupt source. This will be a problem in shared interrupt * scenarios and has to be taken care by the SOC designers. */ - num_events = hal_rpu_event_get_all(hal_dev_ctx); + (void)hal_rpu_event_get_all(hal_dev_ctx); - /* If we received an interrupt without any associated event(s) it is a - * likely indication that the RPU is stuck and this interrupt has been - * raised by the watchdog + /* Check the if this interrupt has been raised by the + * RPU watchdog */ - if (!num_events) { - /* Check the if this interrupt has been raised by the - * RPU watchdog - */ - if (hal_rpu_irq_wdog_chk(hal_dev_ctx)) { - /* TODO: Perform RPU recovery */ - nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv, - "Received watchdog interrupt"); + if (hal_rpu_irq_wdog_chk(hal_dev_ctx)) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "Received watchdog interrupt"); - status = hal_rpu_irq_wdog_ack(hal_dev_ctx); + status = hal_rpu_process_wdog(hal_dev_ctx, do_rpu_recovery); + if (status == NRF_WIFI_STATUS_FAIL) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "%s: hal_rpu_process_wdog failed", + __func__); + goto out; + } - if (status == NRF_WIFI_STATUS_FAIL) { - nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, - "%s: hal_rpu_irq_wdog_ack failed", - __func__); - goto out; - } + status = hal_rpu_irq_wdog_ack(hal_dev_ctx); + if (status == NRF_WIFI_STATUS_FAIL) { + nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv, + "%s: hal_rpu_irq_wdog_ack failed", + __func__); + goto out; } } diff --git a/nrf_wifi/os_if/inc/osal_api.h b/nrf_wifi/os_if/inc/osal_api.h index 1b2b447c5c..61b837948a 100644 --- a/nrf_wifi/os_if/inc/osal_api.h +++ b/nrf_wifi/os_if/inc/osal_api.h @@ -884,7 +884,29 @@ unsigned long nrf_wifi_osal_time_get_curr_us(struct nrf_wifi_osal_priv *opriv); unsigned int nrf_wifi_osal_time_elapsed_us(struct nrf_wifi_osal_priv *opriv, unsigned long start_time_us); +/** + * nrf_wifi_osal_time_get_curr_ms() - Get current system uptime in milliseconds. + * @opriv: Pointer to the OSAL context returned by the @nrf_wifi_osal_init API. + * + * Gets the current system uptime in milliseconds. + * + * Return: System uptime in milliseconds. + */ +unsigned long nrf_wifi_osal_time_get_curr_ms(struct nrf_wifi_osal_priv *opriv); +/** + * nrf_wifi_osal_time_elapsed_ms() - Get elapsed time in milliseconds + * @opriv: Pointer to the OSAL context returned by the @nrf_wifi_osal_init API. + * @start_time_ms: The timestamp in milliseconds from which elapsed + * time is to be measured. + * + * Returns the time elapsed in milliseconds since some + * time instant (@start_time_ms). + * + * Return: Elapsed time in milliseconds. + */ +unsigned int nrf_wifi_osal_time_elapsed_ms(struct nrf_wifi_osal_priv *opriv, + unsigned long start_time_ms); /** * nrf_wifi_osal_bus_pcie_init() - Initialize a PCIe driver. diff --git a/nrf_wifi/os_if/inc/osal_ops.h b/nrf_wifi/os_if/inc/osal_ops.h index 63186ed785..a29d525f8d 100644 --- a/nrf_wifi/os_if/inc/osal_ops.h +++ b/nrf_wifi/os_if/inc/osal_ops.h @@ -258,6 +258,8 @@ struct nrf_wifi_osal_ops { int (*delay_us)(int usecs); unsigned long (*time_get_curr_us)(void); unsigned int (*time_elapsed_us)(unsigned long start_time_us); + unsigned long (*time_get_curr_ms)(void); + unsigned int (*time_elapsed_ms)(unsigned long start_time_us); void *(*bus_pcie_init)(const char *dev_name, unsigned int vendor_id, diff --git a/nrf_wifi/os_if/src/osal.c b/nrf_wifi/os_if/src/osal.c index 5abeae7a00..cf650daed2 100644 --- a/nrf_wifi/os_if/src/osal.c +++ b/nrf_wifi/os_if/src/osal.c @@ -508,6 +508,16 @@ unsigned int nrf_wifi_osal_time_elapsed_us(struct nrf_wifi_osal_priv *opriv, return opriv->ops->time_elapsed_us(start_time_us); } +unsigned long nrf_wifi_osal_time_get_curr_ms(struct nrf_wifi_osal_priv *opriv) +{ + return opriv->ops->time_get_curr_ms(); +} + +unsigned int nrf_wifi_osal_time_elapsed_ms(struct nrf_wifi_osal_priv *opriv, + unsigned long start_time_ms) +{ + return opriv->ops->time_elapsed_ms(start_time_ms); +} void *nrf_wifi_osal_bus_pcie_init(struct nrf_wifi_osal_priv *opriv, const char *dev_name,