Merge tag 'LA.UM.9.14.r1-25800-LAHAINA.QSSI15.0' of https://git.codelinaro.org/clo/la/platform/vendor/opensource/dataipa into android13-5.4-lahaina

"LA.UM.9.14.r1-25800-LAHAINA.QSSI15.0"

* tag 'LA.UM.9.14.r1-25800-LAHAINA.QSSI15.0' of https://git.codelinaro.org/clo/la/platform/vendor/opensource/dataipa:
  msm: ipa: Check GSI status during deepsleep resume
  msm: ipa3: supporting hibernate & cleanup unused deepsleep API's

 Conflicts:
	techpack/dataipa/drivers/platform/msm/ipa/ipa_v3/ipa.c

Change-Id: I7a69389ca80dee1ecb236f14706965b1d2bf3adb
This commit is contained in:
Michael Bestas 2025-02-14 03:34:01 +02:00
commit d1d77077b6
No known key found for this signature in database
GPG key ID: CC95044519BE6669
4 changed files with 141 additions and 39 deletions

View file

@ -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 <linux/of.h>
@ -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)
{

View file

@ -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

View file

@ -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();

View file

@ -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);