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 <rkalidos@codeaurora.org>
This commit is contained in:
Rajasekaran Kalidoss 2019-03-28 14:05:28 +05:30 committed by Gerrit - the friendly Code Review server
parent 9ec08ea59b
commit 04235478f2
2 changed files with 22 additions and 20 deletions

View file

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

View file

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