diff --git a/umac/cmn_services/serialization/src/wlan_serialization_internal.c b/umac/cmn_services/serialization/src/wlan_serialization_internal.c index 2f4d58b17c8d..9f6442a53b1a 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_internal.c +++ b/umac/cmn_services/serialization/src/wlan_serialization_internal.c @@ -307,7 +307,17 @@ QDF_STATUS wlan_serialization_activate_cmd( * command is already pushed to active queue above * now start the timer and notify requestor */ - wlan_serialization_find_and_start_timer(psoc, &cmd_list->cmd); + + status = wlan_serialization_find_and_start_timer(psoc, &cmd_list->cmd, + ser_reason); + if (QDF_IS_STATUS_ERROR(status)) { + ser_err("Failed to start timer cmd type[%d] id[%d] vdev[%d]", + cmd_list->cmd.cmd_type, + cmd_list->cmd.cmd_id, + wlan_vdev_get_id(cmd_list->cmd.vdev)); + goto timer_failed; + } + /* * Remember that serialization module may send * this callback in same context through which it @@ -335,6 +345,7 @@ QDF_STATUS wlan_serialization_activate_cmd( wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); +timer_failed: if (QDF_IS_STATUS_ERROR(status)) { wlan_serialization_dequeue_cmd(&cmd_list->cmd, SER_ACTIVATION_FAILED, @@ -500,7 +511,9 @@ wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd, } if (active_cmd) - wlan_serialization_find_and_stop_timer(psoc, &cmd_list->cmd); + wlan_serialization_find_and_stop_timer( + psoc, &cmd_list->cmd, + ser_reason); qdf_mem_copy(&cmd_bkup, &cmd_list->cmd, sizeof(struct wlan_serialization_command)); @@ -548,14 +561,22 @@ void wlan_serialization_generic_timer_cb(void *arg) { struct wlan_serialization_timer *timer = arg; struct wlan_serialization_command *cmd = timer->cmd; + struct wlan_objmgr_vdev *vdev = NULL; + if (!cmd) { ser_err("Command not found"); return; } - ser_err("active cmd timeout for cmd_type[%d] vdev[%pK]", - cmd->cmd_type, cmd->vdev); + vdev = cmd->vdev; + if (!vdev) { + ser_err("Invalid vdev"); + return; + } + + ser_err("active cmd timeout for cmd_type[%d] vdev[%d]", + cmd->cmd_type, wlan_vdev_get_id(cmd->vdev)); if (cmd->cmd_cb) cmd->cmd_cb(cmd, WLAN_SER_CB_ACTIVE_CMD_TIMEOUT); @@ -565,6 +586,9 @@ void wlan_serialization_generic_timer_cb(void *arg) * dequeue command then we have to destroy the timer. */ wlan_serialization_dequeue_cmd(cmd, SER_TIMEOUT, true); + + /* Release the ref taken before the timer was started */ + wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); } static QDF_STATUS wlan_serialization_mc_flush_noop(struct scheduler_msg *msg) @@ -595,11 +619,19 @@ wlan_serialization_timer_cb_mc_ctx(void *arg) static void wlan_serialization_timer_handler(void *arg) { - ser_enter(); + struct wlan_serialization_timer *timer = arg; + struct wlan_serialization_command *cmd = timer->cmd; + + if (!cmd) { + ser_err("Command not found"); + return; + } + + ser_err("active cmd timeout for cmd_type[%d] vdev[%d]", + cmd->cmd_type, wlan_vdev_get_id(cmd->vdev)); wlan_serialization_timer_cb_mc_ctx(arg); - ser_exit(); } QDF_STATUS @@ -644,7 +676,7 @@ wlan_serialization_find_and_update_timer( ser_debug("Updated the timer for cmd type:%d, id: %d", cmd->cmd_type, cmd->cmd_id); else - ser_err("Can't find timer for cmd_type[%d]", cmd->cmd_type); + ser_debug("Can't find timer for cmd_type[%d]", cmd->cmd_type); exit: return status; @@ -652,13 +684,15 @@ exit: QDF_STATUS wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc, - struct wlan_serialization_command *cmd) + struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason) { struct wlan_ser_psoc_obj *psoc_ser_obj; struct wlan_serialization_timer *ser_timer; QDF_STATUS status = QDF_STATUS_E_FAILURE; int i = 0; uint32_t phy_version; + struct wlan_objmgr_vdev *vdev; if (!psoc || !cmd) { ser_err("invalid param"); @@ -689,8 +723,21 @@ wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc, (ser_timer->cmd->vdev != cmd->vdev)) continue; + vdev = ser_timer->cmd->vdev; status = wlan_serialization_stop_timer(ser_timer); + /* + * Release the vdev reference when the active cmd is removed + * through remove/cancel request. + * + * In case the command removal is because of timer expiry, + * the vdev is released when the timer handler completes. + */ + if (vdev && ser_reason != SER_TIMEOUT) + wlan_objmgr_vdev_release_ref( + vdev, WLAN_SERIALIZATION_ID); + break; + } wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); @@ -708,7 +755,8 @@ exit: QDF_STATUS wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc, - struct wlan_serialization_command *cmd) + struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason) { QDF_STATUS status = QDF_STATUS_E_FAILURE; struct wlan_ser_psoc_obj *psoc_ser_obj; @@ -742,6 +790,24 @@ wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc, /* Remember timer is pointing to command */ ser_timer->cmd = cmd; status = QDF_STATUS_SUCCESS; + + /* + * Get vdev reference before starting the timer + * Remove the reference before removing the command + * in any one of the cases: + * 1. Active command is removed through remove/cancel request + * 2. Timer expiry handler is completed. + */ + + status = wlan_objmgr_vdev_try_get_ref(ser_timer->cmd->vdev, + WLAN_SERIALIZATION_ID); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_serialization_release_lock( + &psoc_ser_obj->timer_lock); + ser_err("Unbale to get vdev reference"); + status = QDF_STATUS_E_FAILURE; + goto error; + } break; } @@ -771,7 +837,6 @@ wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc, error: exit: - return status; } diff --git a/umac/cmn_services/serialization/src/wlan_serialization_internal_i.h b/umac/cmn_services/serialization/src/wlan_serialization_internal_i.h index c79065db0ee5..2e2e724fe38f 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_internal_i.h +++ b/umac/cmn_services/serialization/src/wlan_serialization_internal_i.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-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 @@ -136,6 +136,7 @@ void wlan_serialization_generic_timer_cb(void *arg); * wlan_serialization_find_and_start_timer() - to find and start the timer * @psoc: pointer to psoc * @cmd: pointer to actual command + * @ser_reason: serialization reason * * find the free timer, initialize it, and start it * @@ -143,7 +144,8 @@ void wlan_serialization_generic_timer_cb(void *arg); */ QDF_STATUS wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc, - struct wlan_serialization_command *cmd); + struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason); /** * wlan_serialization_find_and_update_timer() - to find and update the timer @@ -163,6 +165,7 @@ wlan_serialization_find_and_update_timer( * wlan_serialization_find_and_stop_timer() - to find and stop the timer * @psoc: pointer to psoc * @cmd: pointer to actual command + * @ser_reason: serialization reason * * find the timer associated with command, stop it and destroy it * @@ -170,7 +173,9 @@ wlan_serialization_find_and_update_timer( */ QDF_STATUS wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc, - struct wlan_serialization_command *cmd); + struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason); + /** * wlan_serialization_find_and_cancel_cmd() - to find cmd from queue and cancel diff --git a/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c b/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c index e1a1f9a4d683..4aabd72c03cf 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c +++ b/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c @@ -567,7 +567,8 @@ wlan_ser_cancel_non_scan_cmd( } qdf_status = wlan_serialization_find_and_stop_timer( - psoc, &cmd_list->cmd); + psoc, &cmd_list->cmd, + SER_CANCEL); if (QDF_IS_STATUS_ERROR(qdf_status)) { ser_err("Can't find timer for active cmd"); status = WLAN_SER_CMD_NOT_FOUND; diff --git a/umac/cmn_services/serialization/src/wlan_serialization_scan.c b/umac/cmn_services/serialization/src/wlan_serialization_scan.c index 6d66447ddb4c..6a38bf1bf294 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_scan.c +++ b/umac/cmn_services/serialization/src/wlan_serialization_scan.c @@ -270,7 +270,8 @@ wlan_ser_cancel_scan_cmd( } qdf_status = wlan_serialization_find_and_stop_timer( - psoc, &cmd_list->cmd); + psoc, &cmd_list->cmd, + SER_CANCEL); if (QDF_IS_STATUS_ERROR(qdf_status)) { ser_err("Can't fix timer for active cmd"); status = WLAN_SER_CMD_NOT_FOUND;