xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_main.c (revision dae10a5fbc53d54c53c4ba24fa018ad8b1e7c008)
1 /*
2  * Copyright (c) 2016-2018 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_pdev_context *mgmt_txrx_pdev_ctx)
30 {
31 	uint32_t i;
32 
33 	mgmt_txrx_info(
34 			"mgmt_txrx ctx: %pK pdev: %pK mgmt desc pool size %d",
35 			mgmt_txrx_pdev_ctx, mgmt_txrx_pdev_ctx->pdev,
36 			MGMT_DESC_POOL_MAX);
37 	mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool = qdf_mem_malloc(
38 			MGMT_DESC_POOL_MAX *
39 			sizeof(struct mgmt_txrx_desc_elem_t));
40 
41 	if (!mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool) {
42 		mgmt_txrx_err("Failed to allocate desc pool");
43 		return QDF_STATUS_E_NOMEM;
44 	}
45 	qdf_list_create(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list,
46 					MGMT_DESC_POOL_MAX);
47 
48 	for (i = 0; i < MGMT_DESC_POOL_MAX; i++) {
49 		mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].desc_id = i;
50 		mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].in_use = false;
51 		qdf_list_insert_front(
52 				&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list,
53 				&mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].entry);
54 	}
55 
56 	qdf_spinlock_create(
57 		&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock);
58 
59 	return QDF_STATUS_SUCCESS;
60 }
61 
62 void wlan_mgmt_txrx_desc_pool_deinit(
63 			struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx)
64 {
65 	uint32_t i;
66 	uint32_t pool_size;
67 	QDF_STATUS status;
68 
69 	if (!mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool) {
70 		mgmt_txrx_err("Empty mgmt descriptor pool");
71 		qdf_assert_always(0);
72 		return;
73 	}
74 
75 	pool_size = mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size;
76 	for (i = 0; i < pool_size; i++) {
77 		status = qdf_list_remove_node(
78 				&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list,
79 				&mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].entry);
80 		if (status != QDF_STATUS_SUCCESS)
81 			mgmt_txrx_err(
82 				"Failed to get mgmt desc from freelist, desc id: %d: status %d",
83 				i, status);
84 	}
85 
86 	qdf_list_destroy(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list);
87 	qdf_mem_free(mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool);
88 	mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool = NULL;
89 
90 	qdf_spinlock_destroy(
91 		&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock);
92 }
93 
94 struct mgmt_txrx_desc_elem_t *wlan_mgmt_txrx_desc_get(
95 			struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx)
96 {
97 	QDF_STATUS status;
98 	qdf_list_node_t *desc_node;
99 	struct mgmt_txrx_desc_elem_t *mgmt_txrx_desc;
100 
101 	qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock);
102 	if (qdf_list_peek_front(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list,
103 			    &desc_node)
104 			!= QDF_STATUS_SUCCESS) {
105 		qdf_spin_unlock_bh(
106 			&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock);
107 		mgmt_txrx_err("Descriptor freelist empty for mgmt_txrx_ctx %pK",
108 				mgmt_txrx_pdev_ctx);
109 		return NULL;
110 	}
111 
112 	status = qdf_list_remove_node(
113 				&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list,
114 				desc_node);
115 	if (status != QDF_STATUS_SUCCESS) {
116 		qdf_spin_unlock_bh(
117 			&mgmt_txrx_pdev_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 	}
122 
123 	mgmt_txrx_desc = qdf_container_of(desc_node,
124 					  struct mgmt_txrx_desc_elem_t,
125 					  entry);
126 	mgmt_txrx_desc->in_use = true;
127 
128 	/* acquire the wakelock when there are pending mgmt tx frames */
129 	qdf_wake_lock_timeout_acquire(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp,
130 				      MGMT_TXRX_WAKELOCK_TIMEOUT_TX_CMP);
131 
132 	qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock);
133 
134 	mgmt_txrx_info("retrieved mgmt desc: %pK with desc id: %d",
135 			mgmt_txrx_desc, mgmt_txrx_desc->desc_id);
136 	return mgmt_txrx_desc;
137 }
138 
139 void wlan_mgmt_txrx_desc_put(
140 			struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx,
141 			uint32_t desc_id)
142 {
143 	struct mgmt_txrx_desc_elem_t *desc;
144 
145 	desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[desc_id];
146 	qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock);
147 	desc->in_use = false;
148 	qdf_list_insert_front(&mgmt_txrx_pdev_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_pdev_ctx->mgmt_desc_pool.free_list.count ==
153 	    mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size)
154 		qdf_wake_lock_release(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp,
155 				      MGMT_TXRX_WAKELOCK_REASON_TX_CMP);
156 
157 	qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock);
158 
159 	mgmt_txrx_info("put mgmt desc: %pK with desc id: %d into freelist",
160 			desc, desc->desc_id);
161 }
162