diff --git a/dp/wifi3.0/be/dp_be.h b/dp/wifi3.0/be/dp_be.h index dafd7e4026..1602fee710 100644 --- a/dp/wifi3.0/be/dp_be.h +++ b/dp/wifi3.0/be/dp_be.h @@ -465,6 +465,17 @@ static inline struct dp_soc_be *dp_get_be_soc_from_dp_soc(struct dp_soc *soc) return (struct dp_soc_be *)soc; } +/** + * dp_mlo_iter_ptnr_soc() - iterate through mlo soc list and call the callback + * @be_soc: dp_soc_be pointer + * @func: Function to be called for each soc + * @arg: context to be passed to the callback + * + * Return: true if mlo is enabled, false if mlo is disabled + */ +bool dp_mlo_iter_ptnr_soc(struct dp_soc_be *be_soc, dp_ptnr_soc_iter_func func, + void *arg); + #ifdef WLAN_MLO_MULTI_CHIP typedef struct dp_mlo_ctxt *dp_mld_peer_hash_obj_t; @@ -509,8 +520,6 @@ void dp_mlo_partner_chips_unmap(struct dp_soc *soc, typedef void dp_ptnr_vdev_iter_func(struct dp_vdev_be *be_vdev, struct dp_vdev *ptnr_vdev, void *arg); -typedef void dp_ptnr_soc_iter_func(struct dp_soc *ptnr_soc, - void *arg); /** * dp_mcast_mlo_iter_ptnr_vdev() - API to iterate through ptnr vdev list @@ -527,17 +536,7 @@ void dp_mcast_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc, dp_ptnr_vdev_iter_func func, void *arg, enum dp_mod_id mod_id); -/** - * dp_mlo_iter_ptnr_soc() - API to iterate through ptnr soc list - * @be_soc: dp_soc_be pointer - * @func: function to be called for each peer - * @arg: argument need to be passed to func - * - * Return: None - */ -void dp_mlo_iter_ptnr_soc(struct dp_soc_be *be_soc, - dp_ptnr_soc_iter_func func, - void *arg); + /** * dp_mlo_get_mcast_primary_vdev() - get ref to mcast primary vdev * @be_soc: dp_soc_be pointer diff --git a/dp/wifi3.0/be/mlo/dp_mlo.c b/dp/wifi3.0/be/mlo/dp_mlo.c index abbc60f8bb..122e2809eb 100644 --- a/dp/wifi3.0/be/mlo/dp_mlo.c +++ b/dp/wifi3.0/be/mlo/dp_mlo.c @@ -24,7 +24,20 @@ #include #include #include +#include "dp_umac_reset.h" +#ifdef DP_UMAC_HW_RESET_SUPPORT +/** + * dp_umac_reset_update_partner_map() - Update Umac reset partner map + * @mlo_ctx: mlo soc context + * @chip_id: chip id + * @set: flag indicating whether to set or clear the bit + * + * Return: void + */ +static void dp_umac_reset_update_partner_map(struct dp_mlo_ctxt *mlo_ctx, + int chip_id, bool set); +#endif /** * dp_mlo_ctxt_attach_wifi3() - Attach DP MLO context * @ctrl_ctxt: CDP control context @@ -59,6 +72,7 @@ dp_mlo_ctxt_attach_wifi3(struct cdp_ctrl_mlo_mgr *ctrl_ctxt) LRO_IPV6_SEED_ARR_SZ)); qdf_spinlock_create(&mlo_ctxt->ml_soc_list_lock); + qdf_spinlock_create(&mlo_ctxt->grp_umac_reset_ctx.grp_ctx_lock); return dp_mlo_ctx_to_cdp(mlo_ctxt); } @@ -75,6 +89,7 @@ static void dp_mlo_ctxt_detach_wifi3(struct cdp_mlo_ctxt *cdp_ml_ctxt) if (!cdp_ml_ctxt) return; + qdf_spinlock_destroy(&mlo_ctxt->grp_umac_reset_ctx.grp_ctx_lock); qdf_spinlock_destroy(&mlo_ctxt->ml_soc_list_lock); dp_mlo_peer_find_hash_detach_be(mlo_ctxt); qdf_mem_free(mlo_ctxt); @@ -103,6 +118,8 @@ static void dp_mlo_set_soc_by_chip_id(struct dp_mlo_ctxt *ml_ctxt, else ml_ctxt->ml_soc_cnt--; + dp_umac_reset_update_partner_map(ml_ctxt, chip_id, !!soc); + qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock); } @@ -164,7 +181,7 @@ static QDF_STATUS dp_partner_soc_rx_hw_cc_init(struct dp_mlo_ctxt *mlo_ctxt, return qdf_status; } -static void dp_mlo_soc_drain_rx_buf(struct dp_soc *soc, void *arg) +static void dp_mlo_soc_drain_rx_buf(struct dp_soc *soc, void *arg, int chip_id) { uint8_t i = 0; uint8_t cpu = 0; @@ -814,25 +831,6 @@ dp_soc_get_by_idle_bm_id(struct dp_soc *soc, uint8_t idle_bm_id) } #ifdef WLAN_MCAST_MLO -void dp_mlo_iter_ptnr_soc(struct dp_soc_be *be_soc, - dp_ptnr_soc_iter_func func, - void *arg) -{ - int i = 0; - struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; - - for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { - struct dp_soc *ptnr_soc = - dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); - - if (!ptnr_soc) - continue; - (*func)(ptnr_soc, arg); - } -} - -qdf_export_symbol(dp_mlo_iter_ptnr_soc); - void dp_mcast_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc, struct dp_vdev_be *be_vdev, dp_ptnr_vdev_iter_func func, @@ -906,6 +904,37 @@ struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc, qdf_export_symbol(dp_mlo_get_mcast_primary_vdev); #endif +/** + * dp_mlo_iter_ptnr_soc() - iterate through mlo soc list and call the callback + * @be_soc: dp_soc_be pointer + * @func: Function to be called for each soc + * @arg: context to be passed to the callback + * + * Return: true if mlo is enabled, false if mlo is disabled + */ +bool dp_mlo_iter_ptnr_soc(struct dp_soc_be *be_soc, dp_ptnr_soc_iter_func func, + void *arg) +{ + int i = 0; + struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; + + if (!be_soc->mlo_enabled || !be_soc->ml_ctxt) + return false; + + for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { + struct dp_soc *ptnr_soc = + dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); + + if (!ptnr_soc) + continue; + (*func)(ptnr_soc, arg, i); + } + + return true; +} + +qdf_export_symbol(dp_mlo_iter_ptnr_soc); + static inline uint64_t dp_mlo_get_mlo_ts_offset(struct dp_pdev_be *be_pdev) { struct dp_soc *soc; @@ -959,3 +988,272 @@ int32_t dp_mlo_get_delta_tqm_wrt_mlo_offset(struct dp_soc *soc) return delta_tqm_mlo_offset; } + +#ifdef DP_UMAC_HW_RESET_SUPPORT +/** + * dp_umac_reset_update_partner_map() - Update Umac reset partner map + * @mlo_ctx: DP ML context handle + * @chip_id: chip id + * @set: flag indicating whether to set or clear the bit + * + * Return: void + */ +static void dp_umac_reset_update_partner_map(struct dp_mlo_ctxt *mlo_ctx, + int chip_id, bool set) +{ + struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx = + &mlo_ctx->grp_umac_reset_ctx; + + if (set) + qdf_atomic_set_bit(chip_id, &grp_umac_reset_ctx->partner_map); + else + qdf_atomic_clear_bit(chip_id, &grp_umac_reset_ctx->partner_map); +} + +/** + * dp_umac_reset_complete_umac_recovery() - Complete Umac reset session + * @soc: dp soc handle + * + * Return: void + */ +void dp_umac_reset_complete_umac_recovery(struct dp_soc *soc) +{ + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt; + struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx; + + if (!mlo_ctx) { + dp_umac_reset_alert("Umac reset was handled on soc %pK", soc); + return; + } + + grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx; + qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + + grp_umac_reset_ctx->umac_reset_in_progress = false; + grp_umac_reset_ctx->is_target_recovery = false; + grp_umac_reset_ctx->response_map = 0; + grp_umac_reset_ctx->request_map = 0; + grp_umac_reset_ctx->initiator_chip_id = 0; + + qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + + dp_umac_reset_alert("Umac reset was handled on mlo group ctxt %pK", + mlo_ctx); +} + +/** + * dp_umac_reset_initiate_umac_recovery() - Initiate Umac reset session + * @soc: dp soc handle + * @is_target_recovery: Flag to indicate if it is triggered for target recovery + * + * Return: void + */ +void dp_umac_reset_initiate_umac_recovery(struct dp_soc *soc, + bool is_target_recovery) +{ + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt; + struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx; + + if (!mlo_ctx) + return; + + grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx; + qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + + if (grp_umac_reset_ctx->umac_reset_in_progress) { + qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + return; + } + + grp_umac_reset_ctx->umac_reset_in_progress = true; + grp_umac_reset_ctx->is_target_recovery = is_target_recovery; + + /* We don't wait for the 'Umac trigger' message from all socs */ + grp_umac_reset_ctx->request_map = grp_umac_reset_ctx->partner_map; + grp_umac_reset_ctx->response_map = grp_umac_reset_ctx->partner_map; + grp_umac_reset_ctx->initiator_chip_id = dp_mlo_get_chip_id(soc); + grp_umac_reset_ctx->umac_reset_count++; + + qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock); +} + +/** + * dp_umac_reset_handle_action_cb() - Function to call action callback + * @soc: dp soc handle + * @umac_reset_ctx: Umac reset context + * @action: Action to call the callback for + * + * Return: QDF_STATUS status + */ +QDF_STATUS +dp_umac_reset_handle_action_cb(struct dp_soc *soc, + struct dp_soc_umac_reset_ctx *umac_reset_ctx, + enum umac_reset_action action) +{ + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt; + struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx; + + if (!mlo_ctx) { + dp_umac_reset_debug("MLO context is Null"); + goto handle; + } + + grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx; + qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + + qdf_atomic_set_bit(dp_mlo_get_chip_id(soc), + &grp_umac_reset_ctx->request_map); + + dp_umac_reset_debug("partner_map %u request_map %u", + grp_umac_reset_ctx->partner_map, + grp_umac_reset_ctx->request_map); + + /* This logic is needed for synchronization between mlo socs */ + if ((grp_umac_reset_ctx->partner_map & grp_umac_reset_ctx->request_map) + != grp_umac_reset_ctx->partner_map) { + struct hif_softc *hif_sc = HIF_GET_SOFTC(soc->hif_handle); + struct hif_umac_reset_ctx *hif_umac_reset_ctx; + + if (!hif_sc) { + hif_err("scn is null"); + qdf_assert_always(0); + return QDF_STATUS_E_FAILURE; + } + + hif_umac_reset_ctx = &hif_sc->umac_reset_ctx; + + /* Mark the action as pending */ + umac_reset_ctx->pending_action = action; + /* Reschedule the tasklet and exit */ + tasklet_hi_schedule(&hif_umac_reset_ctx->intr_tq); + qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + + return QDF_STATUS_SUCCESS; + } + + qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + umac_reset_ctx->pending_action = UMAC_RESET_ACTION_NONE; + +handle: + if (!umac_reset_ctx->rx_actions.cb[action]) { + dp_umac_reset_err("rx callback is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return umac_reset_ctx->rx_actions.cb[action](soc); +} + +/** + * dp_umac_reset_post_tx_cmd() - Iterate partner socs and post Tx command + * @umac_reset_ctx: UMAC reset context + * @tx_cmd: Tx command to be posted + * + * Return: QDF status of operation + */ +QDF_STATUS +dp_umac_reset_post_tx_cmd(struct dp_soc_umac_reset_ctx *umac_reset_ctx, + enum umac_reset_tx_cmd tx_cmd) +{ + struct dp_soc *soc = container_of(umac_reset_ctx, struct dp_soc, + umac_reset_ctx); + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt; + struct dp_soc_mlo_umac_reset_ctx *grp_umac_reset_ctx; + + if (!mlo_ctx) { + dp_umac_reset_post_tx_cmd_via_shmem(soc, &tx_cmd, 0); + return QDF_STATUS_SUCCESS; + } + + grp_umac_reset_ctx = &mlo_ctx->grp_umac_reset_ctx; + qdf_spin_lock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + + qdf_atomic_set_bit(dp_mlo_get_chip_id(soc), + &grp_umac_reset_ctx->response_map); + + /* This logic is needed for synchronization between mlo socs */ + if ((grp_umac_reset_ctx->partner_map & grp_umac_reset_ctx->response_map) + != grp_umac_reset_ctx->partner_map) { + dp_umac_reset_debug( + "Response(s) pending : expected map %u current map %u", + grp_umac_reset_ctx->partner_map, + grp_umac_reset_ctx->response_map); + + qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + return QDF_STATUS_SUCCESS; + } + + dp_umac_reset_debug( + "All responses received: expected map %u current map %u", + grp_umac_reset_ctx->partner_map, + grp_umac_reset_ctx->response_map); + + grp_umac_reset_ctx->response_map = 0; + grp_umac_reset_ctx->request_map = 0; + qdf_spin_unlock_bh(&grp_umac_reset_ctx->grp_ctx_lock); + + dp_mlo_iter_ptnr_soc(be_soc, &dp_umac_reset_post_tx_cmd_via_shmem, + &tx_cmd); + + if (tx_cmd == UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE) + dp_umac_reset_complete_umac_recovery(soc); + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_umac_reset_initiator_check() - Check if soc is the Umac reset initiator + * @soc: dp soc handle + * + * Return: true if the soc is initiator or false otherwise + */ +bool dp_umac_reset_initiator_check(struct dp_soc *soc) +{ + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt; + + if (!mlo_ctx) + return true; + + return (mlo_ctx->grp_umac_reset_ctx.initiator_chip_id == + dp_mlo_get_chip_id(soc)); +} + +/** + * dp_umac_reset_target_recovery_check() - Check if this is for target recovery + * @soc: dp soc handle + * + * Return: true if the session is for target recovery or false otherwise + */ +bool dp_umac_reset_target_recovery_check(struct dp_soc *soc) +{ + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt; + + if (!mlo_ctx) + return false; + + return mlo_ctx->grp_umac_reset_ctx.is_target_recovery; +} + +/** + * dp_umac_reset_is_soc_ignored() - Check if this soc is to be ignored + * @soc: dp soc handle + * + * Return: true if the soc is ignored or false otherwise + */ +bool dp_umac_reset_is_soc_ignored(struct dp_soc *soc) +{ + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + struct dp_mlo_ctxt *mlo_ctx = be_soc->ml_ctxt; + + if (!mlo_ctx) + return false; + + return !qdf_atomic_test_bit(dp_mlo_get_chip_id(soc), + &mlo_ctx->grp_umac_reset_ctx.partner_map); +} +#endif diff --git a/dp/wifi3.0/be/mlo/dp_mlo.h b/dp/wifi3.0/be/mlo/dp_mlo.h index 47b4b82cc1..65b9456e75 100644 --- a/dp/wifi3.0/be/mlo/dp_mlo.h +++ b/dp/wifi3.0/be/mlo/dp_mlo.h @@ -46,6 +46,7 @@ * @link_to_pdev_map: link to pdev mapping * @rx_fst: pointer to rx_fst handle * @rx_fst_ref_cnt: ref count of rx_fst + * @grp_umac_reset_ctx: UMAC reset context at mlo group level */ struct dp_mlo_ctxt { struct cdp_ctrl_mlo_mgr *ctrl_ctxt; @@ -64,6 +65,9 @@ struct dp_mlo_ctxt { uint32_t toeplitz_hash_ipv6[LRO_IPV6_SEED_ARR_SZ]; struct dp_pdev_be *link_to_pdev_map[WLAN_MAX_MLO_CHIPS * WLAN_MAX_MLO_LINKS_PER_SOC]; +#ifdef DP_UMAC_HW_RESET_SUPPORT + struct dp_soc_mlo_umac_reset_ctx grp_umac_reset_ctx; +#endif }; /** diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index 59affe4487..581478e395 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -2669,6 +2669,74 @@ void dp_reo_desc_freelist_destroy(struct dp_soc *soc); */ void dp_reset_rx_reo_tid_queue(struct dp_soc *soc, void *hw_qdesc_vaddr, uint32_t size); + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) +/** + * dp_umac_reset_complete_umac_recovery() - Complete Umac reset session + * @soc: dp soc handle + * + * Return: void + */ +void dp_umac_reset_complete_umac_recovery(struct dp_soc *soc); + +/** + * dp_umac_reset_initiate_umac_recovery() - Initiate Umac reset session + * @soc: dp soc handle + * @is_target_recovery: Flag to indicate if it is triggered for target recovery + * + * Return: void + */ +void dp_umac_reset_initiate_umac_recovery(struct dp_soc *soc, + bool is_target_recovery); + +/** + * dp_umac_reset_handle_action_cb() - Function to call action callback + * @soc: dp soc handle + * @umac_reset_ctx: Umac reset context + * @action: Action to call the callback for + * + * Return: QDF_STATUS status + */ +QDF_STATUS dp_umac_reset_handle_action_cb(struct dp_soc *soc, + struct dp_soc_umac_reset_ctx *umac_reset_ctx, + enum umac_reset_action action); + +/** + * dp_umac_reset_post_tx_cmd() - Iterate partner socs and post Tx command + * @umac_reset_ctx: UMAC reset context + * @tx_cmd: Tx command to be posted + * + * Return: QDF status of operation + */ +QDF_STATUS +dp_umac_reset_post_tx_cmd(struct dp_soc_umac_reset_ctx *umac_reset_ctx, + enum umac_reset_tx_cmd tx_cmd); + +/** + * dp_umac_reset_initiator_check() - Check if soc is the Umac reset initiator + * @soc: dp soc handle + * + * Return: true if the soc is initiator or false otherwise + */ +bool dp_umac_reset_initiator_check(struct dp_soc *soc); + +/** + * dp_umac_reset_target_recovery_check() - Check if this is for target recovery + * @soc: dp soc handle + * + * Return: true if the session is for target recovery or false otherwise + */ +bool dp_umac_reset_target_recovery_check(struct dp_soc *soc); + +/** + * dp_umac_reset_is_soc_ignored() - Check if this soc is to be ignored + * @soc: dp soc handle + * + * Return: true if the soc is ignored or false otherwise + */ +bool dp_umac_reset_is_soc_ignored(struct dp_soc *soc); +#endif + #endif QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc, enum hal_reo_cmd_type type, diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index f10bfd2f29..1d1b8270e4 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -267,6 +267,7 @@ static uint8_t dp_soc_ring_if_nss_offloaded(struct dp_soc *soc, enum hal_ring_type ring_type, int ring_num); #ifdef DP_UMAC_HW_RESET_SUPPORT +static QDF_STATUS dp_umac_reset_action_trigger_recovery(struct dp_soc *soc); static QDF_STATUS dp_umac_reset_handle_pre_reset(struct dp_soc *soc); static QDF_STATUS dp_umac_reset_handle_post_reset(struct dp_soc *soc); static QDF_STATUS dp_umac_reset_handle_post_reset_complete(struct dp_soc *soc); @@ -2379,18 +2380,6 @@ static inline bool dp_skip_msi_cfg(struct dp_soc *soc, int ring_type) #endif /* DP_CON_MON_MSI_ENABLED */ #endif /* DISABLE_MON_RING_MSI_CFG */ -#ifdef DP_UMAC_HW_RESET_SUPPORT -static bool dp_check_umac_reset_in_progress(struct dp_soc *soc) -{ - return !!soc->umac_reset_ctx.intr_ctx_bkp; -} -#else -static bool dp_check_umac_reset_in_progress(struct dp_soc *soc) -{ - return false; -} -#endif - QDF_STATUS dp_srng_init_idx(struct dp_soc *soc, struct dp_srng *srng, int ring_type, int ring_num, int mac_id, uint32_t idx) @@ -6877,6 +6866,10 @@ void dp_soc_txrx_peer_setup(enum wlan_op_mode vdev_opmode, struct dp_soc *soc, #ifdef DP_UMAC_HW_RESET_SUPPORT static void dp_register_umac_reset_handlers(struct dp_soc *soc) { + dp_umac_reset_register_rx_action_callback(soc, + dp_umac_reset_action_trigger_recovery, + UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY); + dp_umac_reset_register_rx_action_callback(soc, dp_umac_reset_handle_pre_reset, UMAC_RESET_ACTION_DO_PRE_RESET); @@ -13680,7 +13673,8 @@ static void dp_restore_interrupt_ring_masks(struct dp_soc *soc) int num_ctxt = wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); int i; - qdf_assert_always(intr_bkp); + if (!intr_bkp) + return; for (i = 0; i < num_ctxt; i++) { intr_ctx = &soc->intr_ctx[i]; @@ -13892,6 +13886,19 @@ static void dp_reinit_rings(struct dp_soc *soc) dp_soc_srng_init(soc); } +/** + * dp_umac_reset_action_trigger_recovery() - Handle FW Umac recovery trigger + * @soc: dp soc handle + * + * Return: QDF_STATUS + */ +static QDF_STATUS dp_umac_reset_action_trigger_recovery(struct dp_soc *soc) +{ + enum umac_reset_action action = UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY; + + return dp_umac_reset_notify_action_completion(soc, action); +} + /** * dp_umac_reset_handle_pre_reset() - Handle Umac prereset interrupt from FW * @soc: dp soc handle @@ -13975,9 +13982,12 @@ static QDF_STATUS dp_umac_reset_handle_post_reset_complete(struct dp_soc *soc) nbuf_list = nbuf; } - dp_umac_reset_info("Umac reset done on soc %pK\n prereset : %u us\n" + dp_umac_reset_info("Umac reset done on soc %pK\n trigger start : %u us " + "trigger done : %u us prereset : %u us\n" "postreset : %u us \n postreset complete: %u us \n", soc, + soc->umac_reset_ctx.ts.trigger_done - + soc->umac_reset_ctx.ts.trigger_start, soc->umac_reset_ctx.ts.pre_reset_done - soc->umac_reset_ctx.ts.pre_reset_start, soc->umac_reset_ctx.ts.post_reset_done - diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index e4331a0535..59e1c0716f 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -176,6 +176,9 @@ (comb_peer_id_tid & DP_PEER_REO_STATS_PEER_ID_MASK) #endif +typedef void dp_ptnr_soc_iter_func(struct dp_soc *ptnr_soc, void *arg, + int chip_id); + enum rx_pktlog_mode { DP_RX_PKTLOG_DISABLED = 0, DP_RX_PKTLOG_FULL, diff --git a/dp/wifi3.0/dp_umac_reset.c b/dp/wifi3.0/dp_umac_reset.c index 67b8a17950..fed3097903 100644 --- a/dp/wifi3.0/dp_umac_reset.c +++ b/dp/wifi3.0/dp_umac_reset.c @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include #include #include #include @@ -107,7 +107,7 @@ QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) umac_reset_ctx = &soc->umac_reset_ctx; qdf_mem_zero(umac_reset_ctx, sizeof(*umac_reset_ctx)); - umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; + umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER; umac_reset_ctx->shmem_exp_magic_num = DP_UMAC_RESET_SHMEM_MAGIC_NUM; status = dp_get_umac_reset_intr_ctx(soc, &umac_reset_ctx->intr_offset); @@ -155,33 +155,6 @@ QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) return dp_umac_reset_send_setup_cmd(soc); } -QDF_STATUS dp_soc_umac_reset_deinit(struct cdp_soc_t *txrx_soc) -{ - struct dp_soc *soc = (struct dp_soc *)txrx_soc; - struct dp_soc_umac_reset_ctx *umac_reset_ctx; - - if (!soc) { - dp_umac_reset_err("DP SOC is null"); - return QDF_STATUS_E_NULL_VALUE; - } - - if (!soc->features.umac_hw_reset_support) { - dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); - return QDF_STATUS_E_NOSUPPORT; - } - - dp_umac_reset_interrupt_detach(soc); - - umac_reset_ctx = &soc->umac_reset_ctx; - qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, - umac_reset_ctx->shmem_size, - umac_reset_ctx->shmem_vaddr_unaligned, - umac_reset_ctx->shmem_paddr_unaligned, - 0); - - return QDF_STATUS_SUCCESS; -} - /** * dp_umac_reset_get_rx_event_from_shmem() - Extract the Rx event from the * shared memory @@ -219,6 +192,16 @@ dp_umac_reset_get_rx_event_from_shmem( rx_event = UMAC_RESET_RX_EVENT_NONE; + if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_INITIATE_UMAC_RECOVERY_GET(t2h_msg)) { + rx_event |= UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY; + num_events++; + } + + if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_INITIATE_TARGET_RECOVERY_SYNC_USING_UMAC_GET(t2h_msg)) { + rx_event |= UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC; + num_events++; + } + if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_PRE_RESET_GET(t2h_msg)) { rx_event |= UMAC_RESET_RX_EVENT_DO_PRE_RESET; num_events++; @@ -247,6 +230,36 @@ err: return UMAC_RESET_RX_EVENT_ERROR; } +/** + * dp_umac_reset_peek_rx_event_from_shmem() - Peek the Rx event from the + * shared memory without clearing the bit + * @umac_reset_ctx: UMAC reset context + * + * Return: true if the shared memory has any valid bits set + */ +static inline bool dp_umac_reset_peek_rx_event_from_shmem( + struct dp_soc_umac_reset_ctx *umac_reset_ctx) +{ + htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; + + shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; + if (!shmem_vaddr) { + dp_umac_reset_debug("Shared memory address is NULL"); + goto err; + } + + if (shmem_vaddr->magic_num != umac_reset_ctx->shmem_exp_magic_num) { + dp_umac_reset_debug("Shared memory got corrupted"); + goto err; + } + + /* Read the shared memory into a local variable */ + return !!shmem_vaddr->t2h_msg; + +err: + return false; +} + /** * dp_umac_reset_get_rx_event() - Extract the Rx event * @umac_reset_ctx: UMAC reset context @@ -280,7 +293,11 @@ dp_umac_reset_validate_n_update_state_machine_on_rx( dp_umac_reset_err("state machine validation failed on rx event: %d, current state is %d", rx_event, umac_reset_ctx->current_state); - qdf_assert_always(0); + + if ((rx_event != UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY) && + (rx_event != UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC)) + qdf_assert_always(0); + return QDF_STATUS_E_FAILURE; } @@ -289,6 +306,125 @@ dp_umac_reset_validate_n_update_state_machine_on_rx( return QDF_STATUS_SUCCESS; } +static bool dp_umac_reset_peek_rx_event(void *dp_ctx) +{ + struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx; + struct dp_soc *soc = int_ctx->soc; + struct dp_soc_umac_reset_ctx *umac_reset_ctx = &soc->umac_reset_ctx; + + return dp_umac_reset_peek_rx_event_from_shmem(umac_reset_ctx); +} + +/** + * dp_check_umac_reset_in_progress() - Check if Umac reset is in progress + * @soc: dp soc handle + * + * Return: true if Umac reset is in progress or false otherwise + */ +bool dp_check_umac_reset_in_progress(struct dp_soc *soc) +{ + return !!soc->umac_reset_ctx.intr_ctx_bkp; +} + +#if !defined(WLAN_FEATURE_11BE_MLO) || !defined(WLAN_MLO_MULTI_CHIP) +/** + * dp_umac_reset_initiate_umac_recovery() - Initiate Umac reset session + * @soc: dp soc handle + * @is_target_recovery: Flag to indicate if it is triggered for target recovery + * + * Return: void + */ +static void dp_umac_reset_initiate_umac_recovery(struct dp_soc *soc, + bool is_target_recovery) +{ +} + +/** + * dp_umac_reset_complete_umac_recovery() - Complete Umac reset session + * @soc: dp soc handle + * + * Return: void + */ +static void dp_umac_reset_complete_umac_recovery(struct dp_soc *soc) +{ + dp_umac_reset_alert("Umac reset was handled successfully on soc %pK", + soc); +} + +/** + * dp_umac_reset_handle_action_cb() - Function to call action callback + * @soc: dp soc handle + * @umac_reset_ctx: Umac reset context + * @action: Action to call the callback for + * + * Return: QDF_STATUS status + */ +static QDF_STATUS dp_umac_reset_handle_action_cb(struct dp_soc *soc, + struct dp_soc_umac_reset_ctx *umac_reset_ctx, + enum umac_reset_action action) +{ + if (!umac_reset_ctx->rx_actions.cb[action]) { + dp_umac_reset_err("rx callback is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = umac_reset_ctx->rx_actions.cb[action](soc); + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_umac_reset_post_tx_cmd() - Iterate partner socs and post Tx command + * @umac_reset_ctx: UMAC reset context + * @tx_cmd: Tx command to be posted + * + * Return: QDF status of operation + */ +static QDF_STATUS +dp_umac_reset_post_tx_cmd(struct dp_soc_umac_reset_ctx *umac_reset_ctx, + enum umac_reset_tx_cmd tx_cmd) +{ + struct dp_soc *soc = container_of(umac_reset_ctx, struct dp_soc, + umac_reset_ctx); + + dp_umac_reset_post_tx_cmd_via_shmem(soc, &tx_cmd, 0); + return QDF_STATUS_SUCCESS; +} + +/** + * dp_umac_reset_initiator_check() - Check if soc is the Umac reset initiator + * @soc: dp soc handle + * + * Return: true if the soc is initiator or false otherwise + */ +static bool dp_umac_reset_initiator_check(struct dp_soc *soc) +{ + return true; +} + +/** + * dp_umac_reset_target_recovery_check() - Check if this is for target recovery + * @soc: dp soc handle + * + * Return: true if the session is for target recovery or false otherwise + */ +static bool dp_umac_reset_target_recovery_check(struct dp_soc *soc) +{ + return false; +} + +/** + * dp_umac_reset_is_soc_ignored() - Check if this soc is to be ignored + * @soc: dp soc handle + * + * Return: true if the soc is ignored or false otherwise + */ +static bool dp_umac_reset_is_soc_ignored(struct dp_soc *soc) +{ + return false; +} +#endif + /** * dp_umac_reset_rx_event_handler() - Main Rx event handler for UMAC reset * @dp_ctx: Interrupt context corresponding to UMAC reset @@ -302,7 +438,8 @@ static int dp_umac_reset_rx_event_handler(void *dp_ctx) struct dp_soc_umac_reset_ctx *umac_reset_ctx; enum umac_reset_rx_event rx_event; QDF_STATUS status = QDF_STATUS_E_INVAL; - enum umac_reset_action action; + enum umac_reset_action action = UMAC_RESET_ACTION_NONE; + bool target_recovery = false; if (!soc) { dp_umac_reset_err("DP SOC is null"); @@ -314,43 +451,79 @@ static int dp_umac_reset_rx_event_handler(void *dp_ctx) dp_umac_reset_debug("enter"); rx_event = dp_umac_reset_get_rx_event(umac_reset_ctx); + if (umac_reset_ctx->pending_action) { + if (rx_event != UMAC_RESET_RX_EVENT_NONE) { + dp_umac_reset_err("Invalid value(%u) for Rx event when " + "action %u is pending\n", rx_event, + umac_reset_ctx->pending_action); + qdf_assert_always(0); + } + } + switch (rx_event) { case UMAC_RESET_RX_EVENT_NONE: - /* This interrupt is not meant for us, so exit */ - dp_umac_reset_debug("Not a UMAC reset event"); + if (umac_reset_ctx->pending_action) + action = umac_reset_ctx->pending_action; + else + dp_umac_reset_err("Not a UMAC reset event!!"); + status = QDF_STATUS_SUCCESS; - goto exit; + break; + + case UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC: + target_recovery = true; + /* Fall through */ + case UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY: + status = dp_umac_reset_validate_n_update_state_machine_on_rx( + umac_reset_ctx, rx_event, + UMAC_RESET_STATE_WAIT_FOR_TRIGGER, + UMAC_RESET_STATE_DO_TRIGGER_RECEIVED); + + if (status == QDF_STATUS_E_FAILURE) + goto exit; + + umac_reset_ctx->ts.trigger_start = + qdf_get_log_timestamp_usecs(); + + action = UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY; + + dp_umac_reset_initiate_umac_recovery(soc, target_recovery); + + break; case UMAC_RESET_RX_EVENT_DO_PRE_RESET: - umac_reset_ctx->ts.pre_reset_start = - qdf_get_log_timestamp_usecs(); status = dp_umac_reset_validate_n_update_state_machine_on_rx( umac_reset_ctx, rx_event, UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET, UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED); + umac_reset_ctx->ts.pre_reset_start = + qdf_get_log_timestamp_usecs(); + action = UMAC_RESET_ACTION_DO_PRE_RESET; break; case UMAC_RESET_RX_EVENT_DO_POST_RESET_START: - umac_reset_ctx->ts.post_reset_start = - qdf_get_log_timestamp_usecs(); status = dp_umac_reset_validate_n_update_state_machine_on_rx( umac_reset_ctx, rx_event, UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START, UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED); + umac_reset_ctx->ts.post_reset_start = + qdf_get_log_timestamp_usecs(); + action = UMAC_RESET_ACTION_DO_POST_RESET_START; break; case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE: - umac_reset_ctx->ts.post_reset_complete_start = - qdf_get_log_timestamp_usecs(); status = dp_umac_reset_validate_n_update_state_machine_on_rx( umac_reset_ctx, rx_event, UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE, UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED); + umac_reset_ctx->ts.post_reset_complete_start = + qdf_get_log_timestamp_usecs(); + action = UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE; break; @@ -365,12 +538,7 @@ static int dp_umac_reset_rx_event_handler(void *dp_ctx) /* Call the handler for this event */ if (QDF_IS_STATUS_SUCCESS(status)) { - if (!umac_reset_ctx->rx_actions.cb[action]) { - dp_umac_reset_err("rx callback is NULL"); - goto exit; - } - - status = umac_reset_ctx->rx_actions.cb[action](soc); + dp_umac_reset_handle_action_cb(soc, umac_reset_ctx, action); } exit: @@ -432,6 +600,7 @@ QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc) /* Finally register to this IRQ from HIF layer */ return hif_register_umac_reset_handler( soc->hif_handle, + dp_umac_reset_peek_rx_event, dp_umac_reset_rx_event_handler, &soc->intr_ctx[umac_reset_ctx->intr_offset], umac_reset_irq); @@ -465,7 +634,7 @@ QDF_STATUS dp_umac_reset_register_rx_action_callback( } if (!soc->features.umac_hw_reset_support) { - dp_umac_reset_info("Target doesn't support the UMAC HW reset feature"); + dp_umac_reset_info("Target doesn't support UMAC HW reset"); return QDF_STATUS_E_NOSUPPORT; } @@ -483,25 +652,55 @@ QDF_STATUS dp_umac_reset_register_rx_action_callback( /** * dp_umac_reset_post_tx_cmd_via_shmem() - Post Tx command using shared memory - * @umac_reset_ctx: UMAC reset context - * @tx_cmd: Tx command to be posted + * @soc: DP soc object + * @ctxt: Tx command to be posted + * @chip_id: Chip id of the mlo soc * - * Return: QDF status of operation + * Return: None */ -static QDF_STATUS -dp_umac_reset_post_tx_cmd_via_shmem( - struct dp_soc_umac_reset_ctx *umac_reset_ctx, - enum umac_reset_tx_cmd tx_cmd) +void +dp_umac_reset_post_tx_cmd_via_shmem(struct dp_soc *soc, void *ctxt, int chip_id) { + enum umac_reset_tx_cmd tx_cmd = *((enum umac_reset_tx_cmd *)ctxt); htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr; + struct dp_soc_umac_reset_ctx *umac_reset_ctx = &soc->umac_reset_ctx; + bool initiator; + QDF_STATUS status; + + if (dp_umac_reset_is_soc_ignored(soc)) { + dp_umac_reset_debug("Skipping soc (chip id %d)", chip_id); + return; + } shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned; if (!shmem_vaddr) { dp_umac_reset_err("Shared memory address is NULL"); - return QDF_STATUS_E_NULL_VALUE; + return; } + dp_umac_reset_debug("Sending txcmd %u for chip id %u", tx_cmd, chip_id); + switch (tx_cmd) { + case UMAC_RESET_TX_CMD_TRIGGER_DONE: + /* Send htt message to the partner soc */ + initiator = dp_umac_reset_initiator_check(soc); + status = dp_htt_umac_reset_send_start_pre_reset_cmd(soc, + initiator, + !dp_umac_reset_target_recovery_check(soc)); + + if (status != QDF_STATUS_SUCCESS) + dp_umac_reset_err("Unable to send Umac trigger"); + else + dp_umac_reset_debug("Sent trigger for soc (chip_id %d)", + chip_id); + + if (!initiator) + umac_reset_ctx->current_state = + UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; + + umac_reset_ctx->ts.trigger_done = qdf_get_log_timestamp_usecs(); + break; + case UMAC_RESET_TX_CMD_PRE_RESET_DONE: HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_PRE_RESET_DONE_SET( shmem_vaddr->h2t_msg, 1); @@ -528,10 +727,10 @@ dp_umac_reset_post_tx_cmd_via_shmem( default: dp_umac_reset_err("Invalid tx cmd: %d", tx_cmd); - return QDF_STATUS_E_FAILURE; + return; } - return QDF_STATUS_SUCCESS; + return; } /** @@ -552,6 +751,11 @@ dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx) QDF_STATUS status; switch (umac_reset_ctx->current_state) { + case UMAC_RESET_STATE_HOST_TRIGGER_DONE: + tx_cmd = UMAC_RESET_TX_CMD_TRIGGER_DONE; + next_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; + break; + case UMAC_RESET_STATE_HOST_PRE_RESET_DONE: tx_cmd = UMAC_RESET_TX_CMD_PRE_RESET_DONE; next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START; @@ -564,7 +768,7 @@ dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx) case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE: tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE; - next_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET; + next_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER; break; default: @@ -574,7 +778,7 @@ dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx) return QDF_STATUS_E_FAILURE; } - status = dp_umac_reset_post_tx_cmd_via_shmem(umac_reset_ctx, tx_cmd); + status = dp_umac_reset_post_tx_cmd(umac_reset_ctx, tx_cmd); if (QDF_IS_STATUS_ERROR(status)) { dp_umac_reset_err("Couldn't post Tx cmd"); qdf_assert_always(0); @@ -615,6 +819,21 @@ static QDF_STATUS dp_umac_reset_notify_completion( return dp_umac_reset_notify_target(umac_reset_ctx); } +static void dp_umac_wait_for_quiescent_state(struct dp_soc *soc) +{ + enum umac_reset_state current_state; + + do { + msleep(10); + barrier(); + current_state = soc->umac_reset_ctx.current_state; + + } while ((current_state == UMAC_RESET_STATE_DO_TRIGGER_RECEIVED) || + (current_state == UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED) || + (current_state == UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED) || + (current_state == UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED)); +} + QDF_STATUS dp_umac_reset_notify_action_completion( struct dp_soc *soc, enum umac_reset_action action) @@ -632,6 +851,10 @@ QDF_STATUS dp_umac_reset_notify_action_completion( } switch (action) { + case UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY: + next_state = UMAC_RESET_STATE_HOST_TRIGGER_DONE; + break; + case UMAC_RESET_ACTION_DO_PRE_RESET: next_state = UMAC_RESET_STATE_HOST_PRE_RESET_DONE; break; @@ -644,6 +867,10 @@ QDF_STATUS dp_umac_reset_notify_action_completion( next_state = UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE; break; + case UMAC_RESET_ACTION_ABORT: + next_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER; + break; + default: dp_umac_reset_err("Invalid action"); return QDF_STATUS_E_FAILURE; @@ -651,3 +878,56 @@ QDF_STATUS dp_umac_reset_notify_action_completion( return dp_umac_reset_notify_completion(soc, next_state); } + +/** + * dp_soc_umac_reset_deinit() - Deinitialize the umac reset module + * @txrx_soc: DP soc object + * + * Return: QDF status of operation + */ +QDF_STATUS dp_soc_umac_reset_deinit(struct cdp_soc_t *txrx_soc) +{ + struct dp_soc *soc = (struct dp_soc *)txrx_soc; + struct dp_soc_umac_reset_ctx *umac_reset_ctx; + qdf_nbuf_t nbuf_list; + + if (!soc) { + dp_umac_reset_err("DP SOC is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!soc->features.umac_hw_reset_support) { + dp_umac_reset_info("No target support for UMAC reset feature"); + return QDF_STATUS_E_NOSUPPORT; + } + + if (dp_check_umac_reset_in_progress(soc)) { + dp_umac_reset_info("Cleaning up Umac reset context"); + dp_umac_wait_for_quiescent_state(soc); + dp_resume_reo_send_cmd(soc); + dp_umac_reset_notify_action_completion(soc, + UMAC_RESET_ACTION_ABORT); + } + + nbuf_list = soc->umac_reset_ctx.nbuf_list; + soc->umac_reset_ctx.nbuf_list = NULL; + + while (nbuf_list) { + qdf_nbuf_t nbuf = nbuf_list->next; + + qdf_nbuf_free(nbuf_list); + nbuf_list = nbuf; + } + + dp_umac_reset_interrupt_detach(soc); + + umac_reset_ctx = &soc->umac_reset_ctx; + qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, + umac_reset_ctx->shmem_size, + umac_reset_ctx->shmem_vaddr_unaligned, + umac_reset_ctx->shmem_paddr_unaligned, + 0); + + return QDF_STATUS_SUCCESS; +} + diff --git a/dp/wifi3.0/dp_umac_reset.h b/dp/wifi3.0/dp_umac_reset.h index 5cc616e3cd..a8276e9a63 100644 --- a/dp/wifi3.0/dp_umac_reset.h +++ b/dp/wifi3.0/dp_umac_reset.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -22,15 +22,21 @@ struct dp_soc; /** * enum umac_reset_action - Actions supported by the UMAC reset + * @UMAC_RESET_ACTION_NONE: No action + * @UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY: Trigger umac recovery * @UMAC_RESET_ACTION_DO_PRE_RESET: DO_PRE_RESET * @UMAC_RESET_ACTION_DO_POST_RESET_START: DO_POST_RESET_START * @UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE: DO_POST_RESET_COMPLETE + * @UMAC_RESET_ACTION_ABORT: Abort the current Umac reset session * @UMAC_RESET_ACTION_MAX: Maximum actions */ enum umac_reset_action { - UMAC_RESET_ACTION_DO_PRE_RESET = 0, - UMAC_RESET_ACTION_DO_POST_RESET_START = 1, - UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE = 2, + UMAC_RESET_ACTION_NONE, + UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY, + UMAC_RESET_ACTION_DO_PRE_RESET, + UMAC_RESET_ACTION_DO_POST_RESET_START, + UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE, + UMAC_RESET_ACTION_ABORT, UMAC_RESET_ACTION_MAX }; @@ -54,6 +60,9 @@ enum umac_reset_action { /** * enum umac_reset_state - States required by the UMAC reset state machine + * @UMAC_RESET_STATE_WAIT_FOR_TRIGGER: Waiting for trigger event + * @UMAC_RESET_STATE_DO_TRIGGER_RECEIVED: Receivd the DO_TRIGGER event + * @UMAC_RESET_STATE_HOST_TRIGGER_DONE: Host completed handling Trigger event * @UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET: Waiting for the DO_PRE_RESET event * @UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED: Received the DO_PRE_RESET event * @UMAC_RESET_STATE_HOST_PRE_RESET_DONE: Host has completed handling the @@ -72,7 +81,11 @@ enum umac_reset_action { * the DO_POST_RESET_COMPLETE event */ enum umac_reset_state { - UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET = 0, + UMAC_RESET_STATE_WAIT_FOR_TRIGGER = 0, + UMAC_RESET_STATE_DO_TRIGGER_RECEIVED, + UMAC_RESET_STATE_HOST_TRIGGER_DONE, + + UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET, UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED, UMAC_RESET_STATE_HOST_PRE_RESET_DONE, @@ -88,6 +101,8 @@ enum umac_reset_state { /** * enum umac_reset_rx_event - Rx events deduced by the UMAC reset * @UMAC_RESET_RX_EVENT_NONE: No event + * @UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY: ACTION_DO_TRIGGER_RECOVERY event + * @UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC: ACTION_DO_TRIGGER_RECOVERY event * @UMAC_RESET_RX_EVENT_DO_PRE_RESET: DO_PRE_RESET event * @UMAC_RESET_RX_EVENT_DO_POST_RESET_START: DO_POST_RESET_START event * @UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE: DO_POST_RESET_COMPELTE event @@ -95,20 +110,24 @@ enum umac_reset_state { */ enum umac_reset_rx_event { UMAC_RESET_RX_EVENT_NONE = 0x0, - UMAC_RESET_RX_EVENT_DO_PRE_RESET = 0x1, - UMAC_RESET_RX_EVENT_DO_POST_RESET_START = 0x2, - UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE = 0x4, + UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY, + UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC, + UMAC_RESET_RX_EVENT_DO_PRE_RESET, + UMAC_RESET_RX_EVENT_DO_POST_RESET_START, + UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE, UMAC_RESET_RX_EVENT_ERROR = 0xFFFFFFFF, }; /** * enum umac_reset_tx_cmd: UMAC reset Tx command + * @UMAC_RESET_TX_CMD_TRIGGER_DONE: TRIGGER_DONE * @UMAC_RESET_TX_CMD_PRE_RESET_DONE: PRE_RESET_DONE * @UMAC_RESET_TX_CMD_POST_RESET_START_DONE: POST_RESET_START_DONE * @UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE: POST_RESET_COMPLETE_DONE */ enum umac_reset_tx_cmd { + UMAC_RESET_TX_CMD_TRIGGER_DONE, UMAC_RESET_TX_CMD_PRE_RESET_DONE, UMAC_RESET_TX_CMD_POST_RESET_START_DONE, UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE, @@ -125,6 +144,8 @@ struct umac_reset_rx_actions { /** * struct reset_ts - timestamps of for umac reset events for debug + * @trigger_start: Umac reset trigger event timestamp + * @trigger_done: Umac reset trigger done timestamp * @pre_reset_start: Umac prereset start event timestamp * @pre_reset_done: Umac prereset done timestamp * @post_reset_start: Umac postreset start event timestamp @@ -133,6 +154,8 @@ struct umac_reset_rx_actions { * @post_reset_complete_done: Umac postreset complete done timestamp */ struct reset_ts { + uint64_t trigger_start; + uint64_t trigger_done; uint64_t pre_reset_start; uint64_t pre_reset_done; uint64_t post_reset_start; @@ -141,6 +164,30 @@ struct reset_ts { uint64_t post_reset_complete_done; }; +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) +/** + * struct dp_soc_mlo_umac_reset_ctx - UMAC reset context at mlo group level + * @partner_map: Partner soc map + * @request_map: Partner soc request map + * @response_map: Partner soc response map + * @grp_ctx_lock: lock for accessing group level umac reset context + * @umac_reset_in_progress: Flag to indicate if umac reset is in progress + * @is_target_recovery: Flag to indicate if this is for target recovery + * @initiator_chip_id: chip id of the Umac reset initiator + * @umac_reset_count: Number of times Umac reset happened on this MLO group + */ +struct dp_soc_mlo_umac_reset_ctx { + unsigned long partner_map; + unsigned long request_map; + unsigned long response_map; + qdf_spinlock_t grp_ctx_lock; + uint8_t umac_reset_in_progress:1, + is_target_recovery:1; + uint8_t initiator_chip_id; + uint32_t umac_reset_count; +}; +#endif + /** * struct dp_soc_umac_reset_ctx - UMAC reset context at soc level * @shmem_paddr_unaligned: Physical address of the shared memory (unaligned) @@ -152,6 +199,7 @@ struct reset_ts { * @current_state: current state of the UMAC reset state machine * @shmem_exp_magic_num: Expected magic number in the shared memory * @rx_actions: callbacks for handling UMAC reset actions + * @pending_action: Action pending to be executed. * @intr_ctx_bkp: DP Interrupts ring masks backup * @nbuf_list: skb list for delayed free * @skel_enable: Enable skeleton code for umac reset @@ -167,6 +215,7 @@ struct dp_soc_umac_reset_ctx { enum umac_reset_state current_state; uint32_t shmem_exp_magic_num; struct umac_reset_rx_actions rx_actions; + enum umac_reset_rx_event pending_action; struct dp_intr_bkp *intr_ctx_bkp; qdf_nbuf_t nbuf_list; bool skel_enable; @@ -230,7 +279,31 @@ QDF_STATUS dp_umac_reset_register_rx_action_callback( QDF_STATUS dp_umac_reset_notify_action_completion( struct dp_soc *soc, enum umac_reset_action action); + +/** + * dp_umac_reset_post_tx_cmd_via_shmem() - Post Tx command using shared memory + * @soc: DP soc object + * @ctxt: Tx command to be posted + * @chip_id: Chip id of the mlo soc + * + * Return: None + */ +void dp_umac_reset_post_tx_cmd_via_shmem(struct dp_soc *soc, void *ctxt, + int chip_id); + +/** + * dp_check_umac_reset_in_progress() - Check if Umac reset is in progress + * @soc: dp soc handle + * + * Return: true if Umac reset is in progress or false otherwise + */ +bool dp_check_umac_reset_in_progress(struct dp_soc *soc); #else +static inline bool dp_check_umac_reset_in_progress(struct dp_soc *soc) +{ + return false; +} + static inline QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc) { diff --git a/dp/wifi3.0/monitor/2.0/dp_mon_2.0.c b/dp/wifi3.0/monitor/2.0/dp_mon_2.0.c index fa127964e5..96dd55b9d3 100644 --- a/dp/wifi3.0/monitor/2.0/dp_mon_2.0.c +++ b/dp/wifi3.0/monitor/2.0/dp_mon_2.0.c @@ -1759,7 +1759,8 @@ void dp_mon_rx_update_rx_protocol_tag_stats(struct dp_pdev *pdev, #ifdef QCA_ENHANCED_STATS_SUPPORT static void -dp_enable_enhanced_stats_for_each_pdev(struct dp_soc *soc, void *arg) { +dp_enable_enhanced_stats_for_each_pdev(struct dp_soc *soc, void *arg, + int chip_id) { uint8_t i = 0; for (i = 0; i < MAX_PDEV_CNT; i++) @@ -1781,7 +1782,8 @@ dp_enable_enhanced_stats_2_0(struct cdp_soc_t *soc, uint8_t pdev_id) } static void -dp_disable_enhanced_stats_for_each_pdev(struct dp_soc *soc, void *arg) { +dp_disable_enhanced_stats_for_each_pdev(struct dp_soc *soc, void *arg, + int chip_id) { uint8_t i = 0; for (i = 0; i < MAX_PDEV_CNT; i++) diff --git a/hif/inc/hif.h b/hif/inc/hif.h index d65d58d601..5f02f083c2 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -2625,14 +2625,16 @@ uint8_t hif_get_max_wmi_ep(struct hif_opaque_softc *scn); /** * hif_register_umac_reset_handler() - Register UMAC HW reset handler * @hif_scn: hif opaque handle - * @handler: callback handler function + * @irq_handler: irq callback handler function + * @tl_handler: tasklet callback handler function * @cb_ctx: context to passed to @handler * @irq: irq number to be used for UMAC HW reset interrupt * * Return: QDF_STATUS of operation */ QDF_STATUS hif_register_umac_reset_handler(struct hif_opaque_softc *hif_scn, - int (*handler)(void *cb_ctx), + bool (*irq_handler)(void *cb_ctx), + int (*tl_handler)(void *cb_ctx), void *cb_ctx, int irq); /** @@ -2647,7 +2649,8 @@ QDF_STATUS hif_get_umac_reset_irq(struct hif_opaque_softc *hif_scn, #else static inline QDF_STATUS hif_register_umac_reset_handler(struct hif_opaque_softc *hif_scn, - int (*handler)(void *cb_ctx), + bool (*irq_handler)(void *cb_ctx), + int (*tl_handler)(void *cb_ctx), void *cb_ctx, int irq) { return QDF_STATUS_SUCCESS; diff --git a/hif/src/hif_exec.c b/hif/src/hif_exec.c index 62a8cff997..e61d9fb720 100644 --- a/hif/src/hif_exec.c +++ b/hif/src/hif_exec.c @@ -1197,8 +1197,9 @@ static irqreturn_t hif_umac_reset_irq_handler(int irq, void *ctx) { struct hif_umac_reset_ctx *umac_reset_ctx = ctx; - /* Schedule the tasklet and exit */ - tasklet_hi_schedule(&umac_reset_ctx->intr_tq); + /* Schedule the tasklet if it is umac reset interrupt and exit */ + if (umac_reset_ctx->irq_handler(umac_reset_ctx->cb_ctx)) + tasklet_hi_schedule(&umac_reset_ctx->intr_tq); return IRQ_HANDLED; } @@ -1224,7 +1225,8 @@ QDF_STATUS hif_get_umac_reset_irq(struct hif_opaque_softc *hif_scn, qdf_export_symbol(hif_get_umac_reset_irq); QDF_STATUS hif_register_umac_reset_handler(struct hif_opaque_softc *hif_scn, - int (*handler)(void *cb_ctx), + bool (*irq_handler)(void *cb_ctx), + int (*tl_handler)(void *cb_ctx), void *cb_ctx, int irq) { struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_scn); @@ -1238,7 +1240,8 @@ QDF_STATUS hif_register_umac_reset_handler(struct hif_opaque_softc *hif_scn, umac_reset_ctx = &hif_sc->umac_reset_ctx; - umac_reset_ctx->cb_handler = handler; + umac_reset_ctx->irq_handler = irq_handler; + umac_reset_ctx->cb_handler = tl_handler; umac_reset_ctx->cb_ctx = cb_ctx; umac_reset_ctx->os_irq = irq; diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index 616de081dd..ccb18b7c84 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -243,6 +243,7 @@ struct hif_cfg { /** * struct hif_umac_reset_ctx - UMAC HW reset context at HIF layer * @intr_tq: Tasklet structure + * @irq_handler: IRQ handler * @cb_handler: Callback handler * @cb_ctx: Argument to be passed to @cb_handler * @os_irq: Interrupt number for this IRQ @@ -250,6 +251,7 @@ struct hif_cfg { */ struct hif_umac_reset_ctx { struct tasklet_struct intr_tq; + bool (*irq_handler)(void *cb_ctx); int (*cb_handler)(void *cb_ctx); void *cb_ctx; uint32_t os_irq;