blob: 6a9a1d146943113c3a7e83490b3da07bf1d89cc0 [file] [log] [blame]
/*
* Copyright (c) 2016-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: Public APIs to perform operations on Global objects
*/
#include <wlan_objmgr_cmn.h>
#include <wlan_objmgr_global_obj.h>
#include <wlan_objmgr_psoc_obj.h>
#include <wlan_objmgr_pdev_obj.h>
#include <wlan_objmgr_vdev_obj.h>
#include <wlan_objmgr_peer_obj.h>
#include <qdf_mem.h>
#include "wlan_objmgr_global_obj_i.h"
#include "wlan_objmgr_psoc_obj_i.h"
#include "wlan_objmgr_pdev_obj_i.h"
/**
** APIs to Create/Delete Global object APIs
*/
static QDF_STATUS wlan_objmgr_pdev_object_status(
struct wlan_objmgr_pdev *pdev)
{
uint8_t id;
QDF_STATUS status = QDF_STATUS_SUCCESS;
wlan_pdev_obj_lock(pdev);
/* Iterate through all components to derive the object status */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
/* If component disabled, Ignore */
if (pdev->obj_status[id] == QDF_STATUS_COMP_DISABLED) {
continue;
/* If component operates in Async, status is Partially created,
break */
} else if (pdev->obj_status[id] == QDF_STATUS_COMP_ASYNC) {
if (pdev->pdev_comp_priv_obj[id] == NULL) {
status = QDF_STATUS_COMP_ASYNC;
break;
}
/* If component failed to allocate its object, treat it as
failure, complete object need to be cleaned up */
} else if ((pdev->obj_status[id] == QDF_STATUS_E_NOMEM) ||
(pdev->obj_status[id] == QDF_STATUS_E_FAILURE)) {
status = QDF_STATUS_E_FAILURE;
break;
}
}
wlan_pdev_obj_unlock(pdev);
return status;
}
static QDF_STATUS wlan_objmgr_pdev_obj_free(struct wlan_objmgr_pdev *pdev)
{
uint8_t pdev_id;
if (pdev == NULL) {
obj_mgr_err("pdev obj is NULL");
QDF_ASSERT(0);
return QDF_STATUS_E_FAILURE;
}
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
/* Detach PDEV from PSOC PDEV's list */
if (wlan_objmgr_psoc_pdev_detach(pdev->pdev_objmgr.wlan_psoc, pdev) ==
QDF_STATUS_E_FAILURE) {
obj_mgr_err("PSOC PDEV detach failed: pdev-id: %d", pdev_id);
return QDF_STATUS_E_FAILURE;
}
qdf_spinlock_destroy(&pdev->pdev_lock);
qdf_mem_free(pdev);
return QDF_STATUS_SUCCESS;
}
struct wlan_objmgr_pdev *wlan_objmgr_pdev_obj_create(
struct wlan_objmgr_psoc *psoc,
struct pdev_osif_priv *osdev_priv)
{
struct wlan_objmgr_pdev *pdev;
uint8_t id;
wlan_objmgr_pdev_create_handler handler;
wlan_objmgr_pdev_status_handler s_handler;
void *arg;
QDF_STATUS obj_status;
if (psoc == NULL) {
obj_mgr_err("psoc is NULL");
return NULL;
}
/* Allocate PDEV object's memory */
pdev = qdf_mem_malloc(sizeof(*pdev));
if (pdev == NULL) {
obj_mgr_err("pdev alloc failed");
return NULL;
}
/* Attach PDEV with PSOC */
if (wlan_objmgr_psoc_pdev_attach(psoc, pdev)
!= QDF_STATUS_SUCCESS) {
obj_mgr_err("pdev psoc attach failed");
qdf_mem_free(pdev);
return NULL;
}
/* Save PSOC object pointer in PDEV */
wlan_pdev_set_psoc(pdev, psoc);
/* Initialize PDEV spinlock */
qdf_spinlock_create(&pdev->pdev_lock);
/* Initialize PDEV's VDEV list, assign default values */
qdf_list_create(&pdev->pdev_objmgr.wlan_vdev_list,
WLAN_UMAC_PDEV_MAX_VDEVS);
pdev->pdev_objmgr.wlan_vdev_count = 0;
pdev->pdev_objmgr.max_vdev_count = WLAN_UMAC_PDEV_MAX_VDEVS;
pdev->pdev_objmgr.wlan_peer_count = 0;
pdev->pdev_objmgr.max_peer_count = WLAN_UMAC_PSOC_MAX_PEERS;
/* Save HDD/OSIF pointer */
pdev->pdev_nif.pdev_ospriv = osdev_priv;
qdf_atomic_init(&pdev->pdev_objmgr.ref_cnt);
pdev->pdev_objmgr.print_cnt = 0;
wlan_objmgr_pdev_get_ref(pdev, WLAN_OBJMGR_ID);
/* Invoke registered create handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
handler = g_umac_glb_obj->pdev_create_handler[id];
arg = g_umac_glb_obj->pdev_create_handler_arg[id];
if (handler != NULL)
pdev->obj_status[id] = handler(pdev, arg);
else
pdev->obj_status[id] = QDF_STATUS_COMP_DISABLED;
}
/* Derive object status */
obj_status = wlan_objmgr_pdev_object_status(pdev);
if (obj_status == QDF_STATUS_SUCCESS) {
/* Object status is SUCCESS, Object is created */
pdev->obj_state = WLAN_OBJ_STATE_CREATED;
/* Invoke component registered status handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
s_handler = g_umac_glb_obj->pdev_status_handler[id];
arg = g_umac_glb_obj->pdev_status_handler_arg[id];
if (s_handler != NULL) {
s_handler(pdev, arg,
QDF_STATUS_SUCCESS);
}
}
/* Few components operates in Asynchrous communction, Object state
partially created */
} else if (obj_status == QDF_STATUS_COMP_ASYNC) {
pdev->obj_state = WLAN_OBJ_STATE_PARTIALLY_CREATED;
/* Component object failed to be created, clean up the object */
} else if (obj_status == QDF_STATUS_E_FAILURE) {
/* Clean up the psoc */
obj_mgr_err("PDEV component objects allocation failed");
wlan_objmgr_pdev_obj_delete(pdev);
return NULL;
}
return pdev;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_obj_create);
static QDF_STATUS wlan_objmgr_pdev_obj_destroy(struct wlan_objmgr_pdev *pdev)
{
uint8_t id;
wlan_objmgr_pdev_destroy_handler handler;
QDF_STATUS obj_status;
void *arg;
uint8_t pdev_id;
if (pdev == NULL) {
obj_mgr_err("pdev is NULL");
return QDF_STATUS_E_FAILURE;
}
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
if (pdev->obj_state != WLAN_OBJ_STATE_LOGICALLY_DELETED) {
obj_mgr_err("pdev object delete is not invoked: pdev-id:%d",
pdev_id);
WLAN_OBJMGR_BUG(0);
}
/* Invoke registered destroy handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
handler = g_umac_glb_obj->pdev_destroy_handler[id];
arg = g_umac_glb_obj->pdev_destroy_handler_arg[id];
if (handler != NULL)
pdev->obj_status[id] = handler(pdev, arg);
else
pdev->obj_status[id] = QDF_STATUS_COMP_DISABLED;
}
/* Derive object status */
obj_status = wlan_objmgr_pdev_object_status(pdev);
if (obj_status == QDF_STATUS_E_FAILURE) {
obj_mgr_err("PDEV component objects destroy failed: pdev-id:%d",
pdev_id);
/* Ideally should not happen */
/* This leads to memleak ??? how to handle */
QDF_BUG(0);
return QDF_STATUS_E_FAILURE;
}
/* Deletion is in progress */
if (obj_status == QDF_STATUS_COMP_ASYNC) {
pdev->obj_state = WLAN_OBJ_STATE_PARTIALLY_DELETED;
return QDF_STATUS_COMP_ASYNC;
}
/* Free PDEV object */
return wlan_objmgr_pdev_obj_free(pdev);
}
QDF_STATUS wlan_objmgr_pdev_obj_delete(struct wlan_objmgr_pdev *pdev)
{
uint8_t print_idx;
if (pdev == NULL) {
obj_mgr_err("pdev is NULL");
return QDF_STATUS_E_FAILURE;
}
print_idx = qdf_get_pidx();
if (qdf_print_is_verbose_enabled(print_idx, QDF_MODULE_ID_OBJ_MGR,
QDF_TRACE_LEVEL_DEBUG)) {
obj_mgr_debug("Logically deleting the pdev(id:%d)",
pdev->pdev_objmgr.wlan_pdev_id);
wlan_objmgr_print_ref_ids(pdev->pdev_objmgr.ref_id_dbg);
}
/*
* Update PDEV object state to LOGICALLY DELETED
* It prevents further access of this object
*/
wlan_pdev_obj_lock(pdev);
pdev->obj_state = WLAN_OBJ_STATE_LOGICALLY_DELETED;
wlan_pdev_obj_unlock(pdev);
wlan_objmgr_pdev_release_ref(pdev, WLAN_OBJMGR_ID);
return QDF_STATUS_SUCCESS;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_obj_delete);
/**
** APIs to attach/detach component objects
*/
QDF_STATUS wlan_objmgr_pdev_component_obj_attach(
struct wlan_objmgr_pdev *pdev,
enum wlan_umac_comp_id id,
void *comp_priv_obj,
QDF_STATUS status)
{
uint8_t i;
wlan_objmgr_pdev_status_handler s_hlr;
void *a;
QDF_STATUS obj_status;
/* component id is invalid */
if (id >= WLAN_UMAC_MAX_COMPONENTS) {
obj_mgr_err("component-id %d is not supported", id);
return QDF_STATUS_MAXCOMP_FAIL;
}
wlan_pdev_obj_lock(pdev);
/* If there is a valid entry, return failure */
if (pdev->pdev_comp_priv_obj[id] != NULL) {
obj_mgr_err("component-%d already have valid pointer", id);
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_E_FAILURE;
}
/* Save component's pointer and status */
pdev->pdev_comp_priv_obj[id] = comp_priv_obj;
pdev->obj_status[id] = status;
wlan_pdev_obj_unlock(pdev);
if (pdev->obj_state != WLAN_OBJ_STATE_PARTIALLY_CREATED)
return QDF_STATUS_SUCCESS;
/**
* If PDEV object status is partially created means, this API is
* invoked with differnt context, this block should be executed for
* async components only
*/
/* Derive status */
obj_status = wlan_objmgr_pdev_object_status(pdev);
/* STATUS_SUCCESS means, object is CREATED */
if (obj_status == QDF_STATUS_SUCCESS)
pdev->obj_state = WLAN_OBJ_STATE_CREATED;
/* update state as CREATION failed, caller has to delete the
PDEV object */
else if (obj_status == QDF_STATUS_E_FAILURE)
pdev->obj_state = WLAN_OBJ_STATE_CREATION_FAILED;
/* Notify components about the CREATION success/failure */
if ((obj_status == QDF_STATUS_SUCCESS) ||
(obj_status == QDF_STATUS_E_FAILURE)) {
/* nofity object status */
for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) {
s_hlr = g_umac_glb_obj->pdev_status_handler[i];
a = g_umac_glb_obj->pdev_status_handler_arg[i];
if (s_hlr != NULL)
s_hlr(pdev, a, obj_status);
}
}
return QDF_STATUS_SUCCESS;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_component_obj_attach);
QDF_STATUS wlan_objmgr_pdev_component_obj_detach(
struct wlan_objmgr_pdev *pdev,
enum wlan_umac_comp_id id,
void *comp_priv_obj)
{
QDF_STATUS obj_status;
/* component id is invalid */
if (id >= WLAN_UMAC_MAX_COMPONENTS)
return QDF_STATUS_MAXCOMP_FAIL;
wlan_pdev_obj_lock(pdev);
/* If there is a invalid entry, return failure */
if (pdev->pdev_comp_priv_obj[id] != comp_priv_obj) {
pdev->obj_status[id] = QDF_STATUS_E_FAILURE;
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_E_FAILURE;
}
/* Reset pointers to NULL, update the status*/
pdev->pdev_comp_priv_obj[id] = NULL;
pdev->obj_status[id] = QDF_STATUS_SUCCESS;
wlan_pdev_obj_unlock(pdev);
/* If PDEV object status is partially destroyed means, this API is
invoked with differnt context, this block should be executed for async
components only */
if ((pdev->obj_state == WLAN_OBJ_STATE_PARTIALLY_DELETED) ||
(pdev->obj_state == WLAN_OBJ_STATE_COMP_DEL_PROGRESS)) {
/* Derive object status */
obj_status = wlan_objmgr_pdev_object_status(pdev);
if (obj_status == QDF_STATUS_SUCCESS) {
/*Update the status as Deleted, if full object
deletion is in progress */
if (pdev->obj_state ==
WLAN_OBJ_STATE_PARTIALLY_DELETED)
pdev->obj_state = WLAN_OBJ_STATE_DELETED;
/* Move to creation state, since this component
deletion alone requested */
if (pdev->obj_state ==
WLAN_OBJ_STATE_COMP_DEL_PROGRESS)
pdev->obj_state = WLAN_OBJ_STATE_CREATED;
/* Object status is failure */
} else if (obj_status == QDF_STATUS_E_FAILURE) {
/*Update the status as Deletion failed, if full object
deletion is in progress */
if (pdev->obj_state ==
WLAN_OBJ_STATE_PARTIALLY_DELETED)
pdev->obj_state =
WLAN_OBJ_STATE_DELETION_FAILED;
/* Move to creation state, since this component
deletion alone requested (do not block other
components)*/
if (pdev->obj_state ==
WLAN_OBJ_STATE_COMP_DEL_PROGRESS)
pdev->obj_state = WLAN_OBJ_STATE_CREATED;
}
/* Delete pdev object */
if ((obj_status == QDF_STATUS_SUCCESS) &&
(pdev->obj_state == WLAN_OBJ_STATE_DELETED)) {
/* Free PDEV object */
return wlan_objmgr_pdev_obj_free(pdev);
}
}
return QDF_STATUS_SUCCESS;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_component_obj_detach);
/**
** APIs to operations on pdev objects
*/
static void wlan_objmgr_pdev_vdev_iterate_peers(struct wlan_objmgr_pdev *pdev,
struct wlan_objmgr_vdev *vdev,
wlan_objmgr_pdev_op_handler handler,
void *arg, uint8_t lock_free_op,
wlan_objmgr_ref_dbgid dbg_id)
{
qdf_list_t *peer_list = NULL;
struct wlan_objmgr_peer *peer = NULL;
struct wlan_objmgr_peer *peer_next = NULL;
/* Iterating through vdev's peer list, so lock is
needed */
if (!lock_free_op)
wlan_vdev_obj_lock(vdev);
/* Get peer list of the vdev */
peer_list = &vdev->vdev_objmgr.wlan_peer_list;
if (peer_list != NULL) {
peer = wlan_vdev_peer_list_peek_head(peer_list);
while (peer != NULL) {
/* Get next peer pointer */
peer_next = wlan_peer_get_next_peer_of_vdev(peer_list,
peer);
/* Increment ref count, to hold the
peer pointer */
if (wlan_objmgr_peer_try_get_ref(peer, dbg_id) ==
QDF_STATUS_SUCCESS) {
/* Invoke the handler */
handler(pdev, (void *)peer, arg);
wlan_objmgr_peer_release_ref(peer, dbg_id);
}
peer = peer_next;
}
}
if (!lock_free_op)
wlan_vdev_obj_unlock(vdev);
}
QDF_STATUS wlan_objmgr_pdev_iterate_obj_list(
struct wlan_objmgr_pdev *pdev,
enum wlan_objmgr_obj_type obj_type,
wlan_objmgr_pdev_op_handler handler,
void *arg, uint8_t lock_free_op,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_pdev_objmgr *objmgr = &pdev->pdev_objmgr;
qdf_list_t *vdev_list = NULL;
struct wlan_objmgr_vdev *vdev = NULL;
struct wlan_objmgr_vdev *vdev_next = NULL;
/* If caller requests for lock free opeation, do not acquire
handler will handle the synchronization*/
if (!lock_free_op)
wlan_pdev_obj_lock(pdev);
/* VDEV list */
vdev_list = &objmgr->wlan_vdev_list;
switch (obj_type) {
case WLAN_VDEV_OP:
/* Iterate through all VDEV object, and invoke handler for each
VDEV object */
vdev = wlan_pdev_vdev_list_peek_head(vdev_list);
while (vdev != NULL) {
/*
* Get next vdev (handler can be invoked for
* vdev deletion also
*/
vdev_next = wlan_vdev_get_next_vdev_of_pdev(vdev_list,
vdev);
if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) ==
QDF_STATUS_SUCCESS) {
handler(pdev, (void *)vdev, arg);
wlan_objmgr_vdev_release_ref(vdev, dbg_id);
}
vdev = vdev_next;
}
break;
case WLAN_PEER_OP:
vdev = wlan_pdev_vdev_list_peek_head(vdev_list);
while (vdev != NULL) {
/* Get Next VDEV */
vdev_next = wlan_vdev_get_next_vdev_of_pdev(vdev_list,
vdev);
if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) ==
QDF_STATUS_SUCCESS) {
wlan_objmgr_pdev_vdev_iterate_peers(pdev, vdev,
handler, arg,
lock_free_op,
dbg_id);
wlan_objmgr_vdev_release_ref(vdev, dbg_id);
}
vdev = vdev_next;
}
break;
default:
break;
}
if (!lock_free_op)
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_SUCCESS;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_iterate_obj_list);
QDF_STATUS wlan_objmgr_trigger_pdev_comp_priv_object_creation(
struct wlan_objmgr_pdev *pdev,
enum wlan_umac_comp_id id)
{
wlan_objmgr_pdev_create_handler handler;
void *arg;
QDF_STATUS obj_status = QDF_STATUS_SUCCESS;
/* Component id is invalid */
if (id >= WLAN_UMAC_MAX_COMPONENTS)
return QDF_STATUS_MAXCOMP_FAIL;
wlan_pdev_obj_lock(pdev);
/* If component object is already created, delete old
component object, then invoke creation */
if (pdev->pdev_comp_priv_obj[id] != NULL) {
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_E_FAILURE;
}
wlan_pdev_obj_unlock(pdev);
/* Invoke registered create handlers */
handler = g_umac_glb_obj->pdev_create_handler[id];
arg = g_umac_glb_obj->pdev_create_handler_arg[id];
if (handler != NULL)
pdev->obj_status[id] = handler(pdev, arg);
else
return QDF_STATUS_E_FAILURE;
/* If object status is created, then only handle this object status */
if (pdev->obj_state == WLAN_OBJ_STATE_CREATED) {
/* Derive object status */
obj_status = wlan_objmgr_pdev_object_status(pdev);
/* Move PDEV object state to Partially created state */
if (obj_status == QDF_STATUS_COMP_ASYNC) {
/*TODO atomic */
pdev->obj_state = WLAN_OBJ_STATE_PARTIALLY_CREATED;
}
}
return obj_status;
}
QDF_STATUS wlan_objmgr_trigger_pdev_comp_priv_object_deletion(
struct wlan_objmgr_pdev *pdev,
enum wlan_umac_comp_id id)
{
wlan_objmgr_pdev_destroy_handler handler;
void *arg;
QDF_STATUS obj_status = QDF_STATUS_SUCCESS;
/* component id is invalid */
if (id >= WLAN_UMAC_MAX_COMPONENTS)
return QDF_STATUS_MAXCOMP_FAIL;
wlan_pdev_obj_lock(pdev);
/* Component object was never created, invalid operation */
if (pdev->pdev_comp_priv_obj[id] == NULL) {
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_E_FAILURE;
}
wlan_pdev_obj_unlock(pdev);
/* Invoke registered create handlers */
handler = g_umac_glb_obj->pdev_destroy_handler[id];
arg = g_umac_glb_obj->pdev_destroy_handler_arg[id];
if (handler != NULL)
pdev->obj_status[id] = handler(pdev, arg);
else
return QDF_STATUS_E_FAILURE;
/* If object status is created, then only handle this object status */
if (pdev->obj_state == WLAN_OBJ_STATE_CREATED) {
obj_status = wlan_objmgr_pdev_object_status(pdev);
/* move object state to DEL progress */
if (obj_status == QDF_STATUS_COMP_ASYNC)
pdev->obj_state = WLAN_OBJ_STATE_COMP_DEL_PROGRESS;
}
return obj_status;
}
static void wlan_obj_pdev_vdevlist_add_tail(qdf_list_t *obj_list,
struct wlan_objmgr_vdev *obj)
{
qdf_list_insert_back(obj_list, &obj->vdev_node);
}
static QDF_STATUS wlan_obj_pdev_vdevlist_remove_vdev(
qdf_list_t *obj_list,
struct wlan_objmgr_vdev *vdev)
{
qdf_list_node_t *vdev_node = NULL;
if (vdev == NULL)
return QDF_STATUS_E_FAILURE;
/* get vdev list node element */
vdev_node = &vdev->vdev_node;
/* list is empty, return failure */
if (qdf_list_remove_node(obj_list, vdev_node) != QDF_STATUS_SUCCESS)
return QDF_STATUS_E_FAILURE;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_objmgr_pdev_vdev_attach(struct wlan_objmgr_pdev *pdev,
struct wlan_objmgr_vdev *vdev)
{
struct wlan_objmgr_pdev_objmgr *objmgr = &pdev->pdev_objmgr;
wlan_pdev_obj_lock(pdev);
/* If Max vdev count exceeds, return failure */
if (objmgr->wlan_vdev_count > objmgr->max_vdev_count) {
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_E_FAILURE;
}
/* Add vdev to pdev's vdev list */
wlan_obj_pdev_vdevlist_add_tail(&objmgr->wlan_vdev_list, vdev);
/* Increment pdev ref count to make sure it won't be destroyed before */
wlan_objmgr_pdev_get_ref(pdev, WLAN_OBJMGR_ID);
/* Increment vdev count of pdev */
objmgr->wlan_vdev_count++;
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_objmgr_pdev_vdev_detach(struct wlan_objmgr_pdev *pdev,
struct wlan_objmgr_vdev *vdev)
{
struct wlan_objmgr_pdev_objmgr *objmgr = &pdev->pdev_objmgr;
wlan_pdev_obj_lock(pdev);
/* if vdev count is 0, return failure */
if (objmgr->wlan_vdev_count == 0) {
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_E_FAILURE;
}
/* remove vdev from pdev's vdev list */
wlan_obj_pdev_vdevlist_remove_vdev(&objmgr->wlan_vdev_list, vdev);
/* decrement vdev count */
objmgr->wlan_vdev_count--;
wlan_pdev_obj_unlock(pdev);
/* Decrement pdev ref count since vdev is releasing reference */
wlan_objmgr_pdev_release_ref(pdev, WLAN_OBJMGR_ID);
return QDF_STATUS_SUCCESS;
}
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_id_from_pdev(
struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_vdev *vdev_next;
struct wlan_objmgr_pdev_objmgr *objmgr;
qdf_list_t *vdev_list;
wlan_pdev_obj_lock(pdev);
objmgr = &pdev->pdev_objmgr;
vdev_list = &objmgr->wlan_vdev_list;
/* Get first vdev */
vdev = wlan_pdev_vdev_list_peek_head(vdev_list);
/* Iterate through pdev's vdev list, till vdev id matches with
entry of vdev list */
while (vdev != NULL) {
if (wlan_vdev_get_id(vdev) == vdev_id) {
if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) !=
QDF_STATUS_SUCCESS)
vdev = NULL;
wlan_pdev_obj_unlock(pdev);
return vdev;
}
/* get next vdev */
vdev_next = wlan_vdev_get_next_vdev_of_pdev(vdev_list, vdev);
vdev = vdev_next;
}
wlan_pdev_obj_unlock(pdev);
return NULL;
}
EXPORT_SYMBOL(wlan_objmgr_get_vdev_by_id_from_pdev);
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_id_from_pdev_no_state(
struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_vdev *vdev_next;
struct wlan_objmgr_pdev_objmgr *objmgr;
qdf_list_t *vdev_list;
wlan_pdev_obj_lock(pdev);
objmgr = &pdev->pdev_objmgr;
vdev_list = &objmgr->wlan_vdev_list;
/* Get first vdev */
vdev = wlan_pdev_vdev_list_peek_head(vdev_list);
/**
* Iterate through pdev's vdev list, till vdev id matches with
* entry of vdev list
*/
while (vdev != NULL) {
if (wlan_vdev_get_id(vdev) == vdev_id) {
wlan_objmgr_vdev_get_ref(vdev, dbg_id);
wlan_pdev_obj_unlock(pdev);
return vdev;
}
/* get next vdev */
vdev_next = wlan_vdev_get_next_vdev_of_pdev(vdev_list, vdev);
vdev = vdev_next;
}
wlan_pdev_obj_unlock(pdev);
return NULL;
}
EXPORT_SYMBOL(wlan_objmgr_get_vdev_by_id_from_pdev_no_state);
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_macaddr_from_pdev(
struct wlan_objmgr_pdev *pdev, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_vdev *vdev_next;
struct wlan_objmgr_pdev_objmgr *objmgr;
qdf_list_t *vdev_list;
wlan_pdev_obj_lock(pdev);
objmgr = &pdev->pdev_objmgr;
vdev_list = &objmgr->wlan_vdev_list;
/* Get first vdev */
vdev = wlan_pdev_vdev_list_peek_head(vdev_list);
/* Iterate through pdev's vdev list, till vdev macaddr matches with
entry of vdev list */
while (vdev != NULL) {
if (WLAN_ADDR_EQ(wlan_vdev_mlme_get_macaddr(vdev), macaddr)
== QDF_STATUS_SUCCESS) {
if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) !=
QDF_STATUS_SUCCESS)
vdev = NULL;
wlan_pdev_obj_unlock(pdev);
return vdev;
}
/* get next vdev */
vdev_next = wlan_vdev_get_next_vdev_of_pdev(vdev_list, vdev);
vdev = vdev_next;
}
wlan_pdev_obj_unlock(pdev);
return NULL;
}
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_macaddr_from_pdev_no_state(
struct wlan_objmgr_pdev *pdev, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_vdev *vdev_next;
struct wlan_objmgr_pdev_objmgr *objmgr;
qdf_list_t *vdev_list;
wlan_pdev_obj_lock(pdev);
objmgr = &pdev->pdev_objmgr;
vdev_list = &objmgr->wlan_vdev_list;
/* Get first vdev */
vdev = wlan_pdev_vdev_list_peek_head(vdev_list);
/* Iterate through pdev's vdev list, till vdev macaddr matches with
entry of vdev list */
while (vdev != NULL) {
if (WLAN_ADDR_EQ(wlan_vdev_mlme_get_macaddr(vdev), macaddr)
== QDF_STATUS_SUCCESS) {
wlan_objmgr_vdev_get_ref(vdev, dbg_id);
wlan_pdev_obj_unlock(pdev);
return vdev;
}
/* get next vdev */
vdev_next = wlan_vdev_get_next_vdev_of_pdev(vdev_list, vdev);
vdev = vdev_next;
}
wlan_pdev_obj_unlock(pdev);
return NULL;
}
void *wlan_objmgr_pdev_get_comp_private_obj(
struct wlan_objmgr_pdev *pdev,
enum wlan_umac_comp_id id)
{
void *comp_priv_obj;
/* component id is invalid */
if (id >= WLAN_UMAC_MAX_COMPONENTS) {
QDF_BUG(0);
return NULL;
}
if (pdev == NULL) {
QDF_BUG(0);
return NULL;
}
comp_priv_obj = pdev->pdev_comp_priv_obj[id];
return comp_priv_obj;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_get_comp_private_obj);
void wlan_objmgr_pdev_get_ref(struct wlan_objmgr_pdev *pdev,
wlan_objmgr_ref_dbgid id)
{
if (pdev == NULL) {
obj_mgr_err("pdev obj is NULL");
QDF_ASSERT(0);
return;
}
qdf_atomic_inc(&pdev->pdev_objmgr.ref_cnt);
qdf_atomic_inc(&pdev->pdev_objmgr.ref_id_dbg[id]);
return;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_get_ref);
QDF_STATUS wlan_objmgr_pdev_try_get_ref(struct wlan_objmgr_pdev *pdev,
wlan_objmgr_ref_dbgid id)
{
uint8_t pdev_id;
if (pdev == NULL) {
obj_mgr_err("pdev obj is NULL");
QDF_ASSERT(0);
return QDF_STATUS_E_FAILURE;
}
wlan_pdev_obj_lock(pdev);
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
if (pdev->obj_state == WLAN_OBJ_STATE_LOGICALLY_DELETED) {
wlan_pdev_obj_unlock(pdev);
if (pdev->pdev_objmgr.print_cnt++ <=
WLAN_OBJMGR_RATELIMIT_THRESH)
obj_mgr_err("[Ref id: %d] pdev [%d] is in L-Del state",
id, pdev_id);
return QDF_STATUS_E_RESOURCES;
}
wlan_objmgr_pdev_get_ref(pdev, id);
wlan_pdev_obj_unlock(pdev);
return QDF_STATUS_SUCCESS;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_try_get_ref);
void wlan_objmgr_pdev_release_ref(struct wlan_objmgr_pdev *pdev,
wlan_objmgr_ref_dbgid id)
{
uint8_t pdev_id;
if (pdev == NULL) {
obj_mgr_err("pdev obj is NULL");
QDF_ASSERT(0);
return;
}
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
if (!qdf_atomic_read(&pdev->pdev_objmgr.ref_id_dbg[id])) {
obj_mgr_err("pdev (id:%d)ref cnt was not taken by %d",
pdev_id, id);
wlan_objmgr_print_ref_ids(pdev->pdev_objmgr.ref_id_dbg);
WLAN_OBJMGR_BUG(0);
}
if (!qdf_atomic_read(&pdev->pdev_objmgr.ref_cnt)) {
obj_mgr_err("pdev ref cnt is 0: pdev-id:%d", pdev_id);
WLAN_OBJMGR_BUG(0);
return;
}
qdf_atomic_dec(&pdev->pdev_objmgr.ref_id_dbg[id]);
/* Decrement ref count, free pdev, if ref count == 0 */
if (qdf_atomic_dec_and_test(&pdev->pdev_objmgr.ref_cnt))
wlan_objmgr_pdev_obj_destroy(pdev);
return;
}
EXPORT_SYMBOL(wlan_objmgr_pdev_release_ref);