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
Tento commit je obsažen v:
Aditya Kodukula
2022-04-05 16:08:12 -07:00
odevzdal Madan Koyyalamudi
rodič 372e1ff370
revize c4ca02df28
3 změnil soubory, kde provedl 161 přidání a 19 odebrání

3
Kbuild
Zobrazit soubor

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

Zobrazit soubor

@@ -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;
};
/**

Zobrazit soubor

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