1 /*
2  * Copyright (c) 2014-2019,2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*========================================================================
21 
22    \file  epping_main.c
23 
24    \brief WLAN End Point Ping test tool implementation
25 
26    ========================================================================*/
27 
28 /*--------------------------------------------------------------------------
29    Include Files
30    ------------------------------------------------------------------------*/
31 #include <cds_api.h>
32 #include <cds_sched.h>
33 #include <linux/etherdevice.h>
34 #include <linux/firmware.h>
35 #include <wni_api.h>
36 #include <wlan_ptt_sock_svc.h>
37 #include <linux/wireless.h>
38 #include <net/cfg80211.h>
39 #include <linux/rtnetlink.h>
40 #include <linux/semaphore.h>
41 #include <linux/ctype.h>
42 #include "bmi.h"
43 #include "ol_fw.h"
44 #include "ol_if_athvar.h"
45 #include "hif.h"
46 #include "epping_main.h"
47 #include "epping_internal.h"
48 #include "wlan_policy_mgr_api.h"
49 
50 #ifdef TIMER_MANAGER
51 #define TIMER_MANAGER_STR " +TIMER_MANAGER"
52 #else
53 #define TIMER_MANAGER_STR ""
54 #endif
55 
56 #ifdef MEMORY_DEBUG
57 #define MEMORY_DEBUG_STR " +MEMORY_DEBUG"
58 #else
59 #define MEMORY_DEBUG_STR ""
60 #endif
61 
62 #ifdef HIF_SDIO
63 #define WLAN_WAIT_TIME_WLANSTART 10000
64 #else
65 #define WLAN_WAIT_TIME_WLANSTART 2000
66 #endif
67 
68 #ifdef WLAN_FEATURE_EPPING
69 static struct epping_context *g_epping_ctx;
70 
71 /**
72  * epping_open(): End point ping driver open Function
73  *
74  * This function is called by HDD to open epping module
75  *
76  *
77  * return - 0 for success, negative for failure
78  */
epping_open(void)79 int epping_open(void)
80 {
81 	EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__);
82 
83 	g_epping_ctx = qdf_mem_malloc(sizeof(*g_epping_ctx));
84 
85 	if (!g_epping_ctx)
86 		return -ENOMEM;
87 
88 	g_epping_ctx->con_mode = cds_get_conparam();
89 	return 0;
90 }
91 
92 /**
93  * epping_disable(): End point ping driver disable Function
94  *
95  * This is the driver disable function - called by HDD to
96  * disable epping module
97  *
98  * return: none
99  */
epping_disable(void)100 void epping_disable(void)
101 {
102 	epping_context_t *epping_ctx;
103 	struct hif_opaque_softc *hif_ctx;
104 	HTC_HANDLE htc_handle;
105 
106 	epping_ctx = g_epping_ctx;
107 	if (!epping_ctx) {
108 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
109 			   "%s: error: epping_ctx  = NULL", __func__);
110 		return;
111 	}
112 
113 	hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
114 	if (!hif_ctx) {
115 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
116 			   "%s: error: hif_ctx = NULL", __func__);
117 		return;
118 	}
119 	hif_disable_isr(hif_ctx);
120 	hif_reset_soc(hif_ctx);
121 
122 	htc_handle = cds_get_context(QDF_MODULE_ID_HTC);
123 	if (!htc_handle) {
124 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
125 			   "%s: error: htc_handle = NULL", __func__);
126 		return;
127 	}
128 	htc_stop(htc_handle);
129 	epping_cookie_cleanup(epping_ctx);
130 	htc_destroy(htc_handle);
131 
132 	if (epping_ctx->epping_adapter) {
133 		epping_destroy_adapter(epping_ctx->epping_adapter);
134 		epping_ctx->epping_adapter = NULL;
135 	}
136 }
137 
138 /**
139  * epping_close(): End point ping driver close Function
140  *
141  * This is the driver close function - called by HDD to close epping module
142  *
143  * return: none
144  */
epping_close(void)145 void epping_close(void)
146 {
147 	epping_context_t *to_free;
148 
149 	if (!g_epping_ctx) {
150 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
151 			   "%s: error: g_epping_ctx  = NULL", __func__);
152 		return;
153 	}
154 
155 	to_free = g_epping_ctx;
156 	g_epping_ctx = NULL;
157 	qdf_mem_free(to_free);
158 }
159 
160 /**
161  * epping_target_suspend_acknowledge() - process wow ack/nack from fw
162  * @context: htc_init_info->context
163  * @wow_nack: true when wow is rejected
164  * @reason_code : WoW status reason code
165  */
epping_target_suspend_acknowledge(void * context,bool wow_nack,uint16_t reson_code)166 static void epping_target_suspend_acknowledge(void *context, bool wow_nack,
167 					      uint16_t reson_code)
168 {
169 	if (!g_epping_ctx) {
170 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
171 			   "%s: epping_ctx is NULL", __func__);
172 		return;
173 	}
174 	/* EPPING_TODO: do we need wow_nack? */
175 	g_epping_ctx->wow_nack = wow_nack;
176 }
177 
178 #ifdef WLAN_FEATURE_BMI
179 /**
180  * epping_update_ol_config - API to update ol configuration parameters
181  *
182  * Return: void
183  */
epping_update_ol_config(void)184 static void epping_update_ol_config(void)
185 {
186 	struct ol_config_info cfg;
187 	struct ol_context *ol_ctx = cds_get_context(QDF_MODULE_ID_BMI);
188 
189 	if (!ol_ctx)
190 		return;
191 
192 	cfg.enable_self_recovery = 0;
193 	cfg.enable_uart_print = 0;
194 	cfg.enable_fw_log = 0;
195 	cfg.enable_ramdump_collection = 0;
196 	cfg.enable_lpass_support = 0;
197 
198 	ol_init_ini_config(ol_ctx, &cfg);
199 }
200 
201 static
epping_bmi_download_fw(struct ol_context * ol_ctx)202 QDF_STATUS epping_bmi_download_fw(struct ol_context *ol_ctx)
203 {
204 	epping_update_ol_config();
205 
206 	/* Initialize BMI and Download firmware */
207 	if (bmi_download_firmware(ol_ctx)) {
208 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
209 			  "%s: BMI failed to download target", __func__);
210 		bmi_cleanup(ol_ctx);
211 		return QDF_STATUS_E_INVAL;
212 	}
213 
214 	EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
215 		   "%s: bmi_download_firmware done", __func__);
216 	return QDF_STATUS_SUCCESS;
217 }
218 #else
219 static
epping_bmi_download_fw(struct ol_context * ol_ctx)220 QDF_STATUS epping_bmi_download_fw(struct ol_context *ol_ctx)
221 {
222 	return QDF_STATUS_SUCCESS;
223 }
224 #endif
225 
226 /**
227  * epping_enable(): End point ping driver enable Function
228  *
229  * This is the driver enable function - called by HDD to enable
230  * epping module
231  *
232  * return - 0 : success, negative: error
233  */
epping_enable(struct device * parent_dev,bool rtnl_held)234 int epping_enable(struct device *parent_dev, bool rtnl_held)
235 {
236 	int ret = 0;
237 	epping_context_t *epping_ctx = NULL;
238 	struct cds_context *p_cds_context = NULL;
239 	qdf_device_t qdf_ctx;
240 	struct htc_init_info htc_info;
241 	struct hif_opaque_softc *scn;
242 	tSirMacAddr adapter_macAddr;
243 	struct ol_context *ol_ctx = NULL;
244 	struct hif_target_info *tgt_info;
245 
246 	EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__);
247 
248 	p_cds_context = cds_get_global_context();
249 
250 	if (!p_cds_context) {
251 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
252 			   "%s: Failed cds_get_global_context", __func__);
253 		ret = -1;
254 		return ret;
255 	}
256 
257 	epping_ctx = g_epping_ctx;
258 	if (!epping_ctx) {
259 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
260 			   "%s: Failed to get epping_ctx", __func__);
261 		ret = -1;
262 		return ret;
263 	}
264 	epping_ctx->parent_dev = (void *)parent_dev;
265 	epping_get_dummy_mac_addr(adapter_macAddr);
266 
267 	/* Initialize the timer module */
268 	qdf_timer_module_init();
269 
270 	scn = cds_get_context(QDF_MODULE_ID_HIF);
271 	if (!scn) {
272 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
273 			  "%s: scn is null!", __func__);
274 		return A_ERROR;
275 	}
276 
277 	tgt_info = hif_get_target_info_handle(scn);
278 
279 	ol_ctx = cds_get_context(QDF_MODULE_ID_BMI);
280 
281 	if (epping_bmi_download_fw(ol_ctx) != QDF_STATUS_SUCCESS)
282 		return A_ERROR;
283 
284 	/* store target type and target version info in hdd ctx */
285 	epping_ctx->target_type = tgt_info->target_type;
286 
287 	htc_info.pContext = NULL;
288 	htc_info.TargetFailure = ol_target_failure;
289 	htc_info.TargetSendSuspendComplete = epping_target_suspend_acknowledge;
290 	qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
291 
292 	/* Create HTC */
293 	p_cds_context->htc_ctx = htc_create(scn, &htc_info, qdf_ctx,
294 					    cds_get_conparam());
295 	if (!p_cds_context->htc_ctx) {
296 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
297 			  "%s: Failed to Create HTC", __func__);
298 		bmi_cleanup(ol_ctx);
299 		return A_ERROR;
300 	}
301 	epping_ctx->HTCHandle =
302 		cds_get_context(QDF_MODULE_ID_HTC);
303 	if (!epping_ctx->HTCHandle) {
304 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
305 			   "%s: HTCHandle is NULL", __func__);
306 		return A_ERROR;
307 	}
308 
309 	if (bmi_done(ol_ctx)) {
310 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
311 			   "%s: Failed to complete BMI phase", __func__);
312 		goto error_end;
313 	}
314 
315 	/* start HIF */
316 	if (htc_wait_target(epping_ctx->HTCHandle) != QDF_STATUS_SUCCESS) {
317 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
318 			   "%s: htc_wait_target error", __func__);
319 		goto error_end;
320 	}
321 	EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC ready", __func__);
322 
323 	ret = epping_connect_service(epping_ctx);
324 	if (ret != 0) {
325 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
326 			   "%s: htc_wait_targetdone", __func__);
327 		goto error_end;
328 	}
329 	if (htc_start(epping_ctx->HTCHandle) != QDF_STATUS_SUCCESS)
330 		goto error_end;
331 
332 	EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC started", __func__);
333 
334 	/* init the tx cookie resource */
335 	ret = epping_cookie_init(epping_ctx);
336 	if (ret < 0) {
337 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
338 			   "%s: cookie init failed", __func__);
339 		htc_stop(epping_ctx->HTCHandle);
340 		epping_cookie_cleanup(epping_ctx);
341 		goto error_end;
342 	}
343 
344 	EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Exit", __func__);
345 	return ret;
346 
347 error_end:
348 	htc_destroy(p_cds_context->htc_ctx);
349 	p_cds_context->htc_ctx = NULL;
350 	bmi_cleanup(ol_ctx);
351 	return A_ERROR;
352 }
353 
epping_enable_adapter(void)354 void epping_enable_adapter(void)
355 {
356 	epping_context_t *epping_ctx = g_epping_ctx;
357 	tSirMacAddr adapter_macaddr;
358 
359 	if (!epping_ctx) {
360 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL, "epping context is NULL");
361 		return;
362 	}
363 
364 	epping_get_dummy_mac_addr(adapter_macaddr);
365 	epping_ctx->epping_adapter = epping_add_adapter(epping_ctx,
366 							adapter_macaddr,
367 							QDF_STA_MODE, true);
368 	if (!epping_ctx->epping_adapter)
369 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL, "epping add adapter failed");
370 }
371 #endif
372