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
This commit is contained in:
@@ -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
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* 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
|
* 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.
|
* 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
|
* 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
|
* down-tree, and up-tree. So a driver transition effectively prevents any new
|
||||||
* driver transition effectively prevents any new activity in the system, while
|
* activity in the system, while a vdev transition prevents transtitions and
|
||||||
* a vdev transition prevents transtitions on the same vdev, its parent psoc,
|
* operations on the same vdev, its parent psoc, and the driver. This also means
|
||||||
* and the driver. This also means that sibling nodes can transition at the same
|
* that sibling nodes can transition at the same time, e.g. one vdev going up at
|
||||||
* time, e.g. one vdev going up at the same time another is going down.
|
* the same time another is going down.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __WLAN_DSC_H
|
#ifndef __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
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __dsc_driver_can_op(struct dsc_driver *driver)
|
#define __dsc_driver_can_op(driver) __dsc_driver_can_trans(driver)
|
||||||
{
|
|
||||||
return !__dsc_trans_active_or_queued(&driver->trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool __dsc_driver_can_trans(struct dsc_driver *driver)
|
static bool __dsc_driver_can_trans(struct dsc_driver *driver)
|
||||||
{
|
{
|
||||||
|
@@ -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
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __dsc_psoc_can_op(struct dsc_psoc *psoc)
|
#define __dsc_psoc_can_op(psoc) __dsc_psoc_can_trans(psoc)
|
||||||
{
|
|
||||||
return !__dsc_trans_active_or_queued(&psoc->driver->trans) &&
|
|
||||||
!__dsc_trans_active_or_queued(&psoc->trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool __dsc_psoc_can_trans(struct dsc_psoc *psoc)
|
static bool __dsc_psoc_can_trans(struct dsc_psoc *psoc)
|
||||||
{
|
{
|
||||||
|
@@ -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
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
* any purpose with or without fee is hereby granted, provided that the
|
* 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();
|
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) &&
|
return !__dsc_trans_active_or_queued(&vdev->psoc->driver->trans) &&
|
||||||
!__dsc_trans_active_or_queued(&vdev->psoc->trans) &&
|
!__dsc_trans_active_or_queued(&vdev->psoc->trans) &&
|
||||||
!__dsc_trans_active_or_queued(&vdev->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
|
static QDF_STATUS
|
||||||
__dsc_vdev_trans_start_nolock(struct dsc_vdev *vdev, const char *desc)
|
__dsc_vdev_trans_start_nolock(struct dsc_vdev *vdev, const char *desc)
|
||||||
{
|
{
|
||||||
|
@@ -199,17 +199,21 @@ static uint32_t dsc_test_driver_trans_blocks(void)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
action_expect(driver, trans, QDF_STATUS_SUCCESS, errors);
|
|
||||||
|
|
||||||
/* test */
|
/* 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, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(driver, op, 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) {
|
dsc_for_each_driver_psoc(driver, psoc) {
|
||||||
action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
|
action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(psoc, op, 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) {
|
dsc_for_each_psoc_vdev(psoc, vdev) {
|
||||||
action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors);
|
action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(vdev, op, 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 */
|
/* test */
|
||||||
|
|
||||||
|
/* a psoc in transition should cause ... */
|
||||||
psoc = nth_psoc(driver, 1);
|
psoc = nth_psoc(driver, 1);
|
||||||
action_expect(psoc, trans, QDF_STATUS_SUCCESS, errors);
|
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, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(driver, op, QDF_STATUS_SUCCESS, errors);
|
action_expect(driver, op, QDF_STATUS_E_AGAIN, errors);
|
||||||
dsc_driver_op_stop(driver);
|
|
||||||
|
|
||||||
|
/* ... the same psoc trans/ops to fail */
|
||||||
action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
|
action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(psoc, op, 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) {
|
dsc_for_each_psoc_vdev(psoc, vdev) {
|
||||||
action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors);
|
action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(vdev, op, 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);
|
psoc = nth_psoc(driver, 2);
|
||||||
action_expect(psoc, trans, QDF_STATUS_SUCCESS, errors);
|
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, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(driver, op, QDF_STATUS_SUCCESS, errors);
|
action_expect(driver, op, QDF_STATUS_E_AGAIN, errors);
|
||||||
dsc_driver_op_stop(driver);
|
|
||||||
|
|
||||||
|
/* ... the same psoc trans/ops to fail */
|
||||||
action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
|
action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(psoc, op, 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) {
|
dsc_for_each_psoc_vdev(psoc, vdev) {
|
||||||
action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors);
|
action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(vdev, op, 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;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* test */
|
||||||
|
|
||||||
|
/* a vdev in transition should cause ... */
|
||||||
dsc_for_each_driver_psoc(driver, psoc) {
|
dsc_for_each_driver_psoc(driver, psoc) {
|
||||||
dsc_for_each_psoc_vdev(psoc, vdev)
|
dsc_for_each_psoc_vdev(psoc, vdev)
|
||||||
action_expect(vdev, trans, QDF_STATUS_SUCCESS, errors);
|
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, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(driver, op, QDF_STATUS_SUCCESS, errors);
|
action_expect(driver, op, QDF_STATUS_E_AGAIN, errors);
|
||||||
dsc_driver_op_stop(driver);
|
|
||||||
|
|
||||||
|
/* ... psoc trans/ops to fail */
|
||||||
dsc_for_each_driver_psoc(driver, psoc) {
|
dsc_for_each_driver_psoc(driver, psoc) {
|
||||||
action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
|
action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(psoc, op, QDF_STATUS_SUCCESS, errors);
|
action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors);
|
||||||
dsc_psoc_op_stop(psoc);
|
|
||||||
|
|
||||||
|
/* ... the same vdev trans/ops to fail */
|
||||||
dsc_for_each_psoc_vdev(psoc, vdev) {
|
dsc_for_each_psoc_vdev(psoc, vdev) {
|
||||||
action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors);
|
action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors);
|
||||||
action_expect(vdev, op, QDF_STATUS_E_AGAIN, errors);
|
action_expect(vdev, op, QDF_STATUS_E_AGAIN, errors);
|
||||||
|
Reference in New Issue
Block a user