From 2a2981c64345b48f00b3160d8bd99a6aae03bae4 Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Thu, 23 Dec 2021 00:06:59 +0530 Subject: [PATCH] msm: ipa3: Deepsleep enable changes Adding support to deepsleep scenario. Change-Id: I2b388396cf9a7f26f77bbcd49c1014e16475a980 --- drivers/platform/msm/gsi/gsi.c | 3 +- drivers/platform/msm/ipa/ipa_v3/ipa.c | 134 +++++++++++++++++- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 7 + drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 4 +- drivers/platform/msm/ipa/ipa_v3/ipa_rt.c | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa_uc.c | 11 ++ drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 18 +++ drivers/platform/msm/ipa/ipa_v3/teth_bridge.c | 5 + 8 files changed, 176 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index b70eed7d647c..7d75084783e0 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1482,8 +1482,7 @@ int gsi_deregister_device(unsigned long dev_hdl, bool force) devm_free_irq(gsi_ctx->dev, gsi_ctx->per.irq, gsi_ctx); gsi_unmap_base(); - memset(gsi_ctx, 0, sizeof(*gsi_ctx)); - + gsi_ctx->per_registered = false; return GSI_STATUS_SUCCESS; } EXPORT_SYMBOL(gsi_deregister_device); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 514ad94e3e5d..c075241f093a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -41,6 +41,7 @@ #include #include #include +#include #ifdef CONFIG_ARM64 @@ -124,6 +125,11 @@ 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 +static void ipa3_deepsleep_resume(void); +static void ipa3_deepsleep_suspend(void); +#endif + static void ipa3_load_ipa_fw(struct work_struct *work); static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw); static DECLARE_DELAYED_WORK(ipa3_fw_load_failure_handle, ipa3_load_ipa_fw); @@ -438,6 +444,38 @@ int ipa_smmu_free_sgt(struct sg_table **out_sgt_ptr) } EXPORT_SYMBOL(ipa_smmu_free_sgt); +/** + * ipa_pm_notify() - PM notify to listen suspend events + * + * This callback will be invoked by the pm framework to suspend + * operation is invoked. + * + * Returns NOTIFY_DONE to pm framework completed operation. + */ + +static int ipa_pm_notify(struct notifier_block *b, unsigned long event, void *p) +{ + IPAERR("Entry\n"); + switch (event) { + case PM_POST_SUSPEND: +#ifdef CONFIG_DEEPSLEEP + if (mem_sleep_current == PM_SUSPEND_MEM) { + IPADBG("Enter deepsleep resume\n"); + ipa3_deepsleep_resume(); + IPADBG("Exit deepsleep resume\n"); + } +#endif + break; + } + IPAERR("Exit\n"); + return NOTIFY_DONE; +} + + +static struct notifier_block ipa_pm_notifier = { + .notifier_call = ipa_pm_notify, +}; + static const struct dev_pm_ops ipa_pm_ops = { .suspend_late = ipa3_ap_suspend, .resume_early = ipa3_ap_resume, @@ -5063,6 +5101,7 @@ static void ipa3_teardown_apps_pipes(void) __ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl); __ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false); ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd); + ipa3_dealloc_common_event_ring(); } #ifdef CONFIG_COMPAT @@ -6317,6 +6356,12 @@ static inline void ipa3_enable_napi_lan_rx(void) napi_enable(&ipa3_ctx->napi_lan_rx); } +static inline void ipa3_disable_napi_lan_rx(void) +{ + if (ipa3_ctx->lan_rx_napi_enable) + napi_disable(&ipa3_ctx->napi_lan_rx); +} + static inline void ipa3_register_to_fmwk(void) { struct ipa_core_data data; @@ -6691,6 +6736,11 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, IPADBG("register to fmwk\n"); ipa3_register_to_fmwk(); } + +#ifdef CONFIG_DEEPSLEEP + if (!ipa3_is_ready()) + ipa_fmwk_deepsleep_exit_ipa(); +#endif complete_all(&ipa3_ctx->init_completion_obj); ipa_ut_module_init(); @@ -6793,13 +6843,12 @@ static int ipa3_manual_load_ipa_fws(void) static int ipa3_pil_load_ipa_fws(const char *sub_sys) { - void *subsystem_get_retval = NULL; IPADBG("PIL FW loading process initiated sub_sys=%s\n", sub_sys); - subsystem_get_retval = subsystem_get(sub_sys); - if (IS_ERR_OR_NULL(subsystem_get_retval)) { + ipa3_ctx->subsystem_get_retval = subsystem_get(sub_sys); + if (IS_ERR_OR_NULL(ipa3_ctx->subsystem_get_retval)) { IPAERR("Unable to PIL load FW for sub_sys=%s\n", sub_sys); return -EINVAL; } @@ -6808,6 +6857,20 @@ static int ipa3_pil_load_ipa_fws(const char *sub_sys) return 0; } +#ifdef CONFIG_DEEPSLEEP +static int ipa3_pil_unload_ipa_fws(void) +{ + + IPADBG("PIL FW unloading process initiated sub_sys\n"); + + if (ipa3_ctx->subsystem_get_retval) + subsystem_put(ipa3_ctx->subsystem_get_retval); + + IPADBG("PIL FW unloading process is complete sub_sys\n"); + return 0; +} +#endif + static void ipa3_load_ipa_fw(struct work_struct *work) { int result; @@ -9513,7 +9576,8 @@ int ipa3_ap_suspend(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 && @@ -9524,6 +9588,13 @@ int ipa3_ap_suspend(struct device *dev) } } +#ifdef CONFIG_DEEPSLEEP + if (mem_sleep_current == PM_SUSPEND_MEM) { + IPADBG("Enter deepsleep suspend\n"); + ipa3_deepsleep_suspend(); + IPADBG("Exit deepsleep suspend\n"); + } +#endif ipa_pm_deactivate_all_deferred(); IPADBG("Exit\n"); @@ -9556,6 +9627,58 @@ bool ipa3_get_lan_rx_napi(void) return ipa3_ctx->lan_rx_napi_enable; } + +#ifdef CONFIG_DEEPSLEEP +static void ipa3_deepsleep_suspend(void) +{ + IPADBG("Entry\n"); + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + /* To allow default routing table delection using this flag */ + ipa3_ctx->deepsleep = true; + /*Disabling the LAN NAPI*/ + ipa3_disable_napi_lan_rx(); + /*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(); + /*Deregistering the GSI driver*/ + gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false); + /*Destroying filter table ids*/ + ipa3_destroy_flt_tbl_idrs(); + /*Disabling IPA interrupt*/ + ipa3_remove_interrupt_handler(IPA_TX_SUSPEND_IRQ); + ipa3_interrupts_destroy(ipa3_res.ipa_irq, &ipa3_ctx->master_pdev->dev); + /*Destroy the NAT device*/ + ipa3_nat_ipv6ct_destroy_devices(); + /*Freeing memory allocated for coalesing and dma task*/ + ipa3_free_coal_close_frame(); + ipa3_free_dma_task_for_gsi(); + /*Destroying ipa hal module*/ + ipahal_destroy(); + ipa3_ctx->ipa_initialization_complete = false; + ipa3_debugfs_remove(); + /*Unloading IPA FW to allow FW load in resume*/ + ipa3_pil_unload_ipa_fws(); + /*Calling framework API to reset IPA ready flag to false*/ + ipa_fmwk_deepsleep_entry_ipa(); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + IPADBG("Exit\n"); +} + +static void ipa3_deepsleep_resume(void) +{ + + IPADBG("Entry\n"); + /*After deeplseep exit we shouldn't allow delete the default routing table*/ + ipa3_ctx->deepsleep = false; + /*Scheduling WQ to load IPA FW*/ + queue_work(ipa3_ctx->transport_power_mgmt_wq, + &ipa3_fw_loading_work); + IPADBG("Exit\n"); +} +#endif + static void ipa_gsi_notify_cb(struct gsi_per_notify *notify) { /* @@ -9985,6 +10108,8 @@ static int __init ipa_module_init(void) /* Register as a PCI device driver */ return pci_register_driver(&ipa_pci_driver); } + + register_pm_notifier(&ipa_pm_notifier); /* Register as a platform device driver */ return platform_driver_register(&ipa_plat_drv); } @@ -9995,6 +10120,7 @@ static void __exit ipa_module_exit(void) if (running_emulation) pci_unregister_driver(&ipa_pci_driver); platform_driver_unregister(&ipa_plat_drv); + unregister_pm_notifier(&ipa_pm_notifier); kfree(ipa3_ctx); ipa3_ctx = NULL; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 83e65d8799e0..b4a4c22b8abb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -4741,6 +4741,13 @@ static void ipa_dma_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify) } } +void ipa3_dealloc_common_event_ring(void) +{ + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + gsi_dealloc_evt_ring(ipa3_ctx->gsi_evt_comm_hdl); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); +} + int ipa3_alloc_common_event_ring(void) { struct gsi_evt_ring_props gsi_evt_ring_props; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index ed025daa26ba..71d0822f25ea 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2125,6 +2125,8 @@ struct ipa3_context { bool (*get_teth_port_state[IPA_MAX_CLNT])(void); atomic_t is_ssr; + bool deepsleep; + void *subsystem_get_retval; struct IpaHwOffloadStatsAllocCmdData_t gsi_info[IPA_HW_PROTOCOL_MAX]; bool ipa_wan_skb_page; @@ -2506,7 +2508,6 @@ int ipa3_start_stop_client_prod_gsi_chnl(enum ipa_client_type client, bool start_chnl); void ipa3_client_prod_post_shutdown_cleanup(void); - int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, u32 tmr_val, enum ipa_client_type client); @@ -3124,6 +3125,7 @@ int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats); struct dentry *ipa_debugfs_get_root(void); void ipa3_enable_dcd(void); void ipa3_disable_prefetch(enum ipa_client_type client); +void ipa3_dealloc_common_event_ring(void); int ipa3_alloc_common_event_ring(void); int ipa3_allocate_dma_task_for_gsi(void); void ipa3_free_dma_task_for_gsi(void); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index 81a4573b68f2..8c21090ffdab 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -1753,7 +1753,7 @@ int __ipa3_del_rt_rule(u32 rule_hdl) !strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) { IPADBG("Deleting rule from default rt table idx=%u\n", entry->tbl->idx); - if (entry->tbl->rule_cnt == 1) { + if (entry->tbl->rule_cnt == 1 && !ipa3_ctx->deepsleep) { IPAERR_RL("Default tbl last rule cannot be deleted\n"); return -EINVAL; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c index 4200d188284c..96a73878b3ba 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c @@ -1113,6 +1113,17 @@ remap_fail: return result; } +void ipa3_uc_interface_destroy(void) +{ + if(ipa3_ctx->uc_ctx.uc_inited) { + ipa3_remove_interrupt_handler(IPA_UC_IRQ_2); + ipa3_remove_interrupt_handler(IPA_UC_IRQ_1); + ipa3_remove_interrupt_handler(IPA_UC_IRQ_0); + iounmap(ipa3_ctx->uc_ctx.uc_sram_mmio); + ipa3_ctx->uc_ctx.uc_inited = false; + } +} + /** * ipa3_uc_send_cmd() - Send a command to the uC * diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index d14a04e22540..96623321bbe5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -2991,6 +2991,13 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this, break; #if IS_ENABLED(CONFIG_DEEPSLEEP) case SUBSYS_AFTER_DS_ENTRY: + IPAWANINFO("IPA Received AFTER DEEPSLEEP ENTRY\n"); + if (atomic_read(&rmnet_ipa3_ctx->is_ssr) && + ipa3_ctx_get_type(IPA_HW_TYPE) < IPA_HW_v4_0) + ipa3_q6_post_shutdown_cleanup(); + + IPAWANINFO("AFTER DEEPSLEEP ENTRY handling is complete\n"); + break; #endif case SUBSYS_AFTER_SHUTDOWN: IPAWANINFO("IPA Received MPSS AFTER_SHUTDOWN\n"); @@ -3005,6 +3012,17 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this, break; #if IS_ENABLED(CONFIG_DEEPSLEEP) case SUBSYS_BEFORE_DS_EXIT: + IPAWANINFO("IPA received BEFORE DEEPSLEEP EXIT\n"); + if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) { + /* clean up cached QMI msg/handlers */ + ipa3_qmi_service_exit(); + ipa3_q6_pre_powerup_cleanup(); + } + /* hold a proxy vote for the modem. */ + ipa3_proxy_clk_vote(atomic_read(&rmnet_ipa3_ctx->is_ssr)); + ipa3_reset_freeze_vote(); + IPAWANINFO("BEFORE DEEPSLEEP EXIT handling is complete\n"); + break; #endif case SUBSYS_BEFORE_POWERUP: IPAWANINFO("IPA received MPSS BEFORE_POWERUP\n"); diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c index 24f24c908667..965609bb4c56 100644 --- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c +++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c @@ -215,6 +215,11 @@ int ipa3_teth_bridge_driver_init(void) { int res; + if(ipa3_teth_ctx) { + TETH_DBG("Tethering bridge already initlized\n"); + return 0; + } + TETH_DBG("Tethering bridge driver init\n"); ipa3_teth_ctx = kzalloc(sizeof(*ipa3_teth_ctx), GFP_KERNEL); if (!ipa3_teth_ctx)