From 04235478f2978f84c0d6b3bfd60263e02d66aa4f Mon Sep 17 00:00:00 2001 From: Rajasekaran Kalidoss Date: Thu, 28 Mar 2019 14:05:28 +0530 Subject: [PATCH] cnss2: Support USB SSR and disconnect scenarios For USB devices, irrecoverable scenarios in firmware can lead to USB bus disconnect. In USB disconnect, the interface and dev structures passed by USB sub system are freed and are no longer valid. The current implementation is PCIe specific and assumes dev struct being present and valid always. The clean way to handle this for HL(USB/SDIO) is to call pld_usb_remove in disconnect and pld_usb_probe in re-connect after a recovery Change-Id: I3fc9a5a2fc7bb53439b0410e61f381aa94e18634 Signed-off-by: Rajasekaran Kalidoss --- drivers/net/wireless/cnss2/usb.c | 39 ++++++++++++++++---------------- include/net/cnss2.h | 3 ++- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/cnss2/usb.c b/drivers/net/wireless/cnss2/usb.c index cf4137ac5102..def619e05c9e 100644 --- a/drivers/net/wireless/cnss2/usb.c +++ b/drivers/net/wireless/cnss2/usb.c @@ -173,10 +173,10 @@ int cnss_usb_dev_shutdown(struct cnss_usb_data *usb_priv) case QCN7605_VER20_STANDALONE_DEVICE_ID: case QCN7605_VER20_COMPOSITE_DEVICE_ID: cnss_pr_dbg("cnss driver state %lu\n", plat_priv->driver_state); - if (!test_bit(CNSS_DEV_REMOVED, &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); + 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; @@ -199,22 +199,12 @@ int cnss_usb_call_driver_probe(struct cnss_usb_data *usb_priv) goto out; } - if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) && - test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) { - ret = usb_priv->driver_ops->reinit(usb_priv->usb_intf, - usb_priv->usb_device_id); - if (ret) { - cnss_pr_err("Failed to reinit host driver, err = %d\n", - ret); - goto out; - } - clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); - } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) { + if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) || + test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { ret = usb_priv->driver_ops->probe(usb_priv->usb_intf, usb_priv->usb_device_id); if (ret) { - cnss_pr_err("Failed to probe host driver, err = %d\n", - ret); + cnss_pr_err("Host drv probe failed, err = %d\n", ret); goto out; } clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); @@ -331,15 +321,26 @@ static void cnss_usb_remove(struct usb_interface *interface) struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); struct cnss_usb_data *usb_priv = plat_priv->bus_priv; - cnss_pr_dbg("driver state %lu\n", plat_priv->driver_state); + del_timer(&plat_priv->fw_boot_timer); + + clear_bit(CNSS_FW_READY, &plat_priv->driver_state); + set_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state); + set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); + if (usb_priv->driver_ops) { + cnss_pr_dbg("driver_ops remove state %lu\n", + plat_priv->driver_state); + usb_priv->driver_ops->update_status(usb_priv->usb_intf, + CNSS_FW_DOWN); + usb_priv->driver_ops->remove(usb_priv->usb_intf); + clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); + } cnss_unregister_ramdump(plat_priv); cnss_unregister_subsys(plat_priv); usb_dev = interface_to_usbdev(interface); usb_put_dev(usb_dev); 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); + cnss_pr_dbg("driver state %lu\n", plat_priv->driver_state); } static int cnss_usb_suspend(struct usb_interface *interface, pm_message_t state) diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 0b2c9d272fac..de0161915a75 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, 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 @@ -96,6 +96,7 @@ struct cnss_usb_wlan_driver { int (*suspend)(struct usb_interface *pintf, pm_message_t state); int (*resume)(struct usb_interface *pintf); int (*reset_resume)(struct usb_interface *pintf); + void (*update_status)(struct usb_interface *pintf, uint32_t status); const struct usb_device_id *id_table; };