From 19042f697f6ef2ae8494f3fe98e3d66437a27379 Mon Sep 17 00:00:00 2001 From: Jingxiang Ge Date: Thu, 16 Jan 2020 20:36:53 +0800 Subject: [PATCH] qcacld-3.0: Reject Vdev trans when driver in unloading/recovering Previously vdev trans will be rejected if psoc in trans. but it causes issue when __hdd_psoc_idle_shutdown is in psoc trans, if ifconfig comes here, the ifconfig will fail. Add checking if psoc trans in driver recovering and unloading, if yes, it will be safe to reject vdev trans, otherwise, we should let vdev trans waiting for psoc trans. At the same time, we also need to make sure driver state has been set before psoc trans when unloading. Change-Id: Ic47eebef76b8eadc90780b74f75d4ebef73b822d CRs-Fixed: 2601435 --- components/dsc/src/wlan_dsc_vdev.c | 28 ++++++++++++++++++++++++---- components/dsc/test/wlan_dsc_test.c | 27 ++++++++++++++++++++++++--- core/hdd/src/wlan_hdd_main.c | 7 +++---- core/pld/src/pld_pcie.c | 6 +----- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/components/dsc/src/wlan_dsc_vdev.c b/components/dsc/src/wlan_dsc_vdev.c index 95d39692eac4..a50411f80d8a 100644 --- a/components/dsc/src/wlan_dsc_vdev.c +++ b/components/dsc/src/wlan_dsc_vdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020 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 @@ -22,6 +22,7 @@ #include "qdf_types.h" #include "__wlan_dsc.h" #include "wlan_dsc.h" +#include "cds_api.h" #define __dsc_driver_lock(vdev) __dsc_lock((vdev)->psoc->driver) #define __dsc_driver_unlock(vdev) __dsc_unlock((vdev)->psoc->driver) @@ -115,10 +116,19 @@ void dsc_vdev_destroy(struct dsc_vdev **out_vdev) * This function checks if the vdev transition can occur or not by checking if * any other down the tree/up the tree transition/operation is taking place. * - * If there are any driver/psoc transition taking place, then the vdev trans/ops + * If there are any driver transition taking place, then the vdev trans/ops * should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL * in this case. * + * If there are any psoc transition taking place becasue of ssr or driver + * unload, then the vdev trans/ops should be rejected and not queued in the + * DSC queue. Return QDF_STATUS_E_INVAL in this case. + * + * If there is a psoc transition taking place becasue of psoc idle shutdown, + * then the vdev trans/ops should be rejected and queued in the DSC queue so + * that it may be resumed after the current trans/ops is completed. Return + * QDF_STATUS_E_AGAIN in this case. + * * If there are any vdev trans/ops taking place, then the vdev trans/ops * should be rejected and queued in the DSC queue so that it may be resumed * after the current trans/ops is completed. Return QDF_STATUS_E_AGAIN in this @@ -128,10 +138,20 @@ void dsc_vdev_destroy(struct dsc_vdev **out_vdev) */ static QDF_STATUS __dsc_vdev_can_trans(struct dsc_vdev *vdev) { - if (__dsc_trans_active_or_queued(&vdev->psoc->driver->trans) || - __dsc_trans_active_or_queued(&vdev->psoc->trans)) + if (__dsc_trans_active_or_queued(&vdev->psoc->driver->trans)) return QDF_STATUS_E_INVAL; + if (__dsc_trans_active_or_queued(&vdev->psoc->trans)) { + /* psoc idle shutdown(wifi off) needs to be added in DSC queue + * to avoid wifi on failure while previous psoc idle shutdown + * is in progress and wifi is turned on. + */ + if (cds_is_driver_unloading() || qdf_is_recovering()) + return QDF_STATUS_E_INVAL; + else + return QDF_STATUS_E_AGAIN; + } + if (__dsc_trans_active_or_queued(&vdev->trans)) return QDF_STATUS_E_AGAIN; diff --git a/components/dsc/test/wlan_dsc_test.c b/components/dsc/test/wlan_dsc_test.c index 5871cdf5b64b..3354e0d1c1eb 100644 --- a/components/dsc/test/wlan_dsc_test.c +++ b/components/dsc/test/wlan_dsc_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020 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 @@ -23,6 +23,7 @@ #include "qdf_types.h" #include "wlan_dsc.h" #include "wlan_dsc_test.h" +#include "cds_api.h" #define dsc_driver_trans_start(driver) dsc_driver_trans_start(driver, __func__) #define dsc_psoc_trans_start(psoc) dsc_psoc_trans_start(psoc, __func__) @@ -263,10 +264,30 @@ static uint32_t dsc_test_psoc_trans_blocks(void) action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors); /* ... children vdev trans/ops to fail */ + dsc_for_each_psoc_vdev(psoc, vdev) { + action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(vdev, op, QDF_STATUS_E_AGAIN, errors); + } + + /* ... while driver unload in progress vdev op and trans should be + * rejected with EINVAL + */ + cds_set_unload_in_progress(true); dsc_for_each_psoc_vdev(psoc, vdev) { action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors); action_expect(vdev, op, QDF_STATUS_E_INVAL, errors); } + cds_set_unload_in_progress(false); + + /* ... while SSR recovery in progress vdev op and trans should be + * rejected with EINVAL + */ + cds_set_recovery_in_progress(true); + dsc_for_each_psoc_vdev(psoc, vdev) { + action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors); + action_expect(vdev, op, QDF_STATUS_E_INVAL, errors); + } + cds_set_recovery_in_progress(false); /* a sibling psoc in transition should succeed and cause ... */ psoc = nth_psoc(driver, 2); @@ -282,8 +303,8 @@ static uint32_t dsc_test_psoc_trans_blocks(void) /* ... children vdev trans/ops to fail */ dsc_for_each_psoc_vdev(psoc, vdev) { - action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors); - action_expect(vdev, op, QDF_STATUS_E_INVAL, errors); + action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(vdev, op, QDF_STATUS_E_AGAIN, errors); } /* teardown */ diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index e6980d57e9fa..6b52290536fa 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -10213,7 +10213,6 @@ static int __hdd_psoc_idle_shutdown(struct hdd_context *hdd_ctx) } osif_psoc_sync_wait_for_ops(psoc_sync); - errno = hdd_wlan_stop_modules(hdd_ctx, false); osif_psoc_sync_trans_stop(psoc_sync); @@ -14987,6 +14986,9 @@ static void hdd_driver_unload(void) pr_info("%s: Unloading driver v%s\n", WLAN_MODULE_NAME, QWLAN_VERSIONSTR); + cds_set_driver_loaded(false); + cds_set_unload_in_progress(true); + if (hdd_ctx) hdd_psoc_idle_timer_stop(hdd_ctx); @@ -15003,9 +15005,6 @@ static void hdd_driver_unload(void) osif_driver_sync_unregister(); osif_driver_sync_wait_for_ops(driver_sync); - cds_set_driver_loaded(false); - cds_set_unload_in_progress(true); - hdd_driver_mode_change_unregister(); pld_deinit(); wlan_hdd_state_ctrl_param_destroy(); diff --git a/core/pld/src/pld_pcie.c b/core/pld/src/pld_pcie.c index 3139b6026bb7..8f7cc04eb578 100644 --- a/core/pld/src/pld_pcie.c +++ b/core/pld/src/pld_pcie.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020 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 @@ -29,7 +29,6 @@ #include "pld_internal.h" #include "pld_pcie.h" #include "osif_psoc_sync.h" -#include #ifdef CONFIG_PCI @@ -93,9 +92,6 @@ static void pld_pcie_remove(struct pci_dev *pdev) osif_psoc_sync_unregister(&pdev->dev); - cds_set_driver_loaded(false); - cds_set_unload_in_progress(true); - osif_psoc_sync_wait_for_ops(psoc_sync); pld_context = pld_get_global_context();