diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c index 3648a3ad86ff..7fa8305ce554 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -1827,9 +1827,9 @@ done: * This function passes the con_mode and CE configuration to * platform driver to enable wlan. * - * Return: void + * Return: linux error code */ -static int hif_wlan_enable(struct hif_softc *scn) +int hif_wlan_enable(struct hif_softc *scn) { struct icnss_wlan_enable_cfg cfg; enum icnss_driver_mode mode; @@ -1855,26 +1855,15 @@ static int hif_wlan_enable(struct hif_softc *scn) return icnss_wlan_enable(&cfg, mode, QWLAN_VERSIONSTR); } -/* - * Called from PCI layer whenever a new PCI device is probed. - * Initializes per-device HIF state and notifies the main - * driver that a new HIF device is present. +/** + * hif_ce_prepare_config() - load the correct static tables. + * @scn: hif context + * + * Epping uses different static attribute tables than mission mode. */ -int hif_config_ce(struct hif_softc *scn) +void hif_ce_prepare_config(struct hif_softc *scn) { - struct HIF_CE_pipe_info *pipe_info; - int pipe_num; uint32_t mode = hif_get_conparam(scn); -#ifdef ADRASTEA_SHADOW_REGISTERS - int i; -#endif - QDF_STATUS rv = QDF_STATUS_SUCCESS; - int ret; - struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); - struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); - struct icnss_soc_info soc_info; - struct hif_target_info *tgt_info = hif_get_target_info_handle(hif_hdl); - /* if epping is enabled we need to use the epping configuration. */ if (WLAN_IS_EPPING_ENABLED(mode)) { if (WLAN_IS_EPPING_IRQ(mode)) @@ -1888,28 +1877,86 @@ int hif_config_ce(struct hif_softc *scn) target_service_to_ce_map_sz = sizeof(target_service_to_ce_map_wlan_epping); } +} - ret = hif_wlan_enable(scn); - - if (ret) { - HIF_ERROR("%s: hif_wlan_enable error = %d", __func__, ret); - return QDF_STATUS_NOT_INITIALIZED; - } - - scn->notice_send = true; - - qdf_mem_zero(&soc_info, sizeof(soc_info)); - ret = icnss_get_soc_info(scn, &soc_info); - if (ret < 0) { - HIF_ERROR("%s: icnss_get_soc_info error = %d", __func__, ret); - return QDF_STATUS_NOT_INITIALIZED; - } - - scn->mem = soc_info.v_addr; - scn->mem_pa = soc_info.p_addr; - tgt_info->soc_version = soc_info.version; +/** + * hif_ce_open() - do ce specific allocations + * @hif_sc: pointer to hif context + * + * return: 0 for success or QDF_STATUS_E_NOMEM + */ +QDF_STATUS hif_ce_open(struct hif_softc *hif_sc) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); qdf_spinlock_create(&hif_state->keep_awake_lock); + return QDF_STATUS_SUCCESS; +} + +/** + * hif_ce_close() - do ce specific free + * @hif_sc: pointer to hif context + */ +void hif_ce_close(struct hif_softc *hif_sc) +{ +} + +/** + * hif_unconfig_ce() - ensure resources from hif_config_ce are freed + * @hif_sc: hif context + * + * uses state variables to support cleaning up when hif_config_ce fails. + */ +void hif_unconfig_ce(struct hif_softc *hif_sc) +{ + int pipe_num; + struct HIF_CE_pipe_info *pipe_info; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); + + for (pipe_num = 0; pipe_num < hif_sc->ce_count; pipe_num++) { + pipe_info = &hif_state->pipe_info[pipe_num]; + if (pipe_info->ce_hdl) { + ce_unregister_irq(hif_state, (1 << pipe_num)); + hif_sc->request_irq_done = false; + ce_fini(pipe_info->ce_hdl); + pipe_info->ce_hdl = NULL; + pipe_info->buf_sz = 0; + } + } + if (hif_state->sleep_timer_init) { + qdf_timer_stop(&hif_state->sleep_timer); + qdf_timer_free(&hif_state->sleep_timer); + hif_state->sleep_timer_init = false; + } + if (hif_sc->athdiag_procfs_inited) { + athdiag_procfs_remove(); + hif_sc->athdiag_procfs_inited = false; + } +} + +/** + * hif_config_ce() - configure copy engines + * @scn: hif context + * + * Prepares fw, copy engine hardware and host sw according + * to the attributes selected by hif_ce_prepare_config. + * + * also calls athdiag_procfs_init + * + * return: 0 for success nonzero for failure. + */ +int hif_config_ce(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + struct HIF_CE_pipe_info *pipe_info; + int pipe_num; +#ifdef ADRASTEA_SHADOW_REGISTERS + int i; +#endif + QDF_STATUS rv = QDF_STATUS_SUCCESS; + + scn->notice_send = true; hif_state->keep_awake_count = 0; @@ -1920,6 +1967,7 @@ int hif_config_ce(struct hif_softc *scn) QDF_TIMER_TYPE_WAKE_APPS); hif_state->sleep_timer_init = true; hif_state->fw_indicator_address = FW_INDICATOR_ADDRESS; + #ifdef HIF_PCI #if CONFIG_ATH_PCIE_MAX_PERF || CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD /* Force AWAKE forever/till the driver is loaded */ @@ -1932,7 +1980,6 @@ int hif_config_ce(struct hif_softc *scn) /* During CE initializtion */ scn->ce_count = HOST_CE_COUNT; - A_TARGET_ACCESS_LIKELY(scn); for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { struct CE_attr *attr; @@ -1975,32 +2022,9 @@ int hif_config_ce(struct hif_softc *scn) } scn->athdiag_procfs_inited = true; - /* - * Initially, establish CE completion handlers for use with BMI. - * These are overwritten with generic handlers after we exit BMI phase. - */ - pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_TARG]; -#ifdef HIF_PCI - ce_send_cb_register( - pipe_info->ce_hdl, hif_bmi_send_done, pipe_info, 0); -#ifndef BMI_RSP_POLLING - pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_HOST]; - ce_recv_cb_register( - pipe_info->ce_hdl, hif_bmi_recv_data, pipe_info, 0); -#endif -#endif HIF_INFO_MED("%s: ce_init done", __func__); - rv = hif_set_hia(scn); - - HIF_INFO_MED("%s: hif_set_hia done", __func__); - - A_TARGET_ACCESS_UNLIKELY(scn); - - if (rv != QDF_STATUS_SUCCESS) - goto err; - else - init_tasklet_workers(hif_hdl); + init_tasklet_workers(hif_hdl); HIF_TRACE("%s: X, ret = %d\n", __func__, rv); @@ -2013,38 +2037,15 @@ int hif_config_ce(struct hif_softc *scn) } #endif - return rv != QDF_STATUS_SUCCESS; err: /* Failure, so clean up */ - for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { - pipe_info = &hif_state->pipe_info[pipe_num]; - if (pipe_info->ce_hdl) { - ce_unregister_irq(hif_state, (1 << pipe_num)); - scn->request_irq_done = false; - ce_fini(pipe_info->ce_hdl); - pipe_info->ce_hdl = NULL; - pipe_info->buf_sz = 0; - } - } - if (hif_state->sleep_timer_init) { - qdf_timer_stop(&hif_state->sleep_timer); - qdf_timer_free(&hif_state->sleep_timer); - hif_state->sleep_timer_init = false; - } - - athdiag_procfs_remove(); - scn->athdiag_procfs_inited = false; + hif_unconfig_ce(scn); HIF_TRACE("%s: X, ret = %d\n", __func__, rv); return QDF_STATUS_SUCCESS != QDF_STATUS_E_FAILURE; } - - - - - #ifdef IPA_OFFLOAD /** * hif_ipa_get_ce_resource() - get uc resource on hif diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index db8b6ad36ac7..53c477855697 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -556,12 +556,13 @@ QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev, if (ADRASTEA_BU) hif_vote_link_up(hif_ctx); - if (hif_config_ce(scn)) { + if (hif_bus_configure(scn)) { HIF_ERROR("%s: Target probe failed.", __func__); hif_disable_bus(scn); status = QDF_STATUS_E_FAILURE; return status; } + /* * Flag to avoid potential unallocated memory access from MSI * interrupt handler which could get scheduled as soon as MSI @@ -570,15 +571,6 @@ QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev, * in interrupt handlers, is allocated. */ -#ifdef HIF_PCI - status = hif_configure_irq(scn); - if (status < 0) { - HIF_ERROR("%s: ERROR - configure_IRQ_and_CE failed, status = %d", - __func__, status); - return QDF_STATUS_E_FAILURE; - } -#endif - scn->hif_init_done = true; HIF_TRACE("%s: X OK", __func__); diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index be51e3533e4c..ed2245f835b7 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -153,7 +153,15 @@ void hif_dump_pipe_debug_count(struct hif_softc *scn); bool hif_target_forced_awake(struct hif_softc *scn); bool hif_max_num_receives_reached(struct hif_softc *scn, unsigned int count); +int hif_bus_configure(struct hif_softc *scn); int hif_config_ce(struct hif_softc *scn); +void hif_unconfig_ce(struct hif_softc *scn); +void hif_ce_prepare_config(struct hif_softc *scn); +int hif_set_hia(struct hif_softc *scn); +QDF_STATUS hif_ce_open(struct hif_softc *scn); +void hif_ce_close(struct hif_softc *scn); +int hif_wlan_enable(struct hif_softc *scn); +void hif_wlan_disable(struct hif_softc *scn); int athdiag_procfs_init(void *scn); void athdiag_procfs_remove(void); /* routine to modify the initial buffer count to be allocated on an os diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index 687bb1187076..84c413a4033c 100644 --- a/hif/src/pcie/if_pci.c +++ b/hif/src/pcie/if_pci.c @@ -41,6 +41,7 @@ #include "ce_internal.h" #include "ce_reg.h" #include "bmi_msg.h" /* TARGET_TYPE_ */ +#include "ce_bmi.h" #include "regtable.h" #include "ol_fw.h" #include @@ -1202,7 +1203,92 @@ QDF_STATUS hif_bus_open(struct hif_softc *ol_sc, enum qdf_bus_type bus_type) qdf_spinlock_create(&sc->irq_lock); - return QDF_STATUS_SUCCESS; + return hif_ce_open(ol_sc); +} + +#ifdef BMI_RSP_POLLING +#define BMI_RSP_CB_REGISTER 0 +#else +#define BMI_RSP_CB_REGISTER 1 +#endif + +/** + * hif_register_bmi_callbacks() - register bmi callbacks + * @hif_sc: hif context + * + * Bmi phase uses different copy complete callbacks than mission mode. + */ +static void hif_register_bmi_callbacks(struct hif_softc *hif_sc) +{ + struct HIF_CE_pipe_info *pipe_info; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); + + /* + * Initially, establish CE completion handlers for use with BMI. + * These are overwritten with generic handlers after we exit BMI phase. + */ + pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_TARG]; + ce_send_cb_register(pipe_info->ce_hdl, hif_bmi_send_done, pipe_info, 0); + + if (BMI_RSP_CB_REGISTER) { + pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_HOST]; + ce_recv_cb_register( + pipe_info->ce_hdl, hif_bmi_recv_data, pipe_info, 0); + } +} + +/** + * hif_bus_configure() - configure the pcie bus + * @hif_sc: pointer to the hif context. + * + * return: 0 for success. nonzero for failure. + */ +int hif_bus_configure(struct hif_softc *hif_sc) +{ + int status = 0; + + hif_ce_prepare_config(hif_sc); + + if (ADRASTEA_BU) { + status = hif_wlan_enable(hif_sc); + + if (status) { + HIF_ERROR("%s: hif_wlan_enable error = %d", + __func__, status); + return status; + } + } + + A_TARGET_ACCESS_LIKELY(hif_sc); + status = hif_config_ce(hif_sc); + if (status) + goto disable_wlan; + + status = hif_set_hia(hif_sc); + if (status) + goto unconfig_ce; + + HIF_INFO_MED("%s: hif_set_hia done", __func__); + + hif_register_bmi_callbacks(hif_sc); + + status = hif_configure_irq(hif_sc); + if (status < 0) + goto unconfig_ce; + + A_TARGET_ACCESS_UNLIKELY(hif_sc); + + return status; + +unconfig_ce: + hif_unconfig_ce(hif_sc); +disable_wlan: + A_TARGET_ACCESS_UNLIKELY(hif_sc); + if (ADRASTEA_BU) + hif_wlan_disable(hif_sc); + + HIF_ERROR("%s: failed, status = %d", __func__, status); + return status; } /** @@ -1210,11 +1296,13 @@ QDF_STATUS hif_bus_open(struct hif_softc *ol_sc, enum qdf_bus_type bus_type) * * Return: n/a */ -void hif_bus_close(struct hif_softc *ol_sc) +void hif_bus_close(struct hif_softc *hif_sc) { - struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc); + struct hif_pci_softc *hif_pci_sc = HIF_GET_PCI_SOFTC(hif_sc); - hif_pm_runtime_close(sc); + hif_pm_runtime_close(hif_pci_sc); + + hif_ce_close(hif_sc); } #define BAR_NUM 0 @@ -1952,7 +2040,7 @@ static void hif_runtime_pm_set_state_suspended(struct hif_softc *scn) static inline struct hif_pci_softc *get_sc(void *hif_ctx) { - struct hif_pci_softc *scn = HIF_GET_PCI_SOFTC(hif_ctx) + struct hif_pci_softc *scn = HIF_GET_PCI_SOFTC(hif_ctx); if (NULL == scn) { HIF_ERROR("%s: Could not disable ASPM scn is null", diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c index fdb4463d2f70..88c94d20cd71 100644 --- a/hif/src/snoc/if_snoc.c +++ b/hif/src/snoc/if_snoc.c @@ -93,7 +93,7 @@ void hif_reset_soc(struct hif_opaque_softc *hif_ctx) */ void hif_disable_isr(struct hif_opaque_softc *hif_ctx) { - struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx) + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); hif_nointrs(scn); ce_tasklet_kill(scn); @@ -124,7 +124,7 @@ static void hif_dump_snoc_registers(struct hif_softc *scn) int hif_dump_registers(struct hif_opaque_softc *hif_ctx) { int status; - struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx) + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); status = hif_dump_ce_registers(scn); if (status) @@ -186,6 +186,7 @@ void hif_disable_aspm(struct hif_opaque_softc *hif_ctx) */ void hif_bus_close(struct hif_softc *scn) { + hif_ce_close(scn); } /** @@ -206,9 +207,64 @@ int hif_bus_get_context_size(void) */ QDF_STATUS hif_bus_open(struct hif_softc *scn, enum qdf_bus_type bus_type) { + return hif_ce_open(scn); +} + +/** + * hif_snoc_get_soc_info() - populates scn with hw info + * + * fills in the virtual and physical base address as well as + * soc version info. + * + * return 0 or QDF_STATUS_E_FAILURE + */ +static QDF_STATUS hif_snoc_get_soc_info(struct hif_softc *scn) +{ + int ret; + struct icnss_soc_info soc_info; + + cdf_mem_zero(&soc_info, sizeof(soc_info)); + + ret = icnss_get_soc_info(&soc_info); + if (ret < 0) { + HIF_ERROR("%s: icnss_get_soc_info error = %d", __func__, ret); + return QDF_STATUS_E_FAILURE; + } + + scn->mem = soc_info.v_addr; + scn->mem_pa = soc_info.p_addr; return QDF_STATUS_SUCCESS; } +/** + * hif_bus_configure() - configure the snoc bus + * @scn: pointer to the hif context. + * + * return: 0 for success. nonzero for failure. + */ +int hif_bus_configure(struct hif_softc *scn) +{ + int ret; + + ret = hif_snoc_get_soc_info(scn); + if (ret) + return ret; + + hif_ce_prepare_config(scn); + + ret = hif_wlan_enable(scn); + if (ret) { + HIF_ERROR("%s: hif_wlan_enable error = %d", + __func__, ret); + return ret; + } + + ret = hif_config_ce(scn); + if (ret) + hif_wlan_disable(scn); + return ret; +} + /** * hif_get_target_type(): Get the target type *