Преглед на файлове

Merge 90e0212ecc7a7870e5222176ce75d4f5ede5aeb3 on remote branch

Change-Id: I3e43fdfc6597b6c4082f499ac92e43af8df3513e
Linux Build Service Account преди 2 години
родител
ревизия
db90870578
променени са 25 файла, в които са добавени 794 реда и са изтрити 83 реда
  1. 34 0
      BUILD.bazel
  2. 10 0
      Kbuild
  3. 12 0
      build/pineapple_consolidate_defconfig
  4. 12 0
      build/pineapple_gki_defconfig
  5. 30 0
      cnss2/Kconfig
  6. 0 16
      cnss2/bus.h
  7. 35 0
      cnss2/debug.c
  8. 78 16
      cnss2/main.c
  9. 15 1
      cnss2/main.h
  10. 130 4
      cnss2/pci.c
  11. 12 0
      cnss2/pci.h
  12. 8 3
      cnss2/pci_qcom.c
  13. 82 26
      cnss2/power.c
  14. 13 0
      cnss2/qmi.c
  15. 5 0
      cnss_genl/Kconfig
  16. 5 0
      cnss_prealloc/Kconfig
  17. 1 0
      cnss_prealloc/Makefile
  18. 58 9
      cnss_prealloc/cnss_prealloc.c
  19. 5 0
      cnss_utils/Kconfig
  20. 25 0
      cnss_utils/cnss_common.h
  21. 23 0
      icnss2/main.c
  22. 2 3
      icnss2/main.h
  23. 5 5
      inc/cnss2.h
  24. 2 0
      inc/cnss_prealloc.h
  25. 192 0
      wlan_platform_modules.bzl

+ 34 - 0
BUILD.bazel

@@ -0,0 +1,34 @@
+load("//build/kernel/kleaf:kernel.bzl", "ddk_headers")
+load(":wlan_platform_modules.bzl", "define_modules")
+
+
+package(
+    default_visibility = [
+        "//visibility:public",
+    ],
+)
+
+ddk_headers(
+    name = "wlan-platform-headers",
+    hdrs = glob([
+        "inc/*.h",
+    ]),
+    includes = ["inc"],
+)
+
+ddk_headers(
+    name = "wlan-platform-private-headers",
+    hdrs = glob([
+        "cnss2/*.h",
+        "cnss_utils/*.h",
+        "icnss2/*.h"
+    ]),
+    includes = ["cnss2", "cnss_utils", "icnss2"],
+)
+
+ddk_headers(
+    name = "all-wlan-platform-headers",
+    hdrs = [":wlan-platform-headers", ":wlan-platform-private-headers"],
+)
+
+define_modules()

+ 10 - 0
Kbuild

@@ -22,6 +22,12 @@ ifeq ($(CONFIG_ICNSS2_QMI),y)
 KBUILD_CPPFLAGS += -DCONFIG_ICNSS2_QMI
 endif
 
+# CONFIG_WCNSS_MEM_PRE_ALLOC should never be "y" here since it
+# can be only compiled as a module from out-of-kernel-tree source.
+ifeq ($(CONFIG_WCNSS_MEM_PRE_ALLOC),m)
+KBUILD_CPPFLAGS += -DCONFIG_WCNSS_MEM_PRE_ALLOC
+endif
+
 # CONFIG_CNSS_PLAT_IPC_QMI_SVC should never be "y" here since it
 # can be only compiled as a module from out-of-kernel-tree source.
 ifeq ($(CONFIG_CNSS_PLAT_IPC_QMI_SVC),m)
@@ -60,6 +66,10 @@ ifeq ($(CONFIG_DISABLE_CNSS_SRAM_DUMP),y)
 KBUILD_CPPFLAGS += -DCONFIG_DISABLE_CNSS_SRAM_DUMP
 endif
 
+ifeq ($(CONFIG_CNSS2_SMMU_DB_SUPPORT),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS2_SMMU_DB_SUPPORT
+endif
+
 obj-$(CONFIG_CNSS2) += cnss2/
 obj-$(CONFIG_ICNSS2) += icnss2/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/

+ 12 - 0
build/pineapple_consolidate_defconfig

@@ -0,0 +1,12 @@
+CONFIG_CNSS2=y
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=y
+CONFIG_CNSS_GENL=y
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS_HW_SECURE_DISABLE=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS_UTILS=y

+ 12 - 0
build/pineapple_gki_defconfig

@@ -0,0 +1,12 @@
+CONFIG_CNSS2=y
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=y
+CONFIG_CNSS_GENL=y
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS_HW_SECURE_DISABLE=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS_UTILS=y

+ 30 - 0
cnss2/Kconfig

@@ -126,3 +126,33 @@ config DISABLE_CNSS_SRAM_DUMP
 	  If enabled, CNSS plafrom driver will not dump sram when MHI power on
 	  timeout for CNSS QCA6490 chipset only. Since this feature about
 	  sram dump costs 4M memory.
+
+config CNSS2_SMMU_DB_SUPPORT
+	bool "Enable early trace stop support"
+	depends on CNSS2
+	help
+	  If enabled, CNSS platform driver will notify wlan fw to stop
+	  traces by ringing MHI host doorbell register. This feature helps
+	  to get traces which contain smmu fault address and enables
+	  debugging.
+
+config CNSS_HW_SECURE_DISABLE
+	bool "Enable HW secure disable"
+	depends on CNSS2
+	help
+	  If enabled, WLAN HW can be securely disabled. It would be able to
+	  handle WLAN cold boot initialization sequence changes if HW is
+	  disabled at boot and WLAN resume sequence after WLAN HW is enabled.
+
+config CNSS2_SSR_DRIVER_DUMP
+	bool "Enable Host SSR DRIVER DUMP Collection"
+	depends on CNSS2
+	help
+	  If enabled, host driver dump will be collected upon SSR.
+
+config CNSS_OUT_OF_TREE
+	bool "Enable Out of Tree Usage"
+	depends on CNSS2
+	help
+	  If enabled, CNSS platform driver modules would be able to access
+	  functions from the other modules in the platform driver.

+ 0 - 16
cnss2/bus.h

@@ -9,25 +9,9 @@
 
 #include "main.h"
 
-#define QCA6174_VENDOR_ID		0x168C
-#define QCA6174_DEVICE_ID		0x003E
 #define QCA6174_REV_ID_OFFSET		0x08
 #define QCA6174_REV3_VERSION		0x5020000
 #define QCA6174_REV3_2_VERSION		0x5030000
-#define QCA6290_VENDOR_ID		0x17CB
-#define QCA6290_DEVICE_ID		0x1100
-#define QCA6390_VENDOR_ID		0x17CB
-#define QCA6390_DEVICE_ID		0x1101
-#define QCA6490_VENDOR_ID		0x17CB
-#define QCA6490_DEVICE_ID		0x1103
-#define QCN7605_VENDOR_ID               0x17CB
-#define QCN7605_DEVICE_ID               0x1102
-#define KIWI_VENDOR_ID			0x17CB
-#define KIWI_DEVICE_ID			0x1107
-#define MANGO_VENDOR_ID			0x17CB
-#define MANGO_DEVICE_ID			0x110A
-#define PEACH_VENDOR_ID			0x17CB
-#define PEACH_DEVICE_ID			0x110E
 
 enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev);
 enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv);

+ 35 - 0
cnss2/debug.c

@@ -914,6 +914,39 @@ static const struct file_operations cnss_dynamic_feature_fops = {
 	.llseek = seq_lseek,
 };
 
+static int cnss_smmu_fault_timestamp_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *plat_priv = s->private;
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	seq_printf(s, "smmu irq cb entry timestamp : %llu ns\n",
+		   pci_priv->smmu_fault_timestamp[SMMU_CB_ENTRY]);
+	seq_printf(s, "smmu irq cb before doorbell ring timestamp : %llu ns\n",
+		   pci_priv->smmu_fault_timestamp[SMMU_CB_DOORBELL_RING]);
+	seq_printf(s, "smmu irq cb after doorbell ring timestamp : %llu ns\n",
+		   pci_priv->smmu_fault_timestamp[SMMU_CB_EXIT]);
+
+	return 0;
+}
+
+static int cnss_smmu_fault_timestamp_open(struct inode *inode,
+					  struct file *file)
+{
+	return single_open(file, cnss_smmu_fault_timestamp_show,
+			   inode->i_private);
+}
+
+static const struct file_operations cnss_smmu_fault_timestamp_fops = {
+	.read = seq_read,
+	.release = single_release,
+	.open = cnss_smmu_fault_timestamp_open,
+	.owner = THIS_MODULE,
+	.llseek = seq_lseek,
+};
+
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_CNSS2_DEBUG
 static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
@@ -932,6 +965,8 @@ static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
 			    &cnss_control_params_debug_fops);
 	debugfs_create_file("dynamic_feature", 0600, root_dentry, plat_priv,
 			    &cnss_dynamic_feature_fops);
+	debugfs_create_file("cnss_smmu_fault_timestamp", 0600, root_dentry,
+			    plat_priv, &cnss_smmu_fault_timestamp_fops);
 
 	return 0;
 }

+ 78 - 16
cnss2/main.c

@@ -288,6 +288,14 @@ cnss_get_pld_bus_ops_name(struct cnss_plat_data *plat_priv)
 }
 #endif
 
+void cnss_get_sleep_clk_supported(struct cnss_plat_data *plat_priv)
+{
+	plat_priv->sleep_clk = of_property_read_bool(plat_priv->dev_node,
+						     "qcom,sleep-clk-support");
+	cnss_pr_dbg("qcom,sleep-clk-support is %d\n",
+		    plat_priv->sleep_clk);
+}
+
 void cnss_get_bwscal_info(struct cnss_plat_data *plat_priv)
 {
 	plat_priv->no_bwscale = of_property_read_bool(plat_priv->dev_node,
@@ -1340,7 +1348,9 @@ int cnss_idle_restart(struct device *dev)
 	ret = cnss_driver_event_post(plat_priv,
 				     CNSS_DRIVER_EVENT_IDLE_RESTART,
 				     CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
-	if (ret)
+	if (ret == -EINTR && plat_priv->device_id != QCA6174_DEVICE_ID)
+		cnss_pr_err("Idle restart has been interrupted but device power up is still in progress");
+	else if (ret)
 		goto out;
 
 	if (plat_priv->device_id == QCA6174_DEVICE_ID) {
@@ -1874,18 +1884,29 @@ static void cnss_recovery_work_handler(struct work_struct *work)
 {
 }
 #else
-static void cnss_recovery_work_handler(struct work_struct *work)
+void cnss_recovery_handler(struct cnss_plat_data *plat_priv)
 {
 	int ret;
 
-	struct cnss_plat_data *plat_priv =
-		container_of(work, struct cnss_plat_data, recovery_work);
+	set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
 
 	if (!plat_priv->recovery_enabled)
 		panic("subsys-restart: Resetting the SoC wlan crashed\n");
 
 	cnss_bus_dev_shutdown(plat_priv);
 	cnss_bus_dev_ramdump(plat_priv);
+
+	/* If recovery is triggered before Host driver registration,
+	 * avoid device power up because eventually device will be
+	 * power up as part of driver registration.
+	 */
+	if (!test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state) ||
+	    !test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Host driver not registered yet, ignore Device Power Up, 0x%lx\n",
+			    plat_priv->driver_state);
+		return;
+	}
+
 	msleep(POWER_RESET_MIN_DELAY_MS);
 
 	ret = cnss_bus_dev_powerup(plat_priv);
@@ -1895,6 +1916,14 @@ static void cnss_recovery_work_handler(struct work_struct *work)
 	return;
 }
 
+static void cnss_recovery_work_handler(struct work_struct *work)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(work, struct cnss_plat_data, recovery_work);
+
+	cnss_recovery_handler(plat_priv);
+}
+
 void cnss_device_crashed(struct device *dev)
 {
 	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
@@ -2002,6 +2031,18 @@ self_recovery:
 		clear_bit(LINK_DOWN_SELF_RECOVERY,
 			  &plat_priv->ctrl_params.quirks);
 
+	/* If link down self recovery is triggered before Host driver
+	 * registration, avoid device power up because eventually device
+	 * will be power up as part of driver registration.
+	 */
+
+	if (!test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state) ||
+	    !test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Host driver not registered yet, ignore Device Power Up, 0x%lx\n",
+			    plat_priv->driver_state);
+		return 0;
+	}
+
 	cnss_bus_dev_powerup(plat_priv);
 
 	return 0;
@@ -3132,10 +3173,6 @@ int cnss_do_host_ramdump(struct cnss_plat_data *plat_priv,
 		[CNSS_HOST_WMI_EVENT_LOG] = "wmi_event_log",
 		[CNSS_HOST_WMI_RX_EVENT] = "wmi_rx_event",
 		[CNSS_HOST_HAL_SOC] = "hal_soc",
-		[CNSS_HOST_WMI_HANG_DATA] = "wmi_hang_data",
-		[CNSS_HOST_CE_HANG_EVT] = "ce_hang_evt",
-		[CNSS_HOST_PEER_MAC_ADDR_HANG_DATA] = "peer_mac_addr_hang_data",
-		[CNSS_HOST_CP_VDEV_INFO] = "cp_vdev_info",
 		[CNSS_HOST_GWLAN_LOGGING] = "gwlan_logging",
 		[CNSS_HOST_WMI_DEBUG_LOG_INFO] = "wmi_debug_log_info",
 		[CNSS_HOST_HTC_CREDIT_IDX] = "htc_credit_history_idx",
@@ -3143,7 +3180,10 @@ int cnss_do_host_ramdump(struct cnss_plat_data *plat_priv,
 		[CNSS_HOST_WMI_TX_CMP_IDX] = "wmi_tx_cmp_idx",
 		[CNSS_HOST_WMI_COMMAND_LOG_IDX] = "wmi_command_log_idx",
 		[CNSS_HOST_WMI_EVENT_LOG_IDX] = "wmi_event_log_idx",
-		[CNSS_HOST_WMI_RX_EVENT_IDX] = "wmi_rx_event_idx"
+		[CNSS_HOST_WMI_RX_EVENT_IDX] = "wmi_rx_event_idx",
+		[CNSS_HOST_HIF_CE_DESC_HISTORY] = "hif_ce_desc_history",
+		[CNSS_HOST_HIF_CE_DESC_HISTORY_BUFF] = "hif_ce_desc_history_buff",
+		[CNSS_HOST_HANG_EVENT_DATA] = "hang_event_data"
 	};
 	int i;
 	int ret = 0;
@@ -3918,15 +3958,16 @@ static ssize_t shutdown_store(struct device *dev,
 {
 	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
 
+	cnss_pr_dbg("Received shutdown notification\n");
 	if (plat_priv) {
 		set_bit(CNSS_IN_REBOOT, &plat_priv->driver_state);
+		cnss_bus_update_status(plat_priv, CNSS_SYS_REBOOT);
 		del_timer(&plat_priv->fw_boot_timer);
 		complete_all(&plat_priv->power_up_complete);
 		complete_all(&plat_priv->cal_complete);
+		cnss_pr_dbg("Shutdown notification handled\n");
 	}
 
-	cnss_pr_dbg("Received shutdown notification\n");
-
 	return count;
 }
 
@@ -4174,6 +4215,7 @@ static int cnss_reboot_notifier(struct notifier_block *nb,
 		container_of(nb, struct cnss_plat_data, reboot_nb);
 
 	set_bit(CNSS_IN_REBOOT, &plat_priv->driver_state);
+	cnss_bus_update_status(plat_priv, CNSS_SYS_REBOOT);
 	del_timer(&plat_priv->fw_boot_timer);
 	complete_all(&plat_priv->power_up_complete);
 	complete_all(&plat_priv->cal_complete);
@@ -4268,6 +4310,24 @@ static void cnss_sram_dump_init(struct cnss_plat_data *plat_priv)
 }
 #endif
 
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+static void cnss_initialize_mem_pool(unsigned long device_id)
+{
+	cnss_initialize_prealloc_pool(device_id);
+}
+static void cnss_deinitialize_mem_pool(void)
+{
+	cnss_deinitialize_prealloc_pool();
+}
+#else
+static void cnss_initialize_mem_pool(unsigned long device_id)
+{
+}
+static void cnss_deinitialize_mem_pool(void)
+{
+}
+#endif
+
 static int cnss_misc_init(struct cnss_plat_data *plat_priv)
 {
 	int ret;
@@ -4858,6 +4918,8 @@ static int cnss_probe(struct platform_device *plat_dev)
 		goto reset_plat_dev;
 	}
 
+	cnss_initialize_mem_pool(plat_priv->device_id);
+
 	ret = cnss_get_pld_bus_ops_name(plat_priv);
 	if (ret)
 		cnss_pr_err("Failed to find bus ops name, err = %d\n",
@@ -4884,7 +4946,7 @@ static int cnss_probe(struct platform_device *plat_dev)
 	cnss_power_misc_params_init(plat_priv);
 	cnss_get_tcs_info(plat_priv);
 	cnss_get_cpr_info(plat_priv);
-	cnss_aop_mbox_init(plat_priv);
+	cnss_aop_interface_init(plat_priv);
 	cnss_init_control_params(plat_priv);
 
 	ret = cnss_get_resources(plat_priv);
@@ -4960,7 +5022,9 @@ unreg_esoc:
 free_res:
 	cnss_put_resources(plat_priv);
 reset_ctx:
+	cnss_aop_interface_deinit(plat_priv);
 	platform_set_drvdata(plat_dev, NULL);
+	cnss_deinitialize_mem_pool();
 reset_plat_dev:
 	cnss_clear_plat_priv(plat_priv);
 out:
@@ -4986,10 +5050,8 @@ static int cnss_remove(struct platform_device *plat_dev)
 	cnss_unregister_bus_scale(plat_priv);
 	cnss_unregister_esoc(plat_priv);
 	cnss_put_resources(plat_priv);
-
-	if (!IS_ERR_OR_NULL(plat_priv->mbox_chan))
-		mbox_free_channel(plat_priv->mbox_chan);
-
+	cnss_aop_interface_deinit(plat_priv);
+	cnss_deinitialize_mem_pool();
 	platform_set_drvdata(plat_dev, NULL);
 	cnss_clear_plat_priv(plat_priv);
 

+ 15 - 1
cnss2/main.h

@@ -23,6 +23,10 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/time64.h>
+#if IS_ENABLED(CONFIG_MSM_QMP)
+#include <linux/mailbox/qmp.h>
+#include <linux/soc/qcom/qcom_aoss.h>
+#endif
 #ifdef CONFIG_CNSS_OUT_OF_TREE
 #include "cnss2.h"
 #else
@@ -41,6 +45,8 @@
 #endif
 #include <linux/iommu.h>
 #include "qmi.h"
+#include "cnss_prealloc.h"
+#include "cnss_common.h"
 
 #define MAX_NO_OF_MAC_ADDR		4
 #define QMI_WLFW_MAX_TIMESTAMP_LEN	32
@@ -586,6 +592,10 @@ struct cnss_plat_data {
 	u8 charger_mode;
 	struct mbox_client mbox_client_data;
 	struct mbox_chan *mbox_chan;
+#if IS_ENABLED(CONFIG_MSM_QMP)
+	struct qmp *qmp;
+#endif
+	bool use_direct_qmp;
 	const char *vreg_ol_cpr, *vreg_ipa;
 	const char **pdc_init_table, **vreg_pdc_map, **pmu_vreg_map;
 	int pdc_init_table_len, vreg_pdc_map_len, pmu_vreg_map_len;
@@ -610,6 +620,7 @@ struct cnss_plat_data {
 	u32 on_chip_pmic_devices_count;
 	u32 *on_chip_pmic_board_ids;
 	bool no_bwscale;
+	bool sleep_clk;
 };
 
 #if IS_ENABLED(CONFIG_ARCH_QCOM)
@@ -642,6 +653,7 @@ struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num);
 int cnss_get_plat_env_count(void);
 struct cnss_plat_data *cnss_get_plat_env(int index);
 void cnss_get_qrtr_info(struct cnss_plat_data *plat_priv);
+void cnss_get_sleep_clk_supported(struct cnss_plat_data *plat_priv);
 void cnss_get_bwscal_info(struct cnss_plat_data *plat_priv);
 bool cnss_is_dual_wlan_enabled(void);
 int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
@@ -695,7 +707,8 @@ int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv);
 int cnss_get_tcs_info(struct cnss_plat_data *plat_priv);
 unsigned int cnss_get_timeout(struct cnss_plat_data *plat_priv,
 			      enum cnss_timeout_type);
-int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv);
+int cnss_aop_interface_init(struct cnss_plat_data *plat_priv);
+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);
@@ -713,4 +726,5 @@ int cnss_get_feature_list(struct cnss_plat_data *plat_priv,
 int cnss_get_input_gpio_value(struct cnss_plat_data *plat_priv, int gpio_num);
 bool cnss_check_driver_loading_allowed(void);
 int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv);
+void cnss_recovery_handler(struct cnss_plat_data *plat_priv);
 #endif /* _CNSS_MAIN_H */

+ 130 - 4
cnss2/pci.c

@@ -819,6 +819,13 @@ static int cnss_mhi_device_get_sync_atomic(struct cnss_pci_data *pci_priv,
 					  timeout_us, in_panic);
 }
 
+#ifdef CONFIG_CNSS2_SMMU_DB_SUPPORT
+static int cnss_mhi_host_notify_db_disable_trace(struct cnss_pci_data *pci_priv)
+{
+	return mhi_host_notify_db_disable_trace(pci_priv->mhi_ctrl);
+}
+#endif
+
 static void
 cnss_mhi_controller_set_bw_scale_cb(struct cnss_pci_data *pci_priv,
 				    int (*cb)(struct mhi_controller *mhi_ctrl,
@@ -875,6 +882,13 @@ static int cnss_mhi_device_get_sync_atomic(struct cnss_pci_data *pci_priv,
 	return -EOPNOTSUPP;
 }
 
+#ifdef CONFIG_CNSS2_SMMU_DB_SUPPORT
+static int cnss_mhi_host_notify_db_disable_trace(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 static void
 cnss_mhi_controller_set_bw_scale_cb(struct cnss_pci_data *pci_priv,
 				    int (*cb)(struct mhi_controller *mhi_ctrl,
@@ -893,6 +907,51 @@ void cnss_mhi_controller_set_base(struct cnss_pci_data *pci_priv,
 }
 #endif /* CONFIG_MHI_BUS_MISC */
 
+#ifdef CONFIG_CNSS2_SMMU_DB_SUPPORT
+#define CNSS_MHI_WAKE_TIMEOUT		500000
+
+static void cnss_record_smmu_fault_timestamp(struct cnss_pci_data *pci_priv,
+					     enum cnss_smmu_fault_time id)
+{
+	if (id >= SMMU_CB_MAX)
+		return;
+
+	pci_priv->smmu_fault_timestamp[id] = sched_clock();
+}
+
+static void cnss_pci_smmu_fault_handler_irq(struct iommu_domain *domain,
+					    void *handler_token)
+{
+	struct cnss_pci_data *pci_priv = handler_token;
+	int ret = 0;
+
+	cnss_record_smmu_fault_timestamp(pci_priv, SMMU_CB_ENTRY);
+	ret = cnss_mhi_device_get_sync_atomic(pci_priv,
+					      CNSS_MHI_WAKE_TIMEOUT, true);
+	if (ret < 0) {
+		cnss_pr_err("Failed to bring mhi in M0 state, ret %d\n", ret);
+		return;
+	}
+
+	cnss_record_smmu_fault_timestamp(pci_priv, SMMU_CB_DOORBELL_RING);
+	ret = cnss_mhi_host_notify_db_disable_trace(pci_priv);
+	if (ret < 0)
+		cnss_pr_err("Fail to notify wlan fw to stop trace collection, ret %d\n", ret);
+
+	cnss_record_smmu_fault_timestamp(pci_priv, SMMU_CB_EXIT);
+}
+
+void cnss_register_iommu_fault_handler_irq(struct cnss_pci_data *pci_priv)
+{
+	qcom_iommu_set_fault_handler_irq(pci_priv->iommu_domain,
+					 cnss_pci_smmu_fault_handler_irq, pci_priv);
+}
+#else
+void cnss_register_iommu_fault_handler_irq(struct cnss_pci_data *pci_priv)
+{
+}
+#endif
+
 int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv)
 {
 	u16 device_id;
@@ -2062,11 +2121,48 @@ out:
 	return ret;
 }
 
+static int cnss_pci_config_msi_addr(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_dev)
+		return -ENODEV;
+
+	if (!pci_dev->msix_enabled)
+		return ret;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32(plat_priv->plat_dev->dev.of_node,
+				   "msix-match-addr",
+				   &pci_priv->msix_addr);
+	cnss_pr_dbg("MSI-X Match address is 0x%X\n",
+		    pci_priv->msix_addr);
+
+	return ret;
+}
+
 static int cnss_pci_config_msi_data(struct cnss_pci_data *pci_priv)
 {
 	struct msi_desc *msi_desc;
+	struct cnss_msi_config *msi_config;
 	struct pci_dev *pci_dev = pci_priv->pci_dev;
 
+	msi_config = pci_priv->msi_config;
+
+	if (pci_dev->msix_enabled) {
+		pci_priv->msi_ep_base_data = msi_config->users[0].base_vector;
+		cnss_pr_dbg("MSI-X base data is %d\n",
+			    pci_priv->msi_ep_base_data);
+		return 0;
+	}
+
 	msi_desc = irq_get_msi_desc(pci_dev->irq);
 	if (!msi_desc) {
 		cnss_pr_err("msi_desc is NULL!\n");
@@ -4459,8 +4555,8 @@ int cnss_pci_qmi_send_put(struct cnss_pci_data *pci_priv)
 	return ret;
 }
 
-int cnss_send_buffer_to_afcmem(struct device *dev, char *afcdb, uint32_t len,
-			       uint8_t slotid)
+int cnss_send_buffer_to_afcmem(struct device *dev, const uint8_t *afcdb,
+			       uint32_t len, uint8_t slotid)
 {
 	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
 	struct cnss_fw_mem *fw_mem;
@@ -5018,7 +5114,7 @@ static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv)
 	num_vectors = pci_alloc_irq_vectors(pci_dev,
 					    msi_config->total_vectors,
 					    msi_config->total_vectors,
-					    PCI_IRQ_MSI);
+					    PCI_IRQ_MSI | PCI_IRQ_MSIX);
 	if ((num_vectors != msi_config->total_vectors) &&
 	    !cnss_pci_fallback_one_msi(pci_priv, &num_vectors)) {
 		cnss_pr_err("Failed to get enough MSI vectors (%d), available vectors = %d",
@@ -5028,6 +5124,11 @@ static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv)
 		goto reset_msi_config;
 	}
 
+	if (cnss_pci_config_msi_addr(pci_priv)) {
+		ret = -EINVAL;
+		goto free_msi_vector;
+	}
+
 	if (cnss_pci_config_msi_data(pci_priv)) {
 		ret = -EINVAL;
 		goto free_msi_vector;
@@ -5119,8 +5220,25 @@ void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
 			  u32 *msi_addr_high)
 {
 	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv;
 	u16 control;
 
+	if (!pci_dev)
+		return;
+
+	pci_priv = cnss_get_pci_priv(pci_dev);
+	if (!pci_priv)
+		return;
+
+	if (pci_dev->msix_enabled) {
+		*msi_addr_low = pci_priv->msix_addr;
+		*msi_addr_high = 0;
+		if (!print_optimize.msi_addr_chk++)
+			cnss_pr_dbg("Get MSI low addr = 0x%x, high addr = 0x%x\n",
+				    *msi_addr_low, *msi_addr_high);
+		return;
+	}
+
 	pci_read_config_word(pci_dev, pci_dev->msi_cap + PCI_MSI_FLAGS,
 			     &control);
 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
@@ -5824,7 +5942,13 @@ void cnss_pci_device_crashed(struct cnss_pci_data *pci_priv)
 
 	if (plat_priv->recovery_enabled)
 		cnss_pci_collect_host_dump_info(pci_priv);
-	cnss_device_crashed(&pci_priv->pci_dev->dev);
+
+	/* Call recovery handler in the DRIVER_RECOVERY event context
+	 * instead of scheduling work. In that way complete recovery
+	 * will be done as part of DRIVER_RECOVERY event and get
+	 * serialized with other events.
+	 */
+	cnss_recovery_handler(plat_priv);
 }
 
 static int cnss_mhi_pm_runtime_get(struct mhi_controller *mhi_ctrl)
@@ -6762,6 +6886,8 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
 		goto reset_ctx;
 	}
 
+	cnss_get_sleep_clk_supported(plat_priv);
+
 	ret = cnss_dev_specific_power_on(plat_priv);
 	if (ret < 0)
 		goto reset_ctx;

+ 12 - 0
cnss2/pci.h

@@ -9,6 +9,7 @@
 
 #include <linux/cma.h>
 #include <linux/iommu.h>
+#include <linux/qcom-iommu-util.h>
 #include <linux/mhi.h>
 #if IS_ENABLED(CONFIG_MHI_BUS_MISC)
 #include <linux/mhi_misc.h>
@@ -18,6 +19,7 @@
 #endif
 #include <linux/of_reserved_mem.h>
 #include <linux/pci.h>
+#include <linux/sched_clock.h>
 
 #include "main.h"
 
@@ -71,6 +73,13 @@ enum cnss_pci_reg_dev_mask {
 	REG_MASK_PEACH,
 };
 
+enum cnss_smmu_fault_time {
+	SMMU_CB_ENTRY,
+	SMMU_CB_DOORBELL_RING,
+	SMMU_CB_EXIT,
+	SMMU_CB_MAX,
+};
+
 struct cnss_msi_user {
 	char *name;
 	int num_vectors;
@@ -151,6 +160,7 @@ struct cnss_pci_data {
 	void __iomem *bar;
 	struct cnss_msi_config *msi_config;
 	u32 msi_ep_base_data;
+	u32 msix_addr;
 	struct mhi_controller *mhi_ctrl;
 	unsigned long mhi_state;
 	u32 remap_window;
@@ -168,6 +178,7 @@ struct cnss_pci_data {
 	u8 iommu_geometry;
 	bool drv_supported;
 	bool is_smmu_fault;
+	unsigned long long smmu_fault_timestamp[SMMU_CB_MAX];
 };
 
 static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data)
@@ -313,4 +324,5 @@ int cnss_pci_get_user_msi_assignment(struct cnss_pci_data *pci_priv,
 				     int *num_vectors,
 				     u32 *user_base_data,
 				     u32 *base_vector);
+void cnss_register_iommu_fault_handler_irq(struct cnss_pci_data *pci_priv);
 #endif /* _CNSS_PCI_H */

+ 8 - 3
cnss2/pci_qcom.c

@@ -579,6 +579,7 @@ int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
 		pci_priv->smmu_s1_enable = true;
 		iommu_set_fault_handler(pci_priv->iommu_domain,
 					cnss_pci_smmu_fault_handler, pci_priv);
+		cnss_register_iommu_fault_handler_irq(pci_priv);
 	}
 
 	ret = of_property_read_u32_array(of_node,  "qcom,iommu-dma-addr-pool",
@@ -643,9 +644,13 @@ int cnss_pci_of_reserved_mem_device_init(struct cnss_pci_data *pci_priv)
 	 * attached to platform device of_node.
 	 */
 	ret = of_reserved_mem_device_init(dev_pci);
-	if (ret)
-		cnss_pr_err("Failed to init reserved mem device, err = %d\n",
-			    ret);
+	if (ret) {
+		if (ret == -EINVAL)
+			cnss_pr_vdbg("Ignore, no specific reserved-memory assigned\n");
+		else
+			cnss_pr_err("Failed to init reserved mem device, err = %d\n",
+				    ret);
+	}
 	if (dev_pci->cma_area)
 		cnss_pr_dbg("CMA area is %s\n",
 			    cma_get_name(dev_pci->cma_area));

+ 82 - 26
cnss2/power.c

@@ -6,9 +6,6 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
-#if IS_ENABLED(CONFIG_MSM_QMP)
-#include <linux/mailbox/qmp.h>
-#endif
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/pinctrl/consumer.h>
@@ -1323,36 +1320,78 @@ out:
 }
 
 #if IS_ENABLED(CONFIG_MSM_QMP)
-int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv)
+/**
+ * cnss_aop_interface_init: Initialize AOP interface: either mbox channel or direct QMP
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Device tree file should have either mbox or qmp configured, but not both.
+ * Based on device tree configuration setup mbox channel or QMP
+ *
+ * Return: 0 for success, otherwise error code
+ */
+int cnss_aop_interface_init(struct cnss_plat_data *plat_priv)
 {
 	struct mbox_client *mbox = &plat_priv->mbox_client_data;
 	struct mbox_chan *chan;
 	int ret;
 
 	plat_priv->mbox_chan = NULL;
+	plat_priv->qmp = NULL;
+	plat_priv->use_direct_qmp = false;
 
 	mbox->dev = &plat_priv->plat_dev->dev;
 	mbox->tx_block = true;
 	mbox->tx_tout = CNSS_MBOX_TIMEOUT_MS;
 	mbox->knows_txdone = false;
 
+	/* First try to get mbox channel, if it fails then try qmp_get
+	 * In device tree file there should be either mboxes or qmp,
+	 * cannot have both properties at the same time.
+	 */
 	chan = mbox_request_channel(mbox, 0);
 	if (IS_ERR(chan)) {
-		cnss_pr_err("Failed to get mbox channel\n");
-		return PTR_ERR(chan);
+		cnss_pr_dbg("Failed to get mbox channel, try qmp get\n");
+		plat_priv->qmp = qmp_get(&plat_priv->plat_dev->dev);
+		if (IS_ERR(plat_priv->qmp)) {
+			cnss_pr_err("Failed to get qmp\n");
+			return PTR_ERR(plat_priv->qmp);
+		} else {
+			plat_priv->use_direct_qmp = true;
+			cnss_pr_dbg("QMP initialized\n");
+		}
+	} else {
+		plat_priv->mbox_chan = chan;
+		cnss_pr_dbg("Mbox channel initialized\n");
 	}
 
-	plat_priv->mbox_chan = chan;
-	cnss_pr_dbg("Mbox channel initialized\n");
 	ret = cnss_aop_pdc_reconfig(plat_priv);
 	if (ret)
 		cnss_pr_err("Failed to reconfig WLAN PDC, err = %d\n", ret);
 
-	return 0;
+	return ret;
 }
 
 /**
- * cnss_aop_send_msg: Sends json message to AOP using QMP
+ * cnss_aop_interface_deinit: Cleanup AOP interface
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Cleanup mbox channel or QMP whichever was configured during initialization.
+ *
+ * Return: None
+ */
+void cnss_aop_interface_deinit(struct cnss_plat_data *plat_priv)
+{
+	if (!IS_ERR_OR_NULL(plat_priv->mbox_chan))
+		mbox_free_channel(plat_priv->mbox_chan);
+
+	if (!IS_ERR_OR_NULL(plat_priv->qmp)) {
+		qmp_put(plat_priv->qmp);
+		plat_priv->use_direct_qmp = false;
+	}
+}
+
+/**
+ * cnss_aop_send_msg: Sends json message to AOP using either mbox channel or direct QMP
  * @plat_priv: Pointer to cnss platform data
  * @msg: String in json format
  *
@@ -1370,15 +1409,24 @@ int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *mbox_msg)
 	struct qmp_pkt pkt;
 	int ret = 0;
 
-	cnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
-	pkt.size = CNSS_MBOX_MSG_MAX_LEN;
-	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;
+	if (plat_priv->use_direct_qmp) {
+		cnss_pr_dbg("Sending AOP QMP msg: %s\n", mbox_msg);
+		ret = qmp_send(plat_priv->qmp, mbox_msg, CNSS_MBOX_MSG_MAX_LEN);
+		if (ret < 0)
+			cnss_pr_err("Failed to send AOP QMP msg: %s\n", mbox_msg);
+		else
+			ret = 0;
+	} else {
+		cnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
+		pkt.size = CNSS_MBOX_MSG_MAX_LEN;
+		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;
 }
@@ -1470,11 +1518,13 @@ int cnss_aop_ol_cpr_cfg_setup(struct cnss_plat_data *plat_priv,
 	if (config_done)
 		return 0;
 
-	if (plat_priv->pmu_vreg_map_len <= 0 || !plat_priv->mbox_chan ||
-	    !plat_priv->pmu_vreg_map) {
-		cnss_pr_dbg("Mbox channel / PMU VReg Map not configured\n");
+	if (plat_priv->pmu_vreg_map_len <= 0 ||
+	    !plat_priv->pmu_vreg_map ||
+	    (!plat_priv->mbox_chan && !plat_priv->qmp)) {
+		cnss_pr_dbg("Mbox channel / QMP / PMU VReg Map not configured\n");
 		goto end;
 	}
+
 	if (!fw_pmu_cfg)
 		return -EINVAL;
 
@@ -1574,11 +1624,15 @@ end:
 }
 
 #else
-int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv)
+int cnss_aop_interface_init(struct cnss_plat_data *plat_priv)
 {
 	return 0;
 }
 
+void cnss_aop_interface_deinit(struct cnss_plat_data *plat_priv)
+{
+}
+
 int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *msg)
 {
 	return 0;
@@ -1726,8 +1780,9 @@ int cnss_update_cpr_info(struct cnss_plat_data *plat_priv)
 	if (plat_priv->device_id != QCA6490_DEVICE_ID)
 		return -EINVAL;
 
-	if (!plat_priv->vreg_ol_cpr || !plat_priv->mbox_chan) {
-		cnss_pr_dbg("Mbox channel / OL CPR Vreg not configured\n");
+	if (!plat_priv->vreg_ol_cpr ||
+	    (!plat_priv->mbox_chan && !plat_priv->qmp)) {
+		cnss_pr_dbg("Mbox channel / QMP / OL CPR Vreg not configured\n");
 	} else {
 		return cnss_aop_set_vreg_param(plat_priv,
 					       plat_priv->vreg_ol_cpr,
@@ -1806,8 +1861,9 @@ int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv)
 		return 0;
 	}
 
-	if (!plat_priv->vreg_ipa || !plat_priv->mbox_chan) {
-		cnss_pr_dbg("Mbox channel / IPA Vreg not configured\n");
+	if (!plat_priv->vreg_ipa ||
+	    (!plat_priv->mbox_chan && !plat_priv->qmp)) {
+		cnss_pr_dbg("Mbox channel / QMP / IPA Vreg not configured\n");
 	} else {
 		ret = cnss_aop_set_vreg_param(plat_priv,
 					      plat_priv->vreg_ipa,

+ 13 - 0
cnss2/qmi.c

@@ -57,6 +57,11 @@
 #define QMI_WLFW_MAC_READY_TIMEOUT_MS	50
 #define QMI_WLFW_MAC_READY_MAX_RETRY	200
 
+enum nm_modem_bit {
+	SLEEP_CLOCK_SELECT_INTERNAL_BIT = BIT(1),
+	HOST_CSTATE_BIT = BIT(2),
+};
+
 #ifdef CONFIG_CNSS2_DEBUG
 static bool ignore_qmi_failure;
 #define CNSS_QMI_ASSERT() CNSS_ASSERT(ignore_qmi_failure)
@@ -309,6 +314,14 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
 	req->cal_done = plat_priv->cal_done;
 	cnss_pr_dbg("Calibration done is %d\n", plat_priv->cal_done);
 
+	if (plat_priv->sleep_clk) {
+		req->nm_modem_valid = 1;
+		/* Notify firmware about the sleep clock selection,
+		 * nm_modem_bit[1] is used for this purpose.
+		 */
+		req->nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT;
+	}
+
 	if (cnss_bus_is_smmu_s1_enabled(plat_priv) &&
 	    !cnss_bus_get_iova(plat_priv, &iova_start, &iova_size) &&
 	    !cnss_bus_get_iova_ipa(plat_priv, &iova_ipa_start,

+ 5 - 0
cnss_genl/Kconfig

@@ -7,3 +7,8 @@ config CNSS_GENL
 	  used by cld driver and userspace utilities to communicate over
 	  netlink sockets. This module creates different multicast groups to
 	  facilitate the same.
+
+config CNSS_OUT_OF_TREE
+	bool "Build module out-of-tree"
+	help
+	  This enables building the module out of the main kernel tree

+ 5 - 0
cnss_prealloc/Kconfig

@@ -7,3 +7,8 @@ config WCNSS_MEM_PRE_ALLOC
 	  This feature enable cld wlan driver to use pre allocated memory
 	  for it's internal usage and release it to back to pre allocated pool.
 	  This memory is allocated at the cold boot time.
+
+config CNSS_OUT_OF_TREE
+	bool "Build module out-of-tree"
+	help
+	  This enables building the module out of the main kernel tree

+ 1 - 0
cnss_prealloc/Makefile

@@ -2,6 +2,7 @@
 
 ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/cnss_utils
 endif
 
 obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc.o

+ 58 - 9
cnss_prealloc/cnss_prealloc.c

@@ -11,6 +11,7 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/version.h>
+#include "cnss_common.h"
 #ifdef CONFIG_CNSS_OUT_OF_TREE
 #include "cnss_prealloc.h"
 #else
@@ -68,7 +69,7 @@ struct cnss_pool {
  */
 
 /* size, min pool reserve, name, memorypool handler, cache handler*/
-static struct cnss_pool cnss_pools[] = {
+static struct cnss_pool cnss_pools_default[] = {
 	{8 * 1024, 16, "cnss-pool-8k", NULL, NULL},
 	{16 * 1024, 16, "cnss-pool-16k", NULL, NULL},
 	{32 * 1024, 22, "cnss-pool-32k", NULL, NULL},
@@ -76,6 +77,17 @@ static struct cnss_pool cnss_pools[] = {
 	{128 * 1024, 10, "cnss-pool-128k", NULL, NULL},
 };
 
+static struct cnss_pool cnss_pools_adrastea[] = {
+	{8 * 1024, 2, "cnss-pool-8k", NULL, NULL},
+	{16 * 1024, 10, "cnss-pool-16k", NULL, NULL},
+	{32 * 1024, 8, "cnss-pool-32k", NULL, NULL},
+	{64 * 1024, 4, "cnss-pool-64k", NULL, NULL},
+	{128 * 1024, 2, "cnss-pool-128k", NULL, NULL},
+};
+
+struct cnss_pool *cnss_pools;
+unsigned int cnss_prealloc_pool_size = ARRAY_SIZE(cnss_pools_default);
+
 /**
  * cnss_pool_alloc_threshold() - Allocation threshold
  *
@@ -104,7 +116,7 @@ static int cnss_pool_init(void)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(cnss_pools); i++) {
+	for (i = 0; i < cnss_prealloc_pool_size; i++) {
 		/* Create the slab cache */
 		cnss_pools[i].cache =
 			kmem_cache_create_usercopy(cnss_pools[i].name,
@@ -149,14 +161,51 @@ static void cnss_pool_deinit(void)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(cnss_pools); i++) {
+	for (i = 0; i < cnss_prealloc_pool_size; i++) {
 		pr_info("cnss_prealloc: destroy mempool %s\n",
 			cnss_pools[i].name);
 		mempool_destroy(cnss_pools[i].mp);
 		kmem_cache_destroy(cnss_pools[i].cache);
+		cnss_pools[i].mp = NULL;
+		cnss_pools[i].cache = NULL;
+	}
+}
+
+void cnss_assign_prealloc_pool(unsigned long device_id)
+{
+	pr_info("cnss_prealloc: assign cnss pool for device id 0x%lx", device_id);
+
+	switch (device_id) {
+	case ADRASTEA_DEVICE_ID:
+		cnss_pools = cnss_pools_adrastea;
+		cnss_prealloc_pool_size = ARRAY_SIZE(cnss_pools_adrastea);
+		break;
+	case WCN6750_DEVICE_ID:
+	case WCN6450_DEVICE_ID:
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	default:
+		cnss_pools = cnss_pools_default;
+		cnss_prealloc_pool_size = ARRAY_SIZE(cnss_pools_default);
 	}
 }
 
+void cnss_initialize_prealloc_pool(unsigned long device_id)
+{
+	cnss_assign_prealloc_pool(device_id);
+	cnss_pool_init();
+}
+EXPORT_SYMBOL(cnss_initialize_prealloc_pool);
+
+void cnss_deinitialize_prealloc_pool(void)
+{
+	cnss_pool_deinit();
+}
+EXPORT_SYMBOL(cnss_deinitialize_prealloc_pool);
+
 /**
  * cnss_pool_get_index() - Get the index of memory pool
  * @mem: Allocated memory
@@ -186,7 +235,7 @@ static int cnss_pool_get_index(void *mem)
 		return -ENOENT;
 
 	/* Check if memory belongs to a pool */
-	for (i = 0; i < ARRAY_SIZE(cnss_pools); i++) {
+	for (i = 0; i < cnss_prealloc_pool_size; i++) {
 		if (cnss_pools[i].cache == cache)
 			return i;
 	}
@@ -213,7 +262,7 @@ static int cnss_pool_get_index(void *mem)
 		return -ENOENT;
 
 	/* Check if memory belongs to a pool */
-	for (i = 0; i < ARRAY_SIZE(cnss_pools); i++) {
+	for (i = 0; i < cnss_prealloc_pool_size; i++) {
 		if (cnss_pools[i].cache == cache)
 			return i;
 	}
@@ -245,7 +294,7 @@ void *wcnss_prealloc_get(size_t size)
 
 	if (size >= cnss_pool_alloc_threshold()) {
 
-		for (i = 0; i < ARRAY_SIZE(cnss_pools); i++) {
+		for (i = 0; i < cnss_prealloc_pool_size; i++) {
 			if (cnss_pools[i].size >= size && cnss_pools[i].mp) {
 				mem = mempool_alloc(cnss_pools[i].mp, gfp_mask);
 				if (mem)
@@ -281,7 +330,7 @@ int wcnss_prealloc_put(void *mem)
 		return 0;
 
 	i = cnss_pool_get_index(mem);
-	if (i >= 0 && i < ARRAY_SIZE(cnss_pools) && cnss_pools[i].mp) {
+	if (i >= 0 && i < cnss_prealloc_pool_size && cnss_pools[i].mp) {
 		mempool_free(mem, cnss_pools[i].mp);
 		return 1;
 	}
@@ -327,12 +376,12 @@ static int __init cnss_prealloc_init(void)
 	if (!cnss_prealloc_is_valid_dt_node_found())
 		return -ENODEV;
 
-	return cnss_pool_init();
+	return 0;
 }
 
 static void __exit cnss_prealloc_exit(void)
 {
-	cnss_pool_deinit();
+	return;
 }
 
 module_init(cnss_prealloc_init);

+ 5 - 0
cnss_utils/Kconfig

@@ -18,3 +18,8 @@ config CNSS_PLAT_IPC_QMI_SVC
 	tristate "CNSS Platform QMI IPC Support"
 	help
 	  Add CNSS platform kernel and user space components IPC using QMI.
+
+config CNSS_OUT_OF_TREE
+	bool "Build module out-of-tree"
+	help
+	  This enables building the module out of the main kernel tree

+ 25 - 0
cnss_utils/cnss_common.h

@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#define QCA6174_VENDOR_ID	0x168C
+#define QCA6174_DEVICE_ID	0x003E
+#define QCA6290_VENDOR_ID	0x17CB
+#define QCA6290_DEVICE_ID	0x1100
+#define QCA6390_VENDOR_ID	0x17CB
+#define QCA6390_DEVICE_ID	0x1101
+#define QCA6490_VENDOR_ID	0x17CB
+#define QCA6490_DEVICE_ID	0x1103
+#define QCN7605_VENDOR_ID	0x17CB
+#define QCN7605_DEVICE_ID	0x1102
+#define KIWI_VENDOR_ID		0x17CB
+#define KIWI_DEVICE_ID		0x1107
+#define MANGO_VENDOR_ID		0x17CB
+#define MANGO_DEVICE_ID		0x110A
+#define PEACH_VENDOR_ID		0x17CB
+#define PEACH_DEVICE_ID		0x110E
+#define WCN6750_DEVICE_ID	0x6750
+#define WCN6450_DEVICE_ID	0x6450
+#define ADRASTEA_DEVICE_ID	0xabcd

+ 23 - 0
icnss2/main.c

@@ -4503,6 +4503,24 @@ static void rproc_restart_level_notifier(void *data, struct rproc *rproc)
 	}
 }
 
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+static void icnss_initialize_mem_pool(unsigned long device_id)
+{
+	cnss_initialize_prealloc_pool(device_id);
+}
+static void icnss_deinitialize_mem_pool(void)
+{
+	cnss_deinitialize_prealloc_pool();
+}
+#else
+static void icnss_initialize_mem_pool(unsigned long device_id)
+{
+}
+static void icnss_deinitialize_mem_pool(void)
+{
+}
+#endif
+
 static int icnss_probe(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -4541,6 +4559,8 @@ static int icnss_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&priv->clk_list);
 	icnss_allow_recursive_recovery(dev);
 
+	icnss_initialize_mem_pool(priv->device_id);
+
 	icnss_init_control_params(priv);
 
 	icnss_read_device_configs(priv);
@@ -4656,6 +4676,7 @@ smmu_cleanup:
 out_free_resources:
 	icnss_put_resources(priv);
 out_reset_drvdata:
+	icnss_deinitialize_mem_pool();
 	dev_set_drvdata(dev, NULL);
 	return ret;
 }
@@ -4750,6 +4771,8 @@ static int icnss_remove(struct platform_device *pdev)
 
 	icnss_put_resources(priv);
 
+	icnss_deinitialize_mem_pool();
+
 	dev_set_drvdata(&pdev->dev, NULL);
 
 	return 0;

+ 2 - 3
icnss2/main.h

@@ -18,12 +18,11 @@
 #include <soc/qcom/icnss2.h>
 #endif
 #include "wlan_firmware_service_v01.h"
+#include "cnss_prealloc.h"
+#include "cnss_common.h"
 #include <linux/mailbox_client.h>
 #include <linux/timer.h>
 
-#define WCN6750_DEVICE_ID 0x6750
-#define WCN6450_DEVICE_ID 0x6450
-#define ADRASTEA_DEVICE_ID 0xabcd
 #define THERMAL_NAME_LENGTH 20
 #define ICNSS_SMEM_VALUE_MASK 0xFFFFFFFF
 #define ICNSS_SMEM_SEQ_NO_POS 16

+ 5 - 5
inc/cnss2.h

@@ -86,6 +86,7 @@ enum cnss_driver_status {
 	CNSS_FW_DOWN,
 	CNSS_HANG_EVENT,
 	CNSS_BUS_EVENT,
+	CNSS_SYS_REBOOT,
 };
 
 enum cnss_host_dump_type {
@@ -96,10 +97,6 @@ enum cnss_host_dump_type {
 	CNSS_HOST_WMI_EVENT_LOG,
 	CNSS_HOST_WMI_RX_EVENT,
 	CNSS_HOST_HAL_SOC,
-	CNSS_HOST_WMI_HANG_DATA,
-	CNSS_HOST_CE_HANG_EVT,
-	CNSS_HOST_PEER_MAC_ADDR_HANG_DATA,
-	CNSS_HOST_CP_VDEV_INFO,
 	CNSS_HOST_GWLAN_LOGGING,
 	CNSS_HOST_WMI_DEBUG_LOG_INFO,
 	CNSS_HOST_HTC_CREDIT_IDX,
@@ -108,6 +105,9 @@ enum cnss_host_dump_type {
 	CNSS_HOST_WMI_COMMAND_LOG_IDX,
 	CNSS_HOST_WMI_EVENT_LOG_IDX,
 	CNSS_HOST_WMI_RX_EVENT_IDX,
+	CNSS_HOST_HIF_CE_DESC_HISTORY,
+	CNSS_HOST_HIF_CE_DESC_HISTORY_BUFF,
+	CNSS_HOST_HANG_EVENT_DATA,
 	CNSS_HOST_DUMP_TYPE_MAX,
 };
 
@@ -346,7 +346,7 @@ extern int cnss_get_pci_slot(struct device *dev);
 extern int cnss_pci_get_reg_dump(struct device *dev, uint8_t *buffer,
 				 uint32_t len);
 extern struct kobject *cnss_get_wifi_kobj(struct device *dev);
-extern int cnss_send_buffer_to_afcmem(struct device *dev, char *afcdb,
+extern int cnss_send_buffer_to_afcmem(struct device *dev, const uint8_t *afcdb,
 				      uint32_t len, uint8_t slotid);
 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);

+ 2 - 0
inc/cnss_prealloc.h

@@ -15,5 +15,7 @@ extern void *wcnss_prealloc_get(size_t size);
 extern int wcnss_prealloc_put(void *ptr);
 extern int wcnss_pre_alloc_reset(void);
 void wcnss_prealloc_check_memory_leak(void);
+extern void cnss_initialize_prealloc_pool(unsigned long device_id);
+extern void cnss_deinitialize_prealloc_pool(void);
 
 #endif /* _NET_CNSS__PREALLOC_H_ */

+ 192 - 0
wlan_platform_modules.bzl

@@ -0,0 +1,192 @@
+load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir")
+load("//build/kernel/kleaf:kernel.bzl", "ddk_module")
+load("//msm-kernel:target_variants.bzl", "get_all_variants")
+
+_module_enablement_map = {
+    # "ALL" will enable for all target/variant combos
+    "cnss2": ["ALL"],
+    # Empty list disables the module build
+    "icnss2": [],
+    "cnss_nl": ["ALL"],
+    "cnss_prealloc": ["ALL"],
+    # List specific target/variants if needed
+    "cnss_utils": [
+        "pineapple_consolidate",
+    ],
+    "wlan_firmware_service": ["ALL"],
+    "cnss_plat_ipc_qmi_svc": ["ALL"],
+}
+
+def _get_module_list(target, variant):
+    tv = "{}_{}".format(target, variant)
+
+    ret = []
+    for (mod, enabled_platforms) in _module_enablement_map.items():
+        if "ALL" in enabled_platforms or tv in enabled_platforms:
+            ret.append(mod)
+            continue
+
+    return [":{}_{}".format(tv, mod) for mod in ret]
+
+
+def _define_modules_for_target_variant(target, variant):
+    tv = "{}_{}".format(target, variant)
+
+    ddk_module(
+        name = "{}_cnss2".format(tv),
+        srcs = native.glob([
+            "cnss2/main.c",
+            "cnss2/bus.c",
+            "cnss2/debug.c",
+            "cnss2/pci.c",
+            "cnss2/pci_platform.h",
+            "cnss2/power.c",
+            "cnss2/genl.c",
+            "cnss2/*.h",
+            "cnss_utils/*.h",
+        ]),
+        includes = ["cnss", "cnss_utils"],
+        kconfig = "cnss2/Kconfig",
+        defconfig = "build/{}_defconfig".format(tv),
+        conditional_srcs =  {
+            "CONFIG_CNSS2_QMI": {
+                True: [
+                    "cnss2/qmi.c",
+                    "cnss2/coexistence_service_v01.c",
+                    "cnss2/ip_multimedia_subsystem_private_service_v01.c",
+                ]
+            },
+            "CONFIG_PCI_MSM": {
+                True: [
+                    "cnss2/pci_qcom.c",
+                ],
+            },
+        },
+        out = "cnss2.ko",
+        kernel_build = "//msm-kernel:{}".format(tv),
+        deps = [
+            "//vendor/qcom/opensource/securemsm-kernel:{}_smcinvoke_dlkm".format(tv),
+            ":{}_cnss_utils".format(tv),
+            ":{}_wlan_firmware_service".format(tv),
+            ":{}_cnss_plat_ipc_qmi_svc".format(tv),
+            "//msm-kernel:all_headers",
+            ":wlan-platform-headers",
+        ],
+    )
+
+    ddk_module(
+        name = "{}_icnss2".format(tv),
+        srcs = native.glob([
+            "icnss2/main.c",
+            "icnss2/debug.c",
+            "icnss2/power.c",
+            "icnss2/genl.c",
+            "icnss2/*.h",
+            "cnss_utils/*.h",
+        ]),
+        includes = ["icnss2", "cnss_utils"],
+        kconfig = "icnss2/Kconfig",
+        defconfig = "build/{}_defconfig".format(tv),
+        conditional_srcs = {
+            "CONFIG_ICNSS2_QMI": {
+                True: [
+                    "icnss2/qmi.c",
+                ],
+            },
+        },
+        out = "icnss2.ko",
+        kernel_build = "//msm-kernel:{}".format(tv),
+        deps = [
+            "//msm-kernel:all_headers",
+            ":wlan-platform-headers",
+        ],
+    )
+
+    ddk_module(
+        name = "{}_cnss_nl".format(tv),
+        srcs = [
+            "cnss_genl/cnss_nl.c",
+        ],
+        kconfig = "cnss_genl/Kconfig",
+        defconfig = "build/{}_defconfig".format(tv),
+        out = "cnss_nl.ko",
+        kernel_build = "//msm-kernel:{}".format(tv),
+        deps = [
+            "//msm-kernel:all_headers",
+            ":wlan-platform-headers",
+        ],
+    )
+
+    ddk_module(
+        name = "{}_cnss_prealloc".format(tv),
+        srcs = [
+            "cnss_prealloc/cnss_prealloc.c",
+        ],
+        kconfig = "cnss_prealloc/Kconfig",
+        defconfig = "build/{}_defconfig".format(tv),
+        out = "cnss_prealloc.ko",
+        kernel_build = "//msm-kernel:{}".format(tv),
+        deps = [
+            "//msm-kernel:all_headers",
+            ":wlan-platform-headers",
+        ],
+    )
+
+    ddk_module(
+        name = "{}_cnss_utils".format(tv),
+        srcs = native.glob([
+            "cnss_utils/cnss_utils.c",
+            "cnss_utils/*.h"
+        ]),
+        kconfig = "cnss_utils/Kconfig",
+        defconfig = "build/{}_defconfig".format(tv),
+        out = "cnss_utils.ko",
+        kernel_build = "//msm-kernel:{}".format(tv),
+        deps = [
+            "//msm-kernel:all_headers",
+            ":wlan-platform-headers",
+        ],
+    )
+
+    ddk_module(
+        name = "{}_wlan_firmware_service".format(tv),
+        srcs = native.glob([
+            "cnss_utils/wlan_firmware_service_v01.c",
+            "cnss_utils/device_management_service_v01.c",
+            "cnss_utils/*.h"
+        ]),
+        kconfig = "cnss_utils/Kconfig",
+        defconfig = "build/{}_defconfig".format(tv),
+        out = "wlan_firmware_service.ko",
+        kernel_build = "//msm-kernel:{}".format(tv),
+        deps = ["//msm-kernel:all_headers"],
+    )
+
+    ddk_module(
+        name = "{}_cnss_plat_ipc_qmi_svc".format(tv),
+        srcs = native.glob([
+            "cnss_utils/cnss_plat_ipc_qmi.c",
+            "cnss_utils/cnss_plat_ipc_service_v01.c",
+            "cnss_utils/*.h"
+        ]),
+        kconfig = "cnss_utils/Kconfig",
+        defconfig = "build/{}_defconfig".format(tv),
+        out = "cnss_plat_ipc_qmi_svc.ko",
+        kernel_build = "//msm-kernel:{}".format(tv),
+        deps = ["//msm-kernel:all_headers"],
+    )
+
+    copy_to_dist_dir(
+        name = "{}_modules_dist".format(tv),
+        data = _get_module_list(target, variant),
+        dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target),
+        flat = True,
+        wipe_dist_dir = False,
+        allow_duplicate_filenames = False,
+        mode_overrides = {"**/*": "644"},
+        log = "info"
+    )
+
+def define_modules():
+    for (t, v) in get_all_variants():
+        _define_modules_for_target_variant(t, v)