Jelajahi Sumber

Merge 681c14539a16ee472293fc97e9a1ab2827d039b7 on remote branch

Change-Id: I90b968b5c69981f489b3e34de0db40fb5b6f6065
Linux Build Service Account 6 bulan lalu
induk
melakukan
54afb87acc
26 mengubah file dengan 721 tambahan dan 43 penghapusan
  1. 10 0
      Kbuild
  2. 2 0
      cnss2/Makefile
  3. 63 0
      cnss2/bus.c
  4. 6 0
      cnss2/bus.h
  5. 2 1
      cnss2/genl.c
  6. 61 5
      cnss2/main.c
  7. 10 0
      cnss2/main.h
  8. 23 0
      cnss2/pci.c
  9. 11 0
      cnss2/pci.h
  10. 36 2
      cnss2/pci_platform.h
  11. 152 2
      cnss2/pci_qcom.c
  12. 34 4
      cnss2/power.c
  13. 4 4
      cnss2/qmi.c
  14. 2 0
      cnss_genl/Makefile
  15. 2 0
      cnss_prealloc/Makefile
  16. 2 2
      cnss_prealloc/cnss_prealloc.c
  17. 2 0
      cnss_utils/Makefile
  18. 5 5
      cnss_utils/cnss_plat_ipc_qmi.c
  19. 2 0
      icnss2/Makefile
  20. 2 0
      icnss2/genl.c
  21. 231 12
      icnss2/main.c
  22. 51 0
      icnss2/main.h
  23. 2 2
      icnss2/power.c
  24. 4 4
      icnss2/qmi.c
  25. 1 0
      inc/cnss2.h
  26. 1 0
      inc/icnss2.h

+ 10 - 0
Kbuild

@@ -86,6 +86,16 @@ ifeq ($(CONFIG_FEATURE_SMEM_MAILBOX), y)
 KBUILD_CPPFLAGS += -DCONFIG_FEATURE_SMEM_MAILBOX
 endif
 
+found = $(shell if grep -qF "int msm_pcie_dsp_link_control" $(srctree)/include/linux/msm_pcie.h; then echo "yes" ;else echo "no" ;fi;)
+ifeq ($(findstring yes, $(found)), yes)
+KBUILD_CPPFLAGS += -DCONFIG_PCIE_SWITCH_SUPPORT
+endif
+
+found = $(shell if grep -qF "int msm_pcie_retrain_port_link" $(srctree)/include/linux/msm_pcie.h; then echo "yes" ;else echo "no" ;fi;)
+ifeq ($(findstring yes, $(found)), yes)
+KBUILD_CPPFLAGS += -DCONFIG_PCIE_SWITCH_RETRAIN_LINK_SUPPORT
+endif
+
 obj-$(CONFIG_CNSS2) += cnss2/
 obj-$(CONFIG_ICNSS2) += icnss2/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/

+ 2 - 0
cnss2/Makefile

@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+ccflags-y += -Wmissing-prototypes
+
 ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/cnss_utils
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc

+ 63 - 0
cnss2/bus.c

@@ -7,6 +7,7 @@
 #include "bus.h"
 #include "debug.h"
 #include "pci.h"
+#include "pci_platform.h"
 
 enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
 {
@@ -711,6 +712,68 @@ bool cnss_bus_is_smmu_s1_enabled(struct cnss_plat_data *plat_priv)
 	}
 }
 
+int cnss_bus_dsp_link_control(struct cnss_plat_data *plat_priv,
+			      bool link_enable)
+{
+	if (!plat_priv || plat_priv->pcie_switch_type != PCIE_SWITCH_NTN3)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_dsp_link_control(plat_priv->bus_priv, link_enable);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_set_dsp_link_status(struct cnss_plat_data *plat_priv,
+				 bool link_enable)
+{
+	if (!plat_priv || plat_priv->pcie_switch_type != PCIE_SWITCH_NTN3)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_set_dsp_link_status(plat_priv->bus_priv, link_enable);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_get_dsp_link_status(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv || plat_priv->pcie_switch_type != PCIE_SWITCH_NTN3)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_get_dsp_link_status(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_dsp_link_enable(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv || plat_priv->pcie_switch_type != PCIE_SWITCH_NTN3)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_dsp_link_enable(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
 int cnss_bus_update_time_sync_period(struct cnss_plat_data *plat_priv,
 				     unsigned int time_sync_period)
 {

+ 6 - 0
cnss2/bus.h

@@ -77,4 +77,10 @@ int cnss_bus_get_msi_assignment(struct cnss_plat_data *plat_priv,
 				int *num_vectors,
 				u32 *user_base_data,
 				u32 *base_vector);
+int cnss_bus_dsp_link_control(struct cnss_plat_data *plat_priv,
+			      bool link_enable);
+int cnss_bus_set_dsp_link_status(struct cnss_plat_data *plat_priv,
+				 bool link_enable);
+int cnss_bus_get_dsp_link_status(struct cnss_plat_data *plat_priv);
+int cnss_bus_dsp_link_enable(struct cnss_plat_data *plat_priv);
 #endif /* _CNSS_BUS_H */

+ 2 - 1
cnss2/genl.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #define pr_fmt(fmt) "cnss_genl: " fmt
@@ -14,6 +14,7 @@
 
 #include "main.h"
 #include "debug.h"
+#include "genl.h"
 
 #define CNSS_GENL_FAMILY_NAME "cnss-genl"
 #define CNSS_GENL_MCAST_GROUP_NAME "cnss-genl-grp"

+ 61 - 5
cnss2/main.c

@@ -700,6 +700,60 @@ bool cnss_audio_is_direct_link_supported(struct device *dev)
 }
 EXPORT_SYMBOL(cnss_audio_is_direct_link_supported);
 
+/**
+ * cnss_ipa_wlan_shared_smmu_supported: Check whether shared SMMU context bank
+ *                                      can be used between IPA and WLAN.
+ * @dev: Device
+ *
+ * Return: TRUE if supported, FALSE on failure or if not supported
+ */
+bool cnss_ipa_wlan_shared_smmu_supported(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct device_node *ipa_wlan_smmu_node;
+	struct device_node *cnss_iommu_group_node;
+	struct device_node *ipa_iommu_group_node;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv not available for IPA Shared CB cap\n");
+		return false;
+	}
+
+	ipa_wlan_smmu_node = of_find_compatible_node(NULL, NULL,
+						     "qcom,ipa-smmu-wlan-cb");
+	if (!ipa_wlan_smmu_node) {
+		cnss_pr_err("ipa-smmu-wlan-cb not enabled");
+		return false;
+	}
+
+	ipa_iommu_group_node = of_parse_phandle(ipa_wlan_smmu_node,
+						"qcom,iommu-group", 0);
+	of_node_put(ipa_wlan_smmu_node);
+
+	if (!ipa_iommu_group_node) {
+		cnss_pr_err("Unable to get ipa iommu group phandle");
+		return false;
+	}
+	of_node_put(ipa_iommu_group_node);
+
+	cnss_iommu_group_node = of_parse_phandle(dev->of_node,
+						 "qcom,iommu-group", 0);
+	if (!cnss_iommu_group_node) {
+		cnss_pr_err("Unable to get cnss iommu group phandle");
+		return false;
+	}
+	of_node_put(cnss_iommu_group_node);
+
+	if (cnss_iommu_group_node == ipa_iommu_group_node) {
+		plat_priv->ipa_shared_cb_enable = true;
+		cnss_pr_info("CNSS and IPA share IOMMU group");
+	} else {
+		cnss_pr_info("CNSS and IPA do not share IOMMU group");
+	}
+
+	return plat_priv->ipa_shared_cb_enable;
+}
+EXPORT_SYMBOL(cnss_ipa_wlan_shared_smmu_supported);
 
 void cnss_request_pm_qos(struct device *dev, u32 qos_val)
 {
@@ -3246,8 +3300,8 @@ static void init_elf_identification(struct elf32_hdr *ehdr, unsigned char class)
 	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
 }
 
-int cnss_qcom_elf_dump(struct list_head *segs, struct device *dev,
-		       unsigned char class)
+static int cnss_qcom_elf_dump(struct list_head *segs, struct device *dev,
+			      unsigned char class)
 {
 	struct cnss_qcom_dump_segment *segment;
 	void *phdr, *ehdr;
@@ -4176,7 +4230,7 @@ static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv)
 static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv) {}
 #endif /* CONFIG_INTERCONNECT */
 
-void cnss_daemon_connection_update_cb(void *cb_ctx, bool status)
+static void cnss_daemon_connection_update_cb(void *cb_ctx, bool status)
 {
 	struct cnss_plat_data *plat_priv = cb_ctx;
 
@@ -4293,7 +4347,7 @@ static ssize_t time_sync_period_show(struct device *dev,
  *
  * Result: return minimum time sync period present in vote from wlan and sys
  */
-uint32_t cnss_get_min_time_sync_period_by_vote(struct cnss_plat_data *plat_priv)
+static uint32_t cnss_get_min_time_sync_period_by_vote(struct cnss_plat_data *plat_priv)
 {
 	unsigned int i, min_time_sync_period = CNSS_TIME_SYNC_PERIOD_INVALID;
 	unsigned int time_sync_period;
@@ -5544,6 +5598,7 @@ static int cnss_probe(struct platform_device *plat_dev)
 	cnss_get_pm_domain_info(plat_priv);
 	cnss_get_wlaon_pwr_ctrl_info(plat_priv);
 	cnss_power_misc_params_init(plat_priv);
+	cnss_pci_of_switch_type_init(plat_priv);
 	cnss_get_tcs_info(plat_priv);
 	cnss_get_cpr_info(plat_priv);
 	cnss_aop_interface_init(plat_priv);
@@ -5610,6 +5665,7 @@ deinit_misc:
 destroy_debugfs:
 	cnss_debugfs_destroy(plat_priv);
 deinit_dms:
+	cnss_cancel_dms_work();
 	cnss_dms_deinit(plat_priv);
 deinit_event_work:
 	cnss_event_work_deinit(plat_priv);
@@ -5642,10 +5698,10 @@ static int cnss_remove(struct platform_device *plat_dev)
 	cnss_bus_deinit(plat_priv);
 	cnss_misc_deinit(plat_priv);
 	cnss_debugfs_destroy(plat_priv);
+	cnss_cancel_dms_work();
 	cnss_dms_deinit(plat_priv);
 	cnss_qmi_deinit(plat_priv);
 	cnss_event_work_deinit(plat_priv);
-	cnss_cancel_dms_work();
 	cnss_remove_sysfs(plat_priv);
 	cnss_unregister_bus_scale(plat_priv);
 	cnss_unregister_esoc(plat_priv);

+ 10 - 0
cnss2/main.h

@@ -118,6 +118,11 @@ enum cnss_vreg_type {
 	CNSS_VREG_PRIM,
 };
 
+enum cnss_pci_switch_type {
+	PCIE_DIRECT_ATTACH = 0,
+	PCIE_SWITCH_NTN3,
+};
+
 struct cnss_clk_cfg {
 	const char *name;
 	u32 freq;
@@ -649,6 +654,8 @@ struct cnss_plat_data {
 	bool no_bwscale;
 	bool sleep_clk;
 	struct wlchip_serial_id_v01 serial_id;
+	bool ipa_shared_cb_enable;
+	u32 pcie_switch_type;
 };
 
 #if IS_ENABLED(CONFIG_ARCH_QCOM)
@@ -740,6 +747,7 @@ void cnss_aop_interface_deinit(struct cnss_plat_data *plat_priv);
 int cnss_aop_pdc_reconfig(struct cnss_plat_data *plat_priv);
 int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *msg);
 void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv);
+void cnss_pci_of_switch_type_init(struct cnss_plat_data *plat_priv);
 int cnss_aop_ol_cpr_cfg_setup(struct cnss_plat_data *plat_priv,
 			      struct wlfw_pmu_cfg_v01 *fw_pmu_cfg);
 int cnss_request_firmware_direct(struct cnss_plat_data *plat_priv,
@@ -759,4 +767,6 @@ size_t cnss_get_platform_name(struct cnss_plat_data *plat_priv,
 			      char *buf, const size_t buf_len);
 int cnss_iommu_map(struct iommu_domain *domain, unsigned long iova,
 		   phys_addr_t paddr, size_t size, int prot);
+int cnss_select_pinctrl_enable(struct cnss_plat_data *plat_priv);
+int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv, bool state);
 #endif /* _CNSS_MAIN_H */

+ 23 - 0
cnss2/pci.c

@@ -6905,6 +6905,12 @@ static int cnss_mhi_bw_scale(struct mhi_controller *mhi_ctrl,
 	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
 	int ret = 0;
 
+	if (plat_priv->pcie_switch_type == PCIE_SWITCH_NTN3) {
+		ret = cnss_pci_dsp_link_retrain(pci_priv,
+						link_info->target_link_speed);
+		return ret;
+	}
+
 	cnss_pr_dbg("Setting link speed:0x%x, width:0x%x\n",
 		    link_info->target_link_speed,
 		    link_info->target_link_width);
@@ -7377,6 +7383,23 @@ static int cnss_try_suspend(struct cnss_plat_data *plat_priv)
 }
 #endif
 
+void cnss_pci_of_switch_type_init(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+	int ret;
+
+	if (dev && dev->of_node) {
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,pcie-switch-type",
+					   &plat_priv->pcie_switch_type);
+		if (ret)
+			plat_priv->pcie_switch_type = 0;
+	} else {
+		cnss_pr_err("device or node is not available.");
+	}
+	cnss_pr_dbg("pcie_switch_type is %d", plat_priv->pcie_switch_type);
+}
+
 /* Setting to use this cnss_pm_domain ops will let PM framework override the
  * ops from dev->bus->pm which is pci_dev_pm_ops from pci-driver.c. This ops
  * has to take care everything device driver needed which is currently done

+ 11 - 0
cnss2/pci.h

@@ -44,6 +44,14 @@
 				      ee == MHI_EE_WFW || \
 				      ee == MHI_EE_FP)
 
+#define PCI_DSP_LINK_ENABLE                     1
+#define PCI_DSP_LINK_DISABLE                    0
+#ifdef CONFIG_PCIE_SWITCH_SUPPORT
+#define DSP_LINK_ENABLE_DELAY_TIME_US_MIN       (25000)
+#define DSP_LINK_ENABLE_DELAY_TIME_US_MAX       (25100)
+#define DSP_LINK_ENABLE_RETRY_COUNT_MAX         (3)
+#endif
+
 enum cnss_mhi_state {
 	CNSS_MHI_INIT,
 	CNSS_MHI_DEINIT,
@@ -185,6 +193,9 @@ struct cnss_pci_data {
 	bool drv_supported;
 	bool is_smmu_fault;
 	unsigned long long smmu_fault_timestamp[SMMU_CB_MAX];
+#ifdef CONFIG_PCIE_SWITCH_SUPPORT
+	bool pci_dsp_link_status;
+#endif
 };
 
 static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data)

+ 36 - 2
cnss2/pci_platform.h

@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */
+/* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
 
 #ifndef _CNSS_PCI_PLATFORM_H
 #define _CNSS_PCI_PLATFORM_H
@@ -113,7 +113,8 @@ int cnss_pci_get_one_msi_mhi_irq_array_size(struct cnss_pci_data *pci_priv);
 bool cnss_pci_is_force_one_msi(struct cnss_pci_data *pci_priv);
 int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv);
 void cnss_pci_update_drv_supported(struct cnss_pci_data *pci_priv);
-
+int cnss_pci_dsp_link_control(struct cnss_pci_data *pci_priv,
+			      bool link_enable);
 /**
  * _cnss_pci_get_reg_dump() - Dump PCIe RC registers for debug
  * @pci_priv: driver PCI bus context pointer
@@ -127,6 +128,12 @@ void cnss_pci_update_drv_supported(struct cnss_pci_data *pci_priv);
  */
 int _cnss_pci_get_reg_dump(struct cnss_pci_data *pci_priv,
 			   u8 *buf, u32 len);
+int cnss_pci_set_dsp_link_status(struct cnss_pci_data *pci_priv,
+				 bool link_enable);
+int cnss_pci_get_dsp_link_status(struct cnss_pci_data *pci_priv);
+int cnss_pci_dsp_link_enable(struct cnss_pci_data *pci_priv);
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed);
 #else
 int _cnss_pci_enumerate(struct cnss_plat_data *plat_priv, u32 rc_num)
 {
@@ -204,6 +211,33 @@ void cnss_pci_update_drv_supported(struct cnss_pci_data *pci_priv)
 	pci_priv->drv_supported = false;
 }
 
+int cnss_pci_dsp_link_control(struct cnss_pci_data *pci_priv,
+			      bool link_enable)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_set_dsp_link_status(struct cnss_pci_data *pci_priv,
+				 bool link_enable)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_get_dsp_link_status(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_dsp_link_enable(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed)
+{
+	return -EOPNOTSUPP;
+}
 #endif /* CONFIG_PCI_MSM */
 
 static inline bool cnss_pci_get_drv_supported(struct cnss_pci_data *pci_priv)

+ 152 - 2
cnss2/pci_qcom.c

@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */
+/* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
 
 #include "pci_platform.h"
 #include "debug.h"
@@ -34,9 +34,32 @@ static struct cnss_msi_config msi_config_one_msi = {
 };
 #endif
 
+#define ENUM_RETRY_MAX_TIMES 8
+#define ENUM_RETRY_DELAY_MS 500
+
 int _cnss_pci_enumerate(struct cnss_plat_data *plat_priv, u32 rc_num)
 {
-	return msm_pcie_enumerate(rc_num);
+	u32 retry = 0;
+	int ret;
+
+	if (plat_priv->pcie_switch_type == PCIE_SWITCH_NTN3) {
+		while (retry++ < ENUM_RETRY_MAX_TIMES) {
+			ret = msm_pcie_enumerate(rc_num);
+			/* For PCIe switch platform, cnss_probe may called
+			 * before PCIe switch hardware ready, wait for
+			 * msm_pcie_enumerate complete.
+			 */
+			if (ret == -EPROBE_DEFER) {
+				cnss_pr_dbg("PCIe RC%d not ready, retry:%dth\n",
+					    rc_num, retry);
+				msleep(ENUM_RETRY_DELAY_MS);
+			}
+		}
+	} else {
+		return msm_pcie_enumerate(rc_num);
+	}
+
+	return ret;
 }
 
 int cnss_pci_assert_perst(struct cnss_pci_data *pci_priv)
@@ -139,6 +162,7 @@ static int cnss_pci_set_link_up(struct cnss_pci_data *pci_priv)
 static int cnss_pci_set_link_down(struct cnss_pci_data *pci_priv)
 {
 	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
 	enum msm_pcie_pm_opt pm_ops;
 	u32 pm_options = PM_OPTIONS_DEFAULT;
 	int ret;
@@ -147,6 +171,10 @@ static int cnss_pci_set_link_down(struct cnss_pci_data *pci_priv)
 		cnss_pr_vdbg("Use PCIe DRV suspend\n");
 		pm_ops = MSM_PCIE_DRV_SUSPEND;
 	} else {
+		if (plat_priv && PCIE_SWITCH_NTN3 == plat_priv->pcie_switch_type) {
+			cnss_pr_dbg("Skip suspend from client side for pcie switch case\n");
+			return 0;
+		}
 		pm_ops = MSM_PCIE_SUSPEND;
 	}
 
@@ -403,6 +431,128 @@ retry:
 	return ret;
 }
 
+#ifdef CONFIG_PCIE_SWITCH_SUPPORT
+int cnss_pci_dsp_link_control(struct cnss_pci_data *pci_priv,
+			      bool link_enable)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	pci_priv->pci_dsp_link_status = link_enable;
+	return msm_pcie_dsp_link_control(pci_priv->pci_dev, link_enable);
+}
+
+int cnss_pci_set_dsp_link_status(struct cnss_pci_data *pci_priv,
+				 bool link_enable)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	pci_priv->pci_dsp_link_status = link_enable;
+
+	return 0;
+}
+
+int cnss_pci_get_dsp_link_status(struct cnss_pci_data *pci_priv)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	return pci_priv->pci_dsp_link_status;
+}
+
+int cnss_pci_dsp_link_enable(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	int retry_count = 0;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+	/* For PCIe switch platform, wait for link train of DSP<->WLAN complete
+	 */
+	while (retry_count++ < DSP_LINK_ENABLE_RETRY_COUNT_MAX) {
+		ret = cnss_pci_dsp_link_control(pci_priv, true);
+		if (!ret)
+			break;
+
+		cnss_pci_dsp_link_control(pci_priv, false);
+		cnss_pr_err("DSP<->WLAN link train failed, retry...\n");
+		cnss_select_pinctrl_state(plat_priv, false);
+		usleep_range(DSP_LINK_ENABLE_DELAY_TIME_US_MIN,
+			     DSP_LINK_ENABLE_DELAY_TIME_US_MAX);
+		ret = cnss_select_pinctrl_enable(plat_priv);
+		if (ret) {
+			cnss_pr_err("Failed to select pinctrl state, err = %d\n", ret);
+			return ret;
+		}
+		usleep_range(DSP_LINK_ENABLE_DELAY_TIME_US_MIN,
+			     DSP_LINK_ENABLE_DELAY_TIME_US_MAX);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_PCIE_SWITCH_RETRAIN_LINK_SUPPORT
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed)
+{
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Setting DSP <-> EP link speed:0x%x\n", target_link_speed);
+
+	ret = msm_pcie_retrain_port_link(pci_priv->pci_dev, target_link_speed);
+	if (ret) {
+		cnss_pr_err("Failed to retrain link, err = %d\n", ret);
+		return ret;
+	}
+
+	pci_priv->def_link_speed = target_link_speed;
+
+	return ret;
+}
+#else
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+#else
+int cnss_pci_dsp_link_control(struct cnss_pci_data *pci_priv,
+			      bool link_enable)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_set_dsp_link_status(struct cnss_pci_data *pci_priv,
+				 bool link_enable)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_get_dsp_link_status(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_dsp_link_enable(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 int cnss_pci_prevent_l1(struct device *dev)
 {
 	struct pci_dev *pci_dev = to_pci_dev(dev);

+ 34 - 4
cnss2/power.c

@@ -19,6 +19,7 @@
 #include "debug.h"
 #include "bus.h"
 #include <linux/soc/qcom/qcom_aoss.h>
+#include "pci_platform.h"
 
 #if IS_ENABLED(CONFIG_ARCH_QCOM)
 static struct cnss_vreg_cfg cnss_vreg_list[] = {
@@ -1008,8 +1009,8 @@ retry_gpio_req:
 	gpio_free(xo_clk_gpio);
 }
 
-static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
-				     bool state)
+int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
+			      bool state)
 {
 	int ret = 0;
 	struct cnss_pinctrl_info *pinctrl_info;
@@ -1105,7 +1106,7 @@ out:
  *
  * Return: Status of pinctrl select operation. 0 - Success.
  */
-static int cnss_select_pinctrl_enable(struct cnss_plat_data *plat_priv)
+int cnss_select_pinctrl_enable(struct cnss_plat_data *plat_priv)
 {
 	int ret = 0, bt_en_gpio = plat_priv->pinctrl_info.bt_en_gpio;
 	u8 wlan_en_state = 0;
@@ -1157,6 +1158,7 @@ int cnss_get_input_gpio_value(struct cnss_plat_data *plat_priv, int gpio_num)
 int cnss_power_on_device(struct cnss_plat_data *plat_priv, bool reset)
 {
 	int ret = 0;
+	int dsp_link_status = -1;
 
 	if (plat_priv->powered_on) {
 		cnss_pr_dbg("Already powered up");
@@ -1169,6 +1171,12 @@ int cnss_power_on_device(struct cnss_plat_data *plat_priv, bool reset)
 		return -EINVAL;
 	}
 
+	/* For PCIe switch platform, disable DSP downstream link before power
+	 * on/off wlan device to avoid uncorrectable AER erro on DSP side.
+	 */
+	cnss_bus_set_dsp_link_status(plat_priv, true);
+	cnss_bus_dsp_link_control(plat_priv, false);
+
 	ret = cnss_vreg_on_type(plat_priv, CNSS_VREG_PRIM);
 	if (ret) {
 		cnss_pr_err("Failed to turn on vreg, err = %d\n", ret);
@@ -1207,6 +1215,17 @@ int cnss_power_on_device(struct cnss_plat_data *plat_priv, bool reset)
 		goto clk_off;
 	}
 
+	/* For PCIe switch platform, wait for link train of DSP<->WLAN complete
+	 */
+	dsp_link_status = cnss_bus_get_dsp_link_status(plat_priv);
+	if (dsp_link_status == PCI_DSP_LINK_DISABLE) {
+		ret = cnss_bus_dsp_link_enable(plat_priv);
+		if (ret) {
+			cnss_pr_err("Failed to enable bus dsp link, err = %d\n", ret);
+			goto clk_off;
+		}
+	}
+
 	plat_priv->powered_on = true;
 	clear_bit(CNSS_POWER_OFF, &plat_priv->driver_state);
 	cnss_enable_dev_sol_irq(plat_priv);
@@ -1229,6 +1248,7 @@ void cnss_power_off_device(struct cnss_plat_data *plat_priv)
 		return;
 	}
 
+	cnss_bus_dsp_link_control(plat_priv, false);
 	set_bit(CNSS_POWER_OFF, &plat_priv->driver_state);
 	cnss_bus_shutdown_cleanup(plat_priv);
 	cnss_disable_dev_sol_irq(plat_priv);
@@ -1415,17 +1435,27 @@ static int
 cnss_mbox_send_msg(struct cnss_plat_data *plat_priv, char *mbox_msg)
 {
 	struct qmp_pkt pkt;
+	int mbox_msg_size;
 	int ret = 0;
 
 	if (!plat_priv->mbox_chan)
 		return -ENODEV;
 
+	mbox_msg_size = strlen(mbox_msg) + 1;
+
+	if (mbox_msg_size > CNSS_MBOX_MSG_MAX_LEN) {
+		cnss_pr_err("message length greater than max length\n");
+		return -EINVAL;
+	}
+
 	cnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
-	pkt.size = CNSS_MBOX_MSG_MAX_LEN;
+	pkt.size = mbox_msg_size;
 	pkt.data = mbox_msg;
 	ret = mbox_send_message(plat_priv->mbox_chan, &pkt);
 	if (ret < 0)
 		cnss_pr_err("Failed to send AOP mbox msg: %s\n", mbox_msg);
+	else
+		ret = 0;
 
 	return ret;
 }

+ 4 - 4
cnss2/qmi.c

@@ -1429,9 +1429,9 @@ end:
 	return ret;
 }
 
-void cnss_get_qdss_cfg_filename(struct cnss_plat_data *plat_priv,
-				char *filename, u32 filename_len,
-				bool fallback_file)
+static void cnss_get_qdss_cfg_filename(struct cnss_plat_data *plat_priv,
+				       char *filename, u32 filename_len,
+				       bool fallback_file)
 {
 	char filename_tmp[MAX_FIRMWARE_NAME_LEN];
 	char *build_str = QDSS_FILE_BUILD_STR;
@@ -3957,7 +3957,7 @@ void cnss_unregister_coex_service(struct cnss_plat_data *plat_priv)
 }
 
 /* IMS Service */
-int ims_subscribe_for_indication_send_async(struct cnss_plat_data *plat_priv)
+static int ims_subscribe_for_indication_send_async(struct cnss_plat_data *plat_priv)
 {
 	int ret;
 	struct ims_private_service_subscribe_for_indications_req_msg_v01 *req;

+ 2 - 0
cnss_genl/Makefile

@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+ccflags-y += -Wmissing-prototypes
+
 ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc
 endif

+ 2 - 0
cnss_prealloc/Makefile

@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+ccflags-y += -Wmissing-prototypes
+
 ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/cnss_utils

+ 2 - 2
cnss_prealloc/cnss_prealloc.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2012,2014-2017,2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -182,7 +182,7 @@ static void cnss_pool_deinit(void)
 	}
 }
 
-void cnss_assign_prealloc_pool(unsigned long device_id)
+static void cnss_assign_prealloc_pool(unsigned long device_id)
 {
 	pr_info("cnss_prealloc: assign cnss pool for device id 0x%lx", device_id);
 

+ 2 - 0
cnss_utils/Makefile

@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+ccflags-y += -Wmissing-prototypes
+
 ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc
 endif

+ 5 - 5
cnss_utils/cnss_plat_ipc_qmi.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021, 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -108,8 +108,8 @@ static void cnss_plat_ipc_logging_deinit(void)
 	}
 }
 
-void cnss_plat_ipc_debug_log_print(void *log_ctx, char *process, const char *fn,
-				   const char *log_level, char *fmt, ...)
+static void cnss_plat_ipc_debug_log_print(void *log_ctx, char *process, const char *fn,
+					  const char *log_level, char *fmt, ...)
 {
 	struct va_format vaf;
 	va_list va_args;
@@ -132,8 +132,8 @@ void cnss_plat_ipc_debug_log_print(void *log_ctx, char *process, const char *fn,
 static void cnss_plat_ipc_logging_init(void) {};
 static void cnss_plat_ipc_logging_deinit(void) {};
 
-void cnss_plat_ipc_debug_log_print(void *log_ctx, char *process, const char *fn,
-				   const char *log_level, char *fmt, ...)
+static void cnss_plat_ipc_debug_log_print(void *log_ctx, char *process, const char *fn,
+					  const char *log_level, char *fmt, ...)
 {
 	struct va_format vaf;
 	va_list va_args;

+ 2 - 0
icnss2/Makefile

@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+ccflags-y += -Wmissing-prototypes
+
 ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/cnss_utils
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc

+ 2 - 0
icnss2/genl.c

@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2020, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */
 
 #define pr_fmt(fmt) "cnss_genl: " fmt
 
@@ -11,6 +12,7 @@
 
 #include "main.h"
 #include "debug.h"
+#include "genl.h"
 
 #define ICNSS_GENL_FAMILY_NAME "cnss-genl"
 #define ICNSS_GENL_MCAST_GROUP_NAME "cnss-genl-grp"

+ 231 - 12
icnss2/main.c

@@ -413,6 +413,217 @@ bool icnss_is_fw_ready(void)
 }
 EXPORT_SYMBOL(icnss_is_fw_ready);
 
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+/**
+ * icnss_register_bus_scale() - Setup interconnect voting data
+ * @plat_priv: Platform data structure
+ *
+ * For different interconnect path configured in device tree setup voting data
+ * for list of bandwidth requirements.
+ *
+ * Result: 0 for success. -EINVAL if not configured
+ */
+static int icnss_register_bus_scale(struct icnss_priv *plat_priv)
+{
+	int ret = -EINVAL;
+	u32 idx, i, j, cfg_arr_size, *cfg_arr = NULL;
+	struct icnss_bus_bw_info *bus_bw_info, *tmp;
+	struct device *dev = &plat_priv->pdev->dev;
+
+	INIT_LIST_HEAD(&plat_priv->icc.list_head);
+	ret = of_property_read_u32(dev->of_node,
+				   "qcom,icc-path-count",
+				   &plat_priv->icc.path_count);
+	if (ret) {
+		icnss_pr_dbg("Platform Bus Interconnect path not configured\n");
+		return 0;
+	}
+
+	ret = of_property_read_u32(plat_priv->pdev->dev.of_node,
+				   "qcom,bus-bw-cfg-count",
+				   &plat_priv->icc.bus_bw_cfg_count);
+	if (ret) {
+		icnss_pr_err("Failed to get Bus BW Config table size\n");
+		goto cleanup;
+	}
+
+	cfg_arr_size = plat_priv->icc.path_count *
+			plat_priv->icc.bus_bw_cfg_count * ICNSS_ICC_VOTE_MAX;
+	cfg_arr = kcalloc(cfg_arr_size, sizeof(*cfg_arr), GFP_KERNEL);
+	if (!cfg_arr) {
+		icnss_pr_err("Failed to alloc cfg table mem\n");
+		ret = -ENOMEM;
+		goto cleanup;
+	}
+
+	ret = of_property_read_u32_array(plat_priv->pdev->dev.of_node,
+					 "qcom,bus-bw-cfg", cfg_arr,
+					 cfg_arr_size);
+	if (ret) {
+		icnss_pr_err("Invalid Bus BW Config Table\n");
+		goto cleanup;
+	}
+
+	icnss_pr_dbg("ICC Path_Count: %d BW_CFG_Count: %d\n",
+		     plat_priv->icc.path_count,
+		     plat_priv->icc.bus_bw_cfg_count);
+
+	for (idx = 0; idx < plat_priv->icc.path_count; idx++) {
+		bus_bw_info = devm_kzalloc(dev, sizeof(*bus_bw_info),
+					   GFP_KERNEL);
+		if (!bus_bw_info) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		ret = of_property_read_string_index(dev->of_node,
+						    "interconnect-names", idx,
+						    &bus_bw_info->icc_name);
+		if (ret)
+			goto out;
+
+		bus_bw_info->icc_path =
+			of_icc_get(&plat_priv->pdev->dev,
+				   bus_bw_info->icc_name);
+
+		if (IS_ERR(bus_bw_info->icc_path))  {
+			ret = PTR_ERR(bus_bw_info->icc_path);
+			if (ret != -EPROBE_DEFER) {
+				icnss_pr_err("Failed to get Interconnect path for %s. Err: %d\n",
+					     bus_bw_info->icc_name, ret);
+				goto out;
+			}
+		}
+
+		bus_bw_info->cfg_table =
+			devm_kcalloc(dev, plat_priv->icc.bus_bw_cfg_count,
+				     sizeof(*bus_bw_info->cfg_table),
+				     GFP_KERNEL);
+		if (!bus_bw_info->cfg_table) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		icnss_pr_dbg("ICC Vote CFG for path: %s\n",
+			     bus_bw_info->icc_name);
+
+		for (i = 0, j = (idx * plat_priv->icc.bus_bw_cfg_count *
+		     ICNSS_ICC_VOTE_MAX);
+		     i < plat_priv->icc.bus_bw_cfg_count;
+		     i++, j += 2) {
+			bus_bw_info->cfg_table[i].avg_bw = cfg_arr[j];
+			bus_bw_info->cfg_table[i].peak_bw = cfg_arr[j + 1];
+
+			icnss_pr_dbg("ICC Vote BW: %d avg: %d peak: %d\n",
+				     i, bus_bw_info->cfg_table[i].avg_bw,
+				     bus_bw_info->cfg_table[i].peak_bw);
+		}
+		list_add_tail(&bus_bw_info->list,
+			      &plat_priv->icc.list_head);
+	}
+	kfree(cfg_arr);
+	return 0;
+out:
+	list_for_each_entry_safe(bus_bw_info, tmp,
+				 &plat_priv->icc.list_head, list) {
+		list_del(&bus_bw_info->list);
+	}
+cleanup:
+	kfree(cfg_arr);
+	memset(&plat_priv->icc, 0, sizeof(plat_priv->icc));
+	return ret;
+}
+
+static void icnss_unregister_bus_scale(struct icnss_priv *plat_priv)
+{
+	struct icnss_bus_bw_info *bus_bw_info, *tmp;
+
+	list_for_each_entry_safe(bus_bw_info, tmp,
+				 &plat_priv->icc.list_head, list) {
+		list_del(&bus_bw_info->list);
+		if (bus_bw_info->icc_path)
+			icc_put(bus_bw_info->icc_path);
+	}
+	memset(&plat_priv->icc, 0, sizeof(plat_priv->icc));
+}
+
+/**
+ * icnss_setup_bus_bandwidth() - Setup interconnect vote for given bandwidth
+ * @plat_priv: Platform private data struct
+ * @bw: bandwidth
+ * @save: toggle flag to save bandwidth to current_bw_vote
+ *
+ * Setup bandwidth votes for configured interconnect paths
+ *
+ * Return: 0 for success
+ */
+static int icnss_setup_bus_bandwidth(struct icnss_priv *plat_priv,
+				     u32 bw, bool save)
+{
+	int ret = 0;
+	struct icnss_bus_bw_info *bus_bw_info;
+
+	if (!plat_priv->icc.path_count)
+		return -EOPNOTSUPP;
+
+	if (bw >= plat_priv->icc.bus_bw_cfg_count) {
+		icnss_pr_err("Invalid bus bandwidth Type: %d", bw);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(bus_bw_info, &plat_priv->icc.list_head, list) {
+		ret = icc_set_bw(bus_bw_info->icc_path,
+				 bus_bw_info->cfg_table[bw].avg_bw,
+				 bus_bw_info->cfg_table[bw].peak_bw);
+		if (ret) {
+			icnss_pr_err("Could not set BW Cfg: %d, err = %d ICC Path: %s Val: %d %d\n",
+				     bw, ret, bus_bw_info->icc_name,
+				     bus_bw_info->cfg_table[bw].avg_bw,
+				     bus_bw_info->cfg_table[bw].peak_bw);
+			break;
+		}
+	}
+
+	if (ret == 0 && save)
+		plat_priv->icc.current_bw_vote = bw;
+
+	return ret;
+}
+
+int icnss_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+	struct icnss_priv *plat_priv = dev_get_drvdata(dev);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (bandwidth < 0)
+		return -EINVAL;
+
+	return icnss_setup_bus_bandwidth(plat_priv, (u32)bandwidth, true);
+}
+
+#else
+static int icnss_register_bus_scale(struct icnss_priv *plat_priv)
+{
+	return 0;
+}
+
+static void icnss_unregister_bus_scale(struct icnss_priv *plat_priv) {}
+
+static int icnss_setup_bus_bandwidth(struct icnss_priv *plat_priv,
+				     u32 bw, bool save)
+{
+	return 0;
+}
+
+int icnss_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+	return 0;
+}
+#endif /* CONFIG_INTERCONNECT */
+EXPORT_SYMBOL(icnss_request_bus_bandwidth);
+
 void icnss_block_shutdown(bool status)
 {
 	if (!penv)
@@ -1309,7 +1520,7 @@ static int icnss_driver_event_fw_init_done(struct icnss_priv *priv, void *data)
 	return ret;
 }
 
-int icnss_alloc_qdss_mem(struct icnss_priv *priv)
+static int icnss_alloc_qdss_mem(struct icnss_priv *priv)
 {
 	struct platform_device *pdev = priv->pdev;
 	struct icnss_fw_mem *qdss_mem = priv->qdss_mem;
@@ -1642,8 +1853,8 @@ static int icnss_fw_crashed(struct icnss_priv *priv,
 	return 0;
 }
 
-int icnss_update_hang_event_data(struct icnss_priv *priv,
-				 struct icnss_uevent_hang_data *hang_data)
+static int icnss_update_hang_event_data(struct icnss_priv *priv,
+					struct icnss_uevent_hang_data *hang_data)
 {
 	if (!priv->hang_event_data_va)
 		return -EINVAL;
@@ -1661,7 +1872,7 @@ int icnss_update_hang_event_data(struct icnss_priv *priv,
 	return 0;
 }
 
-int icnss_send_hang_event_data(struct icnss_priv *priv)
+static int icnss_send_hang_event_data(struct icnss_priv *priv)
 {
 	struct icnss_uevent_hang_data hang_data = {0};
 	int ret = 0xFF;
@@ -2215,12 +2426,14 @@ static int icnss_wpss_notifier_nb(struct notifier_block *nb,
 
 	switch (code) {
 	case QCOM_SSR_BEFORE_SHUTDOWN:
+		priv->notif_crashed = notif->crashed;
 		break;
 	case QCOM_SSR_AFTER_SHUTDOWN:
 		/* Collect ramdump only when there was a crash. */
-		if (notif->crashed) {
+		if (priv->notif_crashed) {
 			icnss_pr_info("Collecting msa0 segment dump\n");
 			icnss_msa0_ramdump(priv);
+			priv->notif_crashed = false;
 		}
 		goto out;
 	default:
@@ -2745,7 +2958,7 @@ fail_alloc_major:
 	return ret;
 }
 
-void *icnss_create_ramdump_device(struct icnss_priv *priv, const char *dev_name)
+static void *icnss_create_ramdump_device(struct icnss_priv *priv, const char *dev_name)
 {
 	int ret = 0;
 	struct icnss_ramdump_info *ramdump_info;
@@ -3759,14 +3972,14 @@ struct iommu_domain *icnss_smmu_get_domain(struct device *dev)
 EXPORT_SYMBOL(icnss_smmu_get_domain);
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
-int icnss_iommu_map(struct iommu_domain *domain,
-				   unsigned long iova, phys_addr_t paddr, size_t size, int prot)
+static int icnss_iommu_map(struct iommu_domain *domain,
+			   unsigned long iova, phys_addr_t paddr, size_t size, int prot)
 {
 		return iommu_map(domain, iova, paddr, size, prot);
 }
 #else
-int icnss_iommu_map(struct iommu_domain *domain,
-				   unsigned long iova, phys_addr_t paddr, size_t size, int prot)
+static int icnss_iommu_map(struct iommu_domain *domain,
+			   unsigned long iova, phys_addr_t paddr, size_t size, int prot)
 {
 		return iommu_map(domain, iova, paddr, size, prot, GFP_KERNEL);
 }
@@ -4815,10 +5028,14 @@ static int icnss_probe(struct platform_device *pdev)
 	if (ret)
 		goto out_free_resources;
 
-	ret = icnss_smmu_dt_parse(priv);
+	ret = icnss_register_bus_scale(priv);
 	if (ret)
 		goto out_free_resources;
 
+	ret = icnss_smmu_dt_parse(priv);
+	if (ret)
+		goto unreg_bus_scale;
+
 	spin_lock_init(&priv->event_lock);
 	spin_lock_init(&priv->on_off_lock);
 	spin_lock_init(&priv->soc_wake_msg_lock);
@@ -4919,6 +5136,8 @@ out_destroy_wq:
 	destroy_workqueue(priv->event_wq);
 smmu_cleanup:
 	priv->iommu_domain = NULL;
+unreg_bus_scale:
+	icnss_unregister_bus_scale(priv);
 out_free_resources:
 	icnss_put_resources(priv);
 out_reset_drvdata:
@@ -4927,7 +5146,7 @@ out_reset_drvdata:
 	return ret;
 }
 
-void icnss_destroy_ramdump_device(struct icnss_ramdump_info *ramdump_info)
+static void icnss_destroy_ramdump_device(struct icnss_ramdump_info *ramdump_info)
 {
 
 	if (IS_ERR_OR_NULL(ramdump_info))

+ 51 - 0
icnss2/main.h

@@ -20,6 +20,9 @@
 #else
 #include <soc/qcom/icnss2.h>
 #endif
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+#include <linux/interconnect.h>
+#endif
 #include "wlan_firmware_service_v01.h"
 #include "cnss_prealloc.h"
 #include "cnss_common.h"
@@ -53,6 +56,50 @@ struct icnss_control_params {
 	unsigned int bdf_type;
 };
 
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+/**
+ * struct icnss_bus_bw_cfg - Interconnect vote data
+ * @avg_bw: Vote for average bandwidth
+ * @peak_bw: Vote for peak bandwidth
+ */
+struct icnss_bus_bw_cfg {
+	u32 avg_bw;
+	u32 peak_bw;
+};
+
+/* Number of bw votes (avg, peak) entries that ICC requires */
+#define ICNSS_ICC_VOTE_MAX 2
+
+/**
+ * struct icnss_bus_bw_info - Bus bandwidth config for interconnect path
+ * @list: Kernel linked list
+ * @icc_name: Name of interconnect path as defined in Device tree
+ * @icc_path: Interconnect path data structure
+ * @cfg_table: Interconnect vote data for average and peak bandwidth
+ */
+struct icnss_bus_bw_info {
+	struct list_head list;
+	const char *icc_name;
+	struct icc_path *icc_path;
+	struct icnss_bus_bw_cfg *cfg_table;
+};
+
+/**
+ * struct icnss_interconnect_cfg - ICNSS platform interconnect config
+ * @list_head: List of interconnect path bandwidth configs
+ * @path_count: Count of interconnect path configured in device tree
+ * @current_bw_vote: WLAN driver provided bandwidth vote
+ * @bus_bw_cfg_count: Number of bandwidth configs for voting. It is the array
+ * size of struct icnss_bus_bw_info.cfg_table
+ */
+struct icnss_interconnect_cfg {
+	struct list_head list_head;
+	u32 path_count;
+	int current_bw_vote;
+	u32 bus_bw_cfg_count;
+};
+#endif
+
 enum icnss_driver_event_type {
 	ICNSS_DRIVER_EVENT_SERVER_ARRIVE,
 	ICNSS_DRIVER_EVENT_SERVER_EXIT,
@@ -411,6 +458,9 @@ struct icnss_priv {
 	struct list_head soc_wake_msg_list;
 	spinlock_t event_lock;
 	spinlock_t soc_wake_msg_lock;
+	#if IS_ENABLED(CONFIG_INTERCONNECT)
+	struct icnss_interconnect_cfg icc;
+	#endif
 	struct work_struct event_work;
 	struct work_struct fw_recv_msg_work;
 	struct work_struct soc_wake_msg_work;
@@ -440,6 +490,7 @@ struct icnss_priv {
 	void *modem_notify_handler;
 	void *wpss_notify_handler;
 	void *wpss_early_notify_handler;
+	bool notif_crashed;
 	struct notifier_block modem_ssr_nb;
 	struct notifier_block wpss_ssr_nb;
 	struct notifier_block wpss_early_ssr_nb;

+ 2 - 2
icnss2/power.c

@@ -436,8 +436,8 @@ int icnss_vreg_unvote(struct icnss_priv *priv)
 	return 0;
 }
 
-int icnss_get_clk_single(struct icnss_priv *priv,
-			 struct icnss_clk_info *clk_info)
+static int icnss_get_clk_single(struct icnss_priv *priv,
+				struct icnss_clk_info *clk_info)
 {
 	struct device *dev = &priv->pdev->dev;
 	struct clk *clk;

+ 4 - 4
icnss2/qmi.c

@@ -1656,8 +1656,8 @@ int wlfw_qdss_trace_stop(struct icnss_priv *priv, unsigned long long option)
 					     option);
 }
 
-int wlfw_wlan_cfg_send_sync_msg(struct icnss_priv *priv,
-				struct wlfw_wlan_cfg_req_msg_v01 *data)
+static int wlfw_wlan_cfg_send_sync_msg(struct icnss_priv *priv,
+				       struct wlfw_wlan_cfg_req_msg_v01 *data)
 {
 	int ret;
 	struct wlfw_wlan_cfg_req_msg_v01 *req;
@@ -2156,7 +2156,7 @@ out:
 	return ret;
 }
 
-void icnss_handle_rejuvenate(struct icnss_priv *priv)
+static void icnss_handle_rejuvenate(struct icnss_priv *priv)
 {
 	struct icnss_event_pd_service_down_data *event_data;
 	struct icnss_uevent_fw_down_data fw_down_data = {0};
@@ -3802,7 +3802,7 @@ out:
 }
 
 /* IMS Service */
-int ims_subscribe_for_indication_send_async(struct icnss_priv *priv)
+static int ims_subscribe_for_indication_send_async(struct icnss_priv *priv)
 {
 	int ret;
 	struct ims_private_service_subscribe_for_indications_req_msg_v01 *req;

+ 1 - 0
inc/cnss2.h

@@ -452,6 +452,7 @@ extern int cnss_send_buffer_to_afcmem(struct device *dev, const uint8_t *afcdb,
 extern int cnss_reset_afcmem(struct device *dev, uint8_t slotid);
 extern bool cnss_get_fw_cap(struct device *dev, enum cnss_fw_caps fw_cap);
 extern bool cnss_audio_is_direct_link_supported(struct device *dev);
+extern bool cnss_ipa_wlan_shared_smmu_supported(struct device *dev);
 extern int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg);
 extern int cnss_thermal_cdev_register(struct device *dev,
 				      unsigned long max_state,

+ 1 - 0
inc/icnss2.h

@@ -189,6 +189,7 @@ extern int icnss_wlan_disable(struct device *dev, enum icnss_driver_mode mode);
 extern void icnss_enable_irq(struct device *dev, unsigned int ce_id);
 extern void icnss_disable_irq(struct device *dev, unsigned int ce_id);
 extern int icnss_get_soc_info(struct device *dev, struct icnss_soc_info *info);
+extern int icnss_request_bus_bandwidth(struct device *dev, int bandwidth);
 extern int icnss_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx);
 extern int icnss_ce_request_irq(struct device *dev, unsigned int ce_id,
 	irqreturn_t (*handler)(int, void *),