From 992242a17af83ebced2ce0f584ec7bdd423b8d89 Mon Sep 17 00:00:00 2001 From: Arun Kumar Khandavalli Date: Fri, 20 May 2022 03:48:16 -0700 Subject: [PATCH] qcacmn: cleanup scan queue in case of SSR & iff going down When the SSR and interface down happen in parallel, the driver rejects the interface down since the recovery is in progress. Kernel ignores the -EAGAIN request from the driver and as part of NET_DOWN notification in cfg80211_netdown_notifer the kernel invokes the ___cfg80211_scan_done to free the request but doesn't not send scan_result indication, since it expects the scan_done work to get scheduled and then broadcast the request to upperlayer. The scan done checks currently only if the interface is up replace it with driver specific internal driver state. Change-Id: I0e5ac319783b9c1a69e7e19674f76f20da1d1590 CRs-Fixed: 3202812 --- os_if/linux/scan/inc/wlan_cfg80211_scan.h | 4 ++- os_if/linux/scan/src/wlan_cfg80211_scan.c | 34 ++++++++++++++++++----- os_if/linux/wlan_osif_priv.h | 3 ++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/os_if/linux/scan/inc/wlan_cfg80211_scan.h b/os_if/linux/scan/inc/wlan_cfg80211_scan.h index 3409cf4dfd..6842c1130e 100644 --- a/os_if/linux/scan/inc/wlan_cfg80211_scan.h +++ b/os_if/linux/scan/inc/wlan_cfg80211_scan.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 @@ -443,6 +444,7 @@ void wlan_config_sched_scan_plans_to_wiphy(struct wiphy *wiphy, * @netdev: Net device * @req : Scan request * @aborted : true scan aborted false scan success + * @osif_priv: OS private structure * * This function notifies scan done to cfg80211 * @@ -450,7 +452,7 @@ void wlan_config_sched_scan_plans_to_wiphy(struct wiphy *wiphy, */ void wlan_cfg80211_scan_done(struct net_device *netdev, struct cfg80211_scan_request *req, - bool aborted); + bool aborted, struct pdev_osif_priv *osif_priv); /** * convert_nl_scan_priority_to_internal() - Convert NL80211 based scan prioirty diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c index a0cd1c59ca..458a1cd56b 100644 --- a/os_if/linux/scan/src/wlan_cfg80211_scan.c +++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c @@ -841,6 +841,7 @@ static QDF_STATUS wlan_scan_request_dequeue( * @netdev: Net device * @req : Scan request * @aborted : true scan aborted false scan success + * @osif_priv: OS private structure * * This function notifies scan done to cfg80211 * @@ -848,14 +849,23 @@ static QDF_STATUS wlan_scan_request_dequeue( */ void wlan_cfg80211_scan_done(struct net_device *netdev, struct cfg80211_scan_request *req, - bool aborted) + bool aborted, struct pdev_osif_priv *osif_priv) { struct cfg80211_scan_info info = { .aborted = aborted }; + bool driver_internal_netdev_state; - if (netdev->flags & IFF_UP) + driver_internal_netdev_state = netdev->flags & IFF_UP; + if (osif_priv->osif_check_netdev_state) + driver_internal_netdev_state = + osif_priv->osif_check_netdev_state(netdev); + + if (driver_internal_netdev_state) cfg80211_scan_done(req, &info); + else + osif_debug("scan done callback has been dropped :%s", + (netdev)->name); } #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) /** @@ -863,6 +873,7 @@ void wlan_cfg80211_scan_done(struct net_device *netdev, * @netdev: Net device * @req : Scan request * @aborted : true scan aborted false scan success + * @osif_priv - OS private structure * * This function notifies scan done to cfg80211 * @@ -870,10 +881,19 @@ void wlan_cfg80211_scan_done(struct net_device *netdev, */ void wlan_cfg80211_scan_done(struct net_device *netdev, struct cfg80211_scan_request *req, - bool aborted) + bool aborted, struct pdev_osif_priv *osif_priv) { - if (netdev->flags & IFF_UP) + bool driver_internal_net_state; + + driver_internal_netdev_state = netdev->flags & IFF_UP; + if (osif_priv->osif_check_netdev_state) + driver_internal_net_state = + osif_priv->osif_check_netdev_state(netdev); + + if (driver_internal_netdev_state) cfg80211_scan_done(req, aborted); + else + osif_debug("scan request has been dropped :%s", (netdev)->name); } #endif @@ -1082,6 +1102,7 @@ static void wlan_cfg80211_scan_done_callback( return; pdev = wlan_vdev_get_pdev(vdev); + osif_priv = wlan_pdev_get_ospriv(pdev); status = wlan_scan_request_dequeue( pdev, scan_id, &req, &source, &netdev, &scan_start_timestamp); @@ -1122,7 +1143,7 @@ static void wlan_cfg80211_scan_done_callback( * scan done event will be posted */ if (NL_SCAN == source) - wlan_cfg80211_scan_done(netdev, req, !success); + wlan_cfg80211_scan_done(netdev, req, !success, osif_priv); else wlan_vendor_scan_callback(req, !success); @@ -1136,7 +1157,6 @@ static void wlan_cfg80211_scan_done_callback( util_scan_get_ev_reason_name(event->reason), event->reason, unique_bss_count); allow_suspend: - osif_priv = wlan_pdev_get_ospriv(pdev); qdf_mutex_acquire(&osif_priv->osif_scan->scan_req_q_lock); if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q)) { struct wlan_objmgr_psoc *psoc; @@ -1341,7 +1361,7 @@ void wlan_cfg80211_cleanup_scan_queue(struct wlan_objmgr_pdev *pdev, source = scan_req->source; if (NL_SCAN == source) wlan_cfg80211_scan_done(scan_req->dev, req, - aborted); + aborted, osif_priv); else wlan_vendor_scan_callback(req, aborted); diff --git a/os_if/linux/wlan_osif_priv.h b/os_if/linux/wlan_osif_priv.h index 50140624c2..a153e5f359 100644 --- a/os_if/linux/wlan_osif_priv.h +++ b/os_if/linux/wlan_osif_priv.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2016-2017,2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 @@ -33,12 +34,14 @@ struct osif_tdls_vdev; * @legacy_osif_priv: legacy osif private handle * @scan_priv: Scan related data used by cfg80211 scan * @nif: pdev net device + * @osif_check_netdev_state: check driver internal netdev state */ struct pdev_osif_priv { struct wiphy *wiphy; void *legacy_osif_priv; struct osif_scan_pdev *osif_scan; struct qdf_net_if *nif; + int (*osif_check_netdev_state)(struct net_device *netdev); }; /**