diff --git a/components/dsc/src/wlan_dsc_vdev.c b/components/dsc/src/wlan_dsc_vdev.c index 95d39692ea..a50411f80d 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 5871cdf5b6..3354e0d1c1 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 e6980d57e9..6b52290536 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 3139b6026b..8f7cc04eb5 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();