qcacld-3.0: Add infra to disable/enable wifi
As part of protected dynamic interface control feature, add infra to disable/enable wifi, when invoked from user space. Change-Id: I3f6c2abcef1ef89cbd0a735820de9b54d37bfa29 CRs-Fixed: 3166467
This commit is contained in:

committed by
Madan Koyyalamudi

parent
372e1ff370
commit
c4ca02df28
3
Kbuild
3
Kbuild
@@ -4379,6 +4379,9 @@ ifeq ($(CONFIG_DP_HW_TX_DELAY_STATS_ENABLE), y)
|
||||
cppflags-y += -DHW_TX_DELAY_STATS_ENABLE
|
||||
endif
|
||||
|
||||
#Flags to enable/disable Dynamic WLAN interface control feature
|
||||
cppflags-$(CONFIG_WLAN_DYNAMIC_IFACE_CTRL) += -DFEATURE_WLAN_DYNAMIC_IFACE_CTRL
|
||||
|
||||
KBUILD_CPPFLAGS += $(cppflags-y)
|
||||
|
||||
# Currently, for versions of gcc which support it, the kernel Makefile
|
||||
|
@@ -1968,6 +1968,22 @@ struct hdd_rtpm_tput_policy_context {
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum wlan_state_ctrl_str_id - state contrl param string id
|
||||
* @WLAN_OFF_STR: Turn OFF WiFi
|
||||
* @WLAN_ON_STR: Turn ON WiFi
|
||||
* @WLAN_ENABLE_STR: Enable WiFi
|
||||
* @WLAN_DISABLE_STR: Disable Wifi
|
||||
* @WLAN_WAIT_FOR_READY_STR: Driver should wait for ongoing recovery
|
||||
*/
|
||||
enum wlan_state_ctrl_str_id {
|
||||
WLAN_OFF_STR = 0,
|
||||
WLAN_ON_STR,
|
||||
WLAN_ENABLE_STR,
|
||||
WLAN_DISABLE_STR,
|
||||
WLAN_WAIT_FOR_READY_STR
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hdd_context - hdd shared driver and psoc/device context
|
||||
* @psoc: object manager psoc context
|
||||
@@ -1997,6 +2013,7 @@ struct hdd_rtpm_tput_policy_context {
|
||||
* @dump_in_progress: Stores value of dump in progress
|
||||
* @hdd_dual_sta_policy: Concurrent STA policy configuration
|
||||
* @rx_skip_qdisc_chk_conc: flag to skip ingress qdisc check in concurrency
|
||||
* @is_wlan_disabled: if wlan is disabled by userspace
|
||||
*/
|
||||
struct hdd_context {
|
||||
struct wlan_objmgr_psoc *psoc;
|
||||
@@ -2379,6 +2396,7 @@ struct hdd_context {
|
||||
#ifdef CONFIG_WLAN_FREQ_LIST
|
||||
uint8_t power_type;
|
||||
#endif
|
||||
bool is_wlan_disabled;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -1460,6 +1460,11 @@ int __wlan_hdd_validate_context(struct hdd_context *hdd_ctx, const char *func)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (hdd_ctx->is_wlan_disabled) {
|
||||
hdd_debug("WLAN is disabled by user space");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4989,6 +4994,12 @@ static int __hdd_open(struct net_device *dev)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = wlan_hdd_validate_context(hdd_ctx);
|
||||
if (ret) {
|
||||
hdd_err("Can't start WLAN module, WiFi Disabled");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hdd_trigger_psoc_idle_restart(hdd_ctx);
|
||||
if (ret) {
|
||||
hdd_err("Failed to start WLAN modules return");
|
||||
@@ -17486,41 +17497,132 @@ static void hdd_inform_wifi_off(void)
|
||||
osif_psoc_sync_op_stop(psoc_sync);
|
||||
}
|
||||
|
||||
static int hdd_validate_wlan_string(const char __user *user_buf)
|
||||
{
|
||||
char buf[15];
|
||||
int i;
|
||||
static const char * const wlan_str[] = {
|
||||
[WLAN_OFF_STR] = "OFF",
|
||||
[WLAN_ON_STR] = "ON",
|
||||
[WLAN_ENABLE_STR] = "ENABLE",
|
||||
[WLAN_DISABLE_STR] = "DISABLE",
|
||||
[WLAN_WAIT_FOR_READY_STR] = "WAIT_FOR_READY"
|
||||
};
|
||||
|
||||
if (copy_from_user(buf, user_buf, sizeof(buf))) {
|
||||
pr_err("Failed to read buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wlan_str); i++) {
|
||||
if (qdf_str_ncmp(buf, wlan_str[i], strlen(wlan_str[i])) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef FEATURE_WLAN_DYNAMIC_IFACE_CTRL
|
||||
#define WIFI_DISABLE_SLEEP (10)
|
||||
#define WIFI_DISABLE_MAX_RETRY_ATTEMPTS (10)
|
||||
|
||||
static int hdd_disable_wifi(struct hdd_context *hdd_ctx)
|
||||
{
|
||||
int ret;
|
||||
int retries = 0;
|
||||
void *hif_ctx;
|
||||
|
||||
if (!hdd_ctx) {
|
||||
hdd_err_rl("hdd_ctx is Null");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdd_ctx->is_wlan_disabled) {
|
||||
hdd_err_rl("Wifi already disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdd_debug("Initiating WLAN idle shutdown");
|
||||
if (hdd_is_any_interface_open(hdd_ctx)) {
|
||||
hdd_err("Interfaces still open, cannot process wifi disable");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
|
||||
|
||||
hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_SHUTDOWN);
|
||||
|
||||
while (retries < WIFI_DISABLE_MAX_RETRY_ATTEMPTS) {
|
||||
if (hif_ctx) {
|
||||
/*
|
||||
* Trigger runtime sync resume before psoc_idle_shutdown
|
||||
* such that resume can happen successfully
|
||||
*/
|
||||
hif_pm_runtime_sync_resume(hif_ctx,
|
||||
RTPM_ID_SOC_IDLE_SHUTDOWN);
|
||||
}
|
||||
ret = pld_idle_shutdown(hdd_ctx->parent_dev,
|
||||
hdd_psoc_idle_shutdown);
|
||||
|
||||
if (-EAGAIN == ret || hdd_ctx->is_wiphy_suspended) {
|
||||
hdd_debug("System suspend in progress.Retries done:%d",
|
||||
retries);
|
||||
msleep(WIFI_DISABLE_SLEEP);
|
||||
retries++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_SHUTDOWN);
|
||||
|
||||
if (retries > WIFI_DISABLE_MAX_RETRY_ATTEMPTS) {
|
||||
hdd_debug("Max retries reached");
|
||||
return -EINVAL;
|
||||
}
|
||||
hdd_ctx->is_wlan_disabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int hdd_disable_wifi(struct hdd_context *hdd_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* FEATURE_WLAN_DYNAMIC_IFACE_CTRL */
|
||||
|
||||
static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp,
|
||||
const char __user *user_buf,
|
||||
size_t count,
|
||||
loff_t *f_pos)
|
||||
{
|
||||
char buf[3];
|
||||
static const char wlan_off_str[] = "OFF";
|
||||
static const char wlan_on_str[] = "ON";
|
||||
static const char wlan_wait_for_ready_str[] = "WAIT_FOR_READY";
|
||||
int ret;
|
||||
int id, ret;
|
||||
unsigned long rc;
|
||||
struct hdd_context *hdd_ctx;
|
||||
bool is_wait_for_ready = false;
|
||||
|
||||
if (copy_from_user(buf, user_buf, 3)) {
|
||||
pr_err("Failed to read buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (strncmp(buf, wlan_off_str, strlen(wlan_off_str)) == 0) {
|
||||
id = hdd_validate_wlan_string(user_buf);
|
||||
|
||||
switch (id) {
|
||||
case WLAN_OFF_STR:
|
||||
pr_info("Wifi turning off from UI\n");
|
||||
hdd_inform_wifi_off();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) == 0)
|
||||
case WLAN_ON_STR:
|
||||
pr_info("Wifi Turning On from UI\n");
|
||||
|
||||
if (strncmp(buf, wlan_wait_for_ready_str,
|
||||
strlen(wlan_wait_for_ready_str)) == 0) {
|
||||
break;
|
||||
case WLAN_WAIT_FOR_READY_STR:
|
||||
is_wait_for_ready = true;
|
||||
pr_info("Wifi wait for ready from UI\n");
|
||||
} else if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) != 0) {
|
||||
pr_err("Invalid value received from framework");
|
||||
goto exit;
|
||||
break;
|
||||
case WLAN_ENABLE_STR:
|
||||
pr_info("Enabling WiFi\n");
|
||||
break;
|
||||
case WLAN_DISABLE_STR:
|
||||
pr_info("Disabling WiFi\n");
|
||||
break;
|
||||
default:
|
||||
hdd_err_rl("Invalid value received from framework");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdd_info("is_driver_loaded %d is_driver_recovering %d",
|
||||
@@ -17547,6 +17649,25 @@ static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp,
|
||||
if (hdd_ctx)
|
||||
hdd_psoc_idle_timer_stop(hdd_ctx);
|
||||
|
||||
if (id == WLAN_DISABLE_STR) {
|
||||
ret = hdd_disable_wifi(hdd_ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (id == WLAN_ENABLE_STR) {
|
||||
if (!hdd_ctx) {
|
||||
hdd_err_rl("hdd_ctx is Null");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!hdd_ctx->is_wlan_disabled) {
|
||||
hdd_err_rl("WiFi is already enabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
hdd_ctx->is_wlan_disabled = false;
|
||||
}
|
||||
|
||||
exit:
|
||||
return count;
|
||||
}
|
||||
|
Reference in New Issue
Block a user