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