blob: 0041fa2e9a4f8f28ade41e755f7c82b44024f411 [file] [log] [blame]
/*
* Copyright (c) 2017 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
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC: define utility API related to the pmo component
* called by other components
*/
#include "wlan_pmo_obj_mgmt_api.h"
#include "wlan_pmo_tgt_api.h"
#include "wlan_pmo_static_config.h"
#include "wlan_pmo_main.h"
#include "target_if_pmo.h"
QDF_STATUS pmo_init(void)
{
QDF_STATUS status;
struct wlan_pmo_ctx *pmo_ctx;
PMO_ENTER();
if (pmo_allocate_ctx() != QDF_STATUS_SUCCESS) {
pmo_err("unable to allocate psoc ctx");
status = QDF_STATUS_E_FAULT;
goto out;
}
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
pmo_err("unable to get pmo ctx");
status = QDF_STATUS_E_INVAL;
goto out;
}
status = wlan_objmgr_register_psoc_create_handler(
WLAN_UMAC_COMP_PMO,
pmo_psoc_object_created_notification,
(void *)pmo_ctx);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("unable to register psoc create handle");
goto out;
}
status = wlan_objmgr_register_psoc_destroy_handler(
WLAN_UMAC_COMP_PMO,
pmo_psoc_object_destroyed_notification,
(void *)pmo_ctx);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("unable to register psoc create handle");
goto out;
}
status = wlan_objmgr_register_vdev_create_handler(
WLAN_UMAC_COMP_PMO,
pmo_vdev_object_created_notification,
(void *)pmo_ctx);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("unable to register vdev create handle");
goto out;
}
status = wlan_objmgr_register_vdev_destroy_handler(
WLAN_UMAC_COMP_PMO,
pmo_vdev_object_destroyed_notification,
(void *)pmo_ctx);
if (status != QDF_STATUS_SUCCESS)
pmo_err("unable to register vdev create handle");
out:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_deinit(void)
{
QDF_STATUS status;
struct wlan_pmo_ctx *pmo_ctx;
PMO_ENTER();
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
pmo_err("unable to get pmo ctx");
status = QDF_STATUS_E_FAILURE;
goto out;
}
status = wlan_objmgr_unregister_psoc_create_handler(
WLAN_UMAC_COMP_PMO,
pmo_psoc_object_created_notification,
(void *)pmo_ctx);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("unable to unregister psoc create handle");
goto out;
}
status = wlan_objmgr_unregister_psoc_destroy_handler(
WLAN_UMAC_COMP_PMO,
pmo_psoc_object_destroyed_notification,
(void *)pmo_ctx);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("unable to unregister psoc create handle");
goto out;
}
status = wlan_objmgr_unregister_vdev_create_handler(
WLAN_UMAC_COMP_PMO,
pmo_vdev_object_created_notification,
(void *)pmo_ctx);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("unable to unregister vdev create handle");
goto out;
}
status = wlan_objmgr_unregister_vdev_destroy_handler(
WLAN_UMAC_COMP_PMO,
pmo_vdev_object_destroyed_notification,
(void *)pmo_ctx);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("unable to unregister vdev create handle");
goto out;
}
out:
pmo_free_ctx();
PMO_EXIT();
return status;
}
QDF_STATUS pmo_psoc_object_created_notification(
struct wlan_objmgr_psoc *psoc, void *arg)
{
struct pmo_psoc_priv_obj *psoc_ctx = NULL;
QDF_STATUS status;
struct wlan_pmo_ctx *pmo_ctx;
PMO_ENTER();
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
QDF_ASSERT(0);
pmo_err("unable to get pmo ctx");
status = QDF_STATUS_E_FAILURE;
goto out;
}
psoc_ctx = qdf_mem_malloc(sizeof(*psoc_ctx));
if (psoc_ctx == NULL) {
pmo_err("Failed to allocate pmo_psoc");
status = QDF_STATUS_E_NOMEM;
goto out;
}
status = wlan_objmgr_psoc_component_obj_attach(psoc,
WLAN_UMAC_COMP_PMO,
psoc_ctx,
QDF_STATUS_SUCCESS);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("Failed to attach psoc_ctx with psoc");
qdf_mem_free(psoc_ctx);
status = QDF_STATUS_E_FAILURE;
goto out;
}
qdf_spinlock_create(&psoc_ctx->lock);
qdf_wake_lock_create(&psoc_ctx->wow.wow_wake_lock, "pmo_wow_wl");
status = qdf_event_create(&psoc_ctx->wow.target_suspend);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("target suspend event initialization failed");
status = QDF_STATUS_E_FAILURE;
goto out;
}
status = qdf_event_create(&psoc_ctx->wow.target_resume);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("target resume event initialization failed");
status = QDF_STATUS_E_FAILURE;
goto out;
}
/* Register PMO tx ops*/
target_if_pmo_register_tx_ops(&psoc_ctx->pmo_tx_ops);
out:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_psoc_object_destroyed_notification(
struct wlan_objmgr_psoc *psoc, void *arg)
{
struct pmo_psoc_priv_obj *psoc_ctx = NULL;
QDF_STATUS status;
PMO_ENTER();
psoc_ctx = pmo_psoc_get_priv(psoc);
status = wlan_objmgr_psoc_component_obj_detach(psoc,
WLAN_UMAC_COMP_PMO,
psoc_ctx);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("Failed to detach psoc_ctx from psoc");
status = QDF_STATUS_E_FAILURE;
goto out;
}
qdf_spinlock_destroy(&psoc_ctx->lock);
qdf_event_destroy(&psoc_ctx->wow.target_suspend);
qdf_event_destroy(&psoc_ctx->wow.target_resume);
qdf_wake_lock_destroy(&psoc_ctx->wow.wow_wake_lock);
qdf_mem_zero(psoc_ctx, sizeof(*psoc_ctx));
qdf_mem_free(psoc_ctx);
out:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_vdev_object_created_notification(
struct wlan_objmgr_vdev *vdev, void *arg)
{
struct pmo_psoc_priv_obj *psoc_ctx = NULL;
struct wlan_objmgr_psoc *psoc;
struct pmo_vdev_priv_obj *vdev_ctx;
QDF_STATUS status;
PMO_ENTER();
psoc = pmo_vdev_get_psoc(vdev);
psoc_ctx = pmo_psoc_get_priv(psoc);
vdev_ctx = qdf_mem_malloc(sizeof(*vdev_ctx));
if (vdev_ctx == NULL) {
pmo_err("Failed to allocate vdev_ctx");
status = QDF_STATUS_E_NOMEM;
goto out;
}
status = wlan_objmgr_vdev_component_obj_attach(vdev,
WLAN_UMAC_COMP_PMO,
(void *)vdev_ctx, QDF_STATUS_SUCCESS);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("Failed to attach vdev_ctx with vdev");
qdf_mem_free(vdev_ctx);
goto out;
}
qdf_spinlock_create(&vdev_ctx->pmo_vdev_lock);
vdev_ctx->ptrn_match_enable =
psoc_ctx->psoc_cfg.ptrn_match_enable_all_vdev;
vdev_ctx->pmo_psoc_ctx = psoc_ctx;
qdf_atomic_init(&vdev_ctx->gtk_err_enable);
out:
PMO_EXIT();
return QDF_STATUS_SUCCESS;
}
QDF_STATUS pmo_vdev_ready(struct wlan_objmgr_vdev *vdev)
{
QDF_STATUS status;
PMO_ENTER();
status = pmo_vdev_get_ref(vdev);
if (QDF_IS_STATUS_ERROR(status))
return status;
/* Register static configuration with firmware */
pmo_register_wow_wakeup_events(vdev);
pmo_register_action_frame_patterns(vdev);
/* Register default wow patterns with firmware */
pmo_register_wow_default_patterns(vdev);
pmo_vdev_put_ref(vdev);
PMO_EXIT();
/*
* The above APIs should return a status but don't.
* Just return success for now.
*/
return QDF_STATUS_SUCCESS;
}
QDF_STATUS pmo_vdev_object_destroyed_notification(
struct wlan_objmgr_vdev *vdev, void *arg)
{
struct pmo_vdev_priv_obj *vdev_ctx = NULL;
QDF_STATUS status = QDF_STATUS_SUCCESS;
PMO_ENTER();
vdev_ctx = pmo_vdev_get_priv(vdev);
status = wlan_objmgr_vdev_component_obj_detach(vdev,
WLAN_UMAC_COMP_PMO,
(void *)vdev_ctx);
if (status != QDF_STATUS_SUCCESS)
pmo_err("Failed to detach vdev_ctx with vdev");
qdf_spinlock_destroy(&vdev_ctx->pmo_vdev_lock);
qdf_mem_free(vdev_ctx);
PMO_EXIT();
return status;
}
QDF_STATUS pmo_register_suspend_handler(
enum wlan_umac_comp_id id,
pmo_psoc_suspend_handler handler,
void *arg)
{
struct wlan_pmo_ctx *pmo_ctx;
QDF_STATUS status = QDF_STATUS_SUCCESS;
PMO_ENTER();
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
QDF_ASSERT(0);
pmo_err("unable to get pmo ctx");
status = QDF_STATUS_E_FAILURE;
goto out;
}
if (id > WLAN_UMAC_MAX_COMPONENTS || id < 0) {
pmo_err("component id: %d is %s then valid components id",
id, id < 0 ? "Less" : "More");
status = QDF_STATUS_E_FAILURE;
goto out;
}
qdf_spin_lock_bh(&pmo_ctx->lock);
pmo_ctx->pmo_suspend_handler[id] = handler;
pmo_ctx->pmo_suspend_handler_arg[id] = arg;
qdf_spin_unlock_bh(&pmo_ctx->lock);
out:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_unregister_suspend_handler(
enum wlan_umac_comp_id id,
pmo_psoc_suspend_handler handler)
{
struct wlan_pmo_ctx *pmo_ctx;
QDF_STATUS status = QDF_STATUS_SUCCESS;
PMO_ENTER();
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
QDF_ASSERT(0);
pmo_err("unable to get pmo ctx");
status = QDF_STATUS_E_FAILURE;
goto out;
}
if (id > WLAN_UMAC_MAX_COMPONENTS || id < 0) {
pmo_err("component id: %d is %s then valid components id",
id, id < 0 ? "Less" : "More");
status = QDF_STATUS_E_FAILURE;
goto out;
}
qdf_spin_lock_bh(&pmo_ctx->lock);
if (pmo_ctx->pmo_suspend_handler[id] == handler) {
pmo_ctx->pmo_suspend_handler[id] = NULL;
pmo_ctx->pmo_suspend_handler_arg[id] = NULL;
qdf_spin_unlock_bh(&pmo_ctx->lock);
} else {
qdf_spin_unlock_bh(&pmo_ctx->lock);
pmo_err("can't find suspend handler for component id: %d ", id);
status = QDF_STATUS_E_FAILURE;
}
out:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_register_resume_handler(
enum wlan_umac_comp_id id,
pmo_psoc_resume_handler handler,
void *arg)
{
struct wlan_pmo_ctx *pmo_ctx;
QDF_STATUS status = QDF_STATUS_SUCCESS;
PMO_ENTER();
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
pmo_err("unable to get pmo ctx");
status = QDF_STATUS_E_FAILURE;
goto out;
}
if (id > WLAN_UMAC_MAX_COMPONENTS || id < 0) {
pmo_err("component id: %d is %s then valid components id",
id, id < 0 ? "Less" : "More");
status = QDF_STATUS_E_FAILURE;
goto out;
}
qdf_spin_lock_bh(&pmo_ctx->lock);
pmo_ctx->pmo_resume_handler[id] = handler;
pmo_ctx->pmo_resume_handler_arg[id] = arg;
qdf_spin_unlock_bh(&pmo_ctx->lock);
out:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_unregister_resume_handler(
enum wlan_umac_comp_id id,
pmo_psoc_resume_handler handler)
{
struct wlan_pmo_ctx *pmo_ctx;
QDF_STATUS status = QDF_STATUS_SUCCESS;
PMO_ENTER();
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
pmo_err("unable to get pmo ctx");
status = QDF_STATUS_E_FAILURE;
goto out;
}
if (id > WLAN_UMAC_MAX_COMPONENTS || id < 0) {
pmo_err("component id: %d is %s then valid components id",
id, id < 0 ? "Less" : "More");
status = QDF_STATUS_E_FAILURE;
goto out;
}
qdf_spin_lock_bh(&pmo_ctx->lock);
if (pmo_ctx->pmo_resume_handler[id] == handler) {
pmo_ctx->pmo_resume_handler[id] = NULL;
pmo_ctx->pmo_resume_handler_arg[id] = NULL;
qdf_spin_unlock_bh(&pmo_ctx->lock);
} else {
qdf_spin_unlock_bh(&pmo_ctx->lock);
pmo_err("can't find resume handler for component id: %d ", id);
status = QDF_STATUS_E_FAILURE;
}
out:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc,
enum qdf_suspend_type suspend_type)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
QDF_STATUS resume_status;
struct wlan_pmo_ctx *pmo_ctx;
uint8_t i;
pmo_psoc_suspend_handler handler;
void *arg;
PMO_ENTER();
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
pmo_err("unable to get pmo ctx");
QDF_ASSERT(0);
status = QDF_STATUS_E_FAILURE;
goto exit_with_status;
}
/* call each component's suspend handler */
for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) {
qdf_spin_lock_bh(&pmo_ctx->lock);
handler = pmo_ctx->pmo_suspend_handler[i];
arg = pmo_ctx->pmo_suspend_handler_arg[i];
qdf_spin_unlock_bh(&pmo_ctx->lock);
if (!handler)
continue;
status = handler(psoc, arg);
if (QDF_IS_STATUS_ERROR(status)) {
pmo_err("component %d failed to suspend; status: %d",
i, status);
QDF_ASSERT(0);
goto suspend_recovery;
}
}
goto exit_with_status;
suspend_recovery:
/* resume, starting with the last successfully suspended component */
for (i -= 1; i >= 0; i--) {
qdf_spin_lock_bh(&pmo_ctx->lock);
handler = pmo_ctx->pmo_resume_handler[i];
arg = pmo_ctx->pmo_resume_handler_arg[i];
qdf_spin_unlock_bh(&pmo_ctx->lock);
if (!handler)
continue;
resume_status = handler(psoc, arg);
if (QDF_IS_STATUS_ERROR(resume_status)) {
pmo_fatal("Non-recoverable failure occurred!");
pmo_fatal("component %d failed to resume; status: %d",
i, resume_status);
QDF_BUG(0);
}
}
exit_with_status:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_resume_all_components(struct wlan_objmgr_psoc *psoc,
enum qdf_suspend_type suspend_type)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct wlan_pmo_ctx *pmo_ctx;
uint8_t i;
pmo_psoc_suspend_handler handler;
void *arg;
PMO_ENTER();
pmo_ctx = pmo_get_context();
if (!pmo_ctx) {
pmo_err("unable to get pmo ctx");
QDF_ASSERT(0);
status = QDF_STATUS_E_FAILURE;
goto exit_with_status;
}
/* call each component's resume handler */
for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) {
qdf_spin_lock_bh(&pmo_ctx->lock);
handler = pmo_ctx->pmo_resume_handler[i];
arg = pmo_ctx->pmo_resume_handler_arg[i];
qdf_spin_unlock_bh(&pmo_ctx->lock);
if (!handler)
continue;
status = handler(psoc, arg);
if (QDF_IS_STATUS_ERROR(status)) {
pmo_fatal("Non-recoverable failure occurred!");
pmo_fatal("component %d failed to resume; status: %d",
i, status);
QDF_BUG(0);
}
}
exit_with_status:
PMO_EXIT();
return status;
}
QDF_STATUS pmo_register_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc,
pmo_notify_pause_bitmap handler)
{
struct pmo_psoc_priv_obj *psoc_ctx;
QDF_STATUS status;
if (!psoc) {
pmo_err("psoc is null");
return QDF_STATUS_E_NULL_VALUE;
}
if (!handler) {
pmo_err("pmo_notify_vdev_pause_bitmap is null");
return QDF_STATUS_E_NULL_VALUE;
}
status = pmo_psoc_get_ref(psoc);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("pmo cannot get the reference out of psoc");
return status;
}
psoc_ctx = pmo_psoc_get_priv(psoc);
qdf_spin_lock_bh(&psoc_ctx->lock);
psoc_ctx->pause_bitmap_notifier = handler;
qdf_spin_unlock_bh(&psoc_ctx->lock);
pmo_psoc_put_ref(psoc);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS pmo_unregister_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc,
pmo_notify_pause_bitmap handler)
{
struct pmo_psoc_priv_obj *psoc_ctx;
QDF_STATUS status;
if (!psoc) {
pmo_err("psoc is null");
return QDF_STATUS_E_NULL_VALUE;
}
if (!handler) {
pmo_err("pmo_notify_vdev_pause_bitmap is null");
return QDF_STATUS_E_NULL_VALUE;
}
status = pmo_psoc_get_ref(psoc);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("pmo cannot get the reference out of psoc");
return status;
}
psoc_ctx = pmo_psoc_get_priv(psoc);
qdf_spin_lock_bh(&psoc_ctx->lock);
if (psoc_ctx->pause_bitmap_notifier == handler)
psoc_ctx->pause_bitmap_notifier = NULL;
qdf_spin_unlock_bh(&psoc_ctx->lock);
pmo_psoc_put_ref(psoc);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS pmo_register_get_pause_bitmap(struct wlan_objmgr_psoc *psoc,
pmo_get_pause_bitmap handler)
{
struct pmo_psoc_priv_obj *psoc_ctx;
QDF_STATUS status;
if (!psoc) {
pmo_err("psoc is null");
return QDF_STATUS_E_NULL_VALUE;
}
if (!handler) {
pmo_err("pmo_get_pause_bitmap is null");
return QDF_STATUS_E_NULL_VALUE;
}
status = pmo_psoc_get_ref(psoc);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("pmo cannot get the reference out of psoc");
return status;
}
psoc_ctx = pmo_psoc_get_priv(psoc);
qdf_spin_lock_bh(&psoc_ctx->lock);
psoc_ctx->get_pause_bitmap = handler;
qdf_spin_unlock_bh(&psoc_ctx->lock);
pmo_psoc_put_ref(psoc);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS pmo_unregister_get_pause_bitmap(struct wlan_objmgr_psoc *psoc,
pmo_get_pause_bitmap handler)
{
struct pmo_psoc_priv_obj *psoc_ctx;
QDF_STATUS status;
if (!psoc) {
pmo_err("psoc is null");
return QDF_STATUS_E_NULL_VALUE;
}
if (!handler) {
pmo_err("pmo_get_pause_bitmap is null");
return QDF_STATUS_E_NULL_VALUE;
}
status = pmo_psoc_get_ref(psoc);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("pmo cannot get the reference out of psoc");
return status;
}
psoc_ctx = pmo_psoc_get_priv(psoc);
qdf_spin_lock_bh(&psoc_ctx->lock);
if (psoc_ctx->get_pause_bitmap == handler)
psoc_ctx->get_pause_bitmap = NULL;
qdf_spin_unlock_bh(&psoc_ctx->lock);
pmo_psoc_put_ref(psoc);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS pmo_register_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc,
pmo_is_device_in_low_pwr_mode handler)
{
struct pmo_psoc_priv_obj *psoc_ctx;
QDF_STATUS status;
if (!psoc) {
pmo_err("psoc is null");
return QDF_STATUS_E_NULL_VALUE;
}
if (!handler) {
pmo_err("pmo_get_pause_bitmap is null");
return QDF_STATUS_E_NULL_VALUE;
}
status = pmo_psoc_get_ref(psoc);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("pmo cannot get the reference out of psoc");
return status;
}
psoc_ctx = pmo_psoc_get_priv(psoc);
qdf_spin_lock_bh(&psoc_ctx->lock);
psoc_ctx->is_device_in_low_pwr_mode = handler;
qdf_spin_unlock_bh(&psoc_ctx->lock);
pmo_psoc_put_ref(psoc);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS pmo_unregister_is_device_in_low_pwr_mode(
struct wlan_objmgr_psoc *psoc,
pmo_is_device_in_low_pwr_mode handler)
{
struct pmo_psoc_priv_obj *psoc_ctx;
QDF_STATUS status;
if (!psoc) {
pmo_err("psoc is null");
return QDF_STATUS_E_NULL_VALUE;
}
if (!handler) {
pmo_err("pmo_get_pause_bitmap is null");
return QDF_STATUS_E_NULL_VALUE;
}
status = pmo_psoc_get_ref(psoc);
if (status != QDF_STATUS_SUCCESS) {
pmo_err("pmo cannot get the reference out of psoc");
return status;
}
psoc_ctx = pmo_psoc_get_priv(psoc);
qdf_spin_lock_bh(&psoc_ctx->lock);
psoc_ctx->is_device_in_low_pwr_mode = NULL;
qdf_spin_unlock_bh(&psoc_ctx->lock);
pmo_psoc_put_ref(psoc);
return QDF_STATUS_SUCCESS;
}