diff --git a/hif/inc/hif.h b/hif/inc/hif.h index 39368e673b..7cf7f963be 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -463,6 +463,7 @@ struct hif_driver_state_callbacks { bool (*is_recovery_in_progress)(void *context); bool (*is_load_unload_in_progress)(void *context); bool (*is_driver_unloading)(void *context); + bool (*is_target_ready)(void *context); }; /* This API detaches the HTC layer from the HIF device */ diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c index f0e27fa62a..2e663bd54c 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -2897,11 +2897,16 @@ inline unsigned int hif_get_src_ring_read_index(struct hif_softc *scn, struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); attr = hif_state->host_ce_config[COPY_ENGINE_ID(CE_ctrl_addr)]; - if (attr.flags & CE_ATTR_DISABLE_INTR) + if (attr.flags & CE_ATTR_DISABLE_INTR) { return CE_SRC_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr); - else - return A_TARGET_READ(scn, - (CE_ctrl_addr) + CURRENT_SRRI_ADDRESS); + } else { + if (TARGET_REGISTER_ACCESS_ALLOWED(scn)) + return A_TARGET_READ(scn, + (CE_ctrl_addr) + CURRENT_SRRI_ADDRESS); + else + return CE_SRC_RING_READ_IDX_GET_FROM_DDR(scn, + CE_ctrl_addr); + } } /** @@ -2923,11 +2928,16 @@ inline unsigned int hif_get_dst_ring_read_index(struct hif_softc *scn, attr = hif_state->host_ce_config[COPY_ENGINE_ID(CE_ctrl_addr)]; - if (attr.flags & CE_ATTR_DISABLE_INTR) + if (attr.flags & CE_ATTR_DISABLE_INTR) { return CE_DEST_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr); - else - return A_TARGET_READ(scn, - (CE_ctrl_addr) + CURRENT_DRRI_ADDRESS); + } else { + if (TARGET_REGISTER_ACCESS_ALLOWED(scn)) + return A_TARGET_READ(scn, + (CE_ctrl_addr) + CURRENT_DRRI_ADDRESS); + else + return CE_DEST_RING_READ_IDX_GET_FROM_DDR(scn, + CE_ctrl_addr); + } } /** diff --git a/hif/src/ce/ce_service.c b/hif/src/ce/ce_service.c index 86001dfaf3..3e844cc033 100644 --- a/hif/src/ce/ce_service.c +++ b/hif/src/ce/ce_service.c @@ -1894,8 +1894,13 @@ more_data: goto more_data; } qdf_atomic_set(&ce_state->rx_pending, 0); - CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr, - HOST_IS_COPY_COMPLETE_MASK); + if (TARGET_REGISTER_ACCESS_ALLOWED(scn)) { + CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr, + HOST_IS_COPY_COMPLETE_MASK); + } else { + HIF_ERROR("%s: target access is not allowed", __func__); + return; + } if (ce_recv_entries_done_nolock_legacy(scn, ce_state)) { if (more_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) { @@ -2091,10 +2096,16 @@ more_watermarks: * more copy completions happened while the misc interrupts were being * handled. */ - if (!ce_srng_based(scn)) - CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr, - CE_WATERMARK_MASK | - HOST_IS_COPY_COMPLETE_MASK); + if (!ce_srng_based(scn)) { + if (TARGET_REGISTER_ACCESS_ALLOWED(scn)) { + CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr, + CE_WATERMARK_MASK | + HOST_IS_COPY_COMPLETE_MASK); + } else { + HIF_ERROR("%s: target access is not allowed", __func__); + return CE_state->receive_count; + } + } /* * Now that per-engine interrupts are cleared, verify that @@ -2217,6 +2228,11 @@ ce_per_engine_handler_adjust_legacy(struct CE_state *CE_state, if (Q_TARGET_ACCESS_BEGIN(scn) < 0) return; + if (!TARGET_REGISTER_ACCESS_ALLOWED(scn)) { + HIF_ERROR("%s: target access is not allowed", __func__); + return; + } + if ((!disable_copy_compl_intr) && (CE_state->send_cb || CE_state->recv_cb)) CE_COPY_COMPLETE_INTR_ENABLE(scn, ctrl_addr); diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index 038fdadcee..5db6af87c2 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/hif/src/ce/ce_tasklet.c @@ -400,6 +400,10 @@ irqreturn_t ce_dispatch_interrupt(int ce_id, } hif_irq_disable(scn, ce_id); + + if (!TARGET_REGISTER_ACCESS_ALLOWED(scn)) + return IRQ_HANDLED; + hif_record_ce_desc_event(scn, ce_id, HIF_IRQ_EVENT, NULL, NULL, 0); hif_ce_increment_interrupt_count(hif_ce_state, ce_id); diff --git a/hif/src/hif_io32.h b/hif/src/hif_io32.h index 113b94a04b..6d1d1cfff0 100644 --- a/hif/src/hif_io32.h +++ b/hif/src/hif_io32.h @@ -40,6 +40,8 @@ hif_target_sleep_state_adjust(scn, false, true) #define Q_TARGET_ACCESS_END(scn) \ hif_target_sleep_state_adjust(scn, true, false) +#define TARGET_REGISTER_ACCESS_ALLOWED(scn)\ + hif_is_target_register_access_allowed(scn) /* * A_TARGET_ACCESS_LIKELY will not wait for the target to wake up before diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index afecf3b7de..9a217ba2d3 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -1067,6 +1067,23 @@ bool hif_is_recovery_in_progress(struct hif_softc *scn) return false; } + +/** + * hif_is_target_ready() - API to query if target is in ready state + * progress + * @scn: HIF Context + * + * Return: True/False + */ +bool hif_is_target_ready(struct hif_softc *scn) +{ + struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn); + + if (cbk && cbk->is_target_ready) + return cbk->is_target_ready(cbk->context); + + return false; +} #if defined(HIF_PCI) || defined(SNOC) || defined(HIF_AHB) /** * hif_batch_send() - API to access hif specific function diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index 7f33f6b83f..54d5dd7526 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -236,6 +236,7 @@ struct hif_driver_state_callbacks *hif_get_callbacks_handle( bool hif_is_driver_unloading(struct hif_softc *scn); bool hif_is_load_or_unload_in_progress(struct hif_softc *scn); bool hif_is_recovery_in_progress(struct hif_softc *scn); +bool hif_is_target_ready(struct hif_softc *scn); void hif_wlan_disable(struct hif_softc *scn); int hif_target_sleep_state_adjust(struct hif_softc *scn, bool sleep_ok, @@ -259,4 +260,13 @@ static inline void hif_ramdump_handler(struct hif_opaque_softc *scn) {} */ irqreturn_t hif_wake_interrupt_handler(int irq, void *context); +#ifdef HIF_SNOC +bool hif_is_target_register_access_allowed(struct hif_softc *hif_sc); +#else +static inline +bool hif_is_target_register_access_allowed(struct hif_softc *hif_sc) +{ + return true; +} +#endif #endif /* __HIF_MAIN_H__ */ diff --git a/hif/src/snoc/hif_io32_snoc.h b/hif/src/snoc/hif_io32_snoc.h index f2a181698c..f22ac6b2d8 100644 --- a/hif/src/snoc/hif_io32_snoc.h +++ b/hif/src/snoc/hif_io32_snoc.h @@ -47,6 +47,10 @@ static inline void ce_enable_irq_in_individual_register(struct hif_softc *scn, uint32_t offset; offset = HOST_IE_ADDRESS + CE_BASE_ADDRESS(ce_id); + if (!TARGET_REGISTER_ACCESS_ALLOWED(scn)) { + HIF_ERROR("%s: target access is not allowed", __func__); + return; + } hif_write32_mb(scn->mem + offset, 1); } @@ -56,7 +60,16 @@ static inline void ce_disable_irq_in_individual_register(struct hif_softc *scn, uint32_t offset; offset = HOST_IE_ADDRESS + CE_BASE_ADDRESS(ce_id); + if (!TARGET_REGISTER_ACCESS_ALLOWED(scn)) { + HIF_ERROR("%s: target access is not allowed", __func__); + return; + } hif_write32_mb(scn->mem + offset, 0); + + if (!TARGET_REGISTER_ACCESS_ALLOWED(scn)) { + HIF_ERROR("%s: target access is not allowed", __func__); + return; + } hif_read32_mb(scn->mem + offset); } #endif diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c index 1a76ef82f9..0502f8aa49 100644 --- a/hif/src/snoc/if_snoc.c +++ b/hif/src/snoc/if_snoc.c @@ -464,3 +464,19 @@ int hif_snoc_map_ce_to_irq(struct hif_softc *scn, int ce_id) { return icnss_get_irq(ce_id); } + +/** + * hif_is_target_register_access_allowed(): Check target register access allow + * @scn: HIF Context + * + * This function help to check whether target register access is allowed or not + * + * Return: true if target access is allowed else false + */ +bool hif_is_target_register_access_allowed(struct hif_softc *scn) +{ + if (hif_is_recovery_in_progress(scn)) + return hif_is_target_ready(scn); + else + return true; +}