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
This commit is contained in:
Manikandan Mohan
2022-06-01 16:58:59 -07:00
parent 5c067d4008
commit ad4399e37a
8 ha cambiato i file con 180 aggiunte e 20 eliminazioni

Vedi File

@@ -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
Kbuild
Vedi File

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

Vedi File

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

Vedi File

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

Vedi File

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

Vedi File

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

Vedi File

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

Vedi File

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