From: Rajasekaran Kalidoss Date: Tue, 18 Dec 2018 16:08:59 +0000 (+0530) Subject: cnss2: power up & power down during reg and unreg X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=88d22796e16ca2bca7454319a55ac33a0c7137c8;p=sagit-ice-cold%2Fkernel_xiaomi_msm8998.git cnss2: power up & power down during reg and unreg In insmod and rmmod handling, cnss2 should power up and power down WLAN as part of register and unregister. Change-Id: I5c588e7db0748363ffbfec9ee4ec26ebdb85e3aa Signed-off-by: Rajasekaran Kalidoss --- diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c index 0411f7eb4ea1..5f1187c66c7e 100644 --- a/drivers/net/wireless/cnss2/bus.c +++ b/drivers/net/wireless/cnss2/bus.c @@ -196,6 +196,8 @@ void cnss_bus_fw_boot_timeout_hdlr(unsigned long data) switch (plat_priv->bus_type) { case CNSS_BUS_PCI: return cnss_pci_fw_boot_timeout_hdlr(plat_priv->bus_priv); + case CNSS_BUS_USB: + return cnss_usb_fw_boot_timeout_hdlr(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); @@ -269,7 +271,7 @@ int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv) case CNSS_BUS_PCI: return cnss_pci_dev_powerup(plat_priv->bus_priv); case CNSS_BUS_USB: - return 0; + return cnss_usb_dev_powerup(plat_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c index 5e2d44ce1c55..577cbb4482b3 100644 --- a/drivers/net/wireless/cnss2/debug.c +++ b/drivers/net/wireless/cnss2/debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -102,6 +102,9 @@ static int cnss_stats_show_state(struct seq_file *s, case CNSS_DRIVER_DEBUG: seq_puts(s, "DRIVER_DEBUG"); continue; + case CNSS_DEV_REMOVED: + seq_puts(s, "DEV_REMOVED"); + continue; } seq_printf(s, "UNKNOWN-%d", i); diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 8bf7b76f4131..63579cac88c4 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -1696,6 +1696,7 @@ static ssize_t cnss_wl_pwr_on(struct device *dev, { int pwr_state = 0; struct cnss_plat_data *plat_priv = dev_get_drvdata(dev); + unsigned int timeout; if (sscanf(buf, "%du", &pwr_state) != 1) return -EINVAL; @@ -1703,11 +1704,17 @@ static ssize_t cnss_wl_pwr_on(struct device *dev, cnss_pr_dbg("vreg-wlan-en state change %d, count %zu", pwr_state, count); - if (pwr_state) + timeout = cnss_get_qmi_timeout(); + if (pwr_state) { cnss_power_on_device(plat_priv); - else + if (timeout) { + mod_timer(&plat_priv->fw_boot_timer, + jiffies + msecs_to_jiffies(timeout)); + } + } else { cnss_power_off_device(plat_priv); - + del_timer(&plat_priv->fw_boot_timer); + } return count; } diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 28469dfc96af..28a2990ed831 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -143,6 +143,7 @@ enum cnss_driver_state { CNSS_FW_BOOT_RECOVERY, CNSS_DEV_ERR_NOTIFY, CNSS_DRIVER_DEBUG, + CNSS_DEV_REMOVED, }; struct cnss_recovery_data { diff --git a/drivers/net/wireless/cnss2/usb.c b/drivers/net/wireless/cnss2/usb.c index ee9f21349c3f..29b9a00ce156 100644 --- a/drivers/net/wireless/cnss2/usb.c +++ b/drivers/net/wireless/cnss2/usb.c @@ -14,14 +14,50 @@ #include "bus.h" #include "debug.h" #include "usb.h" +#include "linux/delay.h" -int cnss_usb_dev_powerup(struct cnss_usb_data *usb_priv) +void cnss_usb_fw_boot_timeout_hdlr(struct cnss_usb_data *usb_priv) +{ + if (!usb_priv) + return; + + cnss_pr_err("Timeout waiting for FW ready indication\n"); +} + +static int cnss_qcn7605_usb_powerup(struct cnss_plat_data *plat_priv) { int ret = 0; + unsigned int timeout; - if (!usb_priv) { - cnss_pr_err("usb_priv is NULL\n"); - return -ENODEV; + ret = cnss_power_on_device(plat_priv); + if (ret) { + cnss_pr_err("Failed to power on device, err = %d\n", ret); + goto out; + } + + timeout = cnss_get_qmi_timeout(); + if (timeout) { + mod_timer(&plat_priv->fw_boot_timer, + jiffies + msecs_to_jiffies(timeout)); + } + +out: + return ret; +} + +int cnss_usb_dev_powerup(struct cnss_plat_data *plat_priv) +{ + int ret = 0; + + switch (plat_priv->device_id) { + case QCN7605_COMPOSITE_DEVICE_ID: + case QCN7605_STANDALONE_DEVICE_ID: + ret = cnss_qcn7605_usb_powerup(plat_priv); + break; + default: + cnss_pr_err("Unknown device_id found: %lu\n", + plat_priv->device_id); + ret = -ENODEV; } return ret; } @@ -38,10 +74,7 @@ int cnss_usb_wlan_register_driver(struct cnss_usb_wlan_driver *driver_ops) } usb_priv = plat_priv->bus_priv; - if (!usb_priv) { - cnss_pr_err("usb_priv is NULL\n"); - return -ENODEV; - } + usb_priv->plat_priv = plat_priv; if (usb_priv->driver_ops) { cnss_pr_err("Driver has already registered\n"); @@ -74,16 +107,14 @@ EXPORT_SYMBOL(cnss_usb_wlan_unregister_driver); int cnss_usb_is_device_down(struct device *dev) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); - struct cnss_usb_data *usb_priv; if (!plat_priv) { cnss_pr_err("plat_priv is NULL\n"); return -ENODEV; } - usb_priv = plat_priv->bus_priv; - if (!usb_priv) { - cnss_pr_err("usb_priv is NULL\n"); + if (test_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state)) { + cnss_pr_err("usb device disconnected\n"); return -ENODEV; } return 0; @@ -99,7 +130,17 @@ int cnss_usb_register_driver_hdlr(struct cnss_usb_data *usb_priv, set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state); usb_priv->driver_ops = data; - ret = cnss_bus_call_driver_probe(plat_priv); + if (test_bit(CNSS_FW_READY, &plat_priv->driver_state)) { + cnss_pr_dbg("CNSS_FW_READY set - call wlan probe\n"); + ret = cnss_bus_call_driver_probe(plat_priv); + } else { + ret = cnss_usb_dev_powerup(usb_priv->plat_priv); + if (ret) { + clear_bit(CNSS_DRIVER_LOADING, + &plat_priv->driver_state); + usb_priv->driver_ops = NULL; + } + } return ret; } @@ -111,23 +152,31 @@ int cnss_usb_unregister_driver_hdlr(struct cnss_usb_data *usb_priv) set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); cnss_usb_dev_shutdown(usb_priv); usb_priv->driver_ops = NULL; - + usb_priv->plat_priv = NULL; return 0; } int cnss_usb_dev_shutdown(struct cnss_usb_data *usb_priv) { int ret = 0; + struct cnss_plat_data *plat_priv; if (!usb_priv) { cnss_pr_err("usb_priv is NULL\n"); return -ENODEV; } + plat_priv = usb_priv->plat_priv; switch (usb_priv->device_id) { case QCN7605_COMPOSITE_DEVICE_ID: case QCN7605_STANDALONE_DEVICE_ID: - cnss_usb_call_driver_remove(usb_priv); + cnss_pr_dbg("cnss driver state %lu\n", plat_priv->driver_state); + if (!test_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state)) + cnss_usb_call_driver_remove(usb_priv); + + cnss_power_off_device(plat_priv); + clear_bit(CNSS_FW_READY, &plat_priv->driver_state); + clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); break; default: cnss_pr_err("Unknown device_id found: 0x%x\n", @@ -222,8 +271,7 @@ static int cnss_usb_probe(struct usb_interface *interface, id->idVendor, id->idProduct); usb_dev = interface_to_usbdev(interface); - usb_priv = devm_kzalloc(&usb_dev->dev, sizeof(*usb_priv), - GFP_KERNEL); + usb_priv = (struct cnss_usb_data *)plat_priv->bus_priv; if (!usb_priv) { ret = -ENOMEM; goto out; @@ -237,11 +285,11 @@ static int cnss_usb_probe(struct usb_interface *interface, usb_priv->target_version = bcd_device; cnss_set_usb_priv(interface, usb_priv); plat_priv->device_id = usb_priv->device_id; - plat_priv->bus_priv = usb_priv; /*increment the ref count of usb dev structure*/ usb_get_dev(usb_dev); + clear_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state); ret = cnss_register_subsys(plat_priv); if (ret) goto reset_ctx; @@ -269,7 +317,6 @@ unregister_subsys: cnss_unregister_subsys(plat_priv); reset_ctx: plat_priv->bus_priv = NULL; - devm_kfree(&usb_dev->dev, usb_priv); out: return ret; } @@ -283,11 +330,12 @@ static void cnss_usb_remove(struct usb_interface *interface) cnss_pr_dbg("driver state %lu\n", plat_priv->driver_state); cnss_unregister_ramdump(plat_priv); cnss_unregister_subsys(plat_priv); - usb_priv->plat_priv = NULL; - plat_priv->bus_priv = NULL; usb_dev = interface_to_usbdev(interface); usb_put_dev(usb_dev); - devm_kfree(&usb_dev->dev, usb_priv); + usb_priv->usb_intf = NULL; + usb_priv->usb_device_id = NULL; + set_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state); + del_timer(&plat_priv->fw_boot_timer); } static int cnss_usb_suspend(struct usb_interface *interface, pm_message_t state) @@ -349,6 +397,13 @@ static struct usb_driver cnss_usb_driver = { int cnss_usb_init(struct cnss_plat_data *plat_priv) { int ret = 0; + struct cnss_usb_data *usb_priv; + + plat_priv->bus_priv = kzalloc(sizeof(*usb_priv), GFP_KERNEL); + if (!plat_priv->bus_priv) { + ret = -ENOMEM; + goto out; + } ret = usb_register(&cnss_usb_driver); if (ret) { @@ -359,10 +414,12 @@ int cnss_usb_init(struct cnss_plat_data *plat_priv) return 0; out: + kfree(plat_priv->bus_priv); return ret; } void cnss_usb_deinit(struct cnss_plat_data *plat_priv) { + kfree(plat_priv->bus_priv); usb_deregister(&cnss_usb_driver); } diff --git a/drivers/net/wireless/cnss2/usb.h b/drivers/net/wireless/cnss2/usb.h index b285dc27daa9..8196c3de3431 100644 --- a/drivers/net/wireless/cnss2/usb.h +++ b/drivers/net/wireless/cnss2/usb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -52,15 +52,13 @@ int cnss_usb_force_fw_assert_hdlr(struct cnss_usb_data *usb_priv); void cnss_usb_fw_boot_timeout_hdlr(struct cnss_usb_data *usb_priv); int cnss_usb_call_driver_probe(struct cnss_usb_data *usb_priv); int cnss_usb_call_driver_remove(struct cnss_usb_data *usb_priv); -int cnss_usb_dev_powerup(struct cnss_usb_data *usb_priv); +int cnss_usb_dev_powerup(struct cnss_plat_data *plat_priv); int cnss_usb_dev_shutdown(struct cnss_usb_data *usb_priv); int cnss_usb_dev_crash_shutdown(struct cnss_usb_data *usb_priv); int cnss_usb_dev_ramdump(struct cnss_usb_data *usb_priv); - int cnss_usb_register_driver_hdlr(struct cnss_usb_data *usb_priv, void *data); - int cnss_usb_unregister_driver_hdlr(struct cnss_usb_data *usb_priv); int cnss_usb_call_driver_modem_status(struct cnss_usb_data *usb_priv, int modem_current_status); - +int cnss_usb_dev_alloc(struct cnss_plat_data *plat_priv); #endif /* _CNSS_USB_H */