Skip to content

Commit 191e8d5

Browse files
ilanpeer2gregkh
authored andcommitted
wifi: iwlwifi: mvm: Fix a race in scan abort flow
[ Upstream commit 87c1c28 ] When the upper layer requests to cancel an ongoing scan, a race is possible in which by the time the driver starts to handle the upper layers scan cancel flow, the FW already completed handling the scan request and the driver received the scan complete notification but still did not handle the notification. In such a case the FW will simply ignore the scan abort request coming from the driver, no notification would arrive from the FW and the entire abort flow would be considered a failure. To better handle this, check the status code returned by the FW for the scan abort command. In case the status indicates that no scan was aborted, complete the scan abort flow with success, i.e., the scan was aborted, as the flow is expected to consume the scan complete notification. Signed-off-by: Ilan Peer <[email protected]> Signed-off-by: Miri Korenblit <[email protected]> Link: https://patch.msgid.link/20240825085558.483989d3baef.I3340556a222388504c6330b333360bf77d10f9e2@changeid Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 82465e0 commit 191e8d5

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

drivers/net/wireless/intel/iwlwifi/fw/api/scan.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,19 @@ struct iwl_umac_scan_abort {
11231123
__le32 flags;
11241124
} __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */
11251125

1126+
/**
1127+
* enum iwl_umac_scan_abort_status
1128+
*
1129+
* @IWL_UMAC_SCAN_ABORT_STATUS_SUCCESS: scan was successfully aborted
1130+
* @IWL_UMAC_SCAN_ABORT_STATUS_IN_PROGRESS: scan abort is in progress
1131+
* @IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND: nothing to abort
1132+
*/
1133+
enum iwl_umac_scan_abort_status {
1134+
IWL_UMAC_SCAN_ABORT_STATUS_SUCCESS = 0,
1135+
IWL_UMAC_SCAN_ABORT_STATUS_IN_PROGRESS,
1136+
IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND,
1137+
};
1138+
11261139
/**
11271140
* struct iwl_umac_scan_complete
11281141
* @uid: scan id, &enum iwl_umac_scan_uid_offsets

drivers/net/wireless/intel/iwlwifi/mvm/scan.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3222,13 +3222,23 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
32223222
mvm->scan_start);
32233223
}
32243224

3225-
static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
3225+
static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type, bool *wait)
32263226
{
3227-
struct iwl_umac_scan_abort cmd = {};
3227+
struct iwl_umac_scan_abort abort_cmd = {};
3228+
struct iwl_host_cmd cmd = {
3229+
.id = WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC),
3230+
.len = { sizeof(abort_cmd), },
3231+
.data = { &abort_cmd, },
3232+
.flags = CMD_SEND_IN_RFKILL,
3233+
};
3234+
32283235
int uid, ret;
3236+
u32 status = IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND;
32293237

32303238
lockdep_assert_held(&mvm->mutex);
32313239

3240+
*wait = true;
3241+
32323242
/* We should always get a valid index here, because we already
32333243
* checked that this type of scan was running in the generic
32343244
* code.
@@ -3237,17 +3247,28 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
32373247
if (WARN_ON_ONCE(uid < 0))
32383248
return uid;
32393249

3240-
cmd.uid = cpu_to_le32(uid);
3250+
abort_cmd.uid = cpu_to_le32(uid);
32413251

32423252
IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid);
32433253

3244-
ret = iwl_mvm_send_cmd_pdu(mvm,
3245-
WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC),
3246-
CMD_SEND_IN_RFKILL, sizeof(cmd), &cmd);
3254+
ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
3255+
3256+
IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d, status=%u\n", ret, status);
32473257
if (!ret)
32483258
mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT;
32493259

3250-
IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d\n", ret);
3260+
/* Handle the case that the FW is no longer familiar with the scan that
3261+
* is to be stopped. In such a case, it is expected that the scan
3262+
* complete notification was already received but not yet processed.
3263+
* In such a case, there is no need to wait for a scan complete
3264+
* notification and the flow should continue similar to the case that
3265+
* the scan was really aborted.
3266+
*/
3267+
if (status == IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND) {
3268+
mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT;
3269+
*wait = false;
3270+
}
3271+
32513272
return ret;
32523273
}
32533274

@@ -3257,6 +3278,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
32573278
static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC,
32583279
SCAN_OFFLOAD_COMPLETE, };
32593280
int ret;
3281+
bool wait = true;
32603282

32613283
lockdep_assert_held(&mvm->mutex);
32623284

@@ -3268,14 +3290,18 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
32683290
IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type);
32693291

32703292
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
3271-
ret = iwl_mvm_umac_scan_abort(mvm, type);
3293+
ret = iwl_mvm_umac_scan_abort(mvm, type, &wait);
32723294
else
32733295
ret = iwl_mvm_lmac_scan_abort(mvm);
32743296

32753297
if (ret) {
32763298
IWL_DEBUG_SCAN(mvm, "couldn't stop scan type %d\n", type);
32773299
iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
32783300
return ret;
3301+
} else if (!wait) {
3302+
IWL_DEBUG_SCAN(mvm, "no need to wait for scan type %d\n", type);
3303+
iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
3304+
return 0;
32793305
}
32803306

32813307
return iwl_wait_notification(&mvm->notif_wait, &wait_scan_done,

0 commit comments

Comments
 (0)