wcn36xx: dequeue all pending indicator messages

In case wcn36xx_smd_rsp_process() is called more than once before
hal_ind_work was dispatched, the messages will end up in hal_ind_queue,
but wcn36xx_ind_smd_work() will only look at the first message in that
list.

Fix this by dequeing the messages from the list in a loop, and only stop
when it's empty.

This issue was found during a review of the driver. In my tests, that
race never actually occured.

Signed-off-by: Daniel Mack <daniel@zonque.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
Daniel Mack 2018-03-27 11:26:58 +03:00 committed by Kalle Valo
parent e5f9908155
commit f276ba06e8
1 changed files with 52 additions and 43 deletions

View File

@ -2411,54 +2411,63 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
{
struct wcn36xx *wcn =
container_of(work, struct wcn36xx, hal_ind_work);
struct wcn36xx_hal_msg_header *msg_header;
struct wcn36xx_hal_ind_msg *hal_ind_msg;
unsigned long flags;
spin_lock_irqsave(&wcn->hal_ind_lock, flags);
for (;;) {
struct wcn36xx_hal_msg_header *msg_header;
struct wcn36xx_hal_ind_msg *hal_ind_msg;
unsigned long flags;
hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
struct wcn36xx_hal_ind_msg,
list);
list_del(wcn->hal_ind_queue.next);
spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
spin_lock_irqsave(&wcn->hal_ind_lock, flags);
msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
if (list_empty(&wcn->hal_ind_queue)) {
spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
return;
}
switch (msg_header->msg_type) {
case WCN36XX_HAL_COEX_IND:
case WCN36XX_HAL_DEL_BA_IND:
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
break;
case WCN36XX_HAL_OTA_TX_COMPL_IND:
wcn36xx_smd_tx_compl_ind(wcn,
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
case WCN36XX_HAL_MISSED_BEACON_IND:
wcn36xx_smd_missed_beacon_ind(wcn,
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
wcn36xx_smd_delete_sta_context_ind(wcn,
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
case WCN36XX_HAL_PRINT_REG_INFO_IND:
wcn36xx_smd_print_reg_info_ind(wcn,
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
case WCN36XX_HAL_SCAN_OFFLOAD_IND:
wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
default:
wcn36xx_err("SMD_EVENT (%d) not supported\n",
msg_header->msg_type);
hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
struct wcn36xx_hal_ind_msg,
list);
list_del(&hal_ind_msg->list);
spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
switch (msg_header->msg_type) {
case WCN36XX_HAL_COEX_IND:
case WCN36XX_HAL_DEL_BA_IND:
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
break;
case WCN36XX_HAL_OTA_TX_COMPL_IND:
wcn36xx_smd_tx_compl_ind(wcn,
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
case WCN36XX_HAL_MISSED_BEACON_IND:
wcn36xx_smd_missed_beacon_ind(wcn,
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
wcn36xx_smd_delete_sta_context_ind(wcn,
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
case WCN36XX_HAL_PRINT_REG_INFO_IND:
wcn36xx_smd_print_reg_info_ind(wcn,
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
case WCN36XX_HAL_SCAN_OFFLOAD_IND:
wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
default:
wcn36xx_err("SMD_EVENT (%d) not supported\n",
msg_header->msg_type);
}
kfree(hal_ind_msg);
}
kfree(hal_ind_msg);
}
int wcn36xx_smd_open(struct wcn36xx *wcn)
{