Merge "msm: ipa3: Fix to handle right error code"
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index ca5e3a6..771950b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -143,7 +143,7 @@
 static void ipa3_free_pkt_init(void);
 static void ipa3_free_pkt_init_ex(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
@@ -503,19 +503,27 @@
 
 static int ipa_pm_notify(struct notifier_block *b, unsigned long event, void *p)
 {
-	IPAERR("Entry\n");
+	IPADBG("Entry\n");
+#if IS_ENABLED(CONFIG_DEEPSLEEP) || IS_ENABLED(CONFIG_HIBERNATION)
 	switch (event) {
 		case PM_POST_SUSPEND:
-#ifdef CONFIG_DEEPSLEEP
 			if (pm_suspend_via_firmware() && 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;
 	}
-	IPAERR("Exit\n");
+#endif
+	IPADBG("Exit\n");
 	return NOTIFY_DONE;
 }
 
@@ -526,7 +534,9 @@
 
 static const struct dev_pm_ops ipa_pm_ops = {
 	.suspend_late = ipa3_ap_suspend,
+	.freeze_late = ipa3_ap_freeze,
 	.resume_early = ipa3_ap_resume,
+	.restore_early = ipa3_ap_resume,
 };
 
 static struct platform_driver ipa_plat_drv = {
@@ -8268,7 +8278,7 @@
 	/* init uc-activation tbl*/
 	ipa3_setup_uc_act_tbl();
 
-#ifdef CONFIG_DEEPSLEEP
+#if IS_ENABLED(CONFIG_DEEPSLEEP) || IS_ENABLED(CONFIG_HIBERNATION)
 	if (!ipa3_is_ready())
 		ipa_fmwk_deepsleep_exit_ipa();
 #endif
@@ -8498,16 +8508,18 @@
 }
 #endif /* IS_ENABLED(CONFIG_QCOM_MDT_LOADER) */
 
-#ifdef CONFIG_DEEPSLEEP
+#if IS_ENABLED(CONFIG_DEEPSLEEP) || IS_ENABLED(CONFIG_HIBERNATION)
 static int ipa3_pil_unload_ipa_fws(void)
 {
 
+#if !IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
 	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");
+#endif
 	return 0;
 }
 #endif
@@ -11818,7 +11830,7 @@
 		}
 	}
 
-#ifdef CONFIG_DEEPSLEEP
+#if IS_ENABLED(CONFIG_DEEPSLEEP)
 	if (pm_suspend_via_firmware()) {
 		IPADBG("Enter deepsleep suspend\n");
 		ipa3_deepsleep_suspend();
@@ -11832,6 +11844,46 @@
 	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
@@ -11858,7 +11910,7 @@
 }
 
 
-#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_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index ac14f07..61627f9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -24,6 +24,7 @@
 #define IPA_MAX_ENTRY_STRING_LEN 500
 #define IPA_MAX_MSG_LEN 4096
 #define IPA_DBG_MAX_RULE_IN_TBL 128
+#define IPA_TSP_OPTION_LEN 16
 #define IPA_DBG_ACTIVE_CLIENT_BUF_SIZE ((IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN \
 	* IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) + IPA_MAX_MSG_LEN)
 
@@ -3077,6 +3078,9 @@
 	IPA_DUMP_STATUS_FIELD(frag_hit);
 	IPA_DUMP_STATUS_FIELD(frag_rule);
 	IPA_DUMP_STATUS_FIELD(ttl_dec);
+	IPA_DUMP_STATUS_FIELD(tsp);
+	IPA_DUMP_STATUS_FIELD(ingress_tc);
+	IPA_DUMP_STATUS_FIELD(egress_tc);
 }
 
 static ssize_t ipa_status_stats_read(struct file *file, char __user *ubuf,
@@ -3334,12 +3338,25 @@
 	struct ipa_ioc_tsp_ingress_class_params ingr_tc;
 	struct ipa_ioc_tsp_egress_prod_params egr_ep;
 	struct ipa_ioc_tsp_egress_class_params egr_tc;
+	u32 ingr_tc_base, egr_tc_base, prod_base;
+	void *ingr_tc_mmio, *egr_tc_mmio, *prod_mmio;
+
+
+	/* map IPA SRAM */
 
 	/* Print the global TSP state flags */
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+	ingr_tc_base = ipahal_read_reg(IPA_RAM_INGRESS_POLICER_DB_BASE_ADDR);
+	egr_tc_base = ipahal_read_reg(IPA_RAM_EGRESS_SHAPING_TC_DB_BASE_ADDR);
+	prod_base = ipahal_read_reg(IPA_RAM_EGRESS_SHAPING_PROD_DB_BASE_ADDR);
 	ipahal_read_reg_fields(IPA_STATE_TSP, &state_tsp);
 	ipahal_read_reg_fields(IPA_STATE_QMNGR_QUEUE_NONEMPTY, &qm_non_empty);
-	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+	ingr_tc_mmio = ioremap(ipa3_ctx->ipa_wrapper_base + ingr_tc_base,
+		ipa3_ctx->tsp.ingr_tc_tbl.size);
+	egr_tc_mmio = ioremap(ipa3_ctx->ipa_wrapper_base + egr_tc_base,
+		ipa3_ctx->tsp.egr_tc_tbl.size);
+	prod_mmio = ioremap(ipa3_ctx->ipa_wrapper_base + prod_base,
+		ipa3_ctx->tsp.egr_ep_tbl.size);
 
 	if (state_tsp.traffic_shaper_idle)
 		nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
@@ -3372,7 +3389,7 @@
 	nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
 			"TC Index\tMax Rate\tMax Burst\tInclude L2\n");
 	for (i = 1; i <= ipa3_ctx->tsp.ingr_tc_max; i++) {
-		ipahal_tsp_parse_hw_ingr_tc(ipa3_ctx->tsp.ingr_tc_tbl.base, i, &ingr_tc);
+		ipahal_tsp_parse_hw_ingr_tc(ingr_tc_mmio, i, &ingr_tc);
 		nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
 			"%02d:\t\t%u\t\t%u\t\t%u\n",
 			i, ingr_tc.max_rate, ingr_tc.max_burst, ingr_tc.include_l2_len);
@@ -3381,12 +3398,15 @@
 	nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
 			"Egress Producer Table:\n");
 	nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
-			"EP Index\tClient\tMax Rate\tMax Burst\n");
+		"EP Index\tClient\tMax Rate\tMax Burst\tTC low\tTC high\tMaxOut B\t\tMaxOut EN\n");
 	for (i = 0; i < ipa3_ctx->tsp.egr_ep_max; i++) {
-		ipahal_tsp_parse_hw_egr_ep(ipa3_ctx->tsp.egr_ep_tbl.base, i, &egr_ep);
+		ipa_tsp_get_egr_ep(i, &egr_ep);
 		nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
-			"%d:\t\t%d\t%u\t\t%u\n",
-			i, ipa3_ctx->tsp.egr_ep_config[i], egr_ep.max_rate, egr_ep.max_burst);
+			"%d:\t\t%d\t%u\t\t%u\t\t%u\t%u\t%u\t\t%u\n",
+			i, ipa3_ctx->tsp.egr_ep_config[i], egr_ep.max_rate, egr_ep.max_burst,
+			egr_ep.tc_lo, egr_ep.tc_hi,
+			egr_ep.max_out_bytes, egr_ep.policing_by_max_out);
+
 	}
 
 	nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
@@ -3394,30 +3414,275 @@
 	nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
 			"TC Index\tMax Rate\tMax Burst\tG. Rate\tG. Burst\n");
 	for (i = 1; i <= ipa3_ctx->tsp.egr_tc_max; i++) {
-		ipahal_tsp_parse_hw_egr_tc(ipa3_ctx->tsp.egr_tc_tbl.base, i, &egr_tc);
+		ipahal_tsp_parse_hw_egr_tc(egr_tc_mmio, i, &egr_tc);
 		nbytes += scnprintf(dbg_buff + nbytes, IPA_MAX_MSG_LEN - nbytes,
 			"%02d:\t\t%u\t\t%u\t\t%u\t%u\n",
 			i, egr_tc.max_rate, egr_tc.max_burst,
 			egr_tc.guaranteed_rate, egr_tc.guaranteed_burst);
 	}
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+	if (ingr_tc_mmio)
+		iounmap(ingr_tc_mmio);
+	if (egr_tc_mmio)
+		iounmap(egr_tc_mmio);
+	if (prod_mmio)
+		iounmap(prod_mmio);
 
 	return simple_read_from_buffer(buf, count, ppos, dbg_buff, nbytes);
 }
 
+static int ipa3_tsp_ingress_config_commit(char *sptr)
+{
+	struct ipa_ioc_tsp_ingress_class_params tsp_in_tc;
+	char *token;
+	int ret;
+	u8 index;
+	u16 max_rate, max_burst;
+	u32 include_l2_len;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou8(token, 0, &index) || index == 0 || index > ipa3_ctx->tsp.ingr_tc_max)
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou16(token, 0, &max_rate))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou16(token, 0, &max_burst))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &include_l2_len) || include_l2_len > 1)
+		return -EINVAL;
+
+	tsp_in_tc.max_rate = max_rate;
+	tsp_in_tc.max_burst = max_burst;
+	tsp_in_tc.include_l2_len = include_l2_len;
+
+	ret = ipa_tsp_set_ingr_tc(index, &tsp_in_tc);
+	if (ret) {
+		IPAERR("Failed to set ingress Traffic class\n");
+		return ret;
+	}
+
+	ret = ipa_tsp_commit();
+	if (ret) {
+		IPAERR("Failed to commit TSP\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ipa3_tsp_egress_config_commit(char *sptr)
+{
+	struct ipa_ioc_tsp_egress_class_params tsp_e_tc;
+	char *token;
+	int ret;
+	u8 index;
+	u16 max_rate, max_burst ,guaranteed_rate, guaranteed_burst;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou8(token, 0, &index) || index == 0 || index > ipa3_ctx->tsp.egr_tc_max)
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou16(token, 0, &max_rate))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou16(token, 0, &max_burst))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou16(token, 0, &guaranteed_rate))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou16(token, 0, &guaranteed_burst))
+		return -EINVAL;
+
+	tsp_e_tc.max_rate = max_rate;
+	tsp_e_tc.max_burst = max_burst;
+	tsp_e_tc.guaranteed_rate = guaranteed_rate;
+	tsp_e_tc.guaranteed_burst = guaranteed_burst;
+
+	ret = ipa_tsp_set_egr_tc(index, &tsp_e_tc);
+	if (ret) {
+		IPAERR("Failed to set egress Traffic class\n");
+		return ret;
+	}
+
+	ret = ipa_tsp_commit();
+	if (ret) {
+		IPAERR("Failed to commit TSP\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ipa3_tsp_producer_config_commit(char *sptr)
+{
+	struct ipa_ioc_tsp_egress_prod_params tsp_ep;
+	char *token;
+	int ret;
+	u8 index;
+	u16 max_rate, max_burst;
+	u32 max_out_bytes, client_num;
+	u8 tc_lo, tc_hi, policing_by_max_out;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &client_num))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou8(token, 0, &index) || index == 0 || index > ipa3_ctx->tsp.egr_ep_max)
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou16(token, 0, &max_rate))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou16(token, 0, &max_burst))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &max_out_bytes))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou8(token, 0, &tc_lo))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou8(token, 0, &tc_hi))
+		return -EINVAL;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou8(token, 0, &policing_by_max_out) || policing_by_max_out > 1)
+		return -EINVAL;
+
+	tsp_ep.client = client_num;
+	tsp_ep.max_rate = max_rate;
+	tsp_ep.max_burst = max_burst;
+	tsp_ep.max_out_bytes = max_out_bytes;
+	tsp_ep.tc_lo = tc_lo;
+	tsp_ep.tc_hi = tc_hi;
+	tsp_ep.policing_by_max_out = policing_by_max_out;
+
+	ret = ipa_tsp_set_egr_ep(index, &tsp_ep);
+	if (ret) {
+		IPAERR("Failed to set TSP Producer\n");
+		return ret;
+	}
+
+	ret = ipa_tsp_commit();
+	if (ret) {
+		IPAERR("Failed to commit TSP\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static ssize_t ipa3_write_tsp(struct file *file, const char __user *buf,
 			      size_t count, loff_t *ppos) {
 
+	unsigned long missing;
+	char *sptr, *token;
+	char option[IPA_TSP_OPTION_LEN];
 	int ret;
-	u8 option = 0;
 
 	if (count >= sizeof(dbg_buff))
 		return -EFAULT;
 
-	ret = kstrtou8_from_user(buf, count, 0, &option);
-	if(ret)
-		return ret;
+	missing = copy_from_user(dbg_buff, buf, count);
+	if (missing) {
+		IPAERR("Failed to copy data from user\n");
+		return -EFAULT;
+	}
 
-	pr_err("TSP write is not implemented.\n");
+	dbg_buff[count] = '\0';
+
+	sptr = dbg_buff;
+
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+
+	strlcpy(option, token, IPA_TSP_OPTION_LEN);
+	if (strnstr(option, "ingress", IPA_TSP_OPTION_LEN)) {
+		ret = ipa3_tsp_ingress_config_commit(sptr);
+		if (ret) {
+			IPAERR("Failed to config and commit Ingress Traffic class");
+			return ret;
+		}
+		IPADBG("Ingress Traffic Class config and commit done.");
+	} else if (strnstr(option, "egress", IPA_TSP_OPTION_LEN)) {
+		ret = ipa3_tsp_egress_config_commit(sptr);
+		if (ret) {
+			IPAERR("Failed to config and commit Egress Traffic class");
+			return ret;
+		}
+		IPADBG("Egress Traffic Class config and commit done.");
+	} else if (strnstr(option, "producer", IPA_TSP_OPTION_LEN)) {
+		ret = ipa3_tsp_producer_config_commit(sptr);
+		if (ret) {
+			IPAERR("Failed to config and commit TSP Producer");
+			return ret;
+		}
+		IPADBG("TSP Producer config and commit done.");
+	} else if (strnstr(option, "reset", IPA_TSP_OPTION_LEN)) {
+		ret = ipa_tsp_reset();
+		if (ret) {
+			IPAERR("Failed to reset TSP");
+			return ret;
+		}
+		IPADBG("Reset TSP done.");
+	} else {
+		IPAERR("TSP command format should be one of the following:\n \
+			ingress <index> <max_rate> <max_burst> <include_l2_len>\n \
+			egress <index> <max rate> <max_burst> <guaranteed_rate> <guaranteed_burst>\n \
+			producer <client num> <index> <max rate> <max_burst> <max_out_bytes> <tc_lo> <tc_hi> <policing_by_max_out>\n \
+			reset\n");
+	}
 
 	return count;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 9f1ea0b..f0951cb 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -2,7 +2,7 @@
 /*
  * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  *
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _IPA3_I_H_
@@ -3615,6 +3615,7 @@
 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);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_tsp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_tsp.c
index 7a1f0e1..c2a268a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_tsp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_tsp.c
@@ -182,18 +182,45 @@
 
 int ipa_tsp_get_egr_ep(u8 index, struct ipa_ioc_tsp_egress_prod_params *output)
 {
-	u32 regval;
+	u32 regval, prod_base;
 	struct ipa_ep_cfg_prod_cfg prod_cfg;
+	void *prod_mmio;
+
+	if (index >= ipa3_ctx->tsp.egr_ep_max) {
+		IPAERR("Invalid producer index.\n");
+		return -EINVAL;
+	}
+
+	if (ipa3_ctx->tsp.egr_ep_config[index] == IPA_CLIENT_MAX)
+		return 0;
+
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+	prod_base = ipahal_read_reg(IPA_RAM_EGRESS_SHAPING_PROD_DB_BASE_ADDR);
+	prod_mmio = ioremap(ipa3_ctx->ipa_wrapper_base + prod_base,
+		ipa3_ctx->tsp.egr_ep_tbl.size);
+	if (!prod_mmio) {
+		IPAERR("Failed to ioremap TSP SRAM\n");
+		return -EFAULT;
+	}
 
 	/* The function is internal only, assuming valid params */
 
-	ipahal_tsp_parse_hw_egr_ep(ipa3_ctx->tsp.egr_ep_tbl.base, index, output);
+	ipahal_tsp_parse_hw_egr_ep(prod_mmio, index, output);
 
 	output->client = ipa3_ctx->tsp.egr_ep_config[index];
 
 	regval = ipahal_read_reg_n_fields(IPA_ENDP_INIT_PROD_CFG_n,
 		ipa3_get_ep_mapping(output->client), (void *)&prod_cfg);
 
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+	if (prod_mmio)
+		iounmap(prod_mmio);
+
+	if (!prod_cfg.tsp_enable)
+		IPAERR("TSP is not enabled on %s EP %d!\n",
+			ipa_clients_strings[output->client], ipa3_get_ep_mapping(output->client));
+
 	output->max_out_bytes = prod_cfg.max_output_size << 6; // max_output_size*64
 	output->policing_by_max_out = prod_cfg.max_output_size_drop_enable;
 	output->tc_lo = prod_cfg.egress_tc_lowest;
@@ -224,19 +251,35 @@
 
 int ipa_tsp_set_egr_ep(u8 index, const struct ipa_ioc_tsp_egress_prod_params *input)
 {
-	u32 regval, ep_index, ep_tc_mask, new_tc_range_mask;
-	struct ipa_ep_cfg_prod_cfg prod_cfg;
+	int new_ep_index;
+	u32 ep_index, ep_tc_mask, new_tc_range_mask;
+	struct ipa_ep_cfg_aggr aggr_cfg = {0};
+	struct ipa_ep_cfg_prod_cfg prod_cfg = {0};
 	bool cleanup = false;
 
+	if (index >= ipa3_ctx->tsp.egr_ep_max) {
+		IPAERR("Invalid producer index.\n");
+		return -EINVAL;
+	}
+
+	if ((new_ep_index = ipa3_get_ep_mapping(input->client)) == IPA_EP_NOT_ALLOCATED) {
+		IPAERR("Failed getting the producer EP index.\n");
+		return -EINVAL;
+	}
+
+	if (input->max_out_bytes >> 6 > 255) {
+		IPAERR("Invalid max out size: %d bytes. Must be up to 16320 bytes.\n",
+			input->max_out_bytes);
+		return -EINVAL;
+	}
+
 	ep_tc_mask = GENMASK(input->tc_hi, input->tc_lo);
 	new_tc_range_mask = ipa3_ctx->tsp.egr_tc_range_mask;
 
-	ep_index = ipa3_get_ep_mapping(ipa3_ctx->tsp.egr_ep_config[index]);
-	regval = ipahal_read_reg_n_fields(
-		IPA_ENDP_INIT_PROD_CFG_n, ep_index, (void *)&prod_cfg);
-
+	/* Checking for an overlap to clean, if needed */
 	if (ipa3_ctx->tsp.egr_ep_config[index] != IPA_CLIENT_MAX &&
 	    ipa3_ctx->tsp.egr_ep_config[index] != input->client) {
+		ep_index = ipa3_get_ep_mapping(ipa3_ctx->tsp.egr_ep_config[index]);
 		cleanup = true;
 		new_tc_range_mask &= !GENMASK(prod_cfg.egress_tc_highest,prod_cfg.egress_tc_lowest);
 	}
@@ -263,7 +306,8 @@
 	prod_cfg.max_output_size_drop_enable = input->policing_by_max_out;
 	prod_cfg.egress_tc_lowest = input->tc_lo;
 	prod_cfg.egress_tc_highest = input->tc_hi;
-	if (ipa3_cfg_ep_prod_cfg(ipa3_get_ep_mapping(input->client), &prod_cfg) != 0) {
+	if (ipa3_cfg_ep_aggr((u32)new_ep_index, &aggr_cfg) != 0 ||
+	    ipa3_cfg_ep_prod_cfg((u32)new_ep_index, &prod_cfg) != 0) {
 		IPAERR("Failed configuring the producer EP.\n");
 		return -EFAULT;
 	}
@@ -287,9 +331,9 @@
 	 * and only maximal bandwidth rate will be considered.
 	 */
 	if (input->guaranteed_rate || input->guaranteed_burst)
-		ipahal_write_reg_mask(IPA_TSP_EGRESS_POLICING_CFG, 0x1 << index, 0x1 << index);
-	else
 		ipahal_write_reg_mask(IPA_TSP_EGRESS_POLICING_CFG, 0x0, 0x1 << index);
+	else
+		ipahal_write_reg_mask(IPA_TSP_EGRESS_POLICING_CFG, 0x1 << index, 0x1 << index);
 
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index da22550..cf95db4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -7695,7 +7695,7 @@
 	hw_idx = ipa3_ctx->hw_type_index;
 
 	if (client >= IPA_CLIENT_MAX || client < 0) {
-		IPAERR_RL("Bad client number! client =%d\n", client);
+		IPAERR_RL("Bad client number! client = %d\n", client);
 		return IPA_EP_NOT_ALLOCATED;
 	}
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_tsp.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_tsp.c
index 948ab23..0a2cce7 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_tsp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_tsp.c
@@ -10,6 +10,9 @@
 #include "ipahal_reg.h"
 #include "ipahal_tsp.h"
 
+/* The frequency is 65536/rate per HPG, but the container is only 16 bits,
+   the below will solve the rate=1 corner case */
+#define RATE_TO_FREQ(x) ((x <= 1) ? 65535 : (65536 / x))
 
 void ipahal_tsp_fill_hw_ingr_tc(const struct ipa_ioc_tsp_ingress_class_params *input,
 	void *table, u8 index)
@@ -30,17 +33,17 @@
 	union ipahal_tsp_egress_prod *hal_egr_ep =
 		(union ipahal_tsp_egress_prod *)table + index;
 
-	if ((index & 0x1)) {
+	if (!(index & 0x1)) {
 		/* even index */
 		hal_egr_ep->even.max_rate = input->max_rate;
-		hal_egr_ep->even.max_freq = 65536 / input->max_rate;
+		hal_egr_ep->even.max_freq = RATE_TO_FREQ(input->max_rate);
 		hal_egr_ep->even.max_burst = input->max_burst;
 		hal_egr_ep->even.max_bucket = input->max_burst;
 		hal_egr_ep->even.last_rtc = 0x0;
 	} else {
 		/* odd index */
 		hal_egr_ep->odd.max_rate = input->max_rate;
-		hal_egr_ep->odd.max_freq = 65536 / input->max_rate;
+		hal_egr_ep->odd.max_freq = RATE_TO_FREQ(input->max_rate);
 		hal_egr_ep->odd.max_burst = input->max_burst;
 		hal_egr_ep->odd.max_bucket = input->max_burst;
 		hal_egr_ep->odd.last_rtc = 0x0;
@@ -58,8 +61,8 @@
 		/* even index */
 		hal_egr_tc->even.guaranteed_rate = input->guaranteed_rate;
 		hal_egr_tc->even.max_rate = input->max_rate;
-		hal_egr_tc->even.guaranteed_freq = 65536 / input->guaranteed_rate;
-		hal_egr_tc->even.max_freq = 65536 / input->max_rate;
+		hal_egr_tc->even.guaranteed_freq = RATE_TO_FREQ(input->guaranteed_rate);
+		hal_egr_tc->even.max_freq = RATE_TO_FREQ(input->max_rate);
 		hal_egr_tc->even.guaranteed_burst = input->guaranteed_burst;
 		hal_egr_tc->even.max_burst = input->max_burst;
 		hal_egr_tc->even.max_bucket = input->max_burst;
@@ -68,8 +71,8 @@
 		/* odd index */
 		hal_egr_tc->odd.guaranteed_rate = input->guaranteed_rate;
 		hal_egr_tc->odd.max_rate = input->max_rate;
-		hal_egr_tc->odd.guaranteed_freq = 65536 / input->guaranteed_rate;
-		hal_egr_tc->odd.max_freq = 65536 / input->max_rate;
+		hal_egr_tc->odd.guaranteed_freq = RATE_TO_FREQ(input->guaranteed_rate);
+		hal_egr_tc->odd.max_freq = RATE_TO_FREQ(input->max_rate);
 		hal_egr_tc->odd.guaranteed_burst = input->guaranteed_burst;
 		hal_egr_tc->odd.max_burst = input->max_burst;
 		hal_egr_tc->odd.max_bucket = input->max_burst;
@@ -116,7 +119,7 @@
 	union ipahal_tsp_egress_prod *hal_egr_ep =
 		(union ipahal_tsp_egress_prod *)table + index;
 
-	if ((index & 0x1)) {
+	if (!(index & 0x1)) {
 		/* even index */
 		output->max_rate = hal_egr_ep->even.max_rate;
 		output->max_burst = hal_egr_ep->even.max_burst;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_tsp_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_tsp_i.h
index 1ffae65..68319d3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_tsp_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_tsp_i.h
@@ -85,7 +85,7 @@
 };
 
 /**
- * struct ipahal_tsp_egress_class_even - IPA egress traffic-class (even index)
+ * struct ipahal_tsp_egress_class_odd - IPA egress traffic-class (odd index)
  *
  * @last_rtc: For HW use, initialize to 0x0000
  * @reserved: Reserved
@@ -100,7 +100,7 @@
  * @guaranteed_burst: Maximal-burst allowed for guaranteed bandwidth rate (in bytes)
  * @max_burst: Maximal-burst allowed for maximal bandwidth rate (in bytes)
  */
-struct ipahal_tsp_egress_class_even {
+struct ipahal_tsp_egress_class_odd {
 	u16 last_rtc;
 	u16 reserved;
 	u16 guaranteed_bucket;
@@ -114,7 +114,7 @@
 };
 
 /**
- * struct ipahal_tsp_egress_class_odd - IPA egress traffic-class (odd index)
+ * struct ipahal_tsp_egress_class_even - IPA egress traffic-class (even index)
  *
  * @guaranteed_burst: Maximal-burst allowed for guaranteed bandwidth rate (in bytes)
  * @max_burst: Maximal-burst allowed for maximal bandwidth rate (in bytes)
@@ -129,7 +129,7 @@
  * @max_freq: In units of 0.833*usec/64KB, Calculated as:
  * 			 max_freq = 65536/max_rate (always be rounded up)
  */
-struct ipahal_tsp_egress_class_odd {
+struct ipahal_tsp_egress_class_even {
 	u16 guaranteed_burst;
 	u16 max_burst;
 	u16 last_rtc;
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 60ed1a0..c7d66a6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 /*
@@ -3949,9 +3950,13 @@
 	}
 
 	switch (code) {
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
 #if IS_ENABLED(CONFIG_DEEPSLEEP)
 	case SUBSYS_BEFORE_DS_ENTRY:
 #endif
+#endif
+
 #if IS_ENABLED(CONFIG_QCOM_Q6V5_PAS)
 	case QCOM_SSR_BEFORE_SHUTDOWN:
 #else
@@ -3978,6 +3983,8 @@
 		ipa3_odl_pipe_cleanup(true);
 		IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n");
 		break;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
 #if IS_ENABLED(CONFIG_DEEPSLEEP)
 	case SUBSYS_AFTER_DS_ENTRY:
 		IPAWANINFO("IPA Received AFTER DEEPSLEEP ENTRY\n");
@@ -3988,6 +3995,7 @@
 		IPAWANINFO("AFTER DEEPSLEEP ENTRY handling is complete\n");
 		break;
 #endif
+#endif
 
 #if IS_ENABLED(CONFIG_QCOM_Q6V5_PAS)
 	case QCOM_SSR_AFTER_SHUTDOWN:
@@ -4014,6 +4022,8 @@
 			ipa3_client_prod_post_shutdown_cleanup();
 		IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n");
 		break;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
 #if IS_ENABLED(CONFIG_DEEPSLEEP)
 	case SUBSYS_BEFORE_DS_EXIT:
 		IPAWANINFO("IPA received BEFORE DEEPSLEEP EXIT\n");
@@ -4028,6 +4038,7 @@
 		IPAWANINFO("BEFORE DEEPSLEEP EXIT handling is complete\n");
 		break;
 #endif
+#endif
 
 #if IS_ENABLED(CONFIG_QCOM_Q6V5_PAS)
 	case QCOM_SSR_BEFORE_POWERUP:
@@ -4045,9 +4056,13 @@
 		ipa3_reset_freeze_vote();
 		IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n");
 		break;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
 #if IS_ENABLED(CONFIG_DEEPSLEEP)
 	case SUBSYS_AFTER_DS_EXIT:
 #endif
+#endif
+
 #if IS_ENABLED(CONFIG_QCOM_Q6V5_PAS)
 	case QCOM_SSR_AFTER_POWERUP:
 #else