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
|
cppflags-y += -DHW_TX_DELAY_STATS_ENABLE
|
||||||
endif
|
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)
|
KBUILD_CPPFLAGS += $(cppflags-y)
|
||||||
|
|
||||||
# Currently, for versions of gcc which support it, the kernel Makefile
|
# Currently, for versions of gcc which support it, the kernel Makefile
|
||||||
|
@@ -1968,6 +1968,22 @@ struct hdd_rtpm_tput_policy_context {
|
|||||||
};
|
};
|
||||||
#endif
|
#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
|
* struct hdd_context - hdd shared driver and psoc/device context
|
||||||
* @psoc: object manager psoc 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
|
* @dump_in_progress: Stores value of dump in progress
|
||||||
* @hdd_dual_sta_policy: Concurrent STA policy configuration
|
* @hdd_dual_sta_policy: Concurrent STA policy configuration
|
||||||
* @rx_skip_qdisc_chk_conc: flag to skip ingress qdisc check in concurrency
|
* @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 hdd_context {
|
||||||
struct wlan_objmgr_psoc *psoc;
|
struct wlan_objmgr_psoc *psoc;
|
||||||
@@ -2379,6 +2396,7 @@ struct hdd_context {
|
|||||||
#ifdef CONFIG_WLAN_FREQ_LIST
|
#ifdef CONFIG_WLAN_FREQ_LIST
|
||||||
uint8_t power_type;
|
uint8_t power_type;
|
||||||
#endif
|
#endif
|
||||||
|
bool is_wlan_disabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1460,6 +1460,11 @@ int __wlan_hdd_validate_context(struct hdd_context *hdd_ctx, const char *func)
|
|||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdd_ctx->is_wlan_disabled) {
|
||||||
|
hdd_debug("WLAN is disabled by user space");
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4989,6 +4994,12 @@ static int __hdd_open(struct net_device *dev)
|
|||||||
return -EIO;
|
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);
|
ret = hdd_trigger_psoc_idle_restart(hdd_ctx);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
hdd_err("Failed to start WLAN modules return");
|
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);
|
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,
|
static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp,
|
||||||
const char __user *user_buf,
|
const char __user *user_buf,
|
||||||
size_t count,
|
size_t count,
|
||||||
loff_t *f_pos)
|
loff_t *f_pos)
|
||||||
{
|
{
|
||||||
char buf[3];
|
int id, ret;
|
||||||
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;
|
|
||||||
unsigned long rc;
|
unsigned long rc;
|
||||||
struct hdd_context *hdd_ctx;
|
struct hdd_context *hdd_ctx;
|
||||||
bool is_wait_for_ready = false;
|
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");
|
pr_info("Wifi turning off from UI\n");
|
||||||
hdd_inform_wifi_off();
|
hdd_inform_wifi_off();
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
case WLAN_ON_STR:
|
||||||
|
|
||||||
if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) == 0)
|
|
||||||
pr_info("Wifi Turning On from UI\n");
|
pr_info("Wifi Turning On from UI\n");
|
||||||
|
break;
|
||||||
if (strncmp(buf, wlan_wait_for_ready_str,
|
case WLAN_WAIT_FOR_READY_STR:
|
||||||
strlen(wlan_wait_for_ready_str)) == 0) {
|
|
||||||
is_wait_for_ready = true;
|
is_wait_for_ready = true;
|
||||||
pr_info("Wifi wait for ready from UI\n");
|
pr_info("Wifi wait for ready from UI\n");
|
||||||
} else if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) != 0) {
|
break;
|
||||||
pr_err("Invalid value received from framework");
|
case WLAN_ENABLE_STR:
|
||||||
goto exit;
|
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",
|
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)
|
if (hdd_ctx)
|
||||||
hdd_psoc_idle_timer_stop(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:
|
exit:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user