From 7bdca0463d99a7fdc7c38f340a03ef5a53685dc5 Mon Sep 17 00:00:00 2001 From: Pavan Kumar M Date: Mon, 16 Sep 2024 12:43:04 +0530 Subject: [PATCH 1/2] msm: ipa3: supporting hibernate & cleanup unused deepsleep API's Adding changes to listen for new PM driver events to support hibernate feature. Also, in 5.15 kernel, deepsleep & hibernate entry/exit SSR API's are becoming same as regular SSR usecases. So, cleaning up the unused deepsleep API's accordingly. Change-Id: Ie8d901f824b586bbb7a5e61a1cdc877cd14eb1d0 Signed-off-by: Pavan Kumar M Signed-off-by: Jagadeesh Ponduru --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 69 +++++++++++++++++++++---- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 09f5b1cc2fa5..bce110d193f3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/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 @@ -457,17 +457,25 @@ EXPORT_SYMBOL(ipa_smmu_free_sgt); static int ipa_pm_notify(struct notifier_block *b, unsigned long event, void *p) { IPAERR("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 IPAERR("Exit\n"); return NOTIFY_DONE; } @@ -479,7 +487,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 = { @@ -6748,7 +6760,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 @@ -6868,10 +6880,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) @@ -6889,7 +6900,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); @@ -9634,7 +9645,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(); @@ -9648,6 +9659,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 @@ -9674,7 +9725,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"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index ceb439f729b2..39d5f6be8af8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -3114,6 +3114,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); From 2e77a46f0d0575db2ca0065b9dfdad21c387fb78 Mon Sep 17 00:00:00 2001 From: Pavan Kumar M Date: Wed, 11 Sep 2024 16:58:15 +0530 Subject: [PATCH 2/2] msm: ipa: Check GSI status during deepsleep resume Abort could be triggered during deepsleep suspend and HW won't be reset. Check GSI status during deepsleep resume to avoid loading GSI FW and uC again. Change-Id: I360680963e9e65db50a43e17d12ebf75893efaab Signed-off-by: Pavan Kumar M --- drivers/platform/msm/gsi/gsi.c | 26 ++++++++- drivers/platform/msm/gsi/gsi.h | 9 +++ drivers/platform/msm/ipa/ipa_v3/ipa.c | 76 +++++++++++++++---------- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + 4 files changed, 81 insertions(+), 31 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 2ae33a7bbb2a..c745d4ba7176 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/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/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index 284965c48010..5e35443bbd98 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/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/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 09f5b1cc2fa5..e3ca264164ba 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -6666,7 +6666,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"); @@ -6900,38 +6900,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) { @@ -9684,7 +9700,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/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index ceb439f729b2..8eec978bfd39 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/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);