diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 67e6077caf90..938510f869a4 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1131,7 +1131,10 @@ struct hdd_context; * @handle_feature_update: Handle feature update only if it is triggered * by hdd_netdev_feature_update * @netdev_features_update_work: work for handling the netdev features update - for the adapter. + * for the adapter. + * @delete_in_progress: Flag to indicate that the adapter delete is in + * progress, and any operation using rtnl lock inside + * the driver can be avoided/skipped. */ struct hdd_adapter { /* Magic cookie for adapter sanity verification. Note that this @@ -1441,6 +1444,7 @@ struct hdd_adapter { qdf_work_t netdev_features_update_work; /* Flag to indicate whether it is a pre cac adapter or not */ bool is_pre_cac_adapter; + bool delete_in_progress; }; #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station) diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 8a0a9ff9b6f8..13fb20ffc69d 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -5001,11 +5001,15 @@ static int hdd_set_features(struct net_device *net_dev, return errno; } +#define HDD_NETDEV_FEATURES_UPDATE_MAX_WAIT_COUNT 10 +#define HDD_NETDEV_FEATURES_UPDATE_WAIT_INTERVAL_MS 20 + void hdd_netdev_update_features(struct hdd_adapter *adapter) { struct net_device *net_dev = adapter->dev; ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); bool request_feature_update = false; + int wait_count = HDD_NETDEV_FEATURES_UPDATE_MAX_WAIT_COUNT; if (!soc) { hdd_err("soc handle is NULL"); @@ -5027,11 +5031,31 @@ void hdd_netdev_update_features(struct hdd_adapter *adapter) if (request_feature_update) { hdd_debug("Update net_dev features for device mode %d", adapter->device_mode); - rtnl_lock(); - adapter->handle_feature_update = true; - netdev_update_features(net_dev); - adapter->handle_feature_update = false; - rtnl_unlock(); + while (!adapter->delete_in_progress) { + if (rtnl_trylock()) { + adapter->handle_feature_update = true; + netdev_update_features(net_dev); + adapter->handle_feature_update = false; + rtnl_unlock(); + break; + } + + if (wait_count--) { + qdf_sleep( + HDD_NETDEV_FEATURES_UPDATE_WAIT_INTERVAL_MS); + } else { + /* + * We have failed to updated the netdev + * features for very long, so enable the queues + * now. The impact of not being able to update + * the netdev feature is lower TPUT when + * switching from legacy to non-legacy mode. + */ + hdd_err("Failed to update netdev features for device mode %d", + adapter->device_mode); + break; + } + } } } diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c index c785af663e76..30a1f51f7762 100644 --- a/core/hdd/src/wlan_hdd_p2p.c +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -810,6 +810,8 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-ENOSPC); } + adapter->delete_in_progress = false; + /* ensure physcial soc is up */ ret = hdd_trigger_psoc_idle_restart(hdd_ctx); if (ret) { @@ -968,7 +970,9 @@ int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { int errno; struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + adapter->delete_in_progress = true; errno = osif_vdev_sync_trans_start_wait(wdev->netdev, &vdev_sync); if (errno) return errno;