xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_main.c (revision 7fb196901782e8fcd6c82b63746465c66cb3ac55)
1 /*
2  * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  *  DOC:    wlan_mgmt_txrx_main.c
21  *  This file contains mgmt txrx private API definitions for
22  *  mgmt txrx component.
23  */
24 
25 #include "wlan_mgmt_txrx_main_i.h"
26 #include "qdf_nbuf.h"
27 
28 QDF_STATUS wlan_mgmt_txrx_desc_pool_init(
29 			struct mgmt_txrx_priv_context *mgmt_txrx_ctx,
30 			uint32_t pool_size)
31 {
32 	uint32_t i;
33 
34 	if (!pool_size) {
35 		mgmt_txrx_err("Invalid pool size %u given", pool_size);
36 		qdf_assert_always(pool_size);
37 		return QDF_STATUS_E_INVAL;
38 	}
39 
40 	mgmt_txrx_info("mgmt_txrx ctx: %p psoc: %p, initialize mgmt desc pool of size %d",
41 				mgmt_txrx_ctx, mgmt_txrx_ctx->psoc, pool_size);
42 	mgmt_txrx_ctx->mgmt_desc_pool.pool = qdf_mem_malloc(pool_size *
43 					sizeof(struct mgmt_txrx_desc_elem_t));
44 
45 	if (!mgmt_txrx_ctx->mgmt_desc_pool.pool) {
46 		mgmt_txrx_err("Failed to allocate desc pool");
47 		return QDF_STATUS_E_NOMEM;
48 	}
49 	qdf_list_create(&mgmt_txrx_ctx->mgmt_desc_pool.free_list, pool_size);
50 
51 	for (i = 0; i < pool_size; i++) {
52 		mgmt_txrx_ctx->mgmt_desc_pool.pool[i].desc_id = i;
53 		mgmt_txrx_ctx->mgmt_desc_pool.pool[i].in_use = false;
54 		qdf_list_insert_front(&mgmt_txrx_ctx->mgmt_desc_pool.free_list,
55 				&mgmt_txrx_ctx->mgmt_desc_pool.pool[i].entry);
56 	}
57 
58 	qdf_spinlock_create(
59 		&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock);
60 
61 	return QDF_STATUS_SUCCESS;
62 }
63 
64 void wlan_mgmt_txrx_desc_pool_deinit(
65 			struct mgmt_txrx_priv_context *mgmt_txrx_ctx)
66 {
67 	uint8_t i;
68 	uint32_t pool_size;
69 	QDF_STATUS status;
70 
71 	if (!mgmt_txrx_ctx->mgmt_desc_pool.pool) {
72 		mgmt_txrx_err("Empty mgmt descriptor pool");
73 		qdf_assert_always(0);
74 		return;
75 	}
76 
77 	pool_size = mgmt_txrx_ctx->mgmt_desc_pool.free_list.max_size;
78 	for (i = 0; i < pool_size; i++) {
79 		status = qdf_list_remove_node(
80 				&mgmt_txrx_ctx->mgmt_desc_pool.free_list,
81 				&mgmt_txrx_ctx->mgmt_desc_pool.pool[i].entry);
82 		if (status != QDF_STATUS_SUCCESS)
83 			mgmt_txrx_err("Failed to get mgmt descriptor from freelist, desc id: %d with status %d",
84 					i, status);
85 	}
86 
87 	qdf_list_destroy(&mgmt_txrx_ctx->mgmt_desc_pool.free_list);
88 	qdf_mem_free(mgmt_txrx_ctx->mgmt_desc_pool.pool);
89 	mgmt_txrx_ctx->mgmt_desc_pool.pool = NULL;
90 
91 	qdf_spinlock_destroy(
92 		&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock);
93 }
94 
95 struct mgmt_txrx_desc_elem_t *wlan_mgmt_txrx_desc_get(
96 			struct mgmt_txrx_priv_context *mgmt_txrx_ctx)
97 {
98 	QDF_STATUS status;
99 	qdf_list_node_t *desc_node;
100 	struct mgmt_txrx_desc_elem_t *mgmt_txrx_desc;
101 
102 	qdf_spin_lock_bh(&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock);
103 	if (qdf_list_peek_front(&mgmt_txrx_ctx->mgmt_desc_pool.free_list,
104 			    &desc_node)
105 			!= QDF_STATUS_SUCCESS) {
106 		qdf_spin_unlock_bh(
107 			&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock);
108 		mgmt_txrx_err("Descriptor freelist empty for mgmt_txrx_ctx %p",
109 				mgmt_txrx_ctx);
110 		return NULL;
111 	}
112 
113 	status = qdf_list_remove_node(&mgmt_txrx_ctx->mgmt_desc_pool.free_list,
114 			     desc_node);
115 	if (status != QDF_STATUS_SUCCESS) {
116 		qdf_spin_unlock_bh(
117 			&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock);
118 		mgmt_txrx_err("Failed to get descriptor from list: status %d",
119 					status);
120 		qdf_assert_always(0);
121 		return NULL;
122 	}
123 
124 	mgmt_txrx_desc = qdf_container_of(desc_node,
125 					  struct mgmt_txrx_desc_elem_t,
126 					  entry);
127 	mgmt_txrx_desc->in_use = true;
128 
129 	/* acquire the wakelock when there are pending mgmt tx frames */
130 	qdf_wake_lock_timeout_acquire(&mgmt_txrx_ctx->wakelock_tx_cmp,
131 				      MGMT_TXRX_WAKELOCK_TIMEOUT_TX_CMP);
132 
133 	qdf_spin_unlock_bh(&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock);
134 
135 	mgmt_txrx_info("retrieved mgmt desc: %p with desc id: %d",
136 			mgmt_txrx_desc, mgmt_txrx_desc->desc_id);
137 	return mgmt_txrx_desc;
138 }
139 
140 void wlan_mgmt_txrx_desc_put(struct mgmt_txrx_priv_context *mgmt_txrx_ctx,
141 			uint32_t desc_id)
142 {
143 	struct mgmt_txrx_desc_elem_t *desc;
144 
145 	desc = &mgmt_txrx_ctx->mgmt_desc_pool.pool[desc_id];
146 	qdf_spin_lock_bh(&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock);
147 	desc->in_use = false;
148 	qdf_list_insert_front(&mgmt_txrx_ctx->mgmt_desc_pool.free_list,
149 			      &desc->entry);
150 
151 	/* release the wakelock if there are no pending mgmt tx frames */
152 	if (mgmt_txrx_ctx->mgmt_desc_pool.free_list.count ==
153 	    mgmt_txrx_ctx->mgmt_desc_pool.free_list.max_size)
154 		qdf_wake_lock_release(&mgmt_txrx_ctx->wakelock_tx_cmp,
155 				      MGMT_TXRX_WAKELOCK_REASON_TX_CMP);
156 
157 	qdf_spin_unlock_bh(&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock);
158 
159 	mgmt_txrx_info("put mgmt desc: %p with desc id: %d into freelist",
160 			desc, desc->desc_id);
161 }
162