qcacld-3.0: Add peer APIs to get and release peer ref

The existing peer API cdp_peer_find_by_add does not maintain any peer
references. So a peer which is returned by the API may get deleted in a
different context. This may lead to access to a already deleted memory.

Fix the issue by introducing new APIs "peer_get_ref" and
"peer_release_ref" which make sure the peer is valid until it is
"released" (peer_release_ref is called).

Change-Id: I60175ee1d67f01e3ee4b48cb655d1728d29d08f4
CRs-Fixed: 2139801
This commit is contained in:
Mohit Khanna 2017-11-10 11:43:44 -08:00 • committed by snandini
commit b7bec723c3
8 changed files with 271 additions and 159 deletions

View file

@ -1370,7 +1370,8 @@ static inline int ol_tx_encap_wrapper(struct ol_txrx_pdev_t *pdev,
ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1);
if (tx_msdu_info->peer) {
/* remove the peer reference added above */
OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info->peer);
ol_txrx_peer_release_ref(tx_msdu_info->peer,
PEER_DEBUG_ID_OL_INTERNAL);
}
return -EINVAL;
}
@ -1571,7 +1572,8 @@ int ol_txrx_mgmt_send_frame(
out:
if (tx_msdu_info->peer) {
/* remove the peer reference added above */
OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info->peer);
ol_txrx_peer_release_ref(tx_msdu_info->peer,
PEER_DEBUG_ID_OL_INTERNAL);
}
return status;
@ -1760,8 +1762,9 @@ ol_tx_hl_base(
if (tx_msdu_info.peer) {
/* remove the peer reference
* added above */
OL_TXRX_PEER_UNREF_DELETE(
tx_msdu_info.peer);
ol_txrx_peer_release_ref(
tx_msdu_info.peer,
PEER_DEBUG_ID_OL_INTERNAL);
}
goto MSDU_LOOP_BOTTOM;
}
@ -1778,8 +1781,9 @@ ol_tx_hl_base(
ol_tx_desc_frame_free_nonstd(pdev,
tx_desc,
1);
OL_TXRX_PEER_UNREF_DELETE(
tx_msdu_info.peer);
ol_txrx_peer_release_ref(
tx_msdu_info.peer,
PEER_DEBUG_ID_OL_INTERNAL);
msdu = next;
continue;
} else if (tx_msdu_info.peer->state !=
@ -1794,8 +1798,9 @@ ol_tx_hl_base(
ol_tx_desc_frame_free_nonstd(
pdev,
tx_desc, 1);
OL_TXRX_PEER_UNREF_DELETE(
tx_msdu_info.peer);
ol_txrx_peer_release_ref(
tx_msdu_info.peer,
PEER_DEBUG_ID_OL_INTERNAL);
msdu = next;
continue;
}
@ -1843,7 +1848,9 @@ ol_tx_hl_base(
OL_TX_PEER_STATS_UPDATE(tx_msdu_info.peer,
msdu);
/* remove the peer reference added above */
OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info.peer);
ol_txrx_peer_release_ref
(tx_msdu_info.peer,
PEER_DEBUG_ID_OL_INTERNAL);
}
MSDU_LOOP_BOTTOM:
msdu = next;

View file

@ -357,7 +357,8 @@ struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev,
peer = NULL;
} else {
if (peer)
OL_TXRX_PEER_INC_REF_CNT(peer);
ol_txrx_peer_get_ref(peer,
PEER_DEBUG_ID_OL_INTERNAL);
}
}
if (!peer)
@ -464,9 +465,11 @@ ol_tx_classify(
* classify_extension function can check whether to
* encrypt multicast / broadcast frames.
*/
peer = ol_txrx_peer_find_hash_find_inc_ref(pdev,
vdev->mac_addr.raw,
0, 1);
peer = ol_txrx_peer_find_hash_find_get_ref
(pdev,
vdev->mac_addr.raw,
0, 1,
PEER_DEBUG_ID_OL_INTERNAL);
if (!peer) {
QDF_TRACE(QDF_MODULE_ID_TXRX,
QDF_TRACE_LEVEL_ERROR,
@ -523,9 +526,10 @@ ol_tx_classify(
*/
peer = ol_tx_tdls_peer_find(pdev, vdev, &peer_id);
} else {
peer = ol_txrx_peer_find_hash_find_inc_ref(pdev,
dest_addr,
0, 1);
peer = ol_txrx_peer_find_hash_find_get_ref(pdev,
dest_addr,
0, 1,
PEER_DEBUG_ID_OL_INTERNAL);
}
tx_msdu_info->htt.info.is_unicast = true;
if (!peer) {
@ -583,7 +587,9 @@ ol_tx_classify(
"%s: remove the peer for invalid peer_id %pK\n",
__func__, peer);
/* remove the peer reference added above */
OL_TXRX_PEER_UNREF_DELETE(peer);
ol_txrx_peer_release_ref
(peer,
PEER_DEBUG_ID_OL_INTERNAL);
tx_msdu_info->peer = NULL;
}
return NULL;
@ -606,7 +612,8 @@ ol_tx_classify(
"%s: remove the peer reference %pK\n",
__func__, peer);
/* remove the peer reference added above */
OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info->peer);
ol_txrx_peer_release_ref(tx_msdu_info->peer,
PEER_DEBUG_ID_OL_INTERNAL);
/* Making peer NULL in case if multicast non STA mode */
tx_msdu_info->peer = NULL;
}
@ -680,24 +687,26 @@ ol_tx_classify_mgmt(
* frame to vdev queue.
*/
if (peer) {
int rcnt;
qdf_mem_copy(
&local_mac_addr_aligned.raw[0],
dest_addr, OL_TXRX_MAC_ADDR_LEN);
mac_addr = &local_mac_addr_aligned;
if (ol_txrx_peer_find_mac_addr_cmp(
mac_addr,
&peer->mac_addr) != 0) {
rcnt = OL_TXRX_PEER_UNREF_DELETE(peer);
if (ol_txrx_peer_find_mac_addr_cmp
(mac_addr,
&peer->mac_addr) != 0) {
ol_txrx_peer_release_ref
(peer,
PEER_DEBUG_ID_OL_INTERNAL);
peer = NULL;
}
}
} else {
/* find the peer and increment its reference count */
peer = ol_txrx_peer_find_hash_find_inc_ref(pdev,
dest_addr,
0, 1);
peer = ol_txrx_peer_find_hash_find_get_ref(pdev,
dest_addr,
0, 1,
PEER_DEBUG_ID_OL_INTERNAL);
}
tx_msdu_info->peer = peer;
if (!peer) {

View file

@ -111,7 +111,9 @@ ol_tx_queue_vdev_flush(struct ol_txrx_pdev_t *pdev, struct ol_txrx_vdev_t *vdev)
for (i = 0; i < OL_TX_NUM_TIDS; i++) {
txq = &peer->txqs[i];
if (txq->frms) {
OL_TXRX_PEER_INC_REF_CNT(peer);
ol_txrx_peer_get_ref
(peer,
PEER_DEBUG_ID_OL_INTERNAL);
peers[peer_count++] = peer;
break;
}
@ -129,7 +131,8 @@ ol_tx_queue_vdev_flush(struct ol_txrx_pdev_t *pdev, struct ol_txrx_vdev_t *vdev)
}
ol_txrx_info(
"%s: Delete Peer %pK\n", __func__, peer);
OL_TXRX_PEER_UNREF_DELETE(peers[i]);
ol_txrx_peer_release_ref(peers[i],
PEER_DEBUG_ID_OL_INTERNAL);
}
} while (peer_count >= PEER_ARRAY_COUNT);
}

View file

@ -319,7 +319,7 @@ ol_txrx_find_peer_by_addr_and_vdev(struct cdp_pdev *ppdev,
if (!peer)
return NULL;
*peer_id = peer->local_id;
OL_TXRX_PEER_UNREF_DELETE(peer);
ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
return peer;
}
@ -385,16 +385,17 @@ void *ol_txrx_find_peer_by_addr(struct cdp_pdev *ppdev,
struct ol_txrx_peer_t *peer;
struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_addr, 0, 1);
peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_addr, 0, 1,
PEER_DEBUG_ID_OL_INTERNAL);
if (!peer)
return NULL;
*peer_id = peer->local_id;
OL_TXRX_PEER_UNREF_DELETE(peer);
ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
return peer;
}
/**
* ol_txrx_find_peer_by_addr_inc_ref() - find peer via peer mac addr and peer_id
* ol_txrx_peer_get_ref_by_addr() - get peer ref via peer mac addr and peer_id
* @pdev: pointer of type ol_txrx_pdev_handle
* @peer_addr: peer mac addr
* @peer_id: pointer to fill in the value of peer->local_id for caller
@ -402,28 +403,30 @@ void *ol_txrx_find_peer_by_addr(struct cdp_pdev *ppdev,
* This function finds the peer with given mac address and returns its peer_id.
* Note that this function increments the peer->ref_cnt.
* This makes sure that peer will be valid. This also means the caller needs to
* call the corresponding API - OL_TXRX_PEER_UNREF_DELETE to delete the peer
* call the corresponding API - ol_txrx_peer_release_ref to delete the peer
* reference.
* Sample usage:
* {
* //the API call below increments the peer->ref_cnt
* peer = ol_txrx_find_peer_by_addr_inc_ref(pdev, peer_addr, peer_id);
* peer = ol_txrx_peer_get_ref_by_addr(pdev, peer_addr, peer_id, dbg_id);
*
* // Once peer usage is done
*
* //the API call below decrements the peer->ref_cnt
* OL_TXRX_PEER_UNREF_DELETE(peer);
* ol_txrx_peer_release_ref(peer, dbg_id);
* }
*
* Return: peer handle if the peer is found, NULL if peer is not found.
*/
ol_txrx_peer_handle ol_txrx_find_peer_by_addr_inc_ref(ol_txrx_pdev_handle pdev,
uint8_t *peer_addr,
uint8_t *peer_id)
ol_txrx_peer_handle ol_txrx_peer_get_ref_by_addr(ol_txrx_pdev_handle pdev,
u8 *peer_addr,
u8 *peer_id,
enum peer_debug_id_type dbg_id)
{
struct ol_txrx_peer_t *peer;
peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_addr, 0, 1);
peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_addr, 0, 1,
dbg_id);
if (!peer)
return NULL;
*peer_id = peer->local_id;
@ -2644,10 +2647,13 @@ ol_txrx_peer_attach(struct cdp_vdev *pvdev, uint8_t *peer_mac_addr)
qdf_atomic_init(&peer->delete_in_progress);
qdf_atomic_init(&peer->flush_in_progress);
qdf_atomic_init(&peer->ref_cnt);
for (i = 0; i < PEER_DEBUG_ID_MAX; i++)
qdf_atomic_init(&peer->access_list[i]);
/* keep one reference for attach */
OL_TXRX_PEER_INC_REF_CNT(peer);
ol_txrx_peer_get_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
/* Set a flag to indicate peer create is pending in firmware */
qdf_atomic_init(&peer->fw_create_pending);
@ -3073,7 +3079,8 @@ QDF_STATUS ol_txrx_peer_state_update(struct cdp_pdev *ppdev,
return QDF_STATUS_E_INVAL;
}
peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac, 0, 1);
peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac, 0, 1,
PEER_DEBUG_ID_OL_INTERNAL);
if (NULL == peer) {
ol_txrx_err(
"%s: peer is null for peer_mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
@ -3091,7 +3098,9 @@ QDF_STATUS ol_txrx_peer_state_update(struct cdp_pdev *ppdev,
"%s: no state change, returns directly\n",
__func__);
#endif
peer_ref_cnt = OL_TXRX_PEER_UNREF_DELETE(peer);
peer_ref_cnt = ol_txrx_peer_release_ref
(peer,
PEER_DEBUG_ID_OL_INTERNAL);
return QDF_STATUS_SUCCESS;
}
@ -3121,9 +3130,10 @@ QDF_STATUS ol_txrx_peer_state_update(struct cdp_pdev *ppdev,
ol_txrx_peer_tid_unpause(peer, tid);
}
}
peer_ref_cnt = OL_TXRX_PEER_UNREF_DELETE(peer);
peer_ref_cnt = ol_txrx_peer_release_ref(peer,
PEER_DEBUG_ID_OL_INTERNAL);
/*
* after OL_TXRX_PEER_UNREF_DELETE, peer object cannot be accessed
* after ol_txrx_peer_release_ref, peer object cannot be accessed
* if the return code was 0
*/
if (peer_ref_cnt > 0)
@ -3148,9 +3158,9 @@ ol_txrx_peer_update(ol_txrx_vdev_handle vdev,
enum ol_txrx_peer_update_select_t select)
{
struct ol_txrx_peer_t *peer;
int peer_ref_cnt;
peer = ol_txrx_peer_find_hash_find_inc_ref(vdev->pdev, peer_mac, 0, 1);
peer = ol_txrx_peer_find_hash_find_get_ref(vdev->pdev, peer_mac, 0, 1,
PEER_DEBUG_ID_OL_INTERNAL);
if (!peer) {
ol_txrx_dbg("%s: peer is null",
__func__);
@ -3231,7 +3241,7 @@ ol_txrx_peer_update(ol_txrx_vdev_handle vdev,
break;
}
} /* switch */
peer_ref_cnt = OL_TXRX_PEER_UNREF_DELETE(peer);
ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
}
uint8_t
@ -3257,14 +3267,71 @@ ol_txrx_peer_qoscapable_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id)
return 0;
}
int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer,
const char *fname,
int line)
/**
* ol_txrx_dump_peer_access_list() - dump peer access list
* @peer: peer handle
*
* This function will dump if any peer debug ids are still accessing peer
*
* Return: None
*/
static void ol_txrx_dump_peer_access_list(ol_txrx_peer_handle peer)
{
u32 i;
u32 pending_ref;
for (i = 0; i < PEER_DEBUG_ID_MAX; i++) {
pending_ref = qdf_atomic_read(&peer->access_list[i]);
if (pending_ref)
ol_txrx_info_high("id %d pending refs %d",
i, pending_ref);
}
}
/**
* ol_txrx_peer_free_tids() - free tids for the peer
* @peer: peer handle
*
* Return: None
*/
static inline void ol_txrx_peer_free_tids(ol_txrx_peer_handle peer)
{
int i = 0;
/*
* 'array' is allocated in addba handler and is supposed to be
* freed in delba handler. There is the case (for example, in
* SSR) where delba handler is not called. Because array points
* to address of 'base' by default and is reallocated in addba
* handler later, only free the memory when the array does not
* point to base.
*/
for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) {
if (peer->tids_rx_reorder[i].array !=
&peer->tids_rx_reorder[i].base) {
ol_txrx_dbg(
"%s, delete reorder arr, tid:%d\n",
__func__, i);
qdf_mem_free(peer->tids_rx_reorder[i].array);
ol_rx_reorder_init(&peer->tids_rx_reorder[i],
(uint8_t)i);
}
}
}
/**
* ol_txrx_peer_release_ref() - release peer reference
* @peer: peer handle
*
* Release peer reference and delete peer if refcount is 0
*
* Return: None
*/
int ol_txrx_peer_release_ref(ol_txrx_peer_handle peer,
enum peer_debug_id_type debug_id)
{
int rc;
struct ol_txrx_vdev_t *vdev;
struct ol_txrx_pdev_t *pdev;
int i;
/* preconditions */
TXRX_ASSERT2(peer);
@ -3283,6 +3350,11 @@ int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer,
return -EINVAL;
}
if (debug_id >= PEER_DEBUG_ID_MAX || debug_id < 0) {
ol_txrx_err("incorrect debug_id %d ", debug_id);
return -EINVAL;
}
wlan_roam_debug_log(vdev->vdev_id, DEBUG_PEER_UNREF_DELETE,
DEBUG_INVALID_PEER_ID, &peer->mac_addr.raw,
peer, 0,
@ -3323,14 +3395,19 @@ int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer,
*/
rc--;
if (!qdf_atomic_read(&peer->access_list[debug_id])) {
qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
ol_txrx_err("peer %p ref was not taken by %d",
peer, debug_id);
ol_txrx_dump_peer_access_list(peer);
QDF_BUG(0);
return -EACCES;
}
qdf_atomic_dec(&peer->access_list[debug_id]);
if (qdf_atomic_dec_and_test(&peer->ref_cnt)) {
u_int16_t peer_id;
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
"[%s][%d]: Deleting peer %pK (%pM) ref_cnt %d\n",
fname, line, peer, peer->mac_addr.raw,
qdf_atomic_read(&peer->ref_cnt));
u16 peer_id;
wlan_roam_debug_log(vdev->vdev_id,
DEBUG_DELETING_PEER_OBJ,
DEBUG_INVALID_PEER_ID,
@ -3410,46 +3487,31 @@ int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer,
qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
}
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH,
"[%s][%d]: Deleting peer %pK (%pM) peer->ref_cnt = %d %s",
fname, line, peer, peer->mac_addr.raw,
qdf_atomic_read(&peer->ref_cnt),
qdf_atomic_read(&peer->fw_create_pending) == 1 ?
"(No Maps received)" : "");
ol_txrx_info_high("[%d][%d]: Deleting peer %p ref_cnt -> %d %s",
debug_id,
qdf_atomic_read(&peer->access_list[debug_id]),
peer, rc,
qdf_atomic_read(&peer->fw_create_pending)
== 1 ?
"(No Maps received)" : "");
ol_txrx_peer_tx_queue_free(pdev, peer);
/* Remove mappings from peer_id to peer object */
ol_txrx_peer_clear_map_peer(pdev, peer);
/*
* 'array' is allocated in addba handler and is supposed to be
* freed in delba handler. There is the case (for example, in
* SSR) where delba handler is not called. Because array points
* to address of 'base' by default and is reallocated in addba
* handler later, only free the memory when the array does not
* point to base.
*/
for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) {
if (peer->tids_rx_reorder[i].array !=
&peer->tids_rx_reorder[i].base) {
ol_txrx_dbg(
"%s, delete reorder arr, tid:%d\n",
__func__, i);
qdf_mem_free(peer->tids_rx_reorder[i].array);
ol_rx_reorder_init(&peer->tids_rx_reorder[i],
(uint8_t) i);
}
}
ol_txrx_peer_free_tids(peer);
ol_txrx_dump_peer_access_list(peer);
qdf_mem_free(peer);
} else {
qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH,
"[%s][%d]: ref delete peer %pK peer->ref_cnt = %d",
fname, line, peer, rc);
ol_txrx_info_high("[%d][%d]: ref delete peer %p ref_cnt -> %d",
debug_id,
qdf_atomic_read(&peer->access_list[debug_id]),
peer, rc);
}
return rc;
}
@ -3612,12 +3674,10 @@ static void ol_txrx_peer_detach(void *ppeer, uint32_t bitmap)
if (vdev->opmode == wlan_op_mode_sta) {
qdf_timer_start(&peer->peer_unmap_timer,
OL_TXRX_PEER_UNMAP_TIMEOUT);
ol_txrx_info_high("%s: started peer_unmap_timer for peer %pK",
__func__, peer);
ol_txrx_info_high
("started peer_unmap_timer for peer %pK",
peer);
}
} else {
ol_txrx_err("%s unmap timer not started as PEER_DELETE not sent to FW",
__func__);
}
/*
@ -3626,7 +3686,7 @@ static void ol_txrx_peer_detach(void *ppeer, uint32_t bitmap)
* PEER_UNMAP message arrives to remove the other
* reference, added by the PEER_MAP message.
*/
OL_TXRX_PEER_UNREF_DELETE(peer);
ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
}
/**
@ -3653,21 +3713,6 @@ static void ol_txrx_peer_detach_force_delete(void *ppeer)
ol_txrx_peer_detach(peer, CDP_PEER_DELETE_NO_SPECIAL);
}
ol_txrx_peer_handle
ol_txrx_peer_find_by_addr(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac_addr)
{
struct ol_txrx_peer_t *peer;
peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac_addr, 0, 0);
if (peer) {
ol_txrx_info_high(
"%s: Delete extra reference %pK", __func__, peer);
/* release the extra reference */
OL_TXRX_PEER_UNREF_DELETE(peer);
}
return peer;
}
/**
* ol_txrx_dump_tx_desc() - dump tx desc total and free count
* @txrx_pdev: Pointer to txrx pdev
@ -4315,14 +4360,15 @@ static void ol_txrx_disp_peer_stats(ol_txrx_pdev_handle pdev)
qdf_spin_lock_bh(&pdev->local_peer_ids.lock);
peer = pdev->local_peer_ids.map[i];
if (peer)
OL_TXRX_PEER_INC_REF_CNT(peer);
ol_txrx_peer_get_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
qdf_spin_unlock_bh(&pdev->local_peer_ids.lock);
if (peer) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"stats: peer 0x%pK local peer id %d", peer, i);
ol_txrx_disp_peer_cached_bufq_stats(peer);
OL_TXRX_PEER_UNREF_DELETE(peer);
ol_txrx_peer_release_ref(peer,
PEER_DEBUG_ID_OL_INTERNAL);
}
}
}
@ -5590,6 +5636,39 @@ static void *ol_txrx_wrapper_find_peer_by_addr(struct cdp_pdev *pdev,
peer_addr, peer_id);
}
/**
* ol_txrx_wrapper_peer_get_ref_by_addr() - get peer reference by address
* @pdev: pdev handle
* @peer_addr: peer address we want to find
* @peer_id: peer id
* @debug_id: peer debug id for tracking
*
* Return: peer instance pointer
*/
static void *
ol_txrx_wrapper_peer_get_ref_by_addr(struct cdp_pdev *pdev,
u8 *peer_addr, uint8_t *peer_id,
enum peer_debug_id_type debug_id)
{
return ol_txrx_peer_get_ref_by_addr((ol_txrx_pdev_handle)pdev,
peer_addr, peer_id, debug_id);
}
/**
* ol_txrx_wrapper_peer_release_ref() - release peer reference
* @peer: peer handle
* @debug_id: peer debug id for tracking
*
* Release peer ref acquired by peer get ref api
*
* Return: void
*/
static void ol_txrx_wrapper_peer_release_ref(void *peer,
enum peer_debug_id_type debug_id)
{
ol_txrx_peer_release_ref(peer, debug_id);
}
/**
* ol_txrx_wrapper_set_flow_control_parameters() - set flow control parameters
* @cfg_ctx: cfg context
@ -5749,6 +5828,8 @@ static struct cdp_cfg_ops ol_ops_cfg = {
static struct cdp_peer_ops ol_ops_peer = {
.register_peer = ol_txrx_wrapper_register_peer,
.clear_peer = ol_txrx_clear_peer,
.peer_get_ref_by_addr = ol_txrx_wrapper_peer_get_ref_by_addr,
.peer_release_ref = ol_txrx_wrapper_peer_release_ref,
.find_peer_by_addr = ol_txrx_wrapper_find_peer_by_addr,
.find_peer_by_addr_and_vdev = ol_txrx_find_peer_by_addr_and_vdev,
.local_peer_id = ol_txrx_local_peer_id,

View file

@ -39,16 +39,16 @@
* only for forwarding path.
*/
#define OL_TX_NON_FWD_RESERVE 100
#define OL_TXRX_PEER_UNREF_DELETE(peer) \
ol_txrx_peer_unref_delete(peer, __func__, __LINE__);
int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer,
const char *fname,
int line);
ol_txrx_peer_handle ol_txrx_peer_get_ref_by_addr(ol_txrx_pdev_handle pdev,
u8 *peer_addr,
u8 *peer_id,
enum peer_debug_id_type
dbg_id);
int ol_txrx_peer_release_ref(ol_txrx_peer_handle peer,
enum peer_debug_id_type dbg_id);
ol_txrx_peer_handle ol_txrx_find_peer_by_addr_inc_ref(ol_txrx_pdev_handle pdev,
uint8_t *peer_addr,
uint8_t *peer_id);
/**
* ol_tx_desc_pool_size_hl() - allocate tx descriptor pool size for HL systems
* @ctrl_pdev: the control pdev handle

View file

@ -40,7 +40,7 @@
#include <ol_txrx_api.h> /* ol_txrx_pdev_t, etc. */
#include <ol_txrx_dbg.h> /* TXRX_DEBUG_LEVEL */
#include <ol_txrx_internal.h> /* ol_txrx_pdev_t, etc. */
#include <ol_txrx.h> /* ol_txrx_peer_unref_delete */
#include <ol_txrx.h> /* ol_txrx_peer_release_ref */
#include <ol_txrx_peer_find.h> /* ol_txrx_peer_find_attach, etc. */
#include <ol_tx_queue.h>
#include "wlan_roam_debug.h"
@ -70,24 +70,28 @@ static int ol_txrx_log2_ceil(unsigned int value)
return log2;
}
/**
* __ol_txrx_peer_change_ref_cnt() - change peer ref count by the input value
* @peer: pointer to peer structure
* @change: value to add to the peer->ref_cnt, can be negative
* @fname: name of the calling function
* @line: line number of the calling function
*
* Return: the QDF_STATUS return from hdd_execute_config_command
*/
void __ol_txrx_peer_change_ref_cnt(struct ol_txrx_peer_t *peer,
int change,
const char *fname,
int line)
int ol_txrx_peer_get_ref(struct ol_txrx_peer_t *peer,
enum peer_debug_id_type dbg_id)
{
qdf_atomic_add(change, &peer->ref_cnt);
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH,
"[%s][%d]: peer %pK peer->ref_cnt changed by (%d) to %d",
fname, line, peer, change, qdf_atomic_read(&peer->ref_cnt));
int refs_dbg_id;
if (!peer) {
ol_txrx_err("peer is null for ID %d", dbg_id);
return -EINVAL;
}
if (dbg_id >= PEER_DEBUG_ID_MAX || dbg_id < 0) {
ol_txrx_err("incorrect debug_id %d ", dbg_id);
return -EINVAL;
}
qdf_atomic_inc(&peer->ref_cnt);
qdf_atomic_inc(&peer->access_list[dbg_id]);
refs_dbg_id = qdf_atomic_read(&peer->access_list[dbg_id]);
ol_txrx_info_high("[%d][%d] peer %pK ref_cnt -> %d",
dbg_id, refs_dbg_id,
peer, qdf_atomic_read(&peer->ref_cnt));
return refs_dbg_id;
}
/*=== function definitions for peer MAC addr --> peer object hash table =====*/
@ -199,9 +203,8 @@ struct ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev,
if (ol_txrx_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) ==
0 && (check_valid == 0 || peer->valid)
&& peer->vdev == vdev) {
/* found it */
OL_TXRX_PEER_INC_REF_CNT(peer);
ol_txrx_peer_get_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
return peer;
}
@ -211,11 +214,12 @@ struct ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev,
}
struct ol_txrx_peer_t *
ol_txrx_peer_find_hash_find_inc_ref
ol_txrx_peer_find_hash_find_get_ref
(struct ol_txrx_pdev_t *pdev,
uint8_t *peer_mac_addr,
int mac_addr_is_aligned,
uint8_t check_valid)
u8 check_valid,
enum peer_debug_id_type dbg_id)
{
union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr;
unsigned int index;
@ -234,7 +238,7 @@ ol_txrx_peer_find_hash_find_inc_ref
if (ol_txrx_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) ==
0 && (check_valid == 0 || peer->valid)) {
/* found it */
OL_TXRX_PEER_INC_REF_CNT(peer);
ol_txrx_peer_get_ref(peer, dbg_id);
qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
return peer;
}
@ -296,11 +300,9 @@ void ol_txrx_peer_find_hash_erase(struct ol_txrx_pdev_t *pdev)
/*
* Artificially adjust the peer's ref count to
* 1, so it will get deleted by
* OL_TXRX_PEER_UNREF_DELETE.
* ol_txrx_peer_release_ref.
*/
qdf_atomic_init(&peer->ref_cnt); /* set to 0 */
OL_TXRX_PEER_INC_REF_CNT(peer); /* incr to 1 */
OL_TXRX_PEER_UNREF_DELETE(peer);
}
}
}
@ -383,8 +385,9 @@ static inline void ol_txrx_peer_find_add_id(struct ol_txrx_pdev_t *pdev,
/* check if there's already a peer object with this MAC address */
peer =
ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac_addr,
1 /* is aligned */, 0);
ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac_addr,
1 /* is aligned */, 0,
PEER_DEBUG_ID_OL_INTERNAL);
if (!peer || peer_id == HTT_INVALID_PEER) {
/*
@ -644,7 +647,7 @@ void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id)
* Remove a reference to the peer.
* If there are no more references, delete the peer object.
*/
OL_TXRX_PEER_UNREF_DELETE(peer);
ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: peer_id %d peer %pK peer_id_ref_cnt %d",
@ -695,7 +698,7 @@ void ol_txrx_peer_remove_obj_map_entries(ol_txrx_pdev_handle pdev,
/*
* Transfer peer_id_ref_cnt into del_peer_id_ref_cnt so that
* OL_TXRX_PEER_UNREF_DELETE will decrement del_peer_id_ref_cnt
* ol_txrx_peer_release_ref will decrement del_peer_id_ref_cnt
* and any map events will increment peer_id_ref_cnt. Otherwise
* accounting will be messed up.
*
@ -722,7 +725,7 @@ void ol_txrx_peer_remove_obj_map_entries(ol_txrx_pdev_handle pdev,
}
while (num_deleted_maps-- > 0)
OL_TXRX_PEER_UNREF_DELETE(peer);
ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL);
}
struct ol_txrx_peer_t *ol_txrx_assoc_peer_find(struct ol_txrx_vdev_t *vdev)
@ -736,7 +739,8 @@ struct ol_txrx_peer_t *ol_txrx_assoc_peer_find(struct ol_txrx_vdev_t *vdev)
*/
if (vdev->last_real_peer
&& vdev->last_real_peer->peer_ids[0] != HTT_INVALID_PEER_ID) {
OL_TXRX_PEER_INC_REF_CNT(vdev->last_real_peer);
ol_txrx_peer_get_ref(vdev->last_real_peer,
PEER_DEBUG_ID_OL_INTERNAL);
peer = vdev->last_real_peer;
} else {
peer = NULL;

View file

@ -36,14 +36,20 @@
#include <cdp_txrx_cmn.h> /* ol_txrx_pdev_t, etc. */
#include <ol_txrx_internal.h> /* TXRX_ASSERT */
/**
* ol_txrx_peer_get_ref() - get peer reference
* @peer: peer for removing obj map entries
* @dbg_id: debug id to keep track of peer references
*
* The function increments the peer ref count. The ref count can be reduced by
* caling ol_txrx_peer_release_ref function.
*
* Return: peer debug id ref count or error
*/
int
ol_txrx_peer_get_ref(struct ol_txrx_peer_t *peer,
enum peer_debug_id_type dbg_id);
#define OL_TXRX_PEER_INC_REF_CNT(peer) \
__ol_txrx_peer_change_ref_cnt(peer, 1, __func__, __LINE__);
void __ol_txrx_peer_change_ref_cnt(struct ol_txrx_peer_t *peer,
int change,
const char *fname,
int line);
int ol_txrx_peer_find_attach(struct ol_txrx_pdev_t *pdev);
void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev);
@ -97,11 +103,12 @@ ol_txrx_peer_find_hash_add(struct ol_txrx_pdev_t *pdev,
struct ol_txrx_peer_t *peer);
struct ol_txrx_peer_t *
ol_txrx_peer_find_hash_find_inc_ref
ol_txrx_peer_find_hash_find_get_ref
(struct ol_txrx_pdev_t *pdev,
uint8_t *peer_mac_addr,
int mac_addr_is_aligned,
uint8_t check_valid);
u8 check_valid,
enum peer_debug_id_type dbg_id);
struct
ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev,

View file

@ -1207,6 +1207,7 @@ struct ol_txrx_peer_t {
struct ol_txrx_vdev_t *vdev;
qdf_atomic_t ref_cnt;
qdf_atomic_t access_list[PEER_DEBUG_ID_MAX];
qdf_atomic_t delete_in_progress;
qdf_atomic_t flush_in_progress;