Browse Source

cnss2: Add support secured wlan HW disable mode

WLAN HW can be securely disabled. Add support in platform driver to
handle WLAN cold boot initialization sequence changes if HW is disabled
at boot and WLAN resume sequence after WLAN HW is enabled.

Change-Id: If5036560820c54653801298ceebe4f50b7532f3f
CRs-fixed: 3211229
Manikandan Mohan 2 years ago
parent
commit
ad4399e37a
8 changed files with 180 additions and 20 deletions
  1. 4 0
      Android.mk
  2. 4 0
      Kbuild
  3. 5 0
      cnss2/Makefile
  4. 10 0
      cnss2/debug.c
  5. 133 20
      cnss2/main.c
  6. 5 0
      cnss2/main.h
  7. 18 0
      cnss2/pci.c
  8. 1 0
      inc/cnss2.h

+ 4 - 0
Android.mk

@@ -20,6 +20,8 @@ CNSS_SRC_FILES := \
 	$(wildcard $(LOCAL_PATH)/*) \
 	$(wildcard $(LOCAL_PATH)/*/*) \
 
+KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS=$(PWD)/$(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers
+
 # Module.symvers needs to be generated as a intermediate module so that
 # other modules which depend on WLAN platform modules can set local
 # dependencies to it.
@@ -41,6 +43,8 @@ include $(DLKM_DIR)/Build_external_kernelmodule.mk
 
 ################################ cnss2 ################################
 include $(CLEAR_VARS)
+LOCAL_REQUIRED_MODULES := sec-module-symvers
+LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers
 LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
 LOCAL_MODULE              := cnss2.ko
 LOCAL_MODULE_KBUILD_NAME  := cnss2/cnss2.ko

+ 4 - 0
Kbuild

@@ -24,6 +24,10 @@ ifeq ($(CONFIG_CNSS_PLAT_IPC_QMI_SVC),m)
 KBUILD_CPPFLAGS += -DCONFIG_CNSS_PLAT_IPC_QMI_SVC
 endif
 
+ifeq ($(CONFIG_CNSS_HW_SECURE_DISABLE), y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS_HW_SECURE_DISABLE
+endif
+
 obj-$(CONFIG_CNSS2) += cnss2/
 obj-$(CONFIG_ICNSS2) += icnss2/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/

+ 5 - 0
cnss2/Makefile

@@ -7,6 +7,11 @@ else
 ccflags-y += -I$(srctree)/drivers/net/wireless/cnss_utils
 endif
 
+ifeq ($(CONFIG_CNSS_HW_SECURE_DISABLE), y)
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/../../securemsm-kernel/smcinvoke/
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/../../securemsm-kernel/linux/
+endif
+
 obj-$(CONFIG_CNSS2) += cnss2.o
 
 cnss2-y := main.o

+ 10 - 0
cnss2/debug.c

@@ -139,6 +139,12 @@ static int cnss_stats_show_state(struct seq_file *s,
 		case CNSS_DRIVER_REGISTER:
 			seq_puts(s, "DRIVER REGISTERED");
 			continue;
+		case CNSS_WLAN_HW_DISABLED:
+			seq_puts(s, "WLAN HW DISABLED");
+			continue;
+		case CNSS_FS_READY:
+			seq_puts(s, "FS READY");
+			continue;
 		}
 
 		seq_printf(s, "UNKNOWN-%d", i);
@@ -234,6 +240,10 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp,
 		if (!sptr)
 			return -EINVAL;
 		ret = cnss_aop_send_msg(plat_priv, sptr);
+	} else if (sysfs_streq(cmd, "dev_check")) {
+		cnss_wlan_hw_disable_check(plat_priv);
+	} else if (sysfs_streq(cmd, "dev_enable")) {
+		cnss_wlan_hw_enable();
 	} else {
 		pci_priv = plat_priv->bus_priv;
 		if (!pci_priv)

+ 133 - 20
cnss2/main.c

@@ -33,6 +33,16 @@
 #include "genl.h"
 #include "reg.h"
 
+#ifdef CONFIG_CNSS_HW_SECURE_DISABLE
+#include "smcinvoke.h"
+#include "smcinvoke_object.h"
+#include "IClientEnv.h"
+
+#define HW_STATE_UID 0x108
+#define HW_OP_GET_STATE 1
+#define HW_WIFI_UID 0x508
+#endif
+
 #define CNSS_DUMP_FORMAT_VER		0x11
 #define CNSS_DUMP_FORMAT_VER_V2		0x22
 #define CNSS_DUMP_MAGIC_VER_V2		0x42445953
@@ -1936,6 +1946,9 @@ static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
 	} else if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state)) {
 		cnss_pr_dbg("Calibration in progress. Ignore new calibration req\n");
 		goto out;
+	} else if (test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Calibration deferred as WLAN device disabled\n");
+		goto out;
 	}
 
 	if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
@@ -3444,6 +3457,7 @@ static ssize_t fs_ready_store(struct device *dev,
 		return count;
 	}
 
+	set_bit(CNSS_FS_READY, &plat_priv->driver_state);
 	if (fs_ready == FILE_SYSTEM_READY && plat_priv->cbc_enabled) {
 		cnss_driver_event_post(plat_priv,
 				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
@@ -3643,6 +3657,62 @@ static int cnss_reboot_notifier(struct notifier_block *nb,
 	return NOTIFY_DONE;
 }
 
+#ifdef CONFIG_CNSS_HW_SECURE_DISABLE
+int cnss_wlan_hw_disable_check(struct cnss_plat_data *plat_priv)
+{
+	struct Object client_env;
+	struct Object app_object;
+	u32 wifi_uid = HW_WIFI_UID;
+	union ObjectArg obj_arg[2] = {{{0, 0}}};
+	int ret;
+	u8 state = 0;
+
+	/* get rootObj */
+	ret = get_client_env_object(&client_env);
+	if (ret) {
+		cnss_pr_dbg("Failed to get client_env_object, ret: %d\n", ret);
+		goto end;
+	}
+	ret = IClientEnv_open(client_env, HW_STATE_UID, &app_object);
+	if (ret) {
+		cnss_pr_dbg("Failed to get app_object, ret: %d\n",  ret);
+		goto exit_release_clientenv;
+	}
+
+	obj_arg[0].b = (struct ObjectBuf) {&wifi_uid, sizeof(u32)};
+	obj_arg[1].b = (struct ObjectBuf) {&state, sizeof(u8)};
+	ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg,
+			    ObjectCounts_pack(1, 1, 0, 0));
+
+	cnss_pr_dbg("SMC invoke ret: %d state: %d\n", ret, state);
+	if (ret)
+		goto exit_release_app_obj;
+
+	if (state == 1)
+		set_bit(CNSS_WLAN_HW_DISABLED,
+			&plat_priv->driver_state);
+	else
+		clear_bit(CNSS_WLAN_HW_DISABLED,
+			  &plat_priv->driver_state);
+
+exit_release_app_obj:
+	Object_release(app_object);
+exit_release_clientenv:
+	Object_release(client_env);
+end:
+	if (ret) {
+		cnss_pr_err("Unable to get HW disable status\n");
+		CNSS_ASSERT(0);
+	}
+	return ret;
+}
+#else
+int cnss_wlan_hw_disable_check(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+#endif
+
 static int cnss_misc_init(struct cnss_plat_data *plat_priv)
 {
 	int ret;
@@ -3874,13 +3944,67 @@ cnss_is_converged_dt(struct cnss_plat_data *plat_priv)
 				     "qcom,converged-dt");
 }
 
+static int cnss_wlan_device_init(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	int retry = 0;
+
+	if (test_bit(SKIP_DEVICE_BOOT, &plat_priv->ctrl_params.quirks))
+		return 0;
+
+retry:
+	ret = cnss_power_on_device(plat_priv);
+	if (ret)
+		goto end;
+
+	ret = cnss_bus_init(plat_priv);
+	if (ret) {
+		if ((ret != -EPROBE_DEFER) &&
+		    retry++ < POWER_ON_RETRY_MAX_TIMES) {
+			cnss_power_off_device(plat_priv);
+			cnss_pr_dbg("Retry cnss_bus_init #%d\n", retry);
+			msleep(POWER_ON_RETRY_DELAY_MS * retry);
+			goto retry;
+		}
+		goto power_off;
+	}
+power_off:
+	cnss_power_off_device(plat_priv);
+end:
+	return ret;
+}
+
+int cnss_wlan_hw_enable(void)
+{
+	struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
+	int ret = 0;
+
+	clear_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state);
+
+	ret = cnss_wlan_device_init(plat_priv);
+	if (ret) {
+		CNSS_ASSERT(0);
+		return ret;
+	}
+
+	if (test_bit(CNSS_FS_READY, &plat_priv->driver_state))
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
+				       0, NULL);
+
+	if (plat_priv->driver_ops)
+		ret = cnss_wlan_register_driver(plat_priv->driver_ops);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_hw_enable);
+
 static int cnss_probe(struct platform_device *plat_dev)
 {
 	int ret = 0;
 	struct cnss_plat_data *plat_priv;
 	const struct of_device_id *of_id;
 	const struct platform_device_id *device_id;
-	int retry = 0;
 
 	if (cnss_get_plat_priv(plat_dev)) {
 		cnss_pr_err("Driver is already initialized!\n");
@@ -3968,28 +4092,20 @@ static int cnss_probe(struct platform_device *plat_dev)
 	if (ret)
 		goto destroy_debugfs;
 
+	ret = cnss_wlan_hw_disable_check(plat_priv);
+	if (ret)
+		goto deinit_misc;
+
 	/* Make sure all platform related init are done before
 	 * device power on and bus init.
 	 */
-	if (!test_bit(SKIP_DEVICE_BOOT, &plat_priv->ctrl_params.quirks)) {
-retry:
-		ret = cnss_power_on_device(plat_priv);
+	if (!test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state)) {
+		ret = cnss_wlan_device_init(plat_priv);
 		if (ret)
 			goto deinit_misc;
-
-		ret = cnss_bus_init(plat_priv);
-		if (ret) {
-			if ((ret != -EPROBE_DEFER) &&
-			    retry++ < POWER_ON_RETRY_MAX_TIMES) {
-				cnss_power_off_device(plat_priv);
-				cnss_pr_dbg("Retry cnss_bus_init #%d\n", retry);
-				msleep(POWER_ON_RETRY_DELAY_MS * retry);
-				goto retry;
-			}
-			goto power_off;
-		}
+	} else {
+		cnss_pr_info("WLAN HW Disabled. Defer PCI enumeration\n");
 	}
-
 	cnss_register_coex_service(plat_priv);
 	cnss_register_ims_service(plat_priv);
 
@@ -4001,9 +4117,6 @@ retry:
 
 	return 0;
 
-power_off:
-	if (!test_bit(SKIP_DEVICE_BOOT, &plat_priv->ctrl_params.quirks))
-		cnss_power_off_device(plat_priv);
 deinit_misc:
 	cnss_misc_deinit(plat_priv);
 destroy_debugfs:

+ 5 - 0
cnss2/main.h

@@ -318,6 +318,8 @@ enum cnss_driver_state {
 	CNSS_DAEMON_CONNECTED,
 	CNSS_PCI_PROBE_DONE,
 	CNSS_DRIVER_REGISTER,
+	CNSS_WLAN_HW_DISABLED,
+	CNSS_FS_READY = 25,
 };
 
 struct cnss_recovery_data {
@@ -502,6 +504,7 @@ struct cnss_plat_data {
 	struct completion cal_complete;
 	struct mutex dev_lock; /* mutex for register access through debugfs */
 	struct mutex driver_ops_lock; /* mutex for external driver ops */
+	struct cnss_wlan_driver *driver_ops;
 	u32 device_freq_hz;
 	u32 diag_reg_read_addr;
 	u32 diag_reg_read_mem_type;
@@ -570,6 +573,8 @@ static inline u64 cnss_get_host_timestamp(struct cnss_plat_data *plat_priv)
 }
 #endif
 
+int cnss_wlan_hw_disable_check(struct cnss_plat_data *plat_priv);
+int cnss_wlan_hw_enable(void);
 struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
 void cnss_pm_stay_awake(struct cnss_plat_data *plat_priv);
 void cnss_pm_relax(struct cnss_plat_data *plat_priv);

+ 18 - 0
cnss2/pci.c

@@ -2937,6 +2937,24 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
 		return -EAGAIN;
 	}
 
+	if (test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state)) {
+		while (id_table && id_table->device) {
+			if (plat_priv->device_id == id_table->device) {
+				if (plat_priv->device_id == KIWI_DEVICE_ID &&
+				    driver_ops->chip_version != 2) {
+					cnss_pr_err("WLAN HW disabled. kiwi_v2 only supported\n");
+					return -ENODEV;
+				}
+				cnss_pr_info("WLAN register driver deferred for device ID: 0x%x due to HW disable\n",
+					     id_table->device);
+				plat_priv->driver_ops = driver_ops;
+				return 0;
+			}
+			id_table++;
+		}
+		return -ENODEV;
+	}
+
 	if (!test_bit(CNSS_PCI_PROBE_DONE, &plat_priv->driver_state)) {
 		cnss_pr_info("pci probe not yet done for register driver\n");
 		return -EAGAIN;

+ 1 - 0
inc/cnss2.h

@@ -270,6 +270,7 @@ extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name,
 extern int cnss_get_msi_irq(struct device *dev, unsigned int vector);
 extern void cnss_get_msi_address(struct device *dev, uint32_t *msi_addr_low,
 				 uint32_t *msi_addr_high);
+extern int cnss_wlan_hw_enable(void);
 extern int cnss_wlan_enable(struct device *dev,
 			    struct cnss_wlan_enable_cfg *config,
 			    enum cnss_driver_mode mode,