diff --git a/techpack/dataipa/drivers/platform/msm/gsi/gsi.c b/techpack/dataipa/drivers/platform/msm/gsi/gsi.c index 2ae33a7bbb2a..c745d4ba7176 100644 --- a/techpack/dataipa/drivers/platform/msm/gsi/gsi.c +++ b/techpack/dataipa/drivers/platform/msm/gsi/gsi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1136,6 +1137,8 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl) return -GSI_STATUS_UNSUPPORTED_OP; } + gsi_unmap_base(); + switch (props->ver) { case GSI_VER_1_0: case GSI_VER_1_2: @@ -1481,7 +1484,6 @@ int gsi_deregister_device(unsigned long dev_hdl, bool force) __gsi_config_gen_irq(gsi_ctx->per.ee, ~0, 0); devm_free_irq(gsi_ctx->dev, gsi_ctx->per.irq, gsi_ctx); - gsi_unmap_base(); gsi_ctx->per_registered = false; return GSI_STATUS_SUCCESS; } @@ -2813,6 +2815,28 @@ int gsi_write_wdi3_channel_scratch_6_7_reg(unsigned long chan_hdl, } EXPORT_SYMBOL(gsi_write_wdi3_channel_scratch_6_7_reg); +/** + * gsi_status_enabled() - Query GSI Status + * + * Returns: true if ENABLED, false on DISABLED + * + */ +bool gsi_status_enabled(void) +{ + uint32_t val; + bool ret = false; + + if (!gsi_ctx->base) + return ret; + + val = gsi_readl(gsi_ctx->base + + GSI_EE_n_GSI_STATUS_OFFS(gsi_ctx->per.ee)); + if (val & GSI_EE_n_GSI_STATUS_ENABLED_BMSK) + ret = true; + return ret; +} +EXPORT_SYMBOL(gsi_status_enabled); + static void __gsi_read_channel_scratch(unsigned long chan_hdl, union __packed gsi_channel_scratch * val) { diff --git a/techpack/dataipa/drivers/platform/msm/gsi/gsi.h b/techpack/dataipa/drivers/platform/msm/gsi/gsi.h index 284965c48010..5e35443bbd98 100644 --- a/techpack/dataipa/drivers/platform/msm/gsi/gsi.h +++ b/techpack/dataipa/drivers/platform/msm/gsi/gsi.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef GSI_H @@ -1610,6 +1611,14 @@ int gsi_poll_channel(unsigned long chan_hdl, */ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode); +/** + * gsi_status_enabled() - Query GSI Status + * + * Returns: true if ENABLED, false on DISABLED + * + */ +bool gsi_status_enabled(void); + /** * gsi_queue_xfer - Peripheral should call this function * to queue transfers on the given channel diff --git a/techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa.c b/techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa.c index da5609832661..16f2ae6508b0 100644 --- a/techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -126,7 +126,7 @@ static void ipa_gsi_notify_cb(struct gsi_per_notify *notify); static int ipa3_attach_to_smmu(void); static int ipa3_alloc_pkt_init(void); -#ifdef CONFIG_DEEPSLEEP +#if IS_ENABLED(CONFIG_DEEPSLEEP) || IS_ENABLED(CONFIG_HIBERNATION) static void ipa3_deepsleep_resume(void); static void ipa3_deepsleep_suspend(void); #endif @@ -469,17 +469,25 @@ EXPORT_SYMBOL(ipa_smmu_free_sgt); static int ipa_pm_notify(struct notifier_block *b, unsigned long event, void *p) { IPADBG("Entry\n"); +#if IS_ENABLED(CONFIG_DEEPSLEEP) || IS_ENABLED(CONFIG_HIBERNATION) switch (event) { case PM_POST_SUSPEND: -#ifdef CONFIG_DEEPSLEEP if (mem_sleep_current == PM_SUSPEND_MEM && ipa3_ctx->deepsleep) { IPADBG("Enter deepsleep resume\n"); ipa3_deepsleep_resume(); IPADBG("Exit deepsleep resume\n"); } -#endif + break; + case PM_POST_HIBERNATION: + /*Using the same deepsleep flag to check if freeze happened or not.*/ + if (ipa3_ctx->deepsleep) { + IPADBG("Enter hibernate restore\n"); + ipa3_deepsleep_resume(); + IPADBG("Exit hibernate restore\n"); + } break; } +#endif IPADBG("Exit\n"); return NOTIFY_DONE; } @@ -491,7 +499,11 @@ static struct notifier_block ipa_pm_notifier = { static const struct dev_pm_ops ipa_pm_ops = { .suspend_late = ipa3_ap_suspend, +#if IS_ENABLED(CONFIG_HIBERNATION) + .freeze_late = ipa3_ap_freeze, +#endif .resume_early = ipa3_ap_resume, + .restore_early = ipa3_ap_resume, }; static struct platform_driver ipa_plat_drv = { @@ -6678,7 +6690,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, /* GSI 2.2 requires to allocate all EE GSI channel * during device bootup. */ - if (gsi_props.ver == GSI_VER_2_2) { + if (gsi_props.ver == GSI_VER_2_2 && !ipa3_ctx->gsi_status) { result = ipa3_alloc_gsi_channel(); if (result) { IPAERR("Failed to alloc the GSI channels\n"); @@ -6760,7 +6772,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, ipa3_register_to_fmwk(); } -#ifdef CONFIG_DEEPSLEEP +#if IS_ENABLED(CONFIG_DEEPSLEEP) || IS_ENABLED(CONFIG_HIBERNATION) if (!ipa3_is_ready()) ipa_fmwk_deepsleep_exit_ipa(); #endif @@ -6880,10 +6892,9 @@ static int ipa3_pil_load_ipa_fws(const char *sub_sys) return 0; } -#ifdef CONFIG_DEEPSLEEP +#if IS_ENABLED(CONFIG_DEEPSLEEP) || IS_ENABLED(CONFIG_HIBERNATION) static int ipa3_pil_unload_ipa_fws(void) { - IPADBG("PIL FW unloading process initiated sub_sys\n"); if (ipa3_ctx->subsystem_get_retval) @@ -6901,7 +6912,7 @@ static void ipa3_load_ipa_fw(struct work_struct *work) IPADBG("Entry\n"); IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - + result = ipa3_attach_to_smmu(); if (result) { IPAERR("IPA attach to smmu failed %d\n", result); @@ -6912,38 +6923,54 @@ static void ipa3_load_ipa_fw(struct work_struct *work) return; } - if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_EMULATION && - ((ipa3_ctx->platform_type != IPA_PLAT_TYPE_MDM) || - (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))) { - /* some targets sharing same lunch option but - * using different signing images, adding support to - * load specific FW image to based on dt entry. - */ - if (ipa3_ctx->gsi_fw_file_name) - result = ipa3_pil_load_ipa_fws( - ipa3_ctx->gsi_fw_file_name); - else - result = ipa3_pil_load_ipa_fws(IPA_SUBSYSTEM_NAME); + ipa3_ctx->gsi_status = gsi_status_enabled(); + + if(!ipa3_ctx->gsi_status) { + if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_EMULATION && + ((ipa3_ctx->platform_type != IPA_PLAT_TYPE_MDM) || + (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))) { + /* some targets sharing same lunch option but + * using different signing images, adding support to + * load specific FW image to based on dt entry. + */ +#if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) + if (ipa3_ctx->gsi_fw_file_name) + result = ipa3_mdt_load_ipa_fws( + ipa3_ctx->gsi_fw_file_name); + else + result = ipa3_mdt_load_ipa_fws(IPA_SUBSYSTEM_NAME); +#else /* IS_ENABLED(CONFIG_QCOM_MDT_LOADER) */ + if (ipa3_ctx->gsi_fw_file_name) + result = ipa3_pil_load_ipa_fws( + ipa3_ctx->gsi_fw_file_name); + else + result = ipa3_pil_load_ipa_fws(IPA_SUBSYSTEM_NAME); +#endif /* IS_ENABLED(CONFIG_QCOM_MDT_LOADER) */ + } else { + result = ipa3_manual_load_ipa_fws(); + } + + + if (result) { + ipa3_ctx->ipa_pil_load++; + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + IPADBG("IPA firmware loading deffered to a work queue\n"); + queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq, + &ipa3_fw_load_failure_handle, + msecs_to_jiffies(DELAY_BEFORE_FW_LOAD)); + return; + } + mutex_lock(&ipa3_ctx->fw_load_data.lock); + ipa3_ctx->fw_load_data.state = IPA_FW_LOAD_STATE_LOADED; + mutex_unlock(&ipa3_ctx->fw_load_data.lock); + pr_info("IPA FW loaded successfully\n"); } else { - result = ipa3_manual_load_ipa_fws(); + pr_info("IPA FW is already loaded\n"); + /*uC is already loaded. Marking this as after SSR boot to avoid loading uc again*/ + ipa3_ctx->uc_ctx.uc_loaded = true; } - - if (result) { - - ipa3_ctx->ipa_pil_load++; - IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); - IPADBG("IPA firmware loading deffered to a work queue\n"); - queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq, - &ipa3_fw_load_failure_handle, - msecs_to_jiffies(DELAY_BEFORE_FW_LOAD)); - return; - } IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); - mutex_lock(&ipa3_ctx->fw_load_data.lock); - ipa3_ctx->fw_load_data.state = IPA_FW_LOAD_STATE_LOADED; - mutex_unlock(&ipa3_ctx->fw_load_data.lock); - pr_info("IPA FW loaded successfully\n"); result = ipa3_post_init(&ipa3_res, ipa3_ctx->cdev.dev); if (result) { @@ -9646,7 +9673,7 @@ int ipa3_ap_suspend(struct device *dev) } } -#ifdef CONFIG_DEEPSLEEP +#if IS_ENABLED(CONFIG_DEEPSLEEP) if (mem_sleep_current == PM_SUSPEND_MEM) { IPADBG("Enter deepsleep suspend\n"); ipa3_deepsleep_suspend(); @@ -9660,6 +9687,46 @@ int ipa3_ap_suspend(struct device *dev) return 0; } +#if IS_ENABLED(CONFIG_HIBERNATION) +/** + * ipa3_ap_freeze() - hibernate freeze callback for runtime_pm + * @dev: pointer to device + * + * This callback will be invoked by the runtime_pm framework when an AP + * hibernate freeze operation is invoked, usually by pressing a hibernate button. + * + * Returns -EAGAIN to runtime_pm framework in case IPA is in use by AP. + * This will postpone the suspend/freeze operation until IPA is no longer used by AP. + */ +int ipa3_ap_freeze(struct device *dev) +{ + int i; + + IPADBG("Enter\n"); + + if (!of_device_is_compatible(dev->of_node,"qcom,ipa")) + return 0; + /* In case there is a tx/rx handler in polling mode fail to suspend */ + for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) { + if (ipa3_ctx->ep[i].sys && + atomic_read(&ipa3_ctx->ep[i].sys->curr_polling_state)) { + IPAERR("EP %d is in polling state, do not suspend\n", + i); + return -EAGAIN; + } + } + + IPADBG("Enter hibernate freeze\n"); + ipa3_deepsleep_suspend(); + IPADBG("Exit hibernate freeze\n"); + + ipa_pm_deactivate_all_deferred(); + + IPADBG("Exit\n"); + return 0; +} +#endif + /** * ipa3_ap_resume() - resume callback for runtime_pm * @dev: pointer to device @@ -9686,7 +9753,7 @@ bool ipa3_get_lan_rx_napi(void) } -#ifdef CONFIG_DEEPSLEEP +#if IS_ENABLED(CONFIG_DEEPSLEEP) || IS_ENABLED(CONFIG_HIBERNATION) static void ipa3_deepsleep_suspend(void) { IPADBG("Entry\n"); @@ -9696,7 +9763,7 @@ static void ipa3_deepsleep_suspend(void) ipa3_ctx->deepsleep = true; /*Disabling the LAN NAPI*/ ipa3_disable_napi_lan_rx(); - /*NOt allow uC related operations until uC load again*/ + /*Not allow uC related operations until uC load again*/ ipa3_ctx->uc_ctx.uc_loaded = false; /*Disconnecting LAN PROD/LAN CONS/CMD PROD apps pipes*/ ipa3_teardown_apps_pipes(); diff --git a/techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index ceb439f729b2..0d34cdf34eae 100644 --- a/techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2163,6 +2163,7 @@ struct ipa3_context { struct ipa3_mhip_ctx mhip_ctx; struct ipa3_aqc_ctx aqc_ctx; atomic_t ipa_clk_vote; + bool gsi_status; int (*client_lock_unlock[IPA_MAX_CLNT])(bool is_lock); @@ -3114,6 +3115,7 @@ struct iommu_domain *ipa3_get_smmu_domain_by_type int ipa3_iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot); int ipa3_ap_suspend(struct device *dev); +int ipa3_ap_freeze(struct device *dev); int ipa3_ap_resume(struct device *dev); int ipa3_init_interrupts(void); struct iommu_domain *ipa3_get_smmu_domain(void);