From 06878b3a807c6aa8e99dd4ba1c2dcc2a672e7f27 Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Fri, 22 Mar 2019 13:18:27 -0700 Subject: [PATCH] qcacld-3.0: Reject up-tree ops during transition Currently, the Driver Synchronization Core (DSC) blocks transitions up-tree and down-tree from a node currently undergoing a transition, but only rejects operations down-tree from the current node. Instead, reject new operations both up-tree and down-tree from the current node under transition. This provides more forgiving safety guarantees to operation implementations at the cost of a reduced amount of parallelism that can be achieved. Change-Id: I09e1c48f7030a2252380d172c1c00ee22eac39c5 CRs-Fixed: 2421786 --- components/dsc/inc/wlan_dsc.h | 14 +++++------ components/dsc/src/wlan_dsc_driver.c | 7 ++---- components/dsc/src/wlan_dsc_psoc.c | 8 ++----- components/dsc/src/wlan_dsc_vdev.c | 11 ++++----- components/dsc/test/wlan_dsc_test.c | 36 ++++++++++++++++++---------- 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/components/dsc/inc/wlan_dsc.h b/components/dsc/inc/wlan_dsc.h index 49dd2ddfe200..6bacfc37a929 100644 --- a/components/dsc/inc/wlan_dsc.h +++ b/components/dsc/inc/wlan_dsc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019 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 @@ -37,12 +37,12 @@ * and vdev. These levels are arranged into a tree, with a single driver at * the root, zero or more psocs per driver, and zero or more vdevs per psoc. * - * High level transitions block transitions and operations at the same level - * down, and low level transitions block transitions at the same level up. So a - * driver transition effectively prevents any new activity in the system, while - * a vdev transition prevents transtitions on the same vdev, its parent psoc, - * and the driver. This also means that sibling nodes can transition at the same - * time, e.g. one vdev going up at the same time another is going down. + * High level transitions block transitions and operations at the same level, + * down-tree, and up-tree. So a driver transition effectively prevents any new + * activity in the system, while a vdev transition prevents transtitions and + * operations on the same vdev, its parent psoc, and the driver. This also means + * that sibling nodes can transition at the same time, e.g. one vdev going up at + * the same time another is going down. */ #ifndef __WLAN_DSC_H diff --git a/components/dsc/src/wlan_dsc_driver.c b/components/dsc/src/wlan_dsc_driver.c index 192bf8e9a4e3..2933087544dd 100644 --- a/components/dsc/src/wlan_dsc_driver.c +++ b/components/dsc/src/wlan_dsc_driver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019 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 @@ -123,10 +123,7 @@ static bool __dsc_driver_trans_active_down_tree(struct dsc_driver *driver) return false; } -static bool __dsc_driver_can_op(struct dsc_driver *driver) -{ - return !__dsc_trans_active_or_queued(&driver->trans); -} +#define __dsc_driver_can_op(driver) __dsc_driver_can_trans(driver) static bool __dsc_driver_can_trans(struct dsc_driver *driver) { diff --git a/components/dsc/src/wlan_dsc_psoc.c b/components/dsc/src/wlan_dsc_psoc.c index 8c208eb461a0..f0cdc3a6cab6 100644 --- a/components/dsc/src/wlan_dsc_psoc.c +++ b/components/dsc/src/wlan_dsc_psoc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019 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 @@ -124,11 +124,7 @@ static bool __dsc_psoc_trans_active_down_tree(struct dsc_psoc *psoc) return false; } -static bool __dsc_psoc_can_op(struct dsc_psoc *psoc) -{ - return !__dsc_trans_active_or_queued(&psoc->driver->trans) && - !__dsc_trans_active_or_queued(&psoc->trans); -} +#define __dsc_psoc_can_op(psoc) __dsc_psoc_can_trans(psoc) static bool __dsc_psoc_can_trans(struct dsc_psoc *psoc) { diff --git a/components/dsc/src/wlan_dsc_vdev.c b/components/dsc/src/wlan_dsc_vdev.c index c0f19e482e2d..b14905674aa7 100644 --- a/components/dsc/src/wlan_dsc_vdev.c +++ b/components/dsc/src/wlan_dsc_vdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019 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 @@ -106,18 +106,15 @@ void dsc_vdev_destroy(struct dsc_vdev **out_vdev) dsc_exit(); } -static bool __dsc_vdev_can_op(struct dsc_vdev *vdev) +#define __dsc_vdev_can_op(vdev) __dsc_vdev_can_trans(vdev) + +static bool __dsc_vdev_can_trans(struct dsc_vdev *vdev) { return !__dsc_trans_active_or_queued(&vdev->psoc->driver->trans) && !__dsc_trans_active_or_queued(&vdev->psoc->trans) && !__dsc_trans_active_or_queued(&vdev->trans); } -static bool __dsc_vdev_can_trans(struct dsc_vdev *vdev) -{ - return __dsc_vdev_can_op(vdev); -} - static QDF_STATUS __dsc_vdev_trans_start_nolock(struct dsc_vdev *vdev, const char *desc) { diff --git a/components/dsc/test/wlan_dsc_test.c b/components/dsc/test/wlan_dsc_test.c index dd9f2860394f..3eb54b87a4a4 100644 --- a/components/dsc/test/wlan_dsc_test.c +++ b/components/dsc/test/wlan_dsc_test.c @@ -199,17 +199,21 @@ static uint32_t dsc_test_driver_trans_blocks(void) goto exit; } - action_expect(driver, trans, QDF_STATUS_SUCCESS, errors); - /* test */ + /* a driver in transition should cause ... */ + action_expect(driver, trans, QDF_STATUS_SUCCESS, errors); + + /* ... the same driver trans/ops to fail */ action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors); action_expect(driver, op, QDF_STATUS_E_AGAIN, errors); + /* ... children psoc trans/ops to fail */ dsc_for_each_driver_psoc(driver, psoc) { action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors); action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors); + /* ... grandchildren 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); @@ -248,31 +252,37 @@ static uint32_t dsc_test_psoc_trans_blocks(void) /* test */ + /* a psoc in transition should cause ... */ psoc = nth_psoc(driver, 1); action_expect(psoc, trans, QDF_STATUS_SUCCESS, errors); + /* ... driver trans/ops to fail */ action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors); - action_expect(driver, op, QDF_STATUS_SUCCESS, errors); - dsc_driver_op_stop(driver); + action_expect(driver, op, QDF_STATUS_E_AGAIN, errors); + /* ... the same psoc trans/ops to fail */ action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors); 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); } + /* a sibling psoc in transition should succeed and cause ... */ psoc = nth_psoc(driver, 2); action_expect(psoc, trans, QDF_STATUS_SUCCESS, errors); + /* ... driver trans/ops to fail */ action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors); - action_expect(driver, op, QDF_STATUS_SUCCESS, errors); - dsc_driver_op_stop(driver); + action_expect(driver, op, QDF_STATUS_E_AGAIN, errors); + /* ... the same psoc trans/ops to fail */ action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors); 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); @@ -309,22 +319,24 @@ static uint32_t dsc_test_vdev_trans_blocks(void) goto exit; } + /* test */ + + /* a vdev in transition should cause ... */ dsc_for_each_driver_psoc(driver, psoc) { dsc_for_each_psoc_vdev(psoc, vdev) action_expect(vdev, trans, QDF_STATUS_SUCCESS, errors); } - /* test */ - + /* ... driver trans/ops to fail */ action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors); - action_expect(driver, op, QDF_STATUS_SUCCESS, errors); - dsc_driver_op_stop(driver); + action_expect(driver, op, QDF_STATUS_E_AGAIN, errors); + /* ... psoc trans/ops to fail */ dsc_for_each_driver_psoc(driver, psoc) { action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors); - action_expect(psoc, op, QDF_STATUS_SUCCESS, errors); - dsc_psoc_op_stop(psoc); + action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors); + /* ... the same 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);