qcacld-3.0: Vdev trans return directly if psoc/driver is in transition
Issue happen when: thread1: rmmod driver, wlan_hdd_pld_remove which will get psoc trans. then try to get rntl_lock in hdd_unregister_wext; thread2: trigger iw del interface, cfgops in kernel will get get rtnl_lock, in wlan_hdd_del_virtual_intf, vdev trans will be blocked by psoc trans in thread1. as thread1 it is also waiting for rtnl_lock, so both thread will be stuck. Fix is: In psoc trans, vdev trans and vdev ops is not allowed, which should return directly. Change-Id: I9cbd04bac438bb9483b4e89e73801fe71859e139 CRs-Fixed: 2583675
This commit is contained in:
@@ -115,11 +115,11 @@ void dsc_vdev_destroy(struct dsc_vdev **out_vdev)
|
|||||||
* This function checks if the vdev transition can occur or not by checking if
|
* 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.
|
* any other down the tree/up the tree transition/operation is taking place.
|
||||||
*
|
*
|
||||||
* If there are any driver transition taking place, then the vdev trans/ops
|
* If there are any driver/psoc transition taking place, then the vdev trans/ops
|
||||||
* should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL
|
* should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL
|
||||||
* in this case.
|
* in this case.
|
||||||
*
|
*
|
||||||
* If there any psoc or vdev trans/ops is taking place, then the vdev trans/ops
|
* 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
|
* 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
|
* after the current trans/ops is completed. Return QDF_STATUS_E_AGAIN in this
|
||||||
* case.
|
* case.
|
||||||
@@ -128,11 +128,11 @@ void dsc_vdev_destroy(struct dsc_vdev **out_vdev)
|
|||||||
*/
|
*/
|
||||||
static QDF_STATUS __dsc_vdev_can_trans(struct dsc_vdev *vdev)
|
static QDF_STATUS __dsc_vdev_can_trans(struct dsc_vdev *vdev)
|
||||||
{
|
{
|
||||||
if (__dsc_trans_active_or_queued(&vdev->psoc->driver->trans))
|
if (__dsc_trans_active_or_queued(&vdev->psoc->driver->trans) ||
|
||||||
|
__dsc_trans_active_or_queued(&vdev->psoc->trans))
|
||||||
return QDF_STATUS_E_INVAL;
|
return QDF_STATUS_E_INVAL;
|
||||||
|
|
||||||
if (__dsc_trans_active_or_queued(&vdev->psoc->trans) ||
|
if (__dsc_trans_active_or_queued(&vdev->trans))
|
||||||
__dsc_trans_active_or_queued(&vdev->trans))
|
|
||||||
return QDF_STATUS_E_AGAIN;
|
return QDF_STATUS_E_AGAIN;
|
||||||
|
|
||||||
return QDF_STATUS_SUCCESS;
|
return QDF_STATUS_SUCCESS;
|
||||||
|
@@ -264,8 +264,8 @@ static uint32_t dsc_test_psoc_trans_blocks(void)
|
|||||||
|
|
||||||
/* ... children vdev trans/ops to fail */
|
/* ... 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_INVAL, errors);
|
||||||
action_expect(vdev, op, QDF_STATUS_E_AGAIN, errors);
|
action_expect(vdev, op, QDF_STATUS_E_INVAL, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* a sibling psoc in transition should succeed and cause ... */
|
/* a sibling psoc in transition should succeed and cause ... */
|
||||||
@@ -282,8 +282,8 @@ static uint32_t dsc_test_psoc_trans_blocks(void)
|
|||||||
|
|
||||||
/* ... children vdev trans/ops to fail */
|
/* ... 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_INVAL, errors);
|
||||||
action_expect(vdev, op, QDF_STATUS_E_AGAIN, errors);
|
action_expect(vdev, op, QDF_STATUS_E_INVAL, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* teardown */
|
/* teardown */
|
||||||
|
Reference in New Issue
Block a user