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/dump/ipa_reg_dump.c b/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.c index a81bfb204cc0..78aab2747854 100644 --- a/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.c +++ b/drivers/platform/msm/ipa/ipa_v3/dump/ipa_reg_dump.c @@ -735,7 +735,9 @@ static struct map_src_dst_addr_s ipa_uc_regs_to_save_array[] = { }; static void ipa_hal_save_regs_save_ipa_testbus(void); +#ifndef CONFIG_IPA3_APPS_REGDUMP static void ipa_reg_save_gsi_fifo_status(void); +#endif /* CONFIG_IPA3_APPS_REGDUMP */ static void ipa_reg_save_rsrc_cnts(void); static void ipa_hal_save_regs_ipa_cmdq(void); static void ipa_hal_save_regs_rsrc_db(void); @@ -865,9 +867,10 @@ void ipa_save_registers(void) num_regs += (CONFIG_IPA3_REGDUMP_NUM_EXTRA_ENDP_REGS * IPA_REG_SAVE_NUM_EXTRA_ENDP_REGS); +#ifndef CONFIG_IPA3_APPS_REGDUMP /* Saving GSI FIFO Status registers */ ipa_reg_save_gsi_fifo_status(); - +#endif /* CONFIG_IPA3_APPS_REGDUMP */ /* * On targets that support SSR, we generally want to disable * the following reg save functionality as it may cause stalls @@ -896,6 +899,7 @@ void ipa_save_registers(void) } /* GSI test bus */ +#ifndef CONFIG_IPA3_APPS_REGDUMP for (i = 0; i < ARRAY_SIZE(ipa_reg_save_gsi_ch_test_bus_selector_array); i++) { @@ -911,6 +915,7 @@ void ipa_save_registers(void) i].gsi_testbus_reg = (u32) IPA_READ_SCALER_REG(GSI_TEST_BUS_REG); } +#endif /* CONFIG_IPA3_APPS_REGDUMP */ ipa_reg_save_rsrc_cnts(); @@ -1067,6 +1072,7 @@ void ipa_save_registers(void) * * @return */ +#ifndef CONFIG_IPA3_APPS_REGDUMP static void ipa_reg_save_gsi_fifo_status(void) { union ipa_hwio_def_ipa_gsi_fifo_status_ctrl_u gsi_fifo_status_ctrl; @@ -1089,7 +1095,7 @@ static void ipa_reg_save_gsi_fifo_status(void) IPA_READ_SCALER_REG(IPA_GSI_AOS_FIFO_STATUS); } } - +#endif /* CONFIG_IPA3_APPS_REGDUMP */ /* * FUNCTION: ipa_reg_save_rsrc_cnts * diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 514ad94e3e5d..cdd6e54f4249 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; @@ -9475,7 +9538,17 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p) return -EOPNOTSUPP; } } + /* Below update of pre init for non smmu device, As + * existing flow initialzies only for smmu + * enabled node.*/ + + result = ipa3_pre_init(&ipa3_res, pdev_p); + if (result) { + IPAERR("ipa3_init failed\n"); + return result; + } ipa_fw_load_sm_handle_event(IPA_FW_LOAD_EVNT_SMMU_DONE); + goto skip_repeat_pre_init; } /* Proceed to real initialization */ @@ -9485,6 +9558,7 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p) return result; } +skip_repeat_pre_init: result = of_platform_populate(pdev_p->dev.of_node, ipa_plat_drv_match, NULL, &pdev_p->dev); if (result) { @@ -9513,7 +9587,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 +9599,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 +9638,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 +10119,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 +10131,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 e92f84afa1e7..3d829bedd7c4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -4765,6 +4765,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 317790528af9..4267d36c54f2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2128,6 +2128,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; @@ -2509,7 +2511,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); @@ -3127,6 +3128,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_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c index 8ced02501f84..3c24d13e7c76 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c @@ -1366,8 +1366,9 @@ int ipa3_nat_init_cmd( goto bail; } - if (init->table_entries == 0) { - IPAERR_RL("Table entries is zero\n"); + if (init->table_entries == 0 || + init->table_entries == U16_MAX) { + IPAERR_RL("Table entries is %d\n", init->table_entries); result = -EPERM; goto bail; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c index 68fbabcdeb2d..ba2686809ebe 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "ipa_i.h" @@ -284,7 +285,7 @@ int ipa_setup_odl_pipe(void) ipa_odl_ep_cfg = &ipa3_odl_ctx->odl_sys_param; IPADBG("Setting up the odl endpoint\n"); - ipa_odl_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL; + ipa_odl_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en = IPA_DISABLE_CS_OFFLOAD; ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR; ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_hard_byte_limit_en = 1; @@ -366,6 +367,11 @@ int ipa3_odl_pipe_open(void) return 0; } + if (atomic_read(&ipa3_ctx->is_ssr)) { + IPAERR("SSR in progress ODL pipe configuration not allowed\n"); + return 0; + } + memset(&holb_cfg, 0, sizeof(holb_cfg)); holb_cfg.tmr_val = 0; holb_cfg.en = 1; 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)