blob: 00623584e6dd1135ed437c24ab9f32247602d230 [file] [log] [blame]
/*
* Copyright (c) 2016-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
* 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 <qdf_types.h>
#include <qdf_module.h>
#include "wlan_objmgr_global_obj_i.h"
#include "wlan_objmgr_psoc_obj_i.h"
#include "wlan_objmgr_pdev_obj_i.h"
#include "wlan_objmgr_vdev_obj_i.h"
/**
** APIs to Create/Delete Global object APIs
*/
static QDF_STATUS wlan_objmgr_psoc_object_status(
struct wlan_objmgr_psoc *psoc)
{
uint8_t id;
QDF_STATUS status = QDF_STATUS_SUCCESS;
wlan_psoc_obj_lock(psoc);
/* Iterate through all components to derive the object status */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
/* If component disabled, Ignore */
if (psoc->obj_status[id] == QDF_STATUS_COMP_DISABLED)
continue;
/* If component operates in Async, status is Partially created,
* break
*/
else if (psoc->obj_status[id] == QDF_STATUS_COMP_ASYNC) {
if (!psoc->soc_comp_priv_obj[id]) {
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 ((psoc->obj_status[id] == QDF_STATUS_E_NOMEM) ||
(psoc->obj_status[id] == QDF_STATUS_E_FAILURE)) {
status = QDF_STATUS_E_FAILURE;
break;
}
}
wlan_psoc_obj_unlock(psoc);
return status;
}
static void wlan_objmgr_psoc_peer_list_init(struct wlan_peer_list *peer_list)
{
uint8_t i;
qdf_spinlock_create(&peer_list->peer_list_lock);
for (i = 0; i < WLAN_PEER_HASHSIZE; i++)
qdf_list_create(&peer_list->peer_hash[i],
WLAN_UMAC_PSOC_MAX_PEERS +
WLAN_MAX_PSOC_TEMP_PEERS);
}
static void wlan_objmgr_psoc_peer_list_deinit(struct wlan_peer_list *peer_list)
{
uint8_t i;
/* deinit the lock */
qdf_spinlock_destroy(&peer_list->peer_list_lock);
for (i = 0; i < WLAN_PEER_HASHSIZE; i++)
qdf_list_destroy(&peer_list->peer_hash[i]);
}
static QDF_STATUS wlan_objmgr_psoc_obj_free(struct wlan_objmgr_psoc *psoc)
{
/* Detach PSOC from global object's psoc list */
if (wlan_objmgr_psoc_object_detach(psoc) == QDF_STATUS_E_FAILURE) {
obj_mgr_err("PSOC object detach failed");
return QDF_STATUS_E_FAILURE;
}
wlan_objmgr_psoc_peer_list_deinit(&psoc->soc_objmgr.peer_list);
qdf_spinlock_destroy(&psoc->psoc_lock);
qdf_mem_free(psoc);
return QDF_STATUS_SUCCESS;
}
struct wlan_objmgr_psoc *wlan_objmgr_psoc_obj_create(uint32_t phy_version,
WLAN_DEV_TYPE dev_type)
{
uint8_t id;
struct wlan_objmgr_psoc *psoc = NULL;
wlan_objmgr_psoc_create_handler handler;
wlan_objmgr_psoc_status_handler stat_handler;
struct wlan_objmgr_psoc_objmgr *objmgr;
QDF_STATUS obj_status;
void *arg;
psoc = qdf_mem_malloc(sizeof(*psoc));
if (!psoc)
return NULL;
psoc->obj_state = WLAN_OBJ_STATE_ALLOCATED;
qdf_spinlock_create(&psoc->psoc_lock);
/* Initialize with default values */
objmgr = &psoc->soc_objmgr;
objmgr->wlan_pdev_count = 0;
objmgr->wlan_vdev_count = 0;
objmgr->max_vdev_count = WLAN_UMAC_PSOC_MAX_VDEVS;
objmgr->wlan_peer_count = 0;
objmgr->temp_peer_count = 0;
objmgr->max_peer_count = WLAN_UMAC_PSOC_MAX_PEERS;
qdf_atomic_init(&objmgr->ref_cnt);
objmgr->print_cnt = 0;
/* set phy version, dev_type in psoc */
wlan_psoc_set_nif_phy_version(psoc, phy_version);
wlan_psoc_set_dev_type(psoc, dev_type);
/* Initialize peer list */
wlan_objmgr_psoc_peer_list_init(&objmgr->peer_list);
wlan_objmgr_psoc_get_ref(psoc, WLAN_OBJMGR_ID);
/* Invoke registered create handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
handler = g_umac_glb_obj->psoc_create_handler[id];
arg = g_umac_glb_obj->psoc_create_handler_arg[id];
if (handler)
psoc->obj_status[id] = handler(psoc, arg);
else
psoc->obj_status[id] = QDF_STATUS_COMP_DISABLED;
}
/* Derive object status */
obj_status = wlan_objmgr_psoc_object_status(psoc);
if (obj_status == QDF_STATUS_SUCCESS) {
/* Object status is SUCCESS, Object is created */
psoc->obj_state = WLAN_OBJ_STATE_CREATED;
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
stat_handler = g_umac_glb_obj->psoc_status_handler[id];
arg = g_umac_glb_obj->psoc_status_handler_arg[id];
if (stat_handler)
stat_handler(psoc, arg,
QDF_STATUS_SUCCESS);
}
} else if (obj_status == QDF_STATUS_COMP_ASYNC) {
/*
* Few components operates in Asynchrous communction
* Object state partially created
*/
psoc->obj_state = WLAN_OBJ_STATE_PARTIALLY_CREATED;
} else if (obj_status == QDF_STATUS_E_FAILURE) {
/* Component object failed to be created, clean up the object */
obj_mgr_err("PSOC component objects allocation failed");
/* Clean up the psoc */
wlan_objmgr_psoc_obj_delete(psoc);
return NULL;
}
if (wlan_objmgr_psoc_object_attach(psoc) !=
QDF_STATUS_SUCCESS) {
obj_mgr_err("PSOC object attach failed");
wlan_objmgr_psoc_obj_delete(psoc);
return NULL;
}
obj_mgr_info("Created psoc %d", psoc->soc_objmgr.psoc_id);
return psoc;
}
qdf_export_symbol(wlan_objmgr_psoc_obj_create);
static QDF_STATUS wlan_objmgr_psoc_obj_destroy(struct wlan_objmgr_psoc *psoc)
{
uint8_t id;
wlan_objmgr_psoc_destroy_handler handler;
QDF_STATUS obj_status;
void *arg;
if (!psoc) {
obj_mgr_err("psoc is NULL");
return QDF_STATUS_E_FAILURE;
}
wlan_objmgr_notify_destroy(psoc, WLAN_PSOC_OP);
wlan_print_psoc_info(psoc);
obj_mgr_info("Physically deleting psoc %d", psoc->soc_objmgr.psoc_id);
if (psoc->obj_state != WLAN_OBJ_STATE_LOGICALLY_DELETED) {
obj_mgr_err("PSOC object delete is not invoked obj_state:%d",
psoc->obj_state);
WLAN_OBJMGR_BUG(0);
}
/* Invoke registered create handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
handler = g_umac_glb_obj->psoc_destroy_handler[id];
arg = g_umac_glb_obj->psoc_destroy_handler_arg[id];
if (handler &&
(psoc->obj_status[id] == QDF_STATUS_SUCCESS ||
psoc->obj_status[id] == QDF_STATUS_COMP_ASYNC))
psoc->obj_status[id] = handler(psoc, arg);
else
psoc->obj_status[id] = QDF_STATUS_COMP_DISABLED;
}
/* Derive object status */
obj_status = wlan_objmgr_psoc_object_status(psoc);
if (obj_status == QDF_STATUS_E_FAILURE) {
obj_mgr_err("PSOC component object free failed");
/* Ideally should not happen
* This leads to memleak, BUG_ON to find which component
* delete notification failed and fix it.
*/
QDF_BUG(0);
return QDF_STATUS_E_FAILURE;
}
/* Deletion is in progress */
if (obj_status == QDF_STATUS_COMP_ASYNC) {
psoc->obj_state = WLAN_OBJ_STATE_PARTIALLY_DELETED;
return QDF_STATUS_COMP_ASYNC;
}
/* Free psoc object */
return wlan_objmgr_psoc_obj_free(psoc);
}
QDF_STATUS wlan_objmgr_psoc_obj_delete(struct wlan_objmgr_psoc *psoc)
{
uint8_t print_idx;
if (!psoc) {
obj_mgr_err("psoc is NULL");
return QDF_STATUS_E_FAILURE;
}
obj_mgr_info("Logically deleting psoc %d", psoc->soc_objmgr.psoc_id);
print_idx = qdf_get_pidx();
wlan_objmgr_print_ref_ids(psoc->soc_objmgr.ref_id_dbg,
QDF_TRACE_LEVEL_DEBUG);
/*
* Update PSOC object state to LOGICALLY DELETED
* It prevents further access of this object
*/
wlan_psoc_obj_lock(psoc);
psoc->obj_state = WLAN_OBJ_STATE_LOGICALLY_DELETED;
wlan_psoc_obj_unlock(psoc);
wlan_objmgr_notify_log_delete(psoc, WLAN_PSOC_OP);
wlan_objmgr_psoc_release_ref(psoc, WLAN_OBJMGR_ID);
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_psoc_obj_delete);
QDF_STATUS wlan_objmgr_psoc_component_obj_attach(
struct wlan_objmgr_psoc *psoc,
enum wlan_umac_comp_id id,
void *comp_priv_obj,
QDF_STATUS status)
{
wlan_objmgr_psoc_status_handler stat_handler;
void *arg = NULL;
QDF_STATUS obj_status;
uint8_t i;
/* component id is invalid */
if (id >= WLAN_UMAC_MAX_COMPONENTS)
return QDF_STATUS_MAXCOMP_FAIL;
wlan_psoc_obj_lock(psoc);
/* If there is a valid entry, return failure */
if (psoc->soc_comp_priv_obj[id]) {
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_E_FAILURE;
}
/* Save component's pointer and status */
psoc->soc_comp_priv_obj[id] = comp_priv_obj;
psoc->obj_status[id] = status;
wlan_psoc_obj_unlock(psoc);
if (psoc->obj_state != WLAN_OBJ_STATE_PARTIALLY_CREATED)
return QDF_STATUS_SUCCESS;
/* If PSOC 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_psoc_object_status(psoc);
/* STATUS_SUCCESS means, object is CREATED */
if (obj_status == QDF_STATUS_SUCCESS)
psoc->obj_state = WLAN_OBJ_STATE_CREATED;
/* update state as CREATION failed, caller has to delete the
* PSOC object
*/
else if (obj_status == QDF_STATUS_E_FAILURE)
psoc->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++) {
stat_handler = g_umac_glb_obj->psoc_status_handler[i];
arg = g_umac_glb_obj->psoc_status_handler_arg[i];
if (stat_handler)
stat_handler(psoc, arg, obj_status);
}
}
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_psoc_component_obj_attach);
QDF_STATUS wlan_objmgr_psoc_component_obj_detach(
struct wlan_objmgr_psoc *psoc,
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_psoc_obj_lock(psoc);
/* If there is a valid entry, return failure */
if (psoc->soc_comp_priv_obj[id] != comp_priv_obj) {
psoc->obj_status[id] = QDF_STATUS_E_FAILURE;
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_E_FAILURE;
}
/* Reset pointers to NULL, update the status*/
psoc->soc_comp_priv_obj[id] = NULL;
psoc->obj_status[id] = QDF_STATUS_SUCCESS;
wlan_psoc_obj_unlock(psoc);
/* If PSOC object status is partially created means, this API is
* invoked with differnt context, this block should be executed for
* async components only
*/
if ((psoc->obj_state == WLAN_OBJ_STATE_PARTIALLY_DELETED) ||
(psoc->obj_state == WLAN_OBJ_STATE_COMP_DEL_PROGRESS)) {
/* Derive object status */
obj_status = wlan_objmgr_psoc_object_status(psoc);
if (obj_status == QDF_STATUS_SUCCESS) {
/* Update the status as Deleted, if full object
* deletion is in progress
*/
if (psoc->obj_state == WLAN_OBJ_STATE_PARTIALLY_DELETED)
psoc->obj_state = WLAN_OBJ_STATE_DELETED;
/* Move to creation state, since this component
* deletion alone requested
*/
if (psoc->obj_state == WLAN_OBJ_STATE_COMP_DEL_PROGRESS)
psoc->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 (psoc->obj_state == WLAN_OBJ_STATE_PARTIALLY_DELETED)
psoc->obj_state =
WLAN_OBJ_STATE_DELETION_FAILED;
/* Move to creation state, since this component
* deletion alone requested (do not block other
* components)
*/
if (psoc->obj_state == WLAN_OBJ_STATE_COMP_DEL_PROGRESS)
psoc->obj_state = WLAN_OBJ_STATE_CREATED;
}
/* Delete psoc object */
if ((obj_status == QDF_STATUS_SUCCESS) &&
(psoc->obj_state == WLAN_OBJ_STATE_DELETED)) {
/* Free psoc object */
return wlan_objmgr_psoc_obj_free(psoc);
}
}
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_psoc_component_obj_detach);
QDF_STATUS wlan_objmgr_iterate_obj_list(
struct wlan_objmgr_psoc *psoc,
enum wlan_objmgr_obj_type obj_type,
wlan_objmgr_op_handler handler,
void *arg, uint8_t lock_free_op,
wlan_objmgr_ref_dbgid dbg_id)
{
uint16_t obj_id;
uint8_t i;
struct wlan_objmgr_psoc_objmgr *objmgr = &psoc->soc_objmgr;
struct wlan_peer_list *peer_list;
struct wlan_objmgr_pdev *pdev;
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_next;
uint16_t max_vdev_cnt;
switch (obj_type) {
case WLAN_PDEV_OP:
/* Iterate through PDEV list, invoke handler for each pdev */
for (obj_id = 0; obj_id < WLAN_UMAC_MAX_PDEVS; obj_id++) {
pdev = wlan_objmgr_get_pdev_by_id(psoc, obj_id, dbg_id);
if (pdev) {
handler(psoc, (void *)pdev, arg);
wlan_objmgr_pdev_release_ref(pdev, dbg_id);
}
}
break;
case WLAN_VDEV_OP:
/* Iterate through VDEV list, invoke handler for each vdev */
max_vdev_cnt = wlan_psoc_get_max_vdev_count(psoc);
for (obj_id = 0; obj_id < max_vdev_cnt; obj_id++) {
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
obj_id, dbg_id);
if (vdev) {
handler(psoc, vdev, arg);
wlan_objmgr_vdev_release_ref(vdev, dbg_id);
}
}
break;
case WLAN_PEER_OP:
/* Iterate through PEER list, invoke handler for each peer */
peer_list = &objmgr->peer_list;
/* Since peer list has sublist, iterate through sublists */
for (i = 0; i < WLAN_PEER_HASHSIZE; i++) {
peer = wlan_psoc_peer_list_peek_active_head(peer_list,
i, dbg_id);
while (peer) {
handler(psoc, (void *)peer, arg);
/* Get next peer */
peer_next =
wlan_peer_get_next_active_peer_of_psoc(
peer_list, i, peer, dbg_id);
wlan_objmgr_peer_release_ref(peer, dbg_id);
peer = peer_next;
}
}
break;
default:
break;
}
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_iterate_obj_list);
QDF_STATUS wlan_objmgr_iterate_obj_list_all(
struct wlan_objmgr_psoc *psoc,
enum wlan_objmgr_obj_type obj_type,
wlan_objmgr_op_handler handler,
void *arg, uint8_t lock_free_op,
wlan_objmgr_ref_dbgid dbg_id)
{
uint16_t obj_id;
uint8_t i;
struct wlan_objmgr_psoc_objmgr *objmgr = &psoc->soc_objmgr;
struct wlan_peer_list *peer_list;
struct wlan_objmgr_pdev *pdev;
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_next;
uint16_t max_vdev_cnt;
/* If caller requests for lock free opeation, do not acquire,
* handler will handle the synchronization
*/
switch (obj_type) {
case WLAN_PDEV_OP:
/* Iterate through PDEV list, invoke handler for each pdev */
for (obj_id = 0; obj_id < WLAN_UMAC_MAX_PDEVS; obj_id++) {
pdev = wlan_objmgr_get_pdev_by_id_no_state(psoc,
obj_id, dbg_id);
if (pdev) {
handler(psoc, (void *)pdev, arg);
wlan_objmgr_pdev_release_ref(pdev, dbg_id);
}
}
break;
case WLAN_VDEV_OP:
/* Iterate through VDEV list, invoke handler for each vdev */
max_vdev_cnt = wlan_psoc_get_max_vdev_count(psoc);
for (obj_id = 0; obj_id < max_vdev_cnt; obj_id++) {
vdev = wlan_objmgr_get_vdev_by_id_from_psoc_no_state(
psoc, obj_id, dbg_id);
if (vdev) {
handler(psoc, vdev, arg);
wlan_objmgr_vdev_release_ref(vdev, dbg_id);
}
}
break;
case WLAN_PEER_OP:
/* Iterate through PEER list, invoke handler for each peer */
peer_list = &objmgr->peer_list;
/* Since peer list has sublist, iterate through sublists */
for (i = 0; i < WLAN_PEER_HASHSIZE; i++) {
peer = wlan_psoc_peer_list_peek_head_ref(peer_list, i,
dbg_id);
while (peer) {
handler(psoc, (void *)peer, arg);
/* Get next peer */
peer_next = wlan_peer_get_next_peer_of_psoc_ref(
peer_list, i,
peer, dbg_id);
wlan_objmgr_peer_release_ref(peer, dbg_id);
peer = peer_next;
}
}
break;
default:
break;
}
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_iterate_obj_list_all);
/**
* wlan_objmgr_iterate_obj_list_all_noref() - iterate through all psoc objects
* without taking ref
* @psoc: PSOC object
* @obj_type: PDEV_OP/VDEV_OP/PEER_OP
* @handler: the handler will be called for each object of requested type
* the handler should be implemented to perform required operation
* @arg: agruments passed by caller
*
* API to be used for performing the operations on all PDEV/VDEV/PEER objects
* of psoc with lock protected
*
* Return: SUCCESS/FAILURE
*/
static QDF_STATUS wlan_objmgr_iterate_obj_list_all_noref(
struct wlan_objmgr_psoc *psoc,
enum wlan_objmgr_obj_type obj_type,
wlan_objmgr_op_handler handler,
void *arg)
{
uint16_t obj_id;
uint8_t i;
struct wlan_objmgr_psoc_objmgr *objmgr = &psoc->soc_objmgr;
struct wlan_peer_list *peer_list;
qdf_list_t *obj_list;
struct wlan_objmgr_pdev *pdev;
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_next;
uint16_t max_vdev_cnt;
/* If caller requests for lock free opeation, do not acquire,
* handler will handle the synchronization
*/
wlan_psoc_obj_lock(psoc);
switch (obj_type) {
case WLAN_PDEV_OP:
/* Iterate through PDEV list, invoke handler for each pdev */
for (obj_id = 0; obj_id < WLAN_UMAC_MAX_PDEVS; obj_id++) {
pdev = objmgr->wlan_pdev_list[obj_id];
if (pdev)
handler(psoc, (void *)pdev, arg);
}
break;
case WLAN_VDEV_OP:
/* Iterate through VDEV list, invoke handler for each vdev */
max_vdev_cnt = wlan_psoc_get_max_vdev_count(psoc);
for (obj_id = 0; obj_id < max_vdev_cnt; obj_id++) {
vdev = objmgr->wlan_vdev_list[obj_id];
if (vdev)
handler(psoc, vdev, arg);
}
break;
case WLAN_PEER_OP:
/* Iterate through PEER list, invoke handler for each peer */
peer_list = &objmgr->peer_list;
/* psoc lock should be taken before list lock */
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* Since peer list has sublist, iterate through sublists */
for (i = 0; i < WLAN_PEER_HASHSIZE; i++) {
obj_list = &peer_list->peer_hash[i];
peer = wlan_psoc_peer_list_peek_head(obj_list);
while (peer) {
/* Get next peer */
peer_next = wlan_peer_get_next_peer_of_psoc(
obj_list, peer);
handler(psoc, (void *)peer, arg);
peer = peer_next;
}
}
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
break;
default:
break;
}
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_SUCCESS;
}
static void wlan_objmgr_psoc_peer_delete(struct wlan_objmgr_psoc *psoc,
void *obj, void *args)
{
struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)obj;
wlan_objmgr_peer_obj_delete(peer);
}
static void wlan_objmgr_psoc_vdev_delete(struct wlan_objmgr_psoc *psoc,
void *obj, void *args)
{
struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj;
wlan_objmgr_vdev_obj_delete(vdev);
}
static void wlan_objmgr_psoc_pdev_delete(struct wlan_objmgr_psoc *psoc,
void *obj, void *args)
{
struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)obj;
wlan_objmgr_pdev_obj_delete(pdev);
}
QDF_STATUS wlan_objmgr_free_all_objects_per_psoc(
struct wlan_objmgr_psoc *psoc)
{
/* Free all peers */
wlan_objmgr_iterate_obj_list(psoc, WLAN_PEER_OP,
wlan_objmgr_psoc_peer_delete, NULL, 1,
WLAN_OBJMGR_ID);
/* Free all vdevs */
wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
wlan_objmgr_psoc_vdev_delete, NULL, 1,
WLAN_OBJMGR_ID);
/* Free all PDEVs */
wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
wlan_objmgr_psoc_pdev_delete, NULL, 1,
WLAN_OBJMGR_ID);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_objmgr_trigger_psoc_comp_priv_object_creation(
struct wlan_objmgr_psoc *psoc,
enum wlan_umac_comp_id id)
{
wlan_objmgr_psoc_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_psoc_obj_lock(psoc);
/* If component object is already created, delete old
* component object, then invoke creation
*/
if (psoc->soc_comp_priv_obj[id]) {
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_E_FAILURE;
}
wlan_psoc_obj_unlock(psoc);
/* Invoke registered create handlers */
handler = g_umac_glb_obj->psoc_create_handler[id];
arg = g_umac_glb_obj->psoc_create_handler_arg[id];
if (handler)
psoc->obj_status[id] = handler(psoc, arg);
else
return QDF_STATUS_E_FAILURE;
/* If object status is created, then only handle this object status */
if (psoc->obj_state == WLAN_OBJ_STATE_CREATED) {
/* Derive object status */
obj_status = wlan_objmgr_psoc_object_status(psoc);
/* Move PSOC object state to Partially created state */
if (obj_status == QDF_STATUS_COMP_ASYNC) {
/*TODO atomic */
psoc->obj_state = WLAN_OBJ_STATE_PARTIALLY_CREATED;
}
}
return obj_status;
}
QDF_STATUS wlan_objmgr_trigger_psoc_comp_priv_object_deletion(
struct wlan_objmgr_psoc *psoc,
enum wlan_umac_comp_id id)
{
wlan_objmgr_psoc_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_psoc_obj_lock(psoc);
/* Component object was never created, invalid operation */
if (!psoc->soc_comp_priv_obj[id]) {
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_E_FAILURE;
}
wlan_psoc_obj_unlock(psoc);
/* Invoke registered create handlers */
handler = g_umac_glb_obj->psoc_destroy_handler[id];
arg = g_umac_glb_obj->psoc_destroy_handler_arg[id];
if (handler)
psoc->obj_status[id] = handler(psoc, arg);
else
return QDF_STATUS_E_FAILURE;
/* If object status is created, then only handle this object status */
if (psoc->obj_state == WLAN_OBJ_STATE_CREATED) {
obj_status = wlan_objmgr_psoc_object_status(psoc);
/* move object state to DEL progress */
if (obj_status == QDF_STATUS_COMP_ASYNC)
psoc->obj_state = WLAN_OBJ_STATE_COMP_DEL_PROGRESS;
}
return obj_status;
}
/* Util APIs */
QDF_STATUS wlan_objmgr_psoc_pdev_attach(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t id = 0;
QDF_STATUS status;
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/*
* Derive pdev id from pdev map
* First free pdev id is assigned
*/
while ((id < WLAN_UMAC_MAX_PDEVS) &&
(objmgr->wlan_pdev_id_map & (1<<id)))
id++;
if (id == WLAN_UMAC_MAX_PDEVS) {
status = QDF_STATUS_E_FAILURE;
} else {
/* Update the map for reserving the id */
objmgr->wlan_pdev_id_map |= (1<<id);
/* store pdev in pdev list */
objmgr->wlan_pdev_list[id] = pdev;
/* Increment pdev count */
objmgr->wlan_pdev_count++;
/* save pdev id */
pdev->pdev_objmgr.wlan_pdev_id = id;
status = QDF_STATUS_SUCCESS;
/* Inrement psoc ref count to block its free before pdev */
wlan_objmgr_psoc_get_ref(psoc, WLAN_OBJMGR_ID);
}
wlan_psoc_obj_unlock(psoc);
return status;
}
QDF_STATUS wlan_objmgr_psoc_pdev_detach(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t id;
id = pdev->pdev_objmgr.wlan_pdev_id;
/* If id is invalid, return */
if (id >= WLAN_UMAC_MAX_PDEVS)
return QDF_STATUS_E_FAILURE;
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* Free pdev id slot */
objmgr->wlan_pdev_id_map &= ~(1<<id);
objmgr->wlan_pdev_list[id] = NULL;
objmgr->wlan_pdev_count--;
pdev->pdev_objmgr.wlan_pdev_id = 0xff;
wlan_psoc_obj_unlock(psoc);
/* Release ref count of psoc */
wlan_objmgr_psoc_release_ref(psoc, WLAN_OBJMGR_ID);
return QDF_STATUS_SUCCESS;
}
struct wlan_objmgr_pdev *wlan_objmgr_get_pdev_by_id(
struct wlan_objmgr_psoc *psoc, uint8_t id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
struct wlan_objmgr_pdev *pdev = NULL;
/* If id is invalid, return */
if (id >= WLAN_UMAC_MAX_PDEVS)
return NULL;
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* get pdev from pdev list */
pdev = objmgr->wlan_pdev_list[id];
/* Do not return object, if it is not CREATED state */
if (pdev) {
if (wlan_objmgr_pdev_try_get_ref(pdev, dbg_id) !=
QDF_STATUS_SUCCESS)
pdev = NULL;
}
wlan_psoc_obj_unlock(psoc);
return pdev;
}
qdf_export_symbol(wlan_objmgr_get_pdev_by_id);
struct wlan_objmgr_pdev *wlan_objmgr_get_pdev_by_id_no_state(
struct wlan_objmgr_psoc *psoc, uint8_t id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
struct wlan_objmgr_pdev *pdev = NULL;
/* If id is invalid, return */
if (id >= WLAN_UMAC_MAX_PDEVS)
return NULL;
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* get pdev from pdev list */
pdev = objmgr->wlan_pdev_list[id];
/* Do not return object, if it is not CREATED state */
if (pdev)
wlan_objmgr_pdev_get_ref(pdev, dbg_id);
wlan_psoc_obj_unlock(psoc);
return pdev;
}
QDF_STATUS wlan_objmgr_psoc_vdev_attach(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_vdev *vdev)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t id = 0;
uint8_t map_index = 0;
uint8_t map_entry_size = 32;
uint8_t adjust_ix = 0;
QDF_STATUS status;
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* Find first free vdev id */
while ((id < objmgr->max_vdev_count) &&
(objmgr->wlan_vdev_id_map[map_index] & (1<<(id - adjust_ix)))) {
id++;
/*
* The map is two DWORDS(32 bits), so, map_index
* adjust_ix derived based on the id value
*/
if (id == ((map_index + 1) * map_entry_size)) {
map_index++;
adjust_ix = map_index * map_entry_size;
}
}
/* If no free slot, return failure */
if (id == objmgr->max_vdev_count) {
status = QDF_STATUS_E_FAILURE;
} else {
/* set free vdev id index */
objmgr->wlan_vdev_id_map[map_index] |= (1<<(id-adjust_ix));
/* store vdev pointer in vdev list */
objmgr->wlan_vdev_list[id] = vdev;
/* increment vdev counter */
objmgr->wlan_vdev_count++;
/* save vdev id */
vdev->vdev_objmgr.vdev_id = id;
status = QDF_STATUS_SUCCESS;
}
wlan_psoc_obj_unlock(psoc);
return status;
}
QDF_STATUS wlan_objmgr_psoc_vdev_detach(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_vdev *vdev)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t id = 0;
uint8_t map_index = 0;
uint8_t map_entry_size = 32;
uint8_t adjust_ix = 0;
id = vdev->vdev_objmgr.vdev_id;
/* Invalid vdev id */
if (id >= wlan_psoc_get_max_vdev_count(psoc))
return QDF_STATUS_E_FAILURE;
/*
* Derive map_index and adjust_ix to find actual DWORD
* the id map is present
*/
while ((id - adjust_ix) >= map_entry_size) {
map_index++;
adjust_ix = map_index * map_entry_size;
}
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* unset bit, to free the slot */
objmgr->wlan_vdev_id_map[map_index] &= ~(1<<(id-adjust_ix));
/* reset VDEV pointer to NULL in VDEV list array */
objmgr->wlan_vdev_list[id] = NULL;
/* decrement vdev count */
objmgr->wlan_vdev_count--;
vdev->vdev_objmgr.vdev_id = 0xff;
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_SUCCESS;
}
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_opmode_from_psoc(
struct wlan_objmgr_psoc *psoc,
enum QDF_OPMODE opmode,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev = NULL;
int vdev_cnt = 0;
uint16_t max_vdev_cnt;
/* if PSOC is NULL, return */
if (!psoc)
return NULL;
wlan_psoc_obj_lock(psoc);
max_vdev_cnt = wlan_psoc_get_max_vdev_count(psoc);
/* retrieve vdev pointer from vdev list */
while (vdev_cnt < max_vdev_cnt) {
vdev = psoc->soc_objmgr.wlan_vdev_list[vdev_cnt];
vdev_cnt++;
if (!vdev)
continue;
wlan_vdev_obj_lock(vdev);
if (vdev->vdev_mlme.vdev_opmode == opmode) {
wlan_vdev_obj_unlock(vdev);
if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) !=
QDF_STATUS_SUCCESS) {
vdev = NULL;
continue;
}
break;
}
wlan_vdev_obj_unlock(vdev);
}
wlan_psoc_obj_unlock(psoc);
return vdev;
}
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_id_from_psoc(
struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev;
/* if PSOC is NULL, return */
if (!psoc)
return NULL;
/* vdev id is invalid */
if (vdev_id >= wlan_psoc_get_max_vdev_count(psoc))
return NULL;
wlan_psoc_obj_lock(psoc);
/* retrieve vdev pointer from vdev list */
vdev = psoc->soc_objmgr.wlan_vdev_list[vdev_id];
if (vdev) {
if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) !=
QDF_STATUS_SUCCESS)
vdev = NULL;
}
wlan_psoc_obj_unlock(psoc);
return vdev;
}
qdf_export_symbol(wlan_objmgr_get_vdev_by_id_from_psoc);
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_id_from_psoc_no_state(
struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev;
/* if PSOC is NULL, return */
if (!psoc)
return NULL;
/* vdev id is invalid */
if (vdev_id >= wlan_psoc_get_max_vdev_count(psoc))
return NULL;
wlan_psoc_obj_lock(psoc);
/* retrieve vdev pointer from vdev list */
vdev = psoc->soc_objmgr.wlan_vdev_list[vdev_id];
if (vdev)
wlan_objmgr_vdev_get_ref(vdev, dbg_id);
wlan_psoc_obj_unlock(psoc);
return vdev;
}
qdf_export_symbol(wlan_objmgr_get_vdev_by_id_from_psoc_no_state);
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_macaddr_from_psoc(
struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
uint8_t *macaddr, wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_pdev *pdev;
/* if PSOC is NULL, return */
if (!psoc)
return NULL;
if (!macaddr)
return NULL;
pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, dbg_id);
if (!pdev) {
obj_mgr_err("pdev is null");
return NULL;
}
vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev, macaddr, dbg_id);
wlan_objmgr_pdev_release_ref(pdev, dbg_id);
return vdev;
}
qdf_export_symbol(wlan_objmgr_get_vdev_by_macaddr_from_psoc);
struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_macaddr_from_psoc_no_state(
struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
uint8_t *macaddr, wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_pdev *pdev;
/* if PSOC is NULL, return */
if (!psoc)
return NULL;
if (!macaddr)
return NULL;
pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, dbg_id);
if (!pdev) {
obj_mgr_err("pdev is null");
return NULL;
}
vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev_no_state(pdev, macaddr, dbg_id);
wlan_objmgr_pdev_release_ref(pdev, dbg_id);
return vdev;
}
qdf_export_symbol(wlan_objmgr_get_vdev_by_macaddr_from_psoc_no_state);
static void wlan_obj_psoc_peerlist_add_tail(qdf_list_t *obj_list,
struct wlan_objmgr_peer *obj)
{
qdf_list_insert_back(obj_list, &obj->psoc_peer);
}
static QDF_STATUS wlan_obj_psoc_peerlist_remove_peer(
qdf_list_t *obj_list,
struct wlan_objmgr_peer *peer)
{
qdf_list_node_t *psoc_node = NULL;
if (!peer)
return QDF_STATUS_E_FAILURE;
/* get vdev list node element */
psoc_node = &peer->psoc_peer;
/* list is empty, return failure */
if (qdf_list_remove_node(obj_list, psoc_node) != QDF_STATUS_SUCCESS)
return QDF_STATUS_E_FAILURE;
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS wlan_peer_bssid_match(struct wlan_objmgr_peer *peer,
uint8_t *bssid)
{
struct wlan_objmgr_vdev *vdev = wlan_peer_get_vdev(peer);
uint8_t *peer_bssid = wlan_vdev_mlme_get_macaddr(vdev);
if (WLAN_ADDR_EQ(peer_bssid, bssid) == QDF_STATUS_SUCCESS)
return QDF_STATUS_SUCCESS;
else
return QDF_STATUS_E_FAILURE;
}
/**
* wlan_obj_psoc_peerlist_get_peer_logically_deleted() - get peer
* from psoc peer list
* @psoc: PSOC object
* @macaddr: MAC address
*
* API to finds peer object pointer of logically deleted peer
*
* Return: peer pointer
* NULL on FAILURE
*/
static struct wlan_objmgr_peer *
wlan_obj_psoc_peerlist_get_peer_logically_deleted(
qdf_list_t *obj_list, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_temp;
/* Iterate through hash list to get the peer */
peer = wlan_psoc_peer_list_peek_head(obj_list);
while (peer) {
/* For peer, macaddr is key */
if (WLAN_ADDR_EQ(wlan_peer_get_macaddr(peer), macaddr)
== QDF_STATUS_SUCCESS) {
/* Return peer in logically deleted state */
if (peer->obj_state ==
WLAN_OBJ_STATE_LOGICALLY_DELETED) {
wlan_objmgr_peer_get_ref(peer, dbg_id);
return peer;
}
}
/* Move to next peer */
peer_temp = peer;
peer = wlan_peer_get_next_peer_of_psoc(obj_list, peer_temp);
}
/* Not found, return NULL */
return NULL;
}
/**
* wlan_obj_psoc_peerlist_get_peer() - get peer from psoc peer list
* @psoc: PSOC object
* @macaddr: MAC address
*
* API to finds peer object pointer by MAC addr from hash list
*
* Return: peer pointer
* NULL on FAILURE
*/
static struct wlan_objmgr_peer *wlan_obj_psoc_peerlist_get_peer(
qdf_list_t *obj_list, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_temp;
/* Iterate through hash list to get the peer */
peer = wlan_psoc_peer_list_peek_head(obj_list);
while (peer) {
/* For peer, macaddr is key */
if (WLAN_ADDR_EQ(wlan_peer_get_macaddr(peer), macaddr)
== QDF_STATUS_SUCCESS) {
if (wlan_objmgr_peer_try_get_ref(peer, dbg_id) ==
QDF_STATUS_SUCCESS) {
return peer;
}
}
/* Move to next peer */
peer_temp = peer;
peer = wlan_peer_get_next_peer_of_psoc(obj_list, peer_temp);
}
/* Not found, return NULL */
return NULL;
}
/**
* wlan_obj_psoc_peerlist_get_peer_by_pdev_id() - get peer from psoc peer list
* @psoc: PSOC object
* @macaddr: MAC address
* #pdev_id: Pdev id
*
* API to finds peer object pointer by MAC addr and pdev id from hash list
*
* Return: peer pointer
* NULL on FAILURE
*/
static struct wlan_objmgr_peer *wlan_obj_psoc_peerlist_get_peer_by_pdev_id(
qdf_list_t *obj_list, uint8_t *macaddr,
uint8_t pdev_id, wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_temp;
/* Iterate through hash list to get the peer */
peer = wlan_psoc_peer_list_peek_head(obj_list);
while (peer) {
/* For peer, macaddr is key */
if ((WLAN_ADDR_EQ(wlan_peer_get_macaddr(peer), macaddr)
== QDF_STATUS_SUCCESS) &&
(wlan_peer_get_pdev_id(peer) == pdev_id)) {
if (wlan_objmgr_peer_try_get_ref(peer, dbg_id) ==
QDF_STATUS_SUCCESS) {
return peer;
}
}
/* Move to next peer */
peer_temp = peer;
peer = wlan_peer_get_next_peer_of_psoc(obj_list, peer_temp);
}
/* Not found, return NULL */
return NULL;
}
static struct wlan_objmgr_peer *wlan_obj_psoc_peerlist_get_peer_no_state(
qdf_list_t *obj_list, uint8_t *macaddr,
uint8_t pdev_id, wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_temp;
/* Iterate through hash list to get the peer */
peer = wlan_psoc_peer_list_peek_head(obj_list);
while (peer) {
/* For peer, macaddr and pdev_id is key */
if ((WLAN_ADDR_EQ(wlan_peer_get_macaddr(peer), macaddr)
== QDF_STATUS_SUCCESS) &&
(wlan_peer_get_pdev_id(peer) == pdev_id)) {
wlan_objmgr_peer_get_ref(peer, dbg_id);
return peer;
}
/* Move to next peer */
peer_temp = peer;
peer = wlan_peer_get_next_peer_of_psoc(obj_list, peer_temp);
}
/* Not found, return NULL */
return NULL;
}
/**
* wlan_obj_psoc_populate_logically_del_peerlist_by_mac_n_bssid() - get peer
* from psoc peer list using
* mac and vdev self mac
* @obj_list: peer object list
* @macaddr: MAC address
* @bssid: BSSID address
* @dbg_id: id of the caller
*
* API to finds peer object pointer by MAC addr and BSSID from
* peer hash list for a node which is in logically deleted state,
* bssid check is done on matching peer
*
* Caller to free the list allocated in this function
*
* Return: list of peer pointers
* NULL on FAILURE
*/
static qdf_list_t
*wlan_obj_psoc_populate_logically_del_peerlist_by_mac_n_bssid(
qdf_list_t *obj_list, uint8_t *macaddr,
uint8_t *bssid, uint8_t pdev_id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_temp;
struct wlan_logically_del_peer *peer_list = NULL;
qdf_list_t *logical_del_peer_list = NULL;
bool lock_released = false;
logical_del_peer_list = qdf_mem_malloc(sizeof(*logical_del_peer_list));
if (!logical_del_peer_list)
return NULL;
qdf_list_create(logical_del_peer_list, WLAN_UMAC_PSOC_MAX_PEERS);
/* Iterate through hash list to get the peer */
peer = wlan_psoc_peer_list_peek_head(obj_list);
while (peer) {
wlan_peer_obj_lock(peer);
/* For peer, macaddr and pdev id are keys */
if ((WLAN_ADDR_EQ(wlan_peer_get_macaddr(peer), macaddr)
== QDF_STATUS_SUCCESS) &&
(wlan_peer_get_pdev_id(peer) == pdev_id)) {
/*
* if BSSID not NULL,
* then match is requested by caller, check BSSID
* (vdev mac == bssid) -- return peer
* (vdev mac != bssid) -- perform next iteration
*/
if ((!bssid) ||
(wlan_peer_bssid_match(peer, bssid) ==
QDF_STATUS_SUCCESS)) {
/* Return peer in logically deleted state */
if ((peer->obj_state ==
WLAN_OBJ_STATE_LOGICALLY_DELETED) &&
qdf_atomic_read(
&peer->peer_objmgr.ref_cnt)) {
wlan_objmgr_peer_get_ref(peer, dbg_id);
wlan_peer_obj_unlock(peer);
lock_released = true;
peer_list =
qdf_mem_malloc(
sizeof(struct wlan_logically_del_peer));
if (!peer_list) {
wlan_objmgr_peer_release_ref(peer, dbg_id);
/* Lock is already released */
WLAN_OBJMGR_BUG(0);
break;
}
peer_list->peer = peer;
qdf_list_insert_front(
logical_del_peer_list,
&peer_list->list);
}
}
}
if (!lock_released)
wlan_peer_obj_unlock(peer);
/* Move to next peer */
peer_temp = peer;
peer = wlan_peer_get_next_peer_of_psoc(obj_list, peer_temp);
lock_released = false;
}
/* Not found, return NULL */
if (qdf_list_empty(logical_del_peer_list)) {
qdf_mem_free(logical_del_peer_list);
return NULL;
} else {
return logical_del_peer_list;
}
}
/**
* wlan_obj_psoc_peerlist_get_peer_by_mac_n_bssid() - get peer from psoc peer
* list using mac and vdev
* self mac
* @psoc: PSOC object
* @macaddr: MAC address
* @bssid: BSSID address
*
* API to finds peer object pointer by MAC addr and BSSID from
* peer hash list, bssid check is done on matching peer
*
* Return: peer pointer
* NULL on FAILURE
*/
static struct wlan_objmgr_peer *wlan_obj_psoc_peerlist_get_peer_by_mac_n_bssid(
qdf_list_t *obj_list, uint8_t *macaddr,
uint8_t *bssid, uint8_t pdev_id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_temp;
/* Iterate through hash list to get the peer */
peer = wlan_psoc_peer_list_peek_head(obj_list);
while (peer) {
/* For peer, macaddr is key */
if (WLAN_ADDR_EQ(wlan_peer_get_macaddr(peer), macaddr)
== QDF_STATUS_SUCCESS) {
/*
* BSSID match is requested by caller, check BSSID
* (vdev mac == bssid) -- return peer
* (vdev mac != bssid) -- perform next iteration
*/
if ((wlan_peer_bssid_match(peer, bssid) ==
QDF_STATUS_SUCCESS) &&
(wlan_peer_get_pdev_id(peer) == pdev_id)) {
if (wlan_objmgr_peer_try_get_ref(peer, dbg_id)
== QDF_STATUS_SUCCESS) {
return peer;
}
}
}
/* Move to next peer */
peer_temp = peer;
peer = wlan_peer_get_next_peer_of_psoc(obj_list, peer_temp);
}
/* Not found, return NULL */
return NULL;
}
static struct wlan_objmgr_peer
*wlan_obj_psoc_peerlist_get_peer_by_mac_n_bssid_no_state(
qdf_list_t *obj_list, uint8_t *macaddr,
uint8_t *bssid,
uint8_t pdev_id,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_peer *peer_temp;
/* Iterate through hash list to get the peer */
peer = wlan_psoc_peer_list_peek_head(obj_list);
while (peer) {
/* For peer, macaddr is key */
if (WLAN_ADDR_EQ(wlan_peer_get_macaddr(peer), macaddr)
== QDF_STATUS_SUCCESS) {
/*
* BSSID match is requested by caller, check BSSID
* (vdev mac == bssid) -- return peer
* (vdev mac != bssid) -- perform next iteration
*/
if ((wlan_peer_bssid_match(peer, bssid) ==
QDF_STATUS_SUCCESS) &&
(wlan_peer_get_pdev_id(peer) == pdev_id)) {
wlan_objmgr_peer_get_ref(peer, dbg_id);
return peer;
}
}
/* Move to next peer */
peer_temp = peer;
peer = wlan_peer_get_next_peer_of_psoc(obj_list, peer_temp);
}
/* Not found, return NULL */
return NULL;
}
QDF_STATUS wlan_objmgr_psoc_peer_attach(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_peer *peer)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_peer_list *peer_list;
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* Max temporary peer limit is reached, return failure */
if (peer->peer_mlme.peer_type == WLAN_PEER_STA_TEMP) {
if (objmgr->temp_peer_count >= WLAN_MAX_PSOC_TEMP_PEERS) {
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_E_FAILURE;
}
} else {
/* Max peer limit is reached, return failure */
if (objmgr->wlan_peer_count
>= wlan_psoc_get_max_peer_count(psoc)) {
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_E_FAILURE;
}
}
/* Derive hash index from mac address */
hash_index = WLAN_PEER_HASH(peer->macaddr);
peer_list = &objmgr->peer_list;
/* psoc lock should be taken before list lock */
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* add peer to hash peer list */
wlan_obj_psoc_peerlist_add_tail(
&peer_list->peer_hash[hash_index],
peer);
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
/* Increment peer count */
if (peer->peer_mlme.peer_type == WLAN_PEER_STA_TEMP)
objmgr->temp_peer_count++;
else
objmgr->wlan_peer_count++;
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_objmgr_psoc_peer_detach(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_peer *peer)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_peer_list *peer_list;
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* if list is empty, return */
if (objmgr->wlan_peer_count == 0) {
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_E_FAILURE;
}
/* Get hash index, to locate the actual peer list */
hash_index = WLAN_PEER_HASH(peer->macaddr);
peer_list = &objmgr->peer_list;
/* psoc lock should be taken before list lock */
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* removes the peer from peer_list */
if (wlan_obj_psoc_peerlist_remove_peer(
&peer_list->peer_hash[hash_index],
peer) ==
QDF_STATUS_E_FAILURE) {
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
wlan_psoc_obj_unlock(psoc);
obj_mgr_err("Failed to detach peer");
return QDF_STATUS_E_FAILURE;
}
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
/* Decrement peer count */
if (peer->peer_mlme.peer_type == WLAN_PEER_STA_TEMP)
objmgr->temp_peer_count--;
else
objmgr->wlan_peer_count--;
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_SUCCESS;
}
struct wlan_objmgr_peer *wlan_objmgr_get_peer_logically_deleted(
struct wlan_objmgr_psoc *psoc, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_objmgr_peer *peer = NULL;
struct wlan_peer_list *peer_list;
/* psoc lock should be taken before peer list lock */
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* List is empty, return NULL */
if (objmgr->wlan_peer_count == 0) {
wlan_psoc_obj_unlock(psoc);
return NULL;
}
/* reduce the search window, with hash key */
hash_index = WLAN_PEER_HASH(macaddr);
peer_list = &objmgr->peer_list;
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* Iterate through peer list, get peer */
peer = wlan_obj_psoc_peerlist_get_peer_logically_deleted(
&peer_list->peer_hash[hash_index], macaddr, dbg_id);
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
wlan_psoc_obj_unlock(psoc);
return peer;
}
struct wlan_objmgr_peer *wlan_objmgr_get_peer_by_mac(
struct wlan_objmgr_psoc *psoc, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_objmgr_peer *peer = NULL;
struct wlan_peer_list *peer_list;
if (!macaddr)
return NULL;
/* psoc lock should be taken before peer list lock */
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* List is empty, return NULL */
if (objmgr->wlan_peer_count == 0) {
wlan_psoc_obj_unlock(psoc);
return NULL;
}
/* reduce the search window, with hash key */
hash_index = WLAN_PEER_HASH(macaddr);
peer_list = &objmgr->peer_list;
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* Iterate through peer list, get peer */
peer = wlan_obj_psoc_peerlist_get_peer(
&peer_list->peer_hash[hash_index], macaddr, dbg_id);
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
wlan_psoc_obj_unlock(psoc);
return peer;
}
qdf_export_symbol(wlan_objmgr_get_peer_by_mac);
struct wlan_objmgr_peer *wlan_objmgr_get_peer(
struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
uint8_t *macaddr, wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_objmgr_peer *peer = NULL;
struct wlan_peer_list *peer_list;
if (pdev_id >= WLAN_UMAC_MAX_PDEVS)
QDF_ASSERT(0);
if (!macaddr)
return NULL;
/* psoc lock should be taken before peer list lock */
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* List is empty, return NULL */
if (objmgr->wlan_peer_count == 0) {
wlan_psoc_obj_unlock(psoc);
return NULL;
}
/* reduce the search window, with hash key */
hash_index = WLAN_PEER_HASH(macaddr);
peer_list = &objmgr->peer_list;
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* Iterate through peer list, get peer */
peer = wlan_obj_psoc_peerlist_get_peer_by_pdev_id(
&peer_list->peer_hash[hash_index], macaddr, pdev_id, dbg_id);
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
wlan_psoc_obj_unlock(psoc);
return peer;
}
qdf_export_symbol(wlan_objmgr_get_peer);
struct wlan_objmgr_peer *wlan_objmgr_get_peer_nolock(
struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
uint8_t *macaddr, wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_objmgr_peer *peer = NULL;
struct wlan_peer_list *peer_list;
/* psoc lock should be taken before peer list lock */
objmgr = &psoc->soc_objmgr;
/* List is empty, return NULL */
if (objmgr->wlan_peer_count == 0)
return NULL;
/* reduce the search window, with hash key */
hash_index = WLAN_PEER_HASH(macaddr);
peer_list = &objmgr->peer_list;
/* Iterate through peer list, get peer */
peer = wlan_obj_psoc_peerlist_get_peer_by_pdev_id(
&peer_list->peer_hash[hash_index], macaddr, pdev_id, dbg_id);
return peer;
}
qdf_export_symbol(wlan_objmgr_get_peer_nolock);
struct wlan_objmgr_peer *wlan_objmgr_get_peer_no_state(
struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
uint8_t *macaddr, wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_objmgr_peer *peer = NULL;
struct wlan_peer_list *peer_list;
/* psoc lock should be taken before peer list lock */
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* List is empty, return NULL */
if (objmgr->wlan_peer_count == 0) {
wlan_psoc_obj_unlock(psoc);
return NULL;
}
/* reduce the search window, with hash key */
hash_index = WLAN_PEER_HASH(macaddr);
peer_list = &objmgr->peer_list;
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* Iterate through peer list, get peer */
peer = wlan_obj_psoc_peerlist_get_peer_no_state(
&peer_list->peer_hash[hash_index], macaddr, pdev_id, dbg_id);
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
wlan_psoc_obj_unlock(psoc);
return peer;
}
qdf_export_symbol(wlan_objmgr_get_peer_no_state);
struct wlan_objmgr_peer *wlan_objmgr_get_peer_by_mac_n_vdev(
struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
uint8_t *bssid, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_objmgr_peer *peer = NULL;
struct wlan_peer_list *peer_list;
/* psoc lock should be taken before peer list lock */
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* List is empty, return NULL */
if (objmgr->wlan_peer_count == 0) {
wlan_psoc_obj_unlock(psoc);
return NULL;
}
/* reduce the search window, with hash key */
hash_index = WLAN_PEER_HASH(macaddr);
peer_list = &objmgr->peer_list;
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* Iterate through peer list, get peer */
peer = wlan_obj_psoc_peerlist_get_peer_by_mac_n_bssid(
&peer_list->peer_hash[hash_index], macaddr, bssid,
pdev_id, dbg_id);
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
wlan_psoc_obj_unlock(psoc);
return peer;
}
qdf_export_symbol(wlan_objmgr_get_peer_by_mac_n_vdev);
/**
* wlan_objmgr_populate_logically_deleted_peerlist_by_mac_n_vdev() - get peer from psoc
* peer list using
* mac and vdev
* self mac
* @psoc: PSOC object
* @pdev_id: Pdev id
* @macaddr: MAC address
* @bssid: BSSID address. NULL mac means search all.
* @dbg_id: id of the caller
*
* API to finds peer object pointer by MAC addr and BSSID from
* peer hash list, bssid check is done on matching peer
*
* Return: list of peer pointer pointers
* NULL on FAILURE
*/
qdf_list_t *wlan_objmgr_populate_logically_deleted_peerlist_by_mac_n_vdev(
struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
uint8_t *bssid, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_peer_list *peer_list = NULL;
qdf_list_t *logical_del_peer_list = NULL;
/* psoc lock should be taken before peer list lock */
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* List is empty, return NULL */
if (objmgr->wlan_peer_count == 0) {
wlan_psoc_obj_unlock(psoc);
return NULL;
}
/* reduce the search window, with hash key */
hash_index = WLAN_PEER_HASH(macaddr);
peer_list = &objmgr->peer_list;
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* Iterate through peer list, get peer */
logical_del_peer_list =
wlan_obj_psoc_populate_logically_del_peerlist_by_mac_n_bssid(
&peer_list->peer_hash[hash_index], macaddr,
bssid, pdev_id, dbg_id);
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
wlan_psoc_obj_unlock(psoc);
return logical_del_peer_list;
}
qdf_export_symbol(wlan_objmgr_populate_logically_deleted_peerlist_by_mac_n_vdev);
struct wlan_objmgr_peer *wlan_objmgr_get_peer_by_mac_n_vdev_no_state(
struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
uint8_t *bssid, uint8_t *macaddr,
wlan_objmgr_ref_dbgid dbg_id)
{
struct wlan_objmgr_psoc_objmgr *objmgr;
uint8_t hash_index;
struct wlan_objmgr_peer *peer = NULL;
struct wlan_peer_list *peer_list;
/* psoc lock should be taken before peer list lock */
wlan_psoc_obj_lock(psoc);
objmgr = &psoc->soc_objmgr;
/* List is empty, return NULL */
if (objmgr->wlan_peer_count == 0) {
wlan_psoc_obj_unlock(psoc);
return NULL;
}
/* reduce the search window, with hash key */
hash_index = WLAN_PEER_HASH(macaddr);
peer_list = &objmgr->peer_list;
qdf_spin_lock_bh(&peer_list->peer_list_lock);
/* Iterate through peer list, get peer */
peer = wlan_obj_psoc_peerlist_get_peer_by_mac_n_bssid_no_state(
&peer_list->peer_hash[hash_index], macaddr, bssid,
pdev_id, dbg_id);
qdf_spin_unlock_bh(&peer_list->peer_list_lock);
wlan_psoc_obj_unlock(psoc);
return peer;
}
qdf_export_symbol(wlan_objmgr_get_peer_by_mac_n_vdev_no_state);
void *wlan_objmgr_psoc_get_comp_private_obj(struct wlan_objmgr_psoc *psoc,
enum wlan_umac_comp_id id)
{
void *comp_private_obj;
/* component id is invalid */
if (id >= WLAN_UMAC_MAX_COMPONENTS) {
QDF_BUG(0);
return NULL;
}
if (!psoc) {
QDF_BUG(0);
return NULL;
}
comp_private_obj = psoc->soc_comp_priv_obj[id];
return comp_private_obj;
}
qdf_export_symbol(wlan_objmgr_psoc_get_comp_private_obj);
void wlan_objmgr_psoc_get_ref(struct wlan_objmgr_psoc *psoc,
wlan_objmgr_ref_dbgid id)
{
if (!psoc) {
obj_mgr_err("psoc obj is NULL for id:%d", id);
QDF_ASSERT(0);
return;
}
/* Increment ref count */
qdf_atomic_inc(&psoc->soc_objmgr.ref_cnt);
qdf_atomic_inc(&psoc->soc_objmgr.ref_id_dbg[id]);
return;
}
qdf_export_symbol(wlan_objmgr_psoc_get_ref);
QDF_STATUS wlan_objmgr_psoc_try_get_ref(struct wlan_objmgr_psoc *psoc,
wlan_objmgr_ref_dbgid id)
{
if (!psoc) {
obj_mgr_err("psoc obj is NULL for id:%d", id);
QDF_ASSERT(0);
return QDF_STATUS_E_FAILURE;
}
wlan_psoc_obj_lock(psoc);
if (psoc->obj_state != WLAN_OBJ_STATE_CREATED) {
wlan_psoc_obj_unlock(psoc);
if (psoc->soc_objmgr.print_cnt++ <=
WLAN_OBJMGR_RATELIMIT_THRESH)
obj_mgr_err(
"[Ref id: %d] psoc is not in Created state(%d)",
id, psoc->obj_state);
return QDF_STATUS_E_RESOURCES;
}
/* Increment ref count */
wlan_objmgr_psoc_get_ref(psoc, id);
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_psoc_try_get_ref);
void wlan_objmgr_psoc_release_ref(struct wlan_objmgr_psoc *psoc,
wlan_objmgr_ref_dbgid id)
{
if (!psoc) {
obj_mgr_err("psoc obj is NULL for id:%d", id);
QDF_ASSERT(0);
return;
}
if (!qdf_atomic_read(&psoc->soc_objmgr.ref_id_dbg[id])) {
obj_mgr_err("psoc ref cnt was not taken by %d", id);
wlan_objmgr_print_ref_ids(psoc->soc_objmgr.ref_id_dbg,
QDF_TRACE_LEVEL_FATAL);
WLAN_OBJMGR_BUG(0);
}
if (!qdf_atomic_read(&psoc->soc_objmgr.ref_cnt)) {
obj_mgr_err("psoc ref cnt is 0");
WLAN_OBJMGR_BUG(0);
return;
}
qdf_atomic_dec(&psoc->soc_objmgr.ref_id_dbg[id]);
/* Decrement ref count, free psoc, if ref count == 0 */
if (qdf_atomic_dec_and_test(&psoc->soc_objmgr.ref_cnt))
wlan_objmgr_psoc_obj_destroy(psoc);
return;
}
qdf_export_symbol(wlan_objmgr_psoc_release_ref);
static void wlan_objmgr_psoc_peer_ref_print(struct wlan_objmgr_psoc *psoc,
void *obj, void *args)
{
struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)obj;
WLAN_OBJ_STATE obj_state;
uint8_t vdev_id;
uint8_t *macaddr;
wlan_peer_obj_lock(peer);
macaddr = wlan_peer_get_macaddr(peer);
obj_state = peer->obj_state;
vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer));
wlan_peer_obj_unlock(peer);
obj_mgr_alert("Peer MAC:%02x:%02x:%02x:%02x:%02x:%02x state:%d vdev_id:%d",
macaddr[0], macaddr[1], macaddr[2], macaddr[3],
macaddr[4], macaddr[5], obj_state, vdev_id);
wlan_objmgr_print_peer_ref_ids(peer, QDF_TRACE_LEVEL_FATAL);
}
static void wlan_objmgr_psoc_vdev_ref_print(struct wlan_objmgr_psoc *psoc,
void *obj, void *args)
{
struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj;
WLAN_OBJ_STATE obj_state;
uint8_t id;
wlan_vdev_obj_lock(vdev);
id = wlan_vdev_get_id(vdev);
obj_state = vdev->obj_state;
wlan_vdev_obj_unlock(vdev);
obj_mgr_alert("Vdev ID is %d, state %d", id, obj_state);
wlan_objmgr_print_ref_ids(vdev->vdev_objmgr.ref_id_dbg,
QDF_TRACE_LEVEL_FATAL);
}
static void wlan_objmgr_psoc_pdev_ref_print(struct wlan_objmgr_psoc *psoc,
void *obj, void *args)
{
struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)obj;
uint8_t id;
wlan_pdev_obj_lock(pdev);
id = wlan_objmgr_pdev_get_pdev_id(pdev);
wlan_pdev_obj_unlock(pdev);
obj_mgr_alert("pdev ID is %d", id);
wlan_objmgr_print_ref_ids(pdev->pdev_objmgr.ref_id_dbg,
QDF_TRACE_LEVEL_FATAL);
}
QDF_STATUS wlan_objmgr_print_ref_all_objects_per_psoc(
struct wlan_objmgr_psoc *psoc)
{
obj_mgr_alert("Ref counts of PEER");
wlan_objmgr_iterate_obj_list_all_noref(psoc, WLAN_PEER_OP,
wlan_objmgr_psoc_peer_ref_print, NULL);
obj_mgr_alert("Ref counts of VDEV");
wlan_objmgr_iterate_obj_list_all_noref(psoc, WLAN_VDEV_OP,
wlan_objmgr_psoc_vdev_ref_print, NULL);
obj_mgr_alert("Ref counts of PDEV");
wlan_objmgr_iterate_obj_list_all_noref(psoc, WLAN_PDEV_OP,
wlan_objmgr_psoc_pdev_ref_print, NULL);
obj_mgr_alert(" Ref counts of PSOC");
wlan_objmgr_print_ref_ids(psoc->soc_objmgr.ref_id_dbg,
QDF_TRACE_LEVEL_FATAL);
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_print_ref_all_objects_per_psoc);
QDF_STATUS wlan_objmgr_psoc_set_user_config(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_psoc_user_config *user_config_data)
{
if (!user_config_data) {
obj_mgr_err("user_config_data is NULL");
QDF_BUG(0);
return QDF_STATUS_E_FAILURE;
}
wlan_psoc_obj_lock(psoc);
qdf_mem_copy(&psoc->soc_nif.user_config, user_config_data,
sizeof(psoc->soc_nif.user_config));
wlan_psoc_obj_unlock(psoc);
return QDF_STATUS_SUCCESS;
}
void wlan_objmgr_psoc_check_for_pdev_leaks(struct wlan_objmgr_psoc *psoc)
{
struct wlan_objmgr_psoc_objmgr *_psoc;
struct wlan_objmgr_pdev *pdev;
int pdev_id;
uint32_t leaks = 0;
QDF_BUG(psoc);
if (!psoc)
return;
wlan_psoc_obj_lock(psoc);
_psoc = &psoc->soc_objmgr;
if (!_psoc->wlan_pdev_count) {
wlan_psoc_obj_unlock(psoc);
return;
}
obj_mgr_alert("objmgr pdev leaks detected for psoc %u!",
_psoc->psoc_id);
obj_mgr_alert("----------------------------------------------------");
obj_mgr_alert("Pdev Id Refs Module");
obj_mgr_alert("----------------------------------------------------");
wlan_objmgr_for_each_psoc_pdev(psoc, pdev_id, pdev) {
qdf_atomic_t *ref_id_dbg;
int ref_id;
int32_t refs;
wlan_pdev_obj_lock(pdev);
ref_id_dbg = pdev->pdev_objmgr.ref_id_dbg;
wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) {
leaks++;
obj_mgr_alert("%7u %4u %s",
pdev_id, refs,
string_from_dbgid(ref_id));
}
wlan_pdev_obj_unlock(pdev);
}
QDF_DEBUG_PANIC("%u objmgr pdev leaks detected for psoc %u!",
leaks, _psoc->psoc_id);
wlan_psoc_obj_unlock(psoc);
}
qdf_export_symbol(wlan_objmgr_psoc_check_for_pdev_leaks);
void wlan_objmgr_psoc_check_for_vdev_leaks(struct wlan_objmgr_psoc *psoc)
{
struct wlan_objmgr_psoc_objmgr *_psoc;
struct wlan_objmgr_vdev *vdev;
int vdev_id;
uint32_t leaks = 0;
QDF_BUG(psoc);
if (!psoc)
return;
wlan_psoc_obj_lock(psoc);
_psoc = &psoc->soc_objmgr;
if (!_psoc->wlan_vdev_count) {
wlan_psoc_obj_unlock(psoc);
return;
}
obj_mgr_alert("objmgr vdev leaks detected for psoc %u!",
_psoc->psoc_id);
obj_mgr_alert("----------------------------------------------------");
obj_mgr_alert("Vdev Id Refs Module");
obj_mgr_alert("----------------------------------------------------");
wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev) {
qdf_atomic_t *ref_id_dbg;
int ref_id;
int32_t refs;
wlan_vdev_obj_lock(vdev);
ref_id_dbg = vdev->vdev_objmgr.ref_id_dbg;
wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) {
leaks++;
obj_mgr_alert("%7u %4u %s",
vdev_id, refs, string_from_dbgid(ref_id));
}
wlan_vdev_obj_unlock(vdev);
}
QDF_DEBUG_PANIC("%u objmgr vdev leaks detected for psoc %u!",
leaks, _psoc->psoc_id);
wlan_psoc_obj_unlock(psoc);
}
qdf_export_symbol(wlan_objmgr_psoc_check_for_vdev_leaks);
#ifdef WLAN_OBJMGR_REF_ID_DEBUG
static void
wlan_objmgr_print_peer_ref_leaks(struct wlan_objmgr_peer *peer, int vdev_id)
{
qdf_atomic_t *ref_id_dbg;
int32_t refs;
int ref_id;
ref_id_dbg = peer->peer_objmgr.ref_id_dbg;
wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) {
obj_mgr_alert(QDF_MAC_ADDR_STR " %7u %4u %s",
QDF_MAC_ADDR_ARRAY(peer->macaddr),
vdev_id,
refs,
string_from_dbgid(ref_id));
}
}
#else
static inline void
wlan_objmgr_print_peer_ref_leaks(struct wlan_objmgr_peer *peer, int vdev_id)
{
obj_mgr_alert(QDF_MAC_ADDR_STR " %7u %4u %s",
QDF_MAC_ADDR_ARRAY(peer->macaddr),
vdev_id,
qdf_atomic_read(&peer->peer_objmgr.ref_cnt),
"TOTAL_REF_COUNT");
}
#endif
void wlan_objmgr_psoc_check_for_peer_leaks(struct wlan_objmgr_psoc *psoc)
{
struct wlan_objmgr_psoc_objmgr *_psoc;
struct wlan_objmgr_vdev *vdev;
int vdev_id;
uint32_t leaks = 0;
QDF_BUG(psoc);
if (!psoc)
return;
wlan_psoc_obj_lock(psoc);
_psoc = &psoc->soc_objmgr;
if (!_psoc->temp_peer_count && !_psoc->wlan_peer_count) {
wlan_psoc_obj_unlock(psoc);
return;
}
obj_mgr_alert("objmgr peer leaks detected for psoc %u!",
_psoc->psoc_id);
obj_mgr_alert("----------------------------------------------------");
obj_mgr_alert("Peer MAC Vdev Id Refs Module");
obj_mgr_alert("----------------------------------------------------");
wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev) {
struct wlan_objmgr_peer *peer;
wlan_vdev_obj_lock(vdev);
wlan_objmgr_for_each_vdev_peer(vdev, peer) {
wlan_peer_obj_lock(peer);
leaks += qdf_atomic_read(&peer->peer_objmgr.ref_cnt);
wlan_objmgr_print_peer_ref_leaks(peer, vdev_id);
wlan_peer_obj_unlock(peer);
}
wlan_vdev_obj_unlock(vdev);
}
QDF_DEBUG_PANIC("%u objmgr peer leaks detected for psoc %u!",
leaks, _psoc->psoc_id);
wlan_psoc_obj_unlock(psoc);
}
qdf_export_symbol(wlan_objmgr_psoc_check_for_peer_leaks);
#ifdef WLAN_OBJMGR_DEBUG
void wlan_print_psoc_info(struct wlan_objmgr_psoc *psoc)
{
struct wlan_objmgr_psoc_objmgr *psoc_objmgr;
struct wlan_objmgr_pdev *pdev;
struct wlan_objmgr_vdev *vdev;
uint16_t index = 0;
psoc_objmgr = &psoc->soc_objmgr;
obj_mgr_debug("psoc: %pK", psoc);
obj_mgr_debug("psoc_id: %d", psoc_objmgr->psoc_id);
obj_mgr_debug("wlan_pdev_count: %d", psoc_objmgr->wlan_pdev_count);
obj_mgr_debug("wlan_pdev_id_map: 0x%x", psoc_objmgr->wlan_pdev_id_map);
obj_mgr_debug("wlan_vdev_count: %d", psoc_objmgr->wlan_vdev_count);
obj_mgr_debug("max_vdev_count: %d", psoc_objmgr->max_vdev_count);
obj_mgr_debug("wlan_peer_count: %d", psoc_objmgr->wlan_peer_count);
obj_mgr_debug("max_peer_count: %d", psoc_objmgr->max_peer_count);
obj_mgr_debug("temp_peer_count: %d", psoc_objmgr->temp_peer_count);
obj_mgr_debug("ref_cnt: %d", qdf_atomic_read(&psoc_objmgr->ref_cnt));
obj_mgr_debug("qdf_dev: %pK", psoc_objmgr->qdf_dev);
obj_mgr_debug("wlan_vdev_id_map[%d]: 0x%x",
index, psoc_objmgr->wlan_vdev_id_map[index]);
index++;
obj_mgr_debug("wlan_vdev_id_map[%d]: 0x%x",
index, psoc_objmgr->wlan_vdev_id_map[index]);
wlan_objmgr_for_each_psoc_pdev(psoc, index, pdev) {
obj_mgr_debug("wlan_pdev_list[%d]: %pK", index, pdev);
wlan_print_pdev_info(pdev);
}
wlan_objmgr_for_each_psoc_vdev(psoc, index, vdev) {
obj_mgr_debug("wlan_vdev_list[%d]: %pK", index, vdev);
wlan_print_vdev_info(vdev);
}
}
qdf_export_symbol(wlan_print_psoc_info);
#endif