diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 0fbf8b7e7aae..6971f7b94d1b 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -642,6 +642,13 @@ int cnss_idle_restart(struct device *dev) timeout = cnss_get_boot_timeout(dev); reinit_completion(&plat_priv->power_up_complete); + + if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) { + cnss_pr_dbg("Reboot or shutdown is in progress, ignore idle restart\n"); + ret = -EINVAL; + goto out; + } + ret = wait_for_completion_timeout(&plat_priv->power_up_complete, msecs_to_jiffies(timeout) << 2); if (!ret) { @@ -1918,6 +1925,23 @@ static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv) icc_put(bus_bw_info->cnss_path); } +static ssize_t shutdown_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL); + + if (plat_priv) { + set_bit(CNSS_IN_REBOOT, &plat_priv->driver_state); + del_timer(&plat_priv->fw_boot_timer); + complete_all(&plat_priv->power_up_complete); + } + + cnss_pr_dbg("Received shutdown notification\n"); + + return count; +} + static ssize_t fs_ready_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1961,18 +1985,55 @@ static ssize_t fs_ready_store(struct device *dev, return count; } +static struct kobj_attribute shutdown_attribute = __ATTR_WO(shutdown); static DEVICE_ATTR_WO(fs_ready); +static int cnss_create_shutdown_sysfs(struct cnss_plat_data *plat_priv) +{ + int ret = 0; + + plat_priv->shutdown_kobj = kobject_create_and_add("shutdown_wlan", + kernel_kobj); + if (!plat_priv->shutdown_kobj) { + cnss_pr_err("Failed to create shutdown_wlan kernel object\n"); + return -ENOMEM; + } + + ret = sysfs_create_file(plat_priv->shutdown_kobj, + &shutdown_attribute.attr); + if (ret) { + cnss_pr_err("Failed to create sysfs shutdown file, err = %d\n", + ret); + kobject_put(plat_priv->shutdown_kobj); + plat_priv->shutdown_kobj = NULL; + } + + return ret; +} + +static void cnss_remove_shutdown_sysfs(struct cnss_plat_data *plat_priv) +{ + if (plat_priv->shutdown_kobj) { + sysfs_remove_file(plat_priv->shutdown_kobj, + &shutdown_attribute.attr); + kobject_put(plat_priv->shutdown_kobj); + plat_priv->shutdown_kobj = NULL; + } +} + static int cnss_create_sysfs(struct cnss_plat_data *plat_priv) { int ret = 0; ret = device_create_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready); if (ret) { - cnss_pr_err("Failed to create device file, err = %d\n", ret); + cnss_pr_err("Failed to create device fs_ready file, err = %d\n", + ret); goto out; } + cnss_create_shutdown_sysfs(plat_priv); + return 0; out: return ret; @@ -1980,6 +2041,7 @@ out: static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv) { + cnss_remove_shutdown_sysfs(plat_priv); device_remove_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready); } diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 3a88819b8480..ca923bf0a5be 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -374,6 +374,7 @@ struct cnss_plat_data { int (*get_info_cb)(void *ctx, void *event, int event_len); u8 use_nv_mac; u8 set_wlaon_pwr_ctrl; + struct kobject *shutdown_kobj; }; #ifdef CONFIG_ARCH_QCOM