blob: bf285c00975d5f31932d60c9a36c2a5e679ae823 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ftm.c
30 *
31 * This file contains the WLAN factory test mode implementation
32 */
33
34#include <cds_mq.h>
35#include "cds_sched.h"
36#include <cds_api.h>
37#include "sir_types.h"
38#include "cdf_types.h"
39#include "sir_api.h"
40#include "sir_mac_prot_def.h"
41#include "sme_api.h"
42#include "mac_init_api.h"
43#include "wlan_qct_sys.h"
44#include "wlan_hdd_misc.h"
45#include "i_cds_packet.h"
46#include "cds_reg_service.h"
47#include "wlan_hdd_main.h"
48#include "qwlan_version.h"
49#include "wma_types.h"
50#include "cfg_api.h"
51
52#if defined(QCA_WIFI_FTM)
53#include "bmi.h"
54#include "ol_fw.h"
55#include "wlan_hdd_cfg80211.h"
56#include "wlan_hdd_main.h"
57#include "hif.h"
58#endif
59
60#define HDD_FTM_WMA_PRE_START_TIMEOUT (30000) /* 30 seconds */
61
62#if defined(QCA_WIFI_FTM)
63#if defined(LINUX_QCMBR)
64#define ATH_XIOCTL_UNIFIED_UTF_CMD 0x1000
65#define ATH_XIOCTL_UNIFIED_UTF_RSP 0x1001
66#define MAX_UTF_LENGTH 1024
67typedef struct qcmbr_data_s {
68 unsigned int cmd;
69 unsigned int length;
70 unsigned char buf[MAX_UTF_LENGTH + 4];
71 unsigned int copy_to_user;
72} qcmbr_data_t;
73typedef struct qcmbr_queue_s {
74 unsigned char utf_buf[MAX_UTF_LENGTH + 4];
75 struct list_head list;
76} qcmbr_queue_t;
77LIST_HEAD(qcmbr_queue_head);
78DEFINE_SPINLOCK(qcmbr_queue_lock);
79#endif
80#endif
81
82/**
83 * wlan_ftm_postmsg() - Post FTM message
84 * @cmd_ptr: Pointer to FTM command buffer
85 * @cmd_len: Length of command in @cmd_ptr
86 *
87 * This function is used to send FTM commands to firmware
88 *
89 * Return: 0 for success, non zero for failure
90 */
91static uint32_t wlan_ftm_postmsg(uint8_t *cmd_ptr, uint16_t cmd_len)
92{
93 cds_msg_t ftmMsg;
94
95 ENTER();
96
97 ftmMsg.type = WMA_FTM_CMD_REQ;
98 ftmMsg.reserved = 0;
99 ftmMsg.bodyptr = (uint8_t *) cmd_ptr;
100 ftmMsg.bodyval = 0;
101
102 if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA,
103 &ftmMsg)) {
104 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: : Failed to post Msg to HAL",
105 __func__);
106
107 return CDF_STATUS_E_FAILURE;
108 }
109
110 EXIT();
111 return CDF_STATUS_SUCCESS;
112}
113
114/**
115 * wlan_hdd_ftm_update_tgt_cfg() - Update target configuration
116 * @context: context registered with WMA
117 * @param: target configuration
118 *
119 * This function is registered with WMA via wma_open(), and is
120 * invoked via callback when target parameters are received
121 * from firmware.
122 *
123 * Return: None
124 */
125static void wlan_hdd_ftm_update_tgt_cfg(void *context, void *param)
126{
127 hdd_context_t *hdd_ctx = (hdd_context_t *) context;
128 struct wma_tgt_cfg *cfg = (struct wma_tgt_cfg *)param;
129
130 if (!cdf_is_macaddr_zero(&cfg->hw_macaddr)) {
131 hdd_update_macaddr(hdd_ctx->config, cfg->hw_macaddr);
132 } else {
133 hddLog(CDF_TRACE_LEVEL_ERROR,
134 "%s: Invalid MAC passed from target, using MAC from ini file"
135 MAC_ADDRESS_STR, __func__,
136 MAC_ADDR_ARRAY(hdd_ctx->config->intfMacAddr[0].bytes));
137 }
138}
139
140/**
141 * wlan_ftm_cds_open() - Open the CDS Module in FTM mode
142 * @p_cds_context: pointer to the global CDS context
143 * @hddContextSize: Size of the HDD context to allocate.
144 *
145 * The wlan_ftm_cds_open() function opens the CDF Scheduler
146 * Upon successful initialization:
147 * - All CDS submodules should have been initialized
148 * - The CDS scheduler should have opened
149 * - All the WLAN SW components should have been opened. This includes MAC.
150 *
151 * Returns:
152 * CDF_STATUS_SUCCESS - Scheduler was successfully initialized and
153 * is ready to be used.
154 * CDF_STATUS_E_RESOURCES - System resources (other than memory)
155 * are unavailable to initialize the scheduler
156 * CDF_STATUS_E_FAILURE - Failure to initialize the scheduler
157 */
158static CDF_STATUS wlan_ftm_cds_open(v_CONTEXT_t p_cds_context,
159 uint32_t hddContextSize)
160{
161 CDF_STATUS vStatus = CDF_STATUS_SUCCESS;
162 int iter = 0;
163 tSirRetStatus sirStatus = eSIR_SUCCESS;
164 tMacOpenParameters mac_openParms;
165 p_cds_contextType gp_cds_context = (p_cds_contextType) p_cds_context;
166#if defined(QCA_WIFI_FTM)
167 cdf_device_t cdf_ctx;
168 HTC_INIT_INFO htcInfo;
169 void *pHifContext = NULL;
170 void *pHtcContext = NULL;
171#endif
172 hdd_context_t *hdd_ctx;
173
174 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH,
175 "%s: Opening CDS", __func__);
176
177 if (NULL == gp_cds_context) {
178 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
179 "%s: Trying to open CDS without a PreOpen", __func__);
180 CDF_ASSERT(0);
181 return CDF_STATUS_E_FAILURE;
182 }
183
184 /* Initialize the probe event */
185 if (cdf_event_init(&gp_cds_context->ProbeEvent) != CDF_STATUS_SUCCESS) {
186 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
187 "%s: Unable to init probeEvent", __func__);
188 CDF_ASSERT(0);
189 return CDF_STATUS_E_FAILURE;
190 }
191
192 if (cdf_event_init(&(gp_cds_context->wmaCompleteEvent)) !=
193 CDF_STATUS_SUCCESS) {
194 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
195 "%s: Unable to init wmaCompleteEvent", __func__);
196 CDF_ASSERT(0);
197
198 goto err_probe_event;
199 }
200
201 /* Initialize the free message queue */
202 vStatus = cds_mq_init(&gp_cds_context->freeVosMq);
203 if (!CDF_IS_STATUS_SUCCESS(vStatus)) {
204
205 /* Critical Error ... Cannot proceed further */
206 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
207 "%s: Failed to initialize CDS free message queue %d",
208 __func__, vStatus);
209 CDF_ASSERT(0);
210 goto err_wma_complete_event;
211 }
212
213 for (iter = 0; iter < CDS_CORE_MAX_MESSAGES; iter++) {
214 (gp_cds_context->aMsgWrappers[iter]).pVosMsg =
215 &(gp_cds_context->aMsgBuffers[iter]);
216 INIT_LIST_HEAD(&gp_cds_context->aMsgWrappers[iter].msgNode);
217 cds_mq_put(&gp_cds_context->freeVosMq,
218 &(gp_cds_context->aMsgWrappers[iter]));
219 }
220
221 /* Now Open the CDS Scheduler */
222 vStatus = cds_sched_open(gp_cds_context, &gp_cds_context->cdf_sched,
223 sizeof(cds_sched_context));
224
225 if (!CDF_IS_STATUS_SUCCESS(vStatus)) {
226 /* Critical Error ... Cannot proceed further */
227 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
228 "%s: Failed to open CDS Scheduler %d", __func__,
229 vStatus);
230 CDF_ASSERT(0);
231 goto err_msg_queue;
232 }
233#if defined(QCA_WIFI_FTM)
234 /* Initialize BMI and Download firmware */
235 pHifContext = cds_get_context(CDF_MODULE_ID_HIF);
236 if (!pHifContext) {
237 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
238 "%s: failed to get HIF context", __func__);
239 goto err_sched_close;
240 }
241
242 if (bmi_download_firmware(pHifContext)) {
243 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
244 "%s: BMI failed to download target", __func__);
245 goto err_bmi_close;
246 }
247 htcInfo.pContext = gp_cds_context->pHIFContext;
248 htcInfo.TargetFailure = ol_target_failure;
249 htcInfo.TargetSendSuspendComplete = wma_target_suspend_acknowledge;
250 cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE);
251
252 /* Create HTC */
253 gp_cds_context->htc_ctx =
254 htc_create(htcInfo.pContext, &htcInfo, cdf_ctx);
255 if (!gp_cds_context->htc_ctx) {
256 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
257 "%s: Failed to Create HTC", __func__);
258 goto err_bmi_close;
259 }
260
261 if (bmi_done(pHifContext)) {
262 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
263 "%s: Failed to complete BMI phase", __func__);
264 goto err_htc_close;
265 }
266#endif /* QCA_WIFI_FTM */
267
268 /*Open the WMA module */
269 cdf_mem_set(&mac_openParms, sizeof(mac_openParms), 0);
270 mac_openParms.driverType = eDRIVER_TYPE_MFG;
271
272 hdd_ctx = (hdd_context_t *) (gp_cds_context->pHDDContext);
273 if ((NULL == hdd_ctx) || (NULL == hdd_ctx->config)) {
274 /* Critical Error ... Cannot proceed further */
275 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
276 "%s: Hdd Context is Null", __func__);
277 CDF_ASSERT(0);
278 goto err_htc_close;
279 }
280
281 mac_openParms.powersaveOffloadEnabled =
282 hdd_ctx->config->enablePowersaveOffload;
283
284#ifdef WLAN_FEATURE_LPSS
285 mac_openParms.is_lpass_enabled = hdd_ctx->config->enablelpasssupport;
286#endif
287
288 vStatus = wma_open(gp_cds_context,
289 wlan_hdd_ftm_update_tgt_cfg, NULL, &mac_openParms);
290 if (!CDF_IS_STATUS_SUCCESS(vStatus)) {
291 /* Critical Error ... Cannot proceed further */
292 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
293 "%s: Failed to open WMA module %d", __func__,
294 vStatus);
295 CDF_ASSERT(0);
296 goto err_htc_close;
297 }
298#if defined(QCA_WIFI_FTM)
299 ((struct ol_softc *)pHifContext)->enable_ramdump_collection =
300 hdd_ctx->config->is_ramdump_enabled;
301
302 pHtcContext = cds_get_context(CDF_MODULE_ID_HTC);
303 if (!pHtcContext) {
304 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
305 "%s: failed to get HTC context", __func__);
306 goto err_wma_close;
307 }
308 if (htc_wait_target(pHtcContext)) {
309 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
310 "%s: Failed to complete BMI phase", __func__);
311 goto err_wma_close;
312 }
313#endif
314
315 /* Now proceed to open the MAC */
316
317 /* UMA is supported in hardware for performing the
318 * frame translation 802.11 <-> 802.3
319 */
320 mac_openParms.frameTransRequired = 1;
321
322 sirStatus =
323 mac_open(&(gp_cds_context->pMACContext),
324 gp_cds_context->pHDDContext,
325 &mac_openParms);
326
327 if (eSIR_SUCCESS != sirStatus) {
328 /* Critical Error ... Cannot proceed further */
329 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
330 "%s: Failed to open MAC %d", __func__, sirStatus);
331 CDF_ASSERT(0);
332 goto err_wma_close;
333 }
334#ifndef QCA_WIFI_FTM
335 /* Now proceed to open the SME */
336 vStatus = sme_open(gp_cds_context->pMACContext);
337 if (!CDF_IS_STATUS_SUCCESS(vStatus)) {
338 /* Critical Error ... Cannot proceed further */
339 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
340 "%s: Failed to open SME %d", __func__, vStatus);
341 goto err_mac_close;
342 }
343
344 vStatus = sme_init_chan_list(gp_cds_context->pMACContext,
345 hdd_ctx->reg.alpha2, hdd_ctx->reg.cc_src);
346 if (!CDF_IS_STATUS_SUCCESS(vStatus)) {
347 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
348 "%s: Failed to init sme channel list", __func__);
349 } else {
350 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH,
351 "%s: CDS successfully Opened", __func__);
352 return CDF_STATUS_SUCCESS;
353 }
354#else
355 return CDF_STATUS_SUCCESS;
356#endif
357
358#ifndef QCA_WIFI_FTM
359err_mac_close:
360#endif
361 mac_close(gp_cds_context->pMACContext);
362
363err_wma_close:
364 wma_close(gp_cds_context);
365
366err_htc_close:
367#if defined(QCA_WIFI_FTM)
368 if (gp_cds_context->htc_ctx) {
369 htc_destroy(gp_cds_context->htc_ctx);
370 gp_cds_context->htc_ctx = NULL;
371 }
372
373err_bmi_close:
374 bmi_cleanup(pHifContext);
375#endif /* QCA_WIFI_FTM */
376
377err_sched_close:
378 cds_sched_close(gp_cds_context);
379err_msg_queue:
380 cds_mq_deinit(&gp_cds_context->freeVosMq);
381
382err_wma_complete_event:
383 cdf_event_destroy(&gp_cds_context->wmaCompleteEvent);
384
385err_probe_event:
386 cdf_event_destroy(&gp_cds_context->ProbeEvent);
387
388 return CDF_STATUS_E_FAILURE;
389
390} /* wlan_ftm_cds_open() */
391
392/**
393 * wlan_ftm_cds_close() - Close the CDF Module in FTM mode
394 * @cds_context: context of cds
395 *
396 * The wlan_ftm_cds_close() function closes the CDF Module
397 *
398 * Return: CDF_STATUS_SUCCESS - successfully closed
399 */
400static CDF_STATUS wlan_ftm_cds_close(v_CONTEXT_t cds_context)
401{
402 CDF_STATUS cdf_status;
403 p_cds_contextType gp_cds_context = (p_cds_contextType) cds_context;
404
405#ifndef QCA_WIFI_FTM
406 cdf_status = sme_close(((p_cds_contextType) cds_context)->pMACContext);
407 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
408 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
409 "%s: Failed to close SME %d", __func__, cdf_status);
410 CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status));
411 }
412#endif
413
414 cdf_status = mac_close(((p_cds_contextType) cds_context)->pMACContext);
415 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
416 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
417 "%s: Failed to close MAC %d", __func__, cdf_status);
418 CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status));
419 }
420
421 ((p_cds_contextType) cds_context)->pMACContext = NULL;
422
423
424 cdf_status = wma_close(cds_context);
425 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
426 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
427 "%s: Failed to close WMA %d", __func__, cdf_status);
428 CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status));
429 }
430#if defined(QCA_WIFI_FTM)
431 if (gp_cds_context->htc_ctx) {
432 htc_stop(gp_cds_context->htc_ctx);
433 htc_destroy(gp_cds_context->htc_ctx);
434 gp_cds_context->htc_ctx = NULL;
435 }
436 cdf_status = wma_wmi_service_close(cds_context);
437 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
438 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
439 "%s: Failed to close wma_wmi_service", __func__);
440 CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status));
441 }
442
443 hif_disable_isr(gp_cds_context->pHIFContext);
444#endif
445
446 cds_mq_deinit(&((p_cds_contextType) cds_context)->freeVosMq);
447
448 cdf_status = cdf_event_destroy(&gp_cds_context->ProbeEvent);
449 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
450 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
451 "%s: Failed to destroy ProbeEvent %d", __func__,
452 cdf_status);
453 CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status));
454 }
455
456 cdf_status = cdf_event_destroy(&gp_cds_context->wmaCompleteEvent);
457 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
458 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
459 "%s: Failed to destroy wmaCompleteEvent %d", __func__,
460 cdf_status);
461 CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status));
462 }
463
464 return CDF_STATUS_SUCCESS;
465}
466
467/**
468 * cds_ftm_pre_start() - Pre-start CDS Module in FTM Mode
469 * @cds_context: The CDS context
470 *
471 * The cds_ftm_pre_start() function performs all pre-start activities
472 * in FTM mode.
473 *
474 * Return: CDF_STATUS_SUCCESS if pre-start was successful, an
475 * appropriate CDF_STATUS_E_* error code otherwise
476 */
477static CDF_STATUS cds_ftm_pre_start(v_CONTEXT_t cds_context)
478{
479 CDF_STATUS vStatus = CDF_STATUS_SUCCESS;
480 p_cds_contextType p_cds_context = (p_cds_contextType) cds_context;
481#if defined(QCA_WIFI_FTM)
482 p_cds_contextType gp_cds_context =
483 cds_get_global_context();
484#endif
485
486 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, "cds prestart");
487 if (NULL == p_cds_context->pWMAContext) {
488 CDF_ASSERT(0);
489 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR,
490 "%s: WMA NULL context", __func__);
491 return CDF_STATUS_E_FAILURE;
492 }
493
494 /* Reset WMA wait event */
495 cdf_event_reset(&p_cds_context->wmaCompleteEvent);
496
497 /*call WMA pre start */
498 vStatus = wma_pre_start(p_cds_context);
499 if (!CDF_IS_STATUS_SUCCESS(vStatus)) {
500 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR,
501 "Failed to WMA prestart ");
502 CDF_ASSERT(0);
503 return CDF_STATUS_E_FAILURE;
504 }
505
506 /* Need to update time out of complete */
507 vStatus = cdf_wait_single_event(&p_cds_context->wmaCompleteEvent,
508 HDD_FTM_WMA_PRE_START_TIMEOUT);
509 if (vStatus != CDF_STATUS_SUCCESS) {
510 if (vStatus == CDF_STATUS_E_TIMEOUT) {
511 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
512 "%s: Timeout occurred before WMA complete",
513 __func__);
514 } else {
515 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
516 "%s: wma_pre_start reporting other error",
517 __func__);
518 }
519 CDF_ASSERT(0);
520 return CDF_STATUS_E_FAILURE;
521 }
522#if defined(QCA_WIFI_FTM)
523 vStatus = htc_start(gp_cds_context->htc_ctx);
524 if (!CDF_IS_STATUS_SUCCESS(vStatus)) {
525 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_FATAL,
526 "Failed to Start HTC");
527 CDF_ASSERT(0);
528 return CDF_STATUS_E_FAILURE;
529 }
530 wma_wait_for_ready_event(gp_cds_context->pWMAContext);
531#endif /* QCA_WIFI_FTM */
532
533 return CDF_STATUS_SUCCESS;
534}
535
536/**
537 * wlan_hdd_ftm_open() - Open HDD in FTM Mode
538 * @hdd_ctx: global HDD context
539 *
540 * The function hdd_wlan_startup calls this function to initialize the
541 * FTM specific modules.
542 *
543 * Return: 0 on success, non-zero on error
544 */
545int wlan_hdd_ftm_open(hdd_context_t *hdd_ctx)
546{
547 CDF_STATUS vStatus = CDF_STATUS_SUCCESS;
548 p_cds_contextType p_cds_context = NULL;
549
550 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH,
551 "%s: Opening CDS", __func__);
552
553 p_cds_context = cds_get_global_context();
554
555 if (NULL == p_cds_context) {
556 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
557 "%s: Trying to open CDS without a PreOpen", __func__);
558 CDF_ASSERT(0);
559 goto err_cdf_status_failure;
560 }
561
562 vStatus = wlan_ftm_cds_open(p_cds_context, 0);
563
564 if (!CDF_IS_STATUS_SUCCESS(vStatus)) {
565 hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_open failed", __func__);
566 goto err_cdf_status_failure;
567 }
568
569 /*
570 * only needed to start WMA, which happens in wlan_hdd_ftm_start()
571 */
572
573 /* Save the hal context in Adapter */
574 hdd_ctx->hHal =
575 (tHalHandle) cds_get_context(CDF_MODULE_ID_SME);
576
577 if (NULL == hdd_ctx->hHal) {
578 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: HAL context is null",
579 __func__);
580 goto err_ftm_close;
581 }
582
583 return 0;
584
585err_ftm_close:
586 wlan_ftm_cds_close(p_cds_context);
587
588err_cdf_status_failure:
589 return -EPERM;
590}
591
592/**
593 * hdd_ftm_service_registration() - Register FTM service
594 * @hdd_ctx: global HDD context
595 *
596 * Return: 0 on success, non-zero on failure
597 */
598static int hdd_ftm_service_registration(hdd_context_t *hdd_ctx)
599{
600 hdd_adapter_t *adapter;
601 adapter = hdd_open_adapter(hdd_ctx, WLAN_HDD_FTM, "wlan%d",
602 wlan_hdd_get_intf_addr(hdd_ctx), false);
603 if (NULL == adapter) {
604 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: hdd_open_adapter failed",
605 __func__);
606 goto err_adapter_open_failure;
607 }
608
609 hdd_ctx->ftm.ftm_state = WLAN_FTM_INITIALIZED;
610
611 return 0;
612
613err_adapter_open_failure:
614
615 return -EPERM;
616}
617
618/**
619 * wlan_ftm_stop() - Stop HDD in FTM mode
620 * @hdd_ctx: pointer to HDD context
621 *
622 * This function stops the following modules
Varun Reddy Yeturu08efa3a2015-11-03 16:59:57 -0800623 * WMA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800624 *
625 * Return: 0 on success, non-zero on failure
626 */
627static int wlan_ftm_stop(hdd_context_t *hdd_ctx)
628{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800629 if (hdd_ctx->ftm.ftm_state != WLAN_FTM_STARTED) {
Varun Reddy Yeturu08efa3a2015-11-03 16:59:57 -0800630 hddLog(LOGP, FL("FTM has not started. No need to stop"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800631 return -EPERM;
632 }
Varun Reddy Yeturu08efa3a2015-11-03 16:59:57 -0800633 wma_stop(hdd_ctx->pcds_context, HAL_STOP_TYPE_RF_KILL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800634 return 0;
635}
636
637/**
638 * wlan_hdd_ftm_close() - Close HDD in FTM mode
639 * @hdd_ctx: pointer to HDD context
640 *
641 * Return: 0 on success, non-zero on failure
642 */
643int wlan_hdd_ftm_close(hdd_context_t *hdd_ctx)
644{
645 CDF_STATUS cdf_status;
646 v_CONTEXT_t cds_context = hdd_ctx->pcds_context;
647
648 hdd_adapter_t *adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_FTM);
649 ENTER();
650 if (adapter == NULL) {
651 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL,
652 "%s:adapter is NULL", __func__);
653 return -ENXIO;
654 }
655
656 if (WLAN_FTM_STARTED == hdd_ctx->ftm.ftm_state) {
657 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL,
658 "%s: Ftm has been started. stopping ftm", __func__);
659 wlan_ftm_stop(hdd_ctx);
660 }
661
662 hdd_close_all_adapters(hdd_ctx);
663
664 cdf_status = cds_sched_close(cds_context);
665 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
666 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
667 "%s: Failed to close CDS Scheduler", __func__);
668 CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status));
669 }
670 /* Close CDS */
671 wlan_ftm_cds_close(cds_context);
672
673#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
674 spin_lock_bh(&qcmbr_queue_lock);
675 if (!list_empty(&qcmbr_queue_head)) {
676 qcmbr_queue_t *msg_buf, *tmp_buf;
677 list_for_each_entry_safe(msg_buf, tmp_buf, &qcmbr_queue_head,
678 list) {
679 list_del(&msg_buf->list);
680 kfree(msg_buf);
681 }
682 }
683 spin_unlock_bh(&qcmbr_queue_lock);
684#endif
685
686 return 0;
687
688}
689
690
691/**
692 * hdd_ftm_mc_process_msg() - Process FTM mailbox message
693 * @message: FTM response message
694 *
695 * Process FTM mailbox message
696 *
697 * Return: void
698 */
699static void hdd_ftm_mc_process_msg(void *message)
700{
701 void *data;
702 uint32_t data_len;
703
704 if (!message) {
705 hdd_err("Message is NULL, nothing to process.");
706 return;
707 }
708
709 data_len = *((uint32_t *) message);
710 data = (uint32_t *) message + 1;
711
712#if defined(LINUX_QCMBR)
713 wlanqcmbr_mc_process_msg(message);
714#else
715#ifdef CONFIG_NL80211_TESTMODE
716 wlan_hdd_testmode_rx_event(data, (size_t) data_len);
717#endif
718#endif
719 return;
720}
721
722/**
723 * wlan_hdd_ftm_start() - Start HDD in FTM mode
724 * @hdd_ctx: Global HDD context
725 *
726 * This function starts the following modules.
727 * 1) WMA Start.
728 * 2) HTC Start.
729 * 3) MAC Start to download the firmware.
730 *
731 * Return: 0 for success, non zero for failure
732 */
733static int wlan_hdd_ftm_start(hdd_context_t *hdd_ctx)
734{
735 CDF_STATUS vStatus = CDF_STATUS_SUCCESS;
736 p_cds_contextType p_cds_context =
737 (p_cds_contextType) (hdd_ctx->pcds_context);
738
739 if (WLAN_FTM_STARTED == hdd_ctx->ftm.ftm_state) {
740 return 0;
741 }
742
743 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
744 "%s: Starting CLD SW", __func__);
745
746 /* We support only one instance for now ... */
747 if (p_cds_context == NULL) {
748 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
749 "%s: mismatch in context", __func__);
750 goto err_status_failure;
751 }
752
753 if (p_cds_context->pMACContext == NULL) {
754 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
755 "%s: MAC NULL context", __func__);
756 goto err_status_failure;
757 }
758
759 /* Vos preStart is calling */
760 if (!CDF_IS_STATUS_SUCCESS(cds_ftm_pre_start(hdd_ctx->pcds_context))) {
761 hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_pre_enable failed",
762 __func__);
763 goto err_status_failure;
764 }
765
766 sme_register_ftm_msg_processor(hdd_ctx->hHal, hdd_ftm_mc_process_msg);
767
768 vStatus = wma_start(p_cds_context);
769 if (vStatus != CDF_STATUS_SUCCESS) {
770 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
771 "%s: Failed to start WMA", __func__);
772 goto err_status_failure;
773 }
774
775 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
776 "%s: MAC correctly started", __func__);
777
778 if (hdd_ftm_service_registration(hdd_ctx)) {
779 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
780 "%s: failed", __func__);
781 goto err_ftm_service_reg;
782 }
783
784 hdd_ctx->ftm.ftm_state = WLAN_FTM_STARTED;
785
786 return 0;
787
788err_ftm_service_reg:
789 wlan_hdd_ftm_close(hdd_ctx);
790
791err_status_failure:
792
793 return -EPERM;
794
795}
796
797#if defined(QCA_WIFI_FTM)
798/**
799 * hdd_ftm_start() - Start HDD in FTM mode
800 * @hdd_ctx: Global HDD context
801 *
802 * Return: 0 for success, non zero for failure
803 */
804int hdd_ftm_start(hdd_context_t *hdd_ctx)
805{
806 return wlan_hdd_ftm_start(hdd_ctx);
807}
808#endif
809
810#if defined(QCA_WIFI_FTM)
811/**
812 * hdd_ftm_stop() - Stop HDD in FTM mode
813 * @hdd_ctx: Global HDD context
814 *
815 * Return: 0 for success, non zero for failure
816 */
817int hdd_ftm_stop(hdd_context_t *hdd_ctx)
818{
819 return wlan_ftm_stop(hdd_ctx);
820}
821#endif
822
823#if defined(QCA_WIFI_FTM)
824#if defined(LINUX_QCMBR)
825/**
826 * wlan_hdd_qcmbr_command() - QCMBR command handler
827 * @adapter: adapter upon which the command was received
828 * @pqcmbr_data: QCMBR command
829 *
830 * Return: 0 on success, non-zero on error
831 */
832static int wlan_hdd_qcmbr_command(hdd_adapter_t *adapter,
833 qcmbr_data_t *pqcmbr_data)
834{
835 int ret = 0;
836 qcmbr_queue_t *qcmbr_buf = NULL;
837
838 switch (pqcmbr_data->cmd) {
839 case ATH_XIOCTL_UNIFIED_UTF_CMD: {
840 pqcmbr_data->copy_to_user = 0;
841 if (pqcmbr_data->length) {
842 if (wlan_hdd_ftm_testmode_cmd(pqcmbr_data->buf,
843 pqcmbr_data->
844 length)
845 != CDF_STATUS_SUCCESS) {
846 ret = -EBUSY;
847 } else {
848 ret = 0;
849 }
850 }
851 }
852 break;
853
854 case ATH_XIOCTL_UNIFIED_UTF_RSP: {
855 pqcmbr_data->copy_to_user = 1;
856 if (!list_empty(&qcmbr_queue_head)) {
857 spin_lock_bh(&qcmbr_queue_lock);
858 qcmbr_buf = list_first_entry(&qcmbr_queue_head,
859 qcmbr_queue_t,
860 list);
861 list_del(&qcmbr_buf->list);
862 spin_unlock_bh(&qcmbr_queue_lock);
863 ret = 0;
864 } else {
865 ret = -1;
866 }
867
868 if (!ret) {
869 memcpy(pqcmbr_data->buf, qcmbr_buf->utf_buf,
870 (MAX_UTF_LENGTH + 4));
871 kfree(qcmbr_buf);
872 } else {
873 ret = -EAGAIN;
874 }
875 }
876 break;
877 }
878
879 return ret;
880}
881
882#ifdef CONFIG_COMPAT
883/**
884 * wlan_hdd_qcmbr_ioctl() - Compatability-mode QCMBR ioctl handler
885 * @adapter: adapter upon which the ioctl was received
886 * @ifr: the ioctl request
887 *
888 * Return: 0 on success, non-zero on error
889 */
890static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter,
891 struct ifreq *ifr)
892{
893 qcmbr_data_t *qcmbr_data;
894 int ret = 0;
895
896 qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL);
897 if (qcmbr_data == NULL)
898 return -ENOMEM;
899
900 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
901 ret = -EFAULT;
902 goto exit;
903 }
904
905 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
906 if (qcmbr_data->copy_to_user) {
907 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
908 (MAX_UTF_LENGTH + 4));
909 }
910
911exit:
912 kfree(qcmbr_data);
913 return ret;
914}
915#else /* CONFIG_COMPAT */
916static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter,
917 struct ifreq *ifr)
918{
919 return 0;
920}
921#endif /* CONFIG_COMPAT */
922
923/**
924 * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler
925 * @adapter: adapter upon which the ioctl was received
926 * @ifr: the ioctl request
927 *
928 * Return: 0 on success, non-zero on error
929 */
930static int wlan_hdd_qcmbr_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
931{
932 qcmbr_data_t *qcmbr_data;
933 int ret = 0;
934
935 qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL);
936 if (qcmbr_data == NULL)
937 return -ENOMEM;
938
939 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
940 ret = -EFAULT;
941 goto exit;
942 }
943
944 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
945 if (qcmbr_data->copy_to_user) {
946 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
947 (MAX_UTF_LENGTH + 4));
948 }
949
950exit:
951 kfree(qcmbr_data);
952 return ret;
953}
954
955/**
956 * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler
957 * @adapter: adapter upon which the ioctl was received
958 * @ifr: the ioctl request
959 *
960 * Return: 0 on success, non-zero on error
961 */
962int wlan_hdd_qcmbr_unified_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
963{
964 int ret = 0;
965
966 if (is_compat_task()) {
967 ret = wlan_hdd_qcmbr_compat_ioctl(adapter, ifr);
968 } else {
969 ret = wlan_hdd_qcmbr_ioctl(adapter, ifr);
970 }
971
972 return ret;
973}
974
975/**
976 * wlanqcmbr_mc_process_msg() - Process QCMBR response message
977 * @message: QCMBR message
978 *
979 * Return: None
980 */
981static void wlanqcmbr_mc_process_msg(void *message)
982{
983 qcmbr_queue_t *qcmbr_buf = NULL;
984 uint32_t data_len;
985
986 data_len = *((uint32_t *) message) + sizeof(uint32_t);
987 qcmbr_buf = kzalloc(sizeof(qcmbr_queue_t), GFP_KERNEL);
988 if (qcmbr_buf != NULL) {
989 memcpy(qcmbr_buf->utf_buf, message, data_len);
990 spin_lock_bh(&qcmbr_queue_lock);
991 list_add_tail(&(qcmbr_buf->list), &qcmbr_queue_head);
992 spin_unlock_bh(&qcmbr_queue_lock);
993 }
994}
995#endif /*LINUX_QCMBR */
996
997/**
998 * wlan_hdd_ftm_testmode_cmd() - Process FTM testmode command
999 * @data: FTM testmode command
1000 * @len: length of @data
1001 *
1002 * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
1003 */
1004CDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len)
1005{
1006 struct ar6k_testmode_cmd_data *cmd_data;
1007
1008 cmd_data = (struct ar6k_testmode_cmd_data *)
1009 cdf_mem_malloc(sizeof(*cmd_data));
1010
1011 if (!cmd_data) {
1012 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1013 ("Failed to allocate FTM command data"));
1014 return CDF_STATUS_E_NOMEM;
1015 }
1016
1017 cmd_data->data = cdf_mem_malloc(len);
1018
1019 if (!cmd_data->data) {
1020 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1021 ("Failed to allocate FTM command data buffer"));
1022 cdf_mem_free(cmd_data);
1023 return CDF_STATUS_E_NOMEM;
1024 }
1025
1026 cmd_data->len = len;
1027 cdf_mem_copy(cmd_data->data, data, len);
1028
1029 if (wlan_ftm_postmsg((uint8_t *) cmd_data, sizeof(*cmd_data))) {
1030 cdf_mem_free(cmd_data->data);
1031 cdf_mem_free(cmd_data);
1032 return CDF_STATUS_E_FAILURE;
1033 }
1034
1035 return CDF_STATUS_SUCCESS;
1036}
1037#endif /*QCA_WIFI_FTM */