blob: 5c8fc2fc81d72d335469353e3e6df6b402754513 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2013-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: wma_features.c
30 * This file contains different features related functions like WoW,
31 * Offloads, TDLS etc.
32 */
33
34/* Header files */
35
36#include "wma.h"
37#include "wma_api.h"
38#include "cds_api.h"
39#include "wmi_unified_api.h"
40#include "wlan_qct_sys.h"
41#include "wni_api.h"
42#include "ani_global.h"
43#include "wmi_unified.h"
44#include "wni_cfg.h"
45#include "cfg_api.h"
46#include "ol_txrx_ctrl_api.h"
47#include "wlan_tgt_def_config.h"
48
49#include "cdf_nbuf.h"
50#include "cdf_types.h"
51#include "ol_txrx_api.h"
52#include "cdf_memory.h"
53#include "ol_txrx_types.h"
54#include "ol_txrx_peer_find.h"
55
56#include "wma_types.h"
57#include "lim_api.h"
58#include "lim_session_utils.h"
59
60#include "cds_utils.h"
61
62#if !defined(REMOVE_PKT_LOG)
63#include "pktlog_ac.h"
64#endif /* REMOVE_PKT_LOG */
65
66#include "dbglog_host.h"
67#include "csr_api.h"
68#include "ol_fw.h"
69
70#include "dfs.h"
71#include "radar_filters.h"
72#include "wma_internal.h"
73
74#ifndef ARRAY_LENGTH
75#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
76#endif
77
78#define WMA_WOW_STA_WAKE_UP_EVENTS ((1 << WOW_CSA_IE_EVENT) |\
79 (1 << WOW_CLIENT_KICKOUT_EVENT) |\
80 (1 << WOW_PATTERN_MATCH_EVENT) |\
81 (1 << WOW_MAGIC_PKT_RECVD_EVENT) |\
82 (1 << WOW_DEAUTH_RECVD_EVENT) |\
83 (1 << WOW_DISASSOC_RECVD_EVENT) |\
84 (1 << WOW_BMISS_EVENT) |\
85 (1 << WOW_GTK_ERR_EVENT) |\
86 (1 << WOW_BETTER_AP_EVENT) |\
87 (1 << WOW_HTT_EVENT) |\
88 (1 << WOW_RA_MATCH_EVENT) |\
89 (1 << WOW_NLO_DETECTED_EVENT) |\
90 (1 << WOW_EXTSCAN_EVENT))\
91
92#define WMA_WOW_SAP_WAKE_UP_EVENTS ((1 << WOW_PROBE_REQ_WPS_IE_EVENT) |\
93 (1 << WOW_PATTERN_MATCH_EVENT) |\
94 (1 << WOW_AUTH_REQ_EVENT) |\
95 (1 << WOW_ASSOC_REQ_EVENT) |\
96 (1 << WOW_DEAUTH_RECVD_EVENT) |\
97 (1 << WOW_DISASSOC_RECVD_EVENT) |\
98 (1 << WOW_HTT_EVENT))\
99
100static const uint8_t arp_ptrn[] = {0x08, 0x06};
101static const uint8_t arp_mask[] = {0xff, 0xff};
102static const uint8_t ns_ptrn[] = {0x86, 0xDD};
103static const uint8_t discvr_ptrn[] = {0xe0, 0x00, 0x00, 0xf8};
104static const uint8_t discvr_mask[] = {0xf0, 0x00, 0x00, 0xf8};
105
106#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
107/**
108 * wma_post_auto_shutdown_msg() - to post auto shutdown event to sme
109 *
110 * Return: 0 for success or error code
111 */
112static int wma_post_auto_shutdown_msg(void)
113{
114 tSirAutoShutdownEvtParams *auto_sh_evt;
115 CDF_STATUS cdf_status;
116 cds_msg_t sme_msg = { 0 };
117
118 auto_sh_evt = (tSirAutoShutdownEvtParams *)
119 cdf_mem_malloc(sizeof(tSirAutoShutdownEvtParams));
120 if (!auto_sh_evt) {
121 WMA_LOGE(FL("No Mem"));
122 return -ENOMEM;
123 }
124
125 auto_sh_evt->shutdown_reason =
126 WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY;
127 sme_msg.type = eWNI_SME_AUTO_SHUTDOWN_IND;
128 sme_msg.bodyptr = auto_sh_evt;
129 sme_msg.bodyval = 0;
130
131 cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg);
132 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
133 WMA_LOGE("Fail to post eWNI_SME_AUTO_SHUTDOWN_IND msg to SME");
134 cdf_mem_free(auto_sh_evt);
135 return -EINVAL;
136 }
137
138 return 0;
139}
140#endif
141/**
142 * wma_send_snr_request() - send request to fw to get RSSI stats
143 * @wma_handle: wma handle
144 * @pGetRssiReq: get RSSI request
145 *
146 * Return: CDF status
147 */
148CDF_STATUS wma_send_snr_request(tp_wma_handle wma_handle,
149 void *pGetRssiReq)
150{
151 wmi_buf_t buf;
152 wmi_request_stats_cmd_fixed_param *cmd;
153 uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
154 tAniGetRssiReq *pRssiBkUp = NULL;
155
156 /* command is in progess */
157 if (NULL != wma_handle->pGetRssiReq)
158 return CDF_STATUS_SUCCESS;
159
160 /* create a copy of csrRssiCallback to send rssi value
161 * after wmi event
162 */
163 if (pGetRssiReq) {
164 pRssiBkUp = cdf_mem_malloc(sizeof(tAniGetRssiReq));
165 if (!pRssiBkUp) {
166 WMA_LOGE("Failed to allocate memory for tAniGetRssiReq");
167 wma_handle->pGetRssiReq = NULL;
168 return CDF_STATUS_E_NOMEM;
169 }
170 cdf_mem_set(pRssiBkUp, sizeof(tAniGetRssiReq), 0);
171 pRssiBkUp->sessionId =
172 ((tAniGetRssiReq *) pGetRssiReq)->sessionId;
173 pRssiBkUp->rssiCallback =
174 ((tAniGetRssiReq *) pGetRssiReq)->rssiCallback;
175 pRssiBkUp->pDevContext =
176 ((tAniGetRssiReq *) pGetRssiReq)->pDevContext;
177 wma_handle->pGetRssiReq = (void *)pRssiBkUp;
178 }
179
180 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
181 if (!buf) {
182 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
183 cdf_mem_free(pRssiBkUp);
184 wma_handle->pGetRssiReq = NULL;
185 return CDF_STATUS_E_FAILURE;
186 }
187
188 cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf);
189 WMITLV_SET_HDR(&cmd->tlv_header,
190 WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
191 WMITLV_GET_STRUCT_TLVLEN
192 (wmi_request_stats_cmd_fixed_param));
193 cmd->stats_id = WMI_REQUEST_VDEV_STAT;
194 if (wmi_unified_cmd_send
195 (wma_handle->wmi_handle, buf, len, WMI_REQUEST_STATS_CMDID)) {
196 WMA_LOGE("Failed to send host stats request to fw");
197 wmi_buf_free(buf);
198 cdf_mem_free(pRssiBkUp);
199 wma_handle->pGetRssiReq = NULL;
200 return CDF_STATUS_E_FAILURE;
201 }
202 return CDF_STATUS_SUCCESS;
203}
204
205/**
206 * wma_get_snr() - get RSSI from fw
207 * @psnr_req: request params
208 *
209 * Return: CDF status
210 */
211CDF_STATUS wma_get_snr(tAniGetSnrReq *psnr_req)
212{
213 wmi_buf_t buf;
214 wmi_request_stats_cmd_fixed_param *cmd;
215 tAniGetSnrReq *psnr_req_bkp;
216 uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
217 tp_wma_handle wma_handle = NULL;
218 struct wma_txrx_node *intr;
219
220 wma_handle = cds_get_context(CDF_MODULE_ID_WMA);
221
222 if (NULL == wma_handle) {
223 WMA_LOGE("%s : Failed to get wma_handle", __func__);
224 return CDF_STATUS_E_FAULT;
225 }
226
227 intr = &wma_handle->interfaces[psnr_req->sessionId];
228 /* command is in progess */
229 if (NULL != intr->psnr_req) {
230 WMA_LOGE("%s : previous snr request is pending", __func__);
231 return CDF_STATUS_SUCCESS;
232 }
233
234 psnr_req_bkp = cdf_mem_malloc(sizeof(tAniGetSnrReq));
235 if (!psnr_req_bkp) {
236 WMA_LOGE("Failed to allocate memory for tAniGetSnrReq");
237 return CDF_STATUS_E_NOMEM;
238 }
239
240 cdf_mem_set(psnr_req_bkp, sizeof(tAniGetSnrReq), 0);
241 psnr_req_bkp->staId = psnr_req->staId;
242 psnr_req_bkp->pDevContext = psnr_req->pDevContext;
243 psnr_req_bkp->snrCallback = psnr_req->snrCallback;
244 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
245 if (!buf) {
246 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
247 cdf_mem_free(psnr_req_bkp);
248 return CDF_STATUS_E_FAILURE;
249 }
250
251 cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf);
252 cmd->vdev_id = psnr_req->sessionId;
253
254 WMITLV_SET_HDR(&cmd->tlv_header,
255 WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
256 WMITLV_GET_STRUCT_TLVLEN
257 (wmi_request_stats_cmd_fixed_param));
258 cmd->stats_id = WMI_REQUEST_VDEV_STAT;
259 intr->psnr_req = (void *)psnr_req_bkp;
260 if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
261 WMI_REQUEST_STATS_CMDID)) {
262 WMA_LOGE("Failed to send host stats request to fw");
263 wmi_buf_free(buf);
264 cdf_mem_free(psnr_req_bkp);
265 intr->psnr_req = NULL;
266 return CDF_STATUS_E_FAILURE;
267 }
268
269 return CDF_STATUS_SUCCESS;
270}
271
272/**
273 * wma_process_link_status_req() - process link status request from UMAC
274 * @wma: wma handle
275 * @pGetLinkStatus: get link params
276 *
277 * Return: none
278 */
279void wma_process_link_status_req(tp_wma_handle wma,
280 tAniGetLinkStatus *pGetLinkStatus)
281{
282 wmi_buf_t buf;
283 wmi_request_stats_cmd_fixed_param *cmd;
284 uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
285 struct wma_txrx_node *iface =
286 &wma->interfaces[pGetLinkStatus->sessionId];
287
288 if (iface->plink_status_req) {
289 WMA_LOGE("%s:previous link status request is pending,deleting the new request",
290 __func__);
291 cdf_mem_free(pGetLinkStatus);
292 return;
293 }
294
295 buf = wmi_buf_alloc(wma->wmi_handle, len);
296 if (!buf) {
297 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
298 goto end;
299 }
300
301 iface->plink_status_req = pGetLinkStatus;
302 cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf);
303 WMITLV_SET_HDR(&cmd->tlv_header,
304 WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
305 WMITLV_GET_STRUCT_TLVLEN
306 (wmi_request_stats_cmd_fixed_param));
307 cmd->stats_id = WMI_REQUEST_VDEV_RATE_STAT;
308 cmd->vdev_id = pGetLinkStatus->sessionId;
309 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
310 WMI_REQUEST_STATS_CMDID)) {
311 WMA_LOGE("Failed to send WMI link status request to fw");
312 wmi_buf_free(buf);
313 iface->plink_status_req = NULL;
314 goto end;
315 }
316
317 return;
318
319end:
320 wma_post_link_status(pGetLinkStatus, LINK_STATUS_LEGACY);
321}
322
323#ifdef FEATURE_WLAN_LPHB
324/**
325 * wma_lphb_conf_hbenable() - enable command of LPHB configuration requests
326 * @wma_handle: WMA handle
327 * @lphb_conf_req: configuration info
328 * @by_user: whether this call is from user or cached resent
329 *
330 * Return: CDF status
331 */
332CDF_STATUS wma_lphb_conf_hbenable(tp_wma_handle wma_handle,
333 tSirLPHBReq *lphb_conf_req, bool by_user)
334{
335 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
336 int status = 0;
337 tSirLPHBEnableStruct *ts_lphb_enable;
338 wmi_buf_t buf = NULL;
339 uint8_t *buf_ptr;
340 wmi_hb_set_enable_cmd_fixed_param *hb_enable_fp;
341 int len = sizeof(wmi_hb_set_enable_cmd_fixed_param);
342 int i;
343
344 if (lphb_conf_req == NULL) {
345 WMA_LOGE("%s : LPHB configuration is NULL", __func__);
346 return CDF_STATUS_E_FAILURE;
347 }
348
349 ts_lphb_enable = &(lphb_conf_req->params.lphbEnableReq);
350 WMA_LOGI("%s: WMA --> WMI_HB_SET_ENABLE enable=%d, item=%d, session=%d",
351 __func__,
352 ts_lphb_enable->enable,
353 ts_lphb_enable->item, ts_lphb_enable->session);
354
355 if ((ts_lphb_enable->item != 1) && (ts_lphb_enable->item != 2)) {
356 WMA_LOGE("%s : LPHB configuration wrong item %d",
357 __func__, ts_lphb_enable->item);
358 return CDF_STATUS_E_FAILURE;
359 }
360
361 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
362 if (!buf) {
363 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
364 return CDF_STATUS_E_NOMEM;
365 }
366
367 buf_ptr = (uint8_t *) wmi_buf_data(buf);
368 hb_enable_fp = (wmi_hb_set_enable_cmd_fixed_param *) buf_ptr;
369 WMITLV_SET_HDR(&hb_enable_fp->tlv_header,
370 WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param,
371 WMITLV_GET_STRUCT_TLVLEN
372 (wmi_hb_set_enable_cmd_fixed_param));
373
374 /* fill in values */
375 hb_enable_fp->vdev_id = ts_lphb_enable->session;
376 hb_enable_fp->enable = ts_lphb_enable->enable;
377 hb_enable_fp->item = ts_lphb_enable->item;
378 hb_enable_fp->session = ts_lphb_enable->session;
379
380 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
381 len, WMI_HB_SET_ENABLE_CMDID);
382 if (status != EOK) {
383 WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_ENABLE returned Error %d",
384 status);
385 cdf_status = CDF_STATUS_E_FAILURE;
386 goto error;
387 }
388
389 if (by_user) {
390 /* target already configured, now cache command status */
391 if (ts_lphb_enable->enable) {
392 i = ts_lphb_enable->item - 1;
393 wma_handle->wow.lphb_cache[i].cmd
394 = LPHB_SET_EN_PARAMS_INDID;
395 wma_handle->wow.lphb_cache[i].params.lphbEnableReq.
396 enable = ts_lphb_enable->enable;
397 wma_handle->wow.lphb_cache[i].params.lphbEnableReq.
398 item = ts_lphb_enable->item;
399 wma_handle->wow.lphb_cache[i].params.lphbEnableReq.
400 session = ts_lphb_enable->session;
401
402 WMA_LOGI("%s: cached LPHB status in WMA context for item %d",
403 __func__, i);
404 } else {
405 cdf_mem_zero((void *)&wma_handle->wow.lphb_cache,
406 sizeof(wma_handle->wow.lphb_cache));
407 WMA_LOGI("%s: cleared all cached LPHB status in WMA context",
408 __func__);
409 }
410 }
411
412 return CDF_STATUS_SUCCESS;
413error:
414 return cdf_status;
415}
416
417/**
418 * wma_lphb_conf_tcp_params() - set tcp params of LPHB configuration requests
419 * @wma_handle: wma handle
420 * @lphb_conf_req: lphb config request
421 *
422 * Return: CDF status
423 */
424CDF_STATUS wma_lphb_conf_tcp_params(tp_wma_handle wma_handle,
425 tSirLPHBReq *lphb_conf_req)
426{
427 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
428 int status = 0;
429 tSirLPHBTcpParamStruct *ts_lphb_tcp_param;
430 wmi_buf_t buf = NULL;
431 uint8_t *buf_ptr;
432 wmi_hb_set_tcp_params_cmd_fixed_param *hb_tcp_params_fp;
433 int len = sizeof(wmi_hb_set_tcp_params_cmd_fixed_param);
434
435 if (lphb_conf_req == NULL) {
436 WMA_LOGE("%s : LPHB configuration is NULL", __func__);
437 return CDF_STATUS_E_FAILURE;
438 }
439
440 ts_lphb_tcp_param = &(lphb_conf_req->params.lphbTcpParamReq);
441 WMA_LOGI("%s: WMA --> WMI_HB_SET_TCP_PARAMS srv_ip=%08x, dev_ip=%08x, src_port=%d, "
442 "dst_port=%d, timeout=%d, session=%d, gateway_mac=%02x:%02x:%02x:%02x:%02x:%02x, "
443 "timePeriodSec=%d, tcpSn=%d", __func__, ts_lphb_tcp_param->srv_ip,
444 ts_lphb_tcp_param->dev_ip, ts_lphb_tcp_param->src_port,
445 ts_lphb_tcp_param->dst_port, ts_lphb_tcp_param->timeout,
446 ts_lphb_tcp_param->session, ts_lphb_tcp_param->gateway_mac[0],
447 ts_lphb_tcp_param->gateway_mac[1],
448 ts_lphb_tcp_param->gateway_mac[2],
449 ts_lphb_tcp_param->gateway_mac[3],
450 ts_lphb_tcp_param->gateway_mac[4],
451 ts_lphb_tcp_param->gateway_mac[5],
452 ts_lphb_tcp_param->timePeriodSec, ts_lphb_tcp_param->tcpSn);
453
454 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
455 if (!buf) {
456 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
457 return CDF_STATUS_E_NOMEM;
458 }
459
460 buf_ptr = (uint8_t *) wmi_buf_data(buf);
461 hb_tcp_params_fp = (wmi_hb_set_tcp_params_cmd_fixed_param *) buf_ptr;
462 WMITLV_SET_HDR(&hb_tcp_params_fp->tlv_header,
463 WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param,
464 WMITLV_GET_STRUCT_TLVLEN
465 (wmi_hb_set_tcp_params_cmd_fixed_param));
466
467 /* fill in values */
468 hb_tcp_params_fp->vdev_id = ts_lphb_tcp_param->session;
469 hb_tcp_params_fp->srv_ip = ts_lphb_tcp_param->srv_ip;
470 hb_tcp_params_fp->dev_ip = ts_lphb_tcp_param->dev_ip;
471 hb_tcp_params_fp->seq = ts_lphb_tcp_param->tcpSn;
472 hb_tcp_params_fp->src_port = ts_lphb_tcp_param->src_port;
473 hb_tcp_params_fp->dst_port = ts_lphb_tcp_param->dst_port;
474 hb_tcp_params_fp->interval = ts_lphb_tcp_param->timePeriodSec;
475 hb_tcp_params_fp->timeout = ts_lphb_tcp_param->timeout;
476 hb_tcp_params_fp->session = ts_lphb_tcp_param->session;
477 WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_tcp_param->gateway_mac,
478 &hb_tcp_params_fp->gateway_mac);
479
480 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
481 len, WMI_HB_SET_TCP_PARAMS_CMDID);
482 if (status != EOK) {
483 WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_TCP_PARAMS returned Error %d",
484 status);
485 cdf_status = CDF_STATUS_E_FAILURE;
486 goto error;
487 }
488
489 return CDF_STATUS_SUCCESS;
490error:
491 return cdf_status;
492}
493
494/**
495 * wma_lphb_conf_tcp_pkt_filter() - configure tcp packet filter command of LPHB
496 * @wma_handle: wma handle
497 * @lphb_conf_req: lphb config request
498 *
499 * Return: CDF status
500 */
501CDF_STATUS wma_lphb_conf_tcp_pkt_filter(tp_wma_handle wma_handle,
502 tSirLPHBReq *lphb_conf_req)
503{
504 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
505 int status = 0;
506 tSirLPHBTcpFilterStruct *ts_lphb_tcp_filter;
507 wmi_buf_t buf = NULL;
508 uint8_t *buf_ptr;
509 wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *hb_tcp_filter_fp;
510 int len = sizeof(wmi_hb_set_tcp_pkt_filter_cmd_fixed_param);
511
512 if (lphb_conf_req == NULL) {
513 WMA_LOGE("%s : LPHB configuration is NULL", __func__);
514 return CDF_STATUS_E_FAILURE;
515 }
516
517 ts_lphb_tcp_filter = &(lphb_conf_req->params.lphbTcpFilterReq);
518 WMA_LOGI("%s: WMA --> WMI_HB_SET_TCP_PKT_FILTER length=%d, offset=%d, session=%d, "
519 "filter=%2x:%2x:%2x:%2x:%2x:%2x ...", __func__,
520 ts_lphb_tcp_filter->length, ts_lphb_tcp_filter->offset,
521 ts_lphb_tcp_filter->session, ts_lphb_tcp_filter->filter[0],
522 ts_lphb_tcp_filter->filter[1], ts_lphb_tcp_filter->filter[2],
523 ts_lphb_tcp_filter->filter[3], ts_lphb_tcp_filter->filter[4],
524 ts_lphb_tcp_filter->filter[5]);
525
526 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
527 if (!buf) {
528 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
529 return CDF_STATUS_E_NOMEM;
530 }
531
532 buf_ptr = (uint8_t *) wmi_buf_data(buf);
533 hb_tcp_filter_fp =
534 (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *) buf_ptr;
535 WMITLV_SET_HDR(&hb_tcp_filter_fp->tlv_header,
536 WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param,
537 WMITLV_GET_STRUCT_TLVLEN
538 (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param));
539
540 /* fill in values */
541 hb_tcp_filter_fp->vdev_id = ts_lphb_tcp_filter->session;
542 hb_tcp_filter_fp->length = ts_lphb_tcp_filter->length;
543 hb_tcp_filter_fp->offset = ts_lphb_tcp_filter->offset;
544 hb_tcp_filter_fp->session = ts_lphb_tcp_filter->session;
545 memcpy((void *)&hb_tcp_filter_fp->filter,
546 (void *)&ts_lphb_tcp_filter->filter,
547 WMI_WLAN_HB_MAX_FILTER_SIZE);
548
549 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
550 len, WMI_HB_SET_TCP_PKT_FILTER_CMDID);
551 if (status != EOK) {
552 WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_TCP_PKT_FILTER returned Error %d",
553 status);
554 cdf_status = CDF_STATUS_E_FAILURE;
555 goto error;
556 }
557
558 return CDF_STATUS_SUCCESS;
559error:
560 return cdf_status;
561}
562
563/**
564 * wma_lphb_conf_udp_params() - configure udp param command of LPHB
565 * @wma_handle: wma handle
566 * @lphb_conf_req: lphb config request
567 *
568 * Return: CDF status
569 */
570CDF_STATUS wma_lphb_conf_udp_params(tp_wma_handle wma_handle,
571 tSirLPHBReq *lphb_conf_req)
572{
573 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
574 int status = 0;
575 tSirLPHBUdpParamStruct *ts_lphb_udp_param;
576 wmi_buf_t buf = NULL;
577 uint8_t *buf_ptr;
578 wmi_hb_set_udp_params_cmd_fixed_param *hb_udp_params_fp;
579 int len = sizeof(wmi_hb_set_udp_params_cmd_fixed_param);
580
581 if (lphb_conf_req == NULL) {
582 WMA_LOGE("%s : LPHB configuration is NULL", __func__);
583 return CDF_STATUS_E_FAILURE;
584 }
585
586 ts_lphb_udp_param = &(lphb_conf_req->params.lphbUdpParamReq);
587 WMA_LOGI("%s: WMA --> WMI_HB_SET_UDP_PARAMS srv_ip=%d, dev_ip=%d, src_port=%d, "
588 "dst_port=%d, interval=%d, timeout=%d, session=%d, "
589 "gateway_mac=%2x:%2x:%2x:%2x:%2x:%2x", __func__,
590 ts_lphb_udp_param->srv_ip, ts_lphb_udp_param->dev_ip,
591 ts_lphb_udp_param->src_port, ts_lphb_udp_param->dst_port,
592 ts_lphb_udp_param->interval, ts_lphb_udp_param->timeout,
593 ts_lphb_udp_param->session, ts_lphb_udp_param->gateway_mac[0],
594 ts_lphb_udp_param->gateway_mac[1],
595 ts_lphb_udp_param->gateway_mac[2],
596 ts_lphb_udp_param->gateway_mac[3],
597 ts_lphb_udp_param->gateway_mac[4],
598 ts_lphb_udp_param->gateway_mac[5]);
599
600 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
601 if (!buf) {
602 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
603 return CDF_STATUS_E_NOMEM;
604 }
605
606 buf_ptr = (uint8_t *) wmi_buf_data(buf);
607 hb_udp_params_fp = (wmi_hb_set_udp_params_cmd_fixed_param *) buf_ptr;
608 WMITLV_SET_HDR(&hb_udp_params_fp->tlv_header,
609 WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param,
610 WMITLV_GET_STRUCT_TLVLEN
611 (wmi_hb_set_udp_params_cmd_fixed_param));
612
613 /* fill in values */
614 hb_udp_params_fp->vdev_id = ts_lphb_udp_param->session;
615 hb_udp_params_fp->srv_ip = ts_lphb_udp_param->srv_ip;
616 hb_udp_params_fp->dev_ip = ts_lphb_udp_param->dev_ip;
617 hb_udp_params_fp->src_port = ts_lphb_udp_param->src_port;
618 hb_udp_params_fp->dst_port = ts_lphb_udp_param->dst_port;
619 hb_udp_params_fp->interval = ts_lphb_udp_param->interval;
620 hb_udp_params_fp->timeout = ts_lphb_udp_param->timeout;
621 hb_udp_params_fp->session = ts_lphb_udp_param->session;
622 WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_udp_param->gateway_mac,
623 &hb_udp_params_fp->gateway_mac);
624
625 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
626 len, WMI_HB_SET_UDP_PARAMS_CMDID);
627 if (status != EOK) {
628 WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_UDP_PARAMS returned Error %d",
629 status);
630 cdf_status = CDF_STATUS_E_FAILURE;
631 goto error;
632 }
633
634 return CDF_STATUS_SUCCESS;
635error:
636 return cdf_status;
637}
638
639/**
640 * wma_lphb_conf_udp_pkt_filter() - configure udp pkt filter command of LPHB
641 * @wma_handle: wma handle
642 * @lphb_conf_req: lphb config request
643 *
644 * Return: CDF status
645 */
646CDF_STATUS wma_lphb_conf_udp_pkt_filter(tp_wma_handle wma_handle,
647 tSirLPHBReq *lphb_conf_req)
648{
649 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
650 int status = 0;
651 tSirLPHBUdpFilterStruct *ts_lphb_udp_filter;
652 wmi_buf_t buf = NULL;
653 uint8_t *buf_ptr;
654 wmi_hb_set_udp_pkt_filter_cmd_fixed_param *hb_udp_filter_fp;
655 int len = sizeof(wmi_hb_set_udp_pkt_filter_cmd_fixed_param);
656
657 if (lphb_conf_req == NULL) {
658 WMA_LOGE("%s : LPHB configuration is NULL", __func__);
659 return CDF_STATUS_E_FAILURE;
660 }
661
662 ts_lphb_udp_filter = &(lphb_conf_req->params.lphbUdpFilterReq);
663 WMA_LOGI("%s: WMA --> WMI_HB_SET_UDP_PKT_FILTER length=%d, offset=%d, session=%d, "
664 "filter=%2x:%2x:%2x:%2x:%2x:%2x ...", __func__,
665 ts_lphb_udp_filter->length, ts_lphb_udp_filter->offset,
666 ts_lphb_udp_filter->session, ts_lphb_udp_filter->filter[0],
667 ts_lphb_udp_filter->filter[1], ts_lphb_udp_filter->filter[2],
668 ts_lphb_udp_filter->filter[3], ts_lphb_udp_filter->filter[4],
669 ts_lphb_udp_filter->filter[5]);
670
671 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
672 if (!buf) {
673 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
674 return CDF_STATUS_E_NOMEM;
675 }
676
677 buf_ptr = (uint8_t *) wmi_buf_data(buf);
678 hb_udp_filter_fp =
679 (wmi_hb_set_udp_pkt_filter_cmd_fixed_param *) buf_ptr;
680 WMITLV_SET_HDR(&hb_udp_filter_fp->tlv_header,
681 WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param,
682 WMITLV_GET_STRUCT_TLVLEN
683 (wmi_hb_set_udp_pkt_filter_cmd_fixed_param));
684
685 /* fill in values */
686 hb_udp_filter_fp->vdev_id = ts_lphb_udp_filter->session;
687 hb_udp_filter_fp->length = ts_lphb_udp_filter->length;
688 hb_udp_filter_fp->offset = ts_lphb_udp_filter->offset;
689 hb_udp_filter_fp->session = ts_lphb_udp_filter->session;
690 memcpy((void *)&hb_udp_filter_fp->filter,
691 (void *)&ts_lphb_udp_filter->filter,
692 WMI_WLAN_HB_MAX_FILTER_SIZE);
693
694 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
695 len, WMI_HB_SET_UDP_PKT_FILTER_CMDID);
696 if (status != EOK) {
697 WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_UDP_PKT_FILTER returned Error %d",
698 status);
699 cdf_status = CDF_STATUS_E_FAILURE;
700 goto error;
701 }
702
703 return CDF_STATUS_SUCCESS;
704error:
705 return cdf_status;
706}
707
708/**
709 * wma_process_lphb_conf_req() - handle LPHB configuration requests
710 * @wma_handle: wma handle
711 * @lphb_conf_req: lphb config request
712 *
713 * Return: CDF status
714 */
715CDF_STATUS wma_process_lphb_conf_req(tp_wma_handle wma_handle,
716 tSirLPHBReq *lphb_conf_req)
717{
718 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
719
720 if (lphb_conf_req == NULL) {
721 WMA_LOGE("%s : LPHB configuration is NULL", __func__);
722 return CDF_STATUS_E_FAILURE;
723 }
724
725 WMA_LOGI("%s : LPHB configuration cmd id is %d", __func__,
726 lphb_conf_req->cmd);
727 switch (lphb_conf_req->cmd) {
728 case LPHB_SET_EN_PARAMS_INDID:
729 cdf_status = wma_lphb_conf_hbenable(wma_handle,
730 lphb_conf_req, true);
731 break;
732
733 case LPHB_SET_TCP_PARAMS_INDID:
734 cdf_status = wma_lphb_conf_tcp_params(wma_handle,
735 lphb_conf_req);
736 break;
737
738 case LPHB_SET_TCP_PKT_FILTER_INDID:
739 cdf_status = wma_lphb_conf_tcp_pkt_filter(wma_handle,
740 lphb_conf_req);
741 break;
742
743 case LPHB_SET_UDP_PARAMS_INDID:
744 cdf_status = wma_lphb_conf_udp_params(wma_handle,
745 lphb_conf_req);
746 break;
747
748 case LPHB_SET_UDP_PKT_FILTER_INDID:
749 cdf_status = wma_lphb_conf_udp_pkt_filter(wma_handle,
750 lphb_conf_req);
751 break;
752
753 case LPHB_SET_NETWORK_INFO_INDID:
754 default:
755 break;
756 }
757
758 cdf_mem_free(lphb_conf_req);
759 return cdf_status;
760}
761#endif /* FEATURE_WLAN_LPHB */
762
763/**
764 * wma_process_dhcp_ind() - process dhcp indication from SME
765 * @wma_handle: wma handle
766 * @ta_dhcp_ind: DHCP indication
767 *
768 * Return: CDF Status
769 */
770CDF_STATUS wma_process_dhcp_ind(tp_wma_handle wma_handle,
771 tAniDHCPInd *ta_dhcp_ind)
772{
773 uint8_t vdev_id;
774 int status = 0;
775 wmi_buf_t buf = NULL;
776 uint8_t *buf_ptr;
777 wmi_peer_set_param_cmd_fixed_param *peer_set_param_fp;
778 int len = sizeof(wmi_peer_set_param_cmd_fixed_param);
779
780 if (!ta_dhcp_ind) {
781 WMA_LOGE("%s : DHCP indication is NULL", __func__);
782 return CDF_STATUS_E_FAILURE;
783 }
784
Srinivas Girigowda296105a2015-09-24 16:31:16 -0700785 if (!wma_find_vdev_by_addr(wma_handle,
786 ta_dhcp_ind->adapterMacAddr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787 &vdev_id)) {
788 WMA_LOGE("%s: Failed to find vdev id for DHCP indication",
789 __func__);
790 return CDF_STATUS_E_FAILURE;
791 }
792
793 WMA_LOGI("%s: WMA --> WMI_PEER_SET_PARAM triggered by DHCP, "
794 "msgType=%s,"
795 "device_mode=%d, macAddr=" MAC_ADDRESS_STR,
796 __func__,
797 ta_dhcp_ind->msgType == WMA_DHCP_START_IND ?
798 "WMA_DHCP_START_IND" : "WMA_DHCP_STOP_IND",
799 ta_dhcp_ind->device_mode,
Srinivas Girigowda296105a2015-09-24 16:31:16 -0700800 MAC_ADDR_ARRAY(ta_dhcp_ind->peerMacAddr.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800801
802 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
803 if (!buf) {
804 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
805 return CDF_STATUS_E_NOMEM;
806 }
807
808 buf_ptr = (uint8_t *) wmi_buf_data(buf);
809 peer_set_param_fp = (wmi_peer_set_param_cmd_fixed_param *) buf_ptr;
810 WMITLV_SET_HDR(&peer_set_param_fp->tlv_header,
811 WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param,
812 WMITLV_GET_STRUCT_TLVLEN
813 (wmi_peer_set_param_cmd_fixed_param));
814
815 /* fill in values */
816 peer_set_param_fp->vdev_id = vdev_id;
817 peer_set_param_fp->param_id = WMI_PEER_CRIT_PROTO_HINT_ENABLED;
818 if (WMA_DHCP_START_IND == ta_dhcp_ind->msgType)
819 peer_set_param_fp->param_value = 1;
820 else
821 peer_set_param_fp->param_value = 0;
Srinivas Girigowda296105a2015-09-24 16:31:16 -0700822 WMI_CHAR_ARRAY_TO_MAC_ADDR(ta_dhcp_ind->peerMacAddr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800823 &peer_set_param_fp->peer_macaddr);
824
825 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
826 len, WMI_PEER_SET_PARAM_CMDID);
827 if (status != EOK) {
828 WMA_LOGE("%s: wmi_unified_cmd_send WMI_PEER_SET_PARAM_CMD"
829 " returned Error %d", __func__, status);
830 return CDF_STATUS_E_FAILURE;
831 }
832
833 return CDF_STATUS_SUCCESS;
834}
835
836/**
837 * wma_chan_to_mode() - convert channel to phy mode
838 * @chan: channel number
839 * @chan_width: channel width
840 * @vht_capable: vht capable
841 * @dot11_mode: 802.11 mode
842 *
843 * Return: return phy mode
844 */
845WLAN_PHY_MODE wma_chan_to_mode(u8 chan, phy_ch_width chan_width,
846 u8 vht_capable, u8 dot11_mode)
847{
848 WLAN_PHY_MODE phymode = MODE_UNKNOWN;
849
850 /* 2.4 GHz band */
851 if ((chan >= WMA_11G_CHANNEL_BEGIN) && (chan <= WMA_11G_CHANNEL_END)) {
852 switch (chan_width) {
853 case CH_WIDTH_20MHZ:
854 /* In case of no channel bonding, use dot11_mode
855 * to set phy mode
856 */
857 switch (dot11_mode) {
858 case WNI_CFG_DOT11_MODE_11A:
859 phymode = MODE_11A;
860 break;
861 case WNI_CFG_DOT11_MODE_11B:
862 phymode = MODE_11B;
863 break;
864 case WNI_CFG_DOT11_MODE_11G:
865 phymode = MODE_11G;
866 break;
867 case WNI_CFG_DOT11_MODE_11G_ONLY:
868 phymode = MODE_11GONLY;
869 break;
870 default:
871 /* Configure MODE_11NG_HT20 for
872 * self vdev(for vht too)
873 */
874 phymode = MODE_11NG_HT20;
875 break;
876 }
877 break;
878 case CH_WIDTH_40MHZ:
879 phymode = vht_capable ? MODE_11AC_VHT40 :
880 MODE_11NG_HT40;
881 break;
882 default:
883 break;
884 }
885 }
886
887 /* 5 GHz band */
888 if ((chan >= WMA_11A_CHANNEL_BEGIN) && (chan <= WMA_11A_CHANNEL_END)) {
889 switch (chan_width) {
890 case CH_WIDTH_20MHZ:
891 phymode = vht_capable ? MODE_11AC_VHT20 :
892 MODE_11NA_HT20;
893 break;
894 case CH_WIDTH_40MHZ:
895 phymode = vht_capable ? MODE_11AC_VHT40 :
896 MODE_11NA_HT40;
897 break;
898 case CH_WIDTH_80MHZ:
899 phymode = MODE_11AC_VHT80;
900 break;
901#if CONFIG_160MHZ_SUPPORT != 0
902 case CH_WIDTH_160MHZ:
903 phymode = MODE_11AC_VHT160;
904 break;
905 case CH_WIDTH_80P80MHZ:
906 phymode = MODE_11AC_VHT80_80;
907 break;
908#endif
909
910 default:
911 break;
912 }
913 }
914
915 /* 5.9 GHz Band */
916 if ((chan >= WMA_11P_CHANNEL_BEGIN) && (chan <= WMA_11P_CHANNEL_END))
917 /* Only Legacy Modulation Schemes are supported */
918 phymode = MODE_11A;
919
920 WMA_LOGD("%s: phymode %d channel %d ch_width %d vht_capable %d "
921 "dot11_mode %d", __func__, phymode, chan,
922 chan_width, vht_capable, dot11_mode);
923
924 return phymode;
925}
926
927/**
928 * wma_get_link_speed() -send command to get linkspeed
929 * @handle: wma handle
930 * @pLinkSpeed: link speed info
931 *
932 * Return: CDF status
933 */
934CDF_STATUS wma_get_link_speed(WMA_HANDLE handle, tSirLinkSpeedInfo *pLinkSpeed)
935{
936 tp_wma_handle wma_handle = (tp_wma_handle) handle;
937 wmi_peer_get_estimated_linkspeed_cmd_fixed_param *cmd;
938 wmi_buf_t wmi_buf;
939 uint32_t len;
940 uint8_t *buf_ptr;
941
942 if (!wma_handle || !wma_handle->wmi_handle) {
943 WMA_LOGE("%s: WMA is closed, can not issue get link speed cmd",
944 __func__);
945 return CDF_STATUS_E_INVAL;
946 }
947 if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
948 WMI_SERVICE_ESTIMATE_LINKSPEED)) {
949 WMA_LOGE("%s: Linkspeed feature bit not enabled"
950 " Sending value 0 as link speed.", __func__);
951 wma_send_link_speed(0);
952 return CDF_STATUS_E_FAILURE;
953 }
954 len = sizeof(wmi_peer_get_estimated_linkspeed_cmd_fixed_param);
955 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
956 if (!wmi_buf) {
957 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
958 return CDF_STATUS_E_NOMEM;
959 }
960 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
961
962 cmd = (wmi_peer_get_estimated_linkspeed_cmd_fixed_param *) buf_ptr;
963 WMITLV_SET_HDR(&cmd->tlv_header,
964 WMITLV_TAG_STRUC_wmi_peer_get_estimated_linkspeed_cmd_fixed_param,
965 WMITLV_GET_STRUCT_TLVLEN
966 (wmi_peer_get_estimated_linkspeed_cmd_fixed_param));
967
968 /* Copy the peer macaddress to the wma buffer */
969 WMI_CHAR_ARRAY_TO_MAC_ADDR(pLinkSpeed->peer_macaddr,
970 &cmd->peer_macaddr);
971
972 WMA_LOGD("%s: pLinkSpeed->peerMacAddr: %pM, "
973 "peer_macaddr.mac_addr31to0: 0x%x, peer_macaddr.mac_addr47to32: 0x%x",
974 __func__, pLinkSpeed->peer_macaddr,
975 cmd->peer_macaddr.mac_addr31to0,
976 cmd->peer_macaddr.mac_addr47to32);
977
978 if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
979 WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID)) {
980 WMA_LOGE("%s: failed to send link speed command", __func__);
981 cdf_nbuf_free(wmi_buf);
982 return CDF_STATUS_E_FAILURE;
983 }
984 return CDF_STATUS_SUCCESS;
985}
986
987#ifdef FEATURE_GREEN_AP
988
989/**
990 * wmi_unified_pdev_green_ap_ps_enable_cmd() - enable green ap powersave command
991 * @wmi_handle: wmi handle
992 * @value: value
993 *
994 * Return: 0 for success or error code
995 */
996int32_t wmi_unified_pdev_green_ap_ps_enable_cmd(wmi_unified_t wmi_handle,
997 uint32_t value)
998{
999 wmi_pdev_green_ap_ps_enable_cmd_fixed_param *cmd;
1000 wmi_buf_t buf;
1001 int32_t len = sizeof(*cmd);
1002
1003 WMA_LOGD("Set Green AP PS val %d", value);
1004
1005 buf = wmi_buf_alloc(wmi_handle, len);
1006 if (!buf) {
1007 WMA_LOGP("%s: Green AP PS Mem Alloc Failed", __func__);
1008 return -ENOMEM;
1009 }
1010
1011 cmd = (wmi_pdev_green_ap_ps_enable_cmd_fixed_param *) wmi_buf_data(buf);
1012 WMITLV_SET_HDR(&cmd->tlv_header,
1013 WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param,
1014 WMITLV_GET_STRUCT_TLVLEN
1015 (wmi_pdev_green_ap_ps_enable_cmd_fixed_param));
1016 cmd->reserved0 = 0;
1017 cmd->enable = value;
1018
1019 if (wmi_unified_cmd_send(wmi_handle, buf, len,
1020 WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID)) {
1021 WMA_LOGE("Set Green AP PS param Failed val %d", value);
1022 cdf_nbuf_free(buf);
1023 return -EIO;
1024 }
1025 return 0;
1026}
1027#endif /* FEATURE_GREEN_AP */
1028
Govind Singha471e5e2015-10-12 17:11:14 +05301029/**
1030 * wmi_unified_fw_profiling_cmd() - send FW profiling cmd to WLAN FW
1031 * @wma: wma handle
1032 * @cmd: Profiling command index
1033 * @value1: parameter1 value
1034 * @value2: parameter2 value
1035 *
1036 * Return: 0 for success else error code
1037 */
1038int32_t wmi_unified_fw_profiling_cmd(wmi_unified_t wmi_handle,
1039 uint32_t cmd, uint32_t value1, uint32_t value2)
1040{
1041 wmi_buf_t buf;
1042 int32_t len = 0;
1043 int ret;
1044 wmi_wlan_profile_trigger_cmd_fixed_param *prof_trig_cmd;
1045 wmi_wlan_profile_set_hist_intvl_cmd_fixed_param *hist_intvl_cmd;
1046 wmi_wlan_profile_enable_profile_id_cmd_fixed_param *profile_enable_cmd;
1047 wmi_wlan_profile_get_prof_data_cmd_fixed_param *profile_getdata_cmd;
1048
1049 switch (cmd) {
1050 case WMI_WLAN_PROFILE_TRIGGER_CMDID:
1051 len = sizeof(wmi_wlan_profile_trigger_cmd_fixed_param);
1052 buf = wmi_buf_alloc(wmi_handle, len);
1053 if (!buf) {
1054 WMA_LOGP("%s: wmi_buf_alloc Failed", __func__);
1055 return -ENOMEM;
1056 }
1057 prof_trig_cmd =
1058 (wmi_wlan_profile_trigger_cmd_fixed_param *)
1059 wmi_buf_data(buf);
1060 WMITLV_SET_HDR(&prof_trig_cmd->tlv_header,
1061 WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param,
1062 WMITLV_GET_STRUCT_TLVLEN
1063 (wmi_wlan_profile_trigger_cmd_fixed_param));
1064 prof_trig_cmd->enable = value1;
1065 ret = wmi_unified_cmd_send(wmi_handle, buf, len,
1066 WMI_WLAN_PROFILE_TRIGGER_CMDID);
1067 if (ret) {
1068 WMA_LOGE("PROFILE_TRIGGER cmd Failed with value %d",
1069 value1);
1070 cdf_nbuf_free(buf);
1071 return ret;
1072 }
1073 break;
1074
1075 case WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID:
1076 len = sizeof(wmi_wlan_profile_get_prof_data_cmd_fixed_param);
1077 buf = wmi_buf_alloc(wmi_handle, len);
1078 if (!buf) {
1079 WMA_LOGP("%s: wmi_buf_alloc Failed", __func__);
1080 return -ENOMEM;
1081 }
1082 profile_getdata_cmd =
1083 (wmi_wlan_profile_get_prof_data_cmd_fixed_param *)
1084 wmi_buf_data(buf);
1085 WMITLV_SET_HDR(&profile_getdata_cmd->tlv_header,
1086 WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param,
1087 WMITLV_GET_STRUCT_TLVLEN
1088 (wmi_wlan_profile_get_prof_data_cmd_fixed_param));
1089 ret = wmi_unified_cmd_send(wmi_handle, buf, len,
1090 WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID);
1091 if (ret) {
1092 WMA_LOGE("PROFILE_DATA cmd Failed for id %d value %d",
1093 value1, value2);
1094 cdf_nbuf_free(buf);
1095 return ret;
1096 }
1097 break;
1098
1099 case WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID:
1100 len = sizeof(wmi_wlan_profile_set_hist_intvl_cmd_fixed_param);
1101 buf = wmi_buf_alloc(wmi_handle, len);
1102 if (!buf) {
1103 WMA_LOGP("%s: wmi_buf_alloc Failed", __func__);
1104 return -ENOMEM;
1105 }
1106 hist_intvl_cmd =
1107 (wmi_wlan_profile_set_hist_intvl_cmd_fixed_param *)
1108 wmi_buf_data(buf);
1109 WMITLV_SET_HDR(&hist_intvl_cmd->tlv_header,
1110 WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param,
1111 WMITLV_GET_STRUCT_TLVLEN
1112 (wmi_wlan_profile_set_hist_intvl_cmd_fixed_param));
1113 hist_intvl_cmd->profile_id = value1;
1114 hist_intvl_cmd->value = value2;
1115 ret = wmi_unified_cmd_send(wmi_handle, buf, len,
1116 WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID);
1117 if (ret) {
1118 WMA_LOGE("HIST_INTVL cmd Failed for id %d value %d",
1119 value1, value2);
1120 cdf_nbuf_free(buf);
1121 return ret;
1122 }
1123 break;
1124
1125 case WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID:
1126 len =
1127 sizeof(wmi_wlan_profile_enable_profile_id_cmd_fixed_param);
1128 buf = wmi_buf_alloc(wmi_handle, len);
1129 if (!buf) {
1130 WMA_LOGP("%s: wmi_buf_alloc Failed", __func__);
1131 return -ENOMEM;
1132 }
1133 profile_enable_cmd =
1134 (wmi_wlan_profile_enable_profile_id_cmd_fixed_param *)
1135 wmi_buf_data(buf);
1136 WMITLV_SET_HDR(&profile_enable_cmd->tlv_header,
1137 WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param,
1138 WMITLV_GET_STRUCT_TLVLEN
1139 (wmi_wlan_profile_enable_profile_id_cmd_fixed_param));
1140 profile_enable_cmd->profile_id = value1;
1141 profile_enable_cmd->enable = value2;
1142 ret = wmi_unified_cmd_send(wmi_handle, buf, len,
1143 WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID);
1144 if (ret) {
1145 WMA_LOGE("enable cmd Failed for id %d value %d",
1146 value1, value2);
1147 cdf_nbuf_free(buf);
1148 return ret;
1149 }
1150 break;
1151
1152 default:
1153 WMA_LOGD("%s: invalid profiling command", __func__);
1154 break;
1155 }
1156
1157 return 0;
1158}
1159
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001160#ifdef FEATURE_WLAN_LPHB
1161/**
1162 * wma_lphb_handler() - send LPHB indication to SME
1163 * @wma: wma handle
1164 * @event: event handler
1165 *
1166 * Return: 0 for success or error code
1167 */
1168static int wma_lphb_handler(tp_wma_handle wma, uint8_t *event)
1169{
1170 wmi_hb_ind_event_fixed_param *hb_fp;
1171 tSirLPHBInd *slphb_indication;
1172 CDF_STATUS cdf_status;
1173 cds_msg_t sme_msg = { 0 };
1174
1175 hb_fp = (wmi_hb_ind_event_fixed_param *) event;
1176 if (!hb_fp) {
1177 WMA_LOGE("Invalid wmi_hb_ind_event_fixed_param buffer");
1178 return -EINVAL;
1179 }
1180
1181 WMA_LOGD("lphb indication received with vdev_id=%d, session=%d, reason=%d",
1182 hb_fp->vdev_id, hb_fp->session, hb_fp->reason);
1183
1184 slphb_indication = (tSirLPHBInd *) cdf_mem_malloc(sizeof(tSirLPHBInd));
1185
1186 if (!slphb_indication) {
1187 WMA_LOGE("Invalid LPHB indication buffer");
1188 return -ENOMEM;
1189 }
1190
1191 slphb_indication->sessionIdx = hb_fp->session;
1192 slphb_indication->protocolType = hb_fp->reason;
1193 slphb_indication->eventReason = hb_fp->reason;
1194
1195 sme_msg.type = eWNI_SME_LPHB_IND;
1196 sme_msg.bodyptr = slphb_indication;
1197 sme_msg.bodyval = 0;
1198
1199 cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg);
1200 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
1201 WMA_LOGE("Fail to post eWNI_SME_LPHB_IND msg to SME");
1202 cdf_mem_free(slphb_indication);
1203 return -EINVAL;
1204 }
1205
1206 return 0;
1207}
1208#endif /* FEATURE_WLAN_LPHB */
1209
1210#ifdef FEATURE_WLAN_RA_FILTERING
1211/**
1212 * wma_wow_sta_ra_filter() - set RA filter pattern in fw
1213 * @wma: wma handle
1214 * @vdev_id: vdev id
1215 *
1216 * Return: CDF status
1217 */
1218static CDF_STATUS wma_wow_sta_ra_filter(tp_wma_handle wma, uint8_t vdev_id)
1219{
1220
1221 WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd;
1222 struct wma_txrx_node *iface;
1223 wmi_buf_t buf;
1224 uint8_t *buf_ptr;
1225 int32_t len;
1226 int ret;
1227
1228 iface = &wma->interfaces[vdev_id];
1229
1230 len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) +
1231 WMI_TLV_HDR_SIZE +
1232 0 * sizeof(WOW_BITMAP_PATTERN_T) +
1233 WMI_TLV_HDR_SIZE +
1234 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) +
1235 WMI_TLV_HDR_SIZE +
1236 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) +
1237 WMI_TLV_HDR_SIZE +
1238 0 * sizeof(WOW_MAGIC_PATTERN_CMD) +
1239 WMI_TLV_HDR_SIZE +
1240 0 * sizeof(A_UINT32) + WMI_TLV_HDR_SIZE + 1 * sizeof(A_UINT32);
1241
1242 buf = wmi_buf_alloc(wma->wmi_handle, len);
1243 if (!buf) {
1244 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
1245 return CDF_STATUS_E_NOMEM;
1246 }
1247
1248 cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf);
1249 buf_ptr = (uint8_t *) cmd;
1250
1251 WMITLV_SET_HDR(&cmd->tlv_header,
1252 WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param,
1253 WMITLV_GET_STRUCT_TLVLEN
1254 (WMI_WOW_ADD_PATTERN_CMD_fixed_param));
1255 cmd->vdev_id = vdev_id;
1256 cmd->pattern_id = iface->num_wow_default_patterns++,
1257 cmd->pattern_type = WOW_IPV6_RA_PATTERN;
1258 buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param);
1259
1260 /* Fill TLV for WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T but no data. */
1261 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
1262 buf_ptr += WMI_TLV_HDR_SIZE;
1263
1264 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */
1265 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
1266 buf_ptr += WMI_TLV_HDR_SIZE;
1267
1268 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */
1269 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
1270 buf_ptr += WMI_TLV_HDR_SIZE;
1271
1272 /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */
1273 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
1274 buf_ptr += WMI_TLV_HDR_SIZE;
1275
1276 /* Fill TLV for pattern_info_timeout but no data. */
1277 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
1278 buf_ptr += WMI_TLV_HDR_SIZE;
1279
1280 /* Fill TLV for ra_ratelimit_interval. */
1281 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(A_UINT32));
1282 buf_ptr += WMI_TLV_HDR_SIZE;
1283
1284 *((A_UINT32 *) buf_ptr) = wma->RArateLimitInterval;
1285
1286 WMA_LOGD("%s: send RA rate limit [%d] to fw vdev = %d", __func__,
1287 wma->RArateLimitInterval, vdev_id);
1288
1289 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
1290 WMI_WOW_ADD_WAKE_PATTERN_CMDID);
1291 if (ret) {
1292 WMA_LOGE("%s: Failed to send RA rate limit to fw", __func__);
1293 wmi_buf_free(buf);
1294 iface->num_wow_default_patterns--;
1295 return CDF_STATUS_E_FAILURE;
1296 }
1297
1298 return CDF_STATUS_SUCCESS;
1299
1300}
1301#endif /* FEATURE_WLAN_RA_FILTERING */
1302
1303/**
1304 * wmi_unified_nat_keepalive_enable() - enable NAT keepalive filter
1305 * @wma: wma handle
1306 * @vdev_id: vdev id
1307 *
1308 * Return: 0 for success or error code
1309 */
1310int wmi_unified_nat_keepalive_enable(tp_wma_handle wma, uint8_t vdev_id)
1311{
1312 WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param *cmd;
1313 wmi_buf_t buf;
1314 int32_t len = sizeof(*cmd);
1315
1316 WMA_LOGD("%s: vdev_id %d", __func__, vdev_id);
1317 buf = wmi_buf_alloc(wma->wmi_handle, len);
1318 if (!buf) {
1319 WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
1320 return -ENOMEM;
1321 }
1322 cmd = (WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param *)
1323 wmi_buf_data(buf);
1324 WMITLV_SET_HDR(&cmd->tlv_header,
1325 WMITLV_TAG_STRUC_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param,
1326 WMITLV_GET_STRUCT_TLVLEN
1327 (WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param));
1328 cmd->vdev_id = vdev_id;
1329 cmd->action = IPSEC_NATKEEPALIVE_FILTER_ENABLE;
1330 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
1331 WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID)) {
1332 WMA_LOGP("%s: Failed to send NAT keepalive enable command",
1333 __func__);
1334 wmi_buf_free(buf);
1335 return -EIO;
1336 }
1337 return 0;
1338}
1339
1340/**
1341 * wmi_unified_csa_offload_enable() - sen CSA offload enable command
1342 * @wma: wma handle
1343 * @vdev_id: vdev id
1344 *
1345 * Return: 0 for success or error code
1346 */
1347int wmi_unified_csa_offload_enable(tp_wma_handle wma, uint8_t vdev_id)
1348{
1349 wmi_csa_offload_enable_cmd_fixed_param *cmd;
1350 wmi_buf_t buf;
1351 int32_t len = sizeof(*cmd);
1352
1353 WMA_LOGD("%s: vdev_id %d", __func__, vdev_id);
1354 buf = wmi_buf_alloc(wma->wmi_handle, len);
1355 if (!buf) {
1356 WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
1357 return -ENOMEM;
1358 }
1359 cmd = (wmi_csa_offload_enable_cmd_fixed_param *) wmi_buf_data(buf);
1360 WMITLV_SET_HDR(&cmd->tlv_header,
1361 WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param,
1362 WMITLV_GET_STRUCT_TLVLEN
1363 (wmi_csa_offload_enable_cmd_fixed_param));
1364 cmd->vdev_id = vdev_id;
1365 cmd->csa_offload_enable = WMI_CSA_OFFLOAD_ENABLE;
1366 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
1367 WMI_CSA_OFFLOAD_ENABLE_CMDID)) {
1368 WMA_LOGP("%s: Failed to send CSA offload enable command",
1369 __func__);
1370 wmi_buf_free(buf);
1371 return -EIO;
1372 }
1373 return 0;
1374}
1375
1376#ifdef WLAN_FEATURE_NAN
1377/**
1378 * wma_nan_rsp_event_handler() - Function is used to handle nan response
1379 * @handle: wma handle
1380 * @event_buf: event buffer
1381 * @len: length of buffer
1382 *
1383 * Return: 0 for success or error code
1384 */
1385int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf,
1386 uint32_t len)
1387{
1388 WMI_NAN_EVENTID_param_tlvs *param_buf;
1389 tSirNanEvent *nan_rsp_event;
1390 wmi_nan_event_hdr *nan_rsp_event_hdr;
1391 CDF_STATUS status;
1392 cds_msg_t cds_msg;
1393 uint8_t *buf_ptr;
1394 uint32_t alloc_len;
1395
1396 /*
1397 * This is how received event_buf looks like
1398 *
1399 * <-------------------- event_buf ----------------------------------->
1400 *
1401 * <--wmi_nan_event_hdr--><---WMI_TLV_HDR_SIZE---><----- data -------->
1402 *
1403 * +-----------+---------+-----------------------+--------------------+
1404 * | tlv_header| data_len| WMITLV_TAG_ARRAY_BYTE | nan_rsp_event_data |
1405 * +-----------+---------+-----------------------+--------------------+
1406 */
1407
1408 WMA_LOGD("%s: Posting NaN response event to SME", __func__);
1409 param_buf = (WMI_NAN_EVENTID_param_tlvs *) event_buf;
1410 if (!param_buf) {
1411 WMA_LOGE("%s: Invalid nan response event buf", __func__);
1412 return -EINVAL;
1413 }
1414 nan_rsp_event_hdr = param_buf->fixed_param;
1415 buf_ptr = (uint8_t *) nan_rsp_event_hdr;
1416 alloc_len = sizeof(tSirNanEvent);
1417 alloc_len += nan_rsp_event_hdr->data_len;
1418 nan_rsp_event = (tSirNanEvent *) cdf_mem_malloc(alloc_len);
1419 if (NULL == nan_rsp_event) {
1420 WMA_LOGE("%s: Memory allocation failure", __func__);
1421 return -ENOMEM;
1422 }
1423
1424 nan_rsp_event->event_data_len = nan_rsp_event_hdr->data_len;
1425 cdf_mem_copy(nan_rsp_event->event_data, buf_ptr +
1426 sizeof(wmi_nan_event_hdr) + WMI_TLV_HDR_SIZE,
1427 nan_rsp_event->event_data_len);
1428 cds_msg.type = eWNI_SME_NAN_EVENT;
1429 cds_msg.bodyptr = (void *)nan_rsp_event;
1430 cds_msg.bodyval = 0;
1431
1432 status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg);
1433 if (status != CDF_STATUS_SUCCESS) {
1434 WMA_LOGE("%s: Failed to post NaN response event to SME",
1435 __func__);
1436 cdf_mem_free(nan_rsp_event);
1437 return -EFAULT;
1438 }
1439 WMA_LOGD("%s: NaN response event Posted to SME", __func__);
1440 return 0;
1441}
1442#endif /* WLAN_FEATURE_NAN */
1443
1444/**
1445 * wma_csa_offload_handler() - CSA event handler
1446 * @handle: wma handle
1447 * @event: event buffer
1448 * @len: buffer length
1449 *
1450 * This event is sent by firmware when it receives CSA IE.
1451 *
1452 * Return: 0 for success or error code
1453 */
1454int wma_csa_offload_handler(void *handle, uint8_t *event, uint32_t len)
1455{
1456 tp_wma_handle wma = (tp_wma_handle) handle;
1457 WMI_CSA_HANDLING_EVENTID_param_tlvs *param_buf;
1458 wmi_csa_event_fixed_param *csa_event;
1459 uint8_t bssid[IEEE80211_ADDR_LEN];
1460 uint8_t vdev_id = 0;
1461 uint8_t cur_chan = 0;
1462 struct ieee80211_channelswitch_ie *csa_ie;
1463 tpCSAOffloadParams csa_offload_event;
1464 struct ieee80211_extendedchannelswitch_ie *xcsa_ie;
1465 struct ieee80211_ie_wide_bw_switch *wb_ie;
1466 struct wma_txrx_node *intr = wma->interfaces;
1467
1468 param_buf = (WMI_CSA_HANDLING_EVENTID_param_tlvs *) event;
1469
1470 WMA_LOGD("%s: Enter", __func__);
1471 if (!param_buf) {
1472 WMA_LOGE("Invalid csa event buffer");
1473 return -EINVAL;
1474 }
1475 csa_event = param_buf->fixed_param;
1476 WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->i_addr2, &bssid[0]);
1477
1478 if (wma_find_vdev_by_bssid(wma, bssid, &vdev_id) == NULL) {
1479 WMA_LOGE("Invalid bssid received %s:%d", __func__, __LINE__);
1480 return -EINVAL;
1481 }
1482
1483 csa_offload_event = cdf_mem_malloc(sizeof(*csa_offload_event));
1484 if (!csa_offload_event) {
1485 WMA_LOGE("CDF MEM Alloc Failed for csa_offload_event");
1486 return -EINVAL;
1487 }
1488
1489 cdf_mem_zero(csa_offload_event, sizeof(*csa_offload_event));
1490 cdf_mem_copy(csa_offload_event->bssId, &bssid, IEEE80211_ADDR_LEN);
1491
1492 if (csa_event->ies_present_flag & WMI_CSA_IE_PRESENT) {
1493 csa_ie = (struct ieee80211_channelswitch_ie *)
1494 (&csa_event->csa_ie[0]);
1495 csa_offload_event->channel = csa_ie->newchannel;
1496 csa_offload_event->switchmode = csa_ie->switchmode;
1497 } else if (csa_event->ies_present_flag & WMI_XCSA_IE_PRESENT) {
1498 xcsa_ie = (struct ieee80211_extendedchannelswitch_ie *)
1499 (&csa_event->xcsa_ie[0]);
1500 csa_offload_event->channel = xcsa_ie->newchannel;
1501 csa_offload_event->switchmode = xcsa_ie->switchmode;
1502 } else {
1503 WMA_LOGE("CSA Event error: No CSA IE present");
1504 cdf_mem_free(csa_offload_event);
1505 return -EINVAL;
1506 }
1507
1508 if (csa_event->ies_present_flag & WMI_WBW_IE_PRESENT) {
1509 wb_ie = (struct ieee80211_ie_wide_bw_switch *)
1510 (&csa_event->wb_ie[0]);
1511 csa_offload_event->new_ch_width = wb_ie->new_ch_width;
1512 csa_offload_event->new_ch_freq_seg1 = wb_ie->new_ch_freq_seg1;
1513 csa_offload_event->new_ch_freq_seg2 = wb_ie->new_ch_freq_seg2;
1514 }
1515
1516 csa_offload_event->ies_present_flag = csa_event->ies_present_flag;
1517
1518 WMA_LOGD("CSA: New Channel = %d BSSID:%pM",
1519 csa_offload_event->channel, csa_offload_event->bssId);
1520
1521 cur_chan = cds_freq_to_chan(intr[vdev_id].mhz);
1522 /*
1523 * basic sanity check: requested channel should not be 0
1524 * and equal to home channel
1525 */
1526 if ((0 == csa_offload_event->channel) ||
1527 (cur_chan == csa_offload_event->channel)) {
1528 WMA_LOGE("CSA Event with channel %d. Ignore !!",
1529 csa_offload_event->channel);
1530 cdf_mem_free(csa_offload_event);
1531 return -EINVAL;
1532 }
1533 wma->interfaces[vdev_id].is_channel_switch = true;
1534 wma_send_msg(wma, WMA_CSA_OFFLOAD_EVENT, (void *)csa_offload_event, 0);
1535 return 0;
1536}
1537
1538#ifdef FEATURE_OEM_DATA_SUPPORT
1539
1540/**
1541 * wma_oem_capability_event_callback() - OEM capability event handler
1542 * @handle: wma handle
1543 * @datap: data ptr
1544 * @len: data length
1545 *
1546 * Return: 0 for success or error code
1547 */
1548int wma_oem_capability_event_callback(void *handle,
1549 uint8_t *datap, uint32_t len)
1550{
1551 tp_wma_handle wma = (tp_wma_handle) handle;
1552 WMI_OEM_CAPABILITY_EVENTID_param_tlvs *param_buf;
1553 uint8_t *data;
1554 uint32_t datalen;
1555 uint32_t *msg_subtype;
1556 tStartOemDataRsp *pStartOemDataRsp;
1557
1558 param_buf = (WMI_OEM_CAPABILITY_EVENTID_param_tlvs *) datap;
1559 if (!param_buf) {
1560 WMA_LOGE("%s: Received NULL buf ptr from FW", __func__);
1561 return -ENOMEM;
1562 }
1563
1564 data = param_buf->data;
1565 datalen = param_buf->num_data;
1566
1567 if (!data) {
1568 WMA_LOGE("%s: Received NULL data from FW", __func__);
1569 return -EINVAL;
1570 }
1571
1572 /* wma puts 4 bytes prefix for msg subtype, so length
1573 * of data received from target should be 4 bytes less
1574 * then max allowed
1575 */
1576 if (datalen > (OEM_DATA_RSP_SIZE - 4)) {
1577 WMA_LOGE("%s: Received data len (%d) exceeds max value (%d)",
1578 __func__, datalen, (OEM_DATA_RSP_SIZE - 4));
1579 return -EINVAL;
1580 }
1581
1582 pStartOemDataRsp = cdf_mem_malloc(sizeof(*pStartOemDataRsp));
1583 if (!pStartOemDataRsp) {
1584 WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__);
1585 return -ENOMEM;
1586 }
1587
1588 cdf_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp));
1589 msg_subtype = (uint32_t *) (&pStartOemDataRsp->oemDataRsp[0]);
1590 *msg_subtype = WMI_OEM_CAPABILITY_RSP;
1591 cdf_mem_copy(&pStartOemDataRsp->oemDataRsp[4], data, datalen);
1592
1593 WMA_LOGI("%s: Sending WMA_START_OEM_DATA_RSP, data len (%d)",
1594 __func__, datalen);
1595
1596 wma_send_msg(wma, WMA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0);
1597 return 0;
1598}
1599
1600/**
1601 * wma_oem_measurement_report_event_callback() - OEM measurement report handler
1602 * @handle: wma handle
1603 * @datap: data ptr
1604 * @len: data length
1605 *
1606 * Return: 0 for success or error code
1607 */
1608int wma_oem_measurement_report_event_callback(void *handle,
1609 uint8_t *datap,
1610 uint32_t len)
1611{
1612 tp_wma_handle wma = (tp_wma_handle) handle;
1613 WMI_OEM_MEASUREMENT_REPORT_EVENTID_param_tlvs *param_buf;
1614 uint8_t *data;
1615 uint32_t datalen;
1616 uint32_t *msg_subtype;
1617 tStartOemDataRsp *pStartOemDataRsp;
1618
1619 param_buf = (WMI_OEM_MEASUREMENT_REPORT_EVENTID_param_tlvs *) datap;
1620 if (!param_buf) {
1621 WMA_LOGE("%s: Received NULL buf ptr from FW", __func__);
1622 return -ENOMEM;
1623 }
1624
1625 data = param_buf->data;
1626 datalen = param_buf->num_data;
1627
1628 if (!data) {
1629 WMA_LOGE("%s: Received NULL data from FW", __func__);
1630 return -EINVAL;
1631 }
1632
1633 /* wma puts 4 bytes prefix for msg subtype, so length
1634 * of data received from target should be 4 bytes less
1635 * then max allowed
1636 */
1637 if (datalen > (OEM_DATA_RSP_SIZE - 4)) {
1638 WMA_LOGE("%s: Received data len (%d) exceeds max value (%d)",
1639 __func__, datalen, (OEM_DATA_RSP_SIZE - 4));
1640 return -EINVAL;
1641 }
1642
1643 pStartOemDataRsp = cdf_mem_malloc(sizeof(*pStartOemDataRsp));
1644 if (!pStartOemDataRsp) {
1645 WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__);
1646 return -ENOMEM;
1647 }
1648
1649 cdf_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp));
1650 msg_subtype = (uint32_t *) (&pStartOemDataRsp->oemDataRsp[0]);
1651 *msg_subtype = WMI_OEM_MEASUREMENT_RSP;
1652 cdf_mem_copy(&pStartOemDataRsp->oemDataRsp[4], data, datalen);
1653
1654 WMA_LOGI("%s: Sending WMA_START_OEM_DATA_RSP, data len (%d)",
1655 __func__, datalen);
1656
1657 wma_send_msg(wma, WMA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0);
1658 return 0;
1659}
1660
1661/**
1662 * wma_oem_error_report_event_callback() - OEM error report handler
1663 * @handle: wma handle
1664 * @datap: data ptr
1665 * @len: data length
1666 *
1667 * Return: 0 for success or error code
1668 */
1669int wma_oem_error_report_event_callback(void *handle,
1670 uint8_t *datap, uint32_t len)
1671{
1672 tp_wma_handle wma = (tp_wma_handle) handle;
1673 WMI_OEM_ERROR_REPORT_EVENTID_param_tlvs *param_buf;
1674 uint8_t *data;
1675 uint32_t datalen;
1676 uint32_t *msg_subtype;
1677 tStartOemDataRsp *pStartOemDataRsp;
1678
1679 param_buf = (WMI_OEM_ERROR_REPORT_EVENTID_param_tlvs *) datap;
1680 if (!param_buf) {
1681 WMA_LOGE("%s: Received NULL buf ptr from FW", __func__);
1682 return -ENOMEM;
1683 }
1684
1685 data = param_buf->data;
1686 datalen = param_buf->num_data;
1687
1688 if (!data) {
1689 WMA_LOGE("%s: Received NULL data from FW", __func__);
1690 return -EINVAL;
1691 }
1692
1693 /* wma puts 4 bytes prefix for msg subtype, so length
1694 * of data received from target should be 4 bytes less
1695 * then max allowed
1696 */
1697 if (datalen > (OEM_DATA_RSP_SIZE - 4)) {
1698 WMA_LOGE("%s: Received data len (%d) exceeds max value (%d)",
1699 __func__, datalen, (OEM_DATA_RSP_SIZE - 4));
1700 return -EINVAL;
1701 }
1702
1703 pStartOemDataRsp = cdf_mem_malloc(sizeof(*pStartOemDataRsp));
1704 if (!pStartOemDataRsp) {
1705 WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__);
1706 return -ENOMEM;
1707 }
1708
1709 cdf_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp));
1710 msg_subtype = (uint32_t *) (&pStartOemDataRsp->oemDataRsp[0]);
1711 *msg_subtype = WMI_OEM_ERROR_REPORT_RSP;
1712 cdf_mem_copy(&pStartOemDataRsp->oemDataRsp[4], data, datalen);
1713
1714 WMA_LOGI("%s: Sending WMA_START_OEM_DATA_RSP, data len (%d)",
1715 __func__, datalen);
1716
1717 wma_send_msg(wma, WMA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0);
1718 return 0;
1719}
1720
1721/**
1722 * wma_start_oem_data_req() - start OEM data request to target
1723 * @wma_handle: wma handle
1724 * @startOemDataReq: start request params
1725 *
1726 * Return: none
1727 */
1728void wma_start_oem_data_req(tp_wma_handle wma_handle,
1729 tStartOemDataReq *startOemDataReq)
1730{
1731 wmi_buf_t buf;
1732 uint8_t *cmd;
1733 int ret = 0;
1734 uint32_t *msg_subtype;
1735 tStartOemDataRsp *pStartOemDataRsp;
1736
1737 WMA_LOGD("%s: Send OEM Data Request to target", __func__);
1738
1739 if (!startOemDataReq) {
1740 WMA_LOGE("%s: startOemDataReq is null", __func__);
1741 goto out;
1742 }
1743
1744 if (!wma_handle || !wma_handle->wmi_handle) {
1745 WMA_LOGE("%s: WMA is closed, can not send Oem data request cmd",
1746 __func__);
1747 return;
1748 }
1749
1750 buf = wmi_buf_alloc(wma_handle->wmi_handle,
1751 (OEM_DATA_REQ_SIZE + WMI_TLV_HDR_SIZE));
1752 if (!buf) {
1753 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
1754 goto out;
1755 }
1756
1757 cmd = (uint8_t *) wmi_buf_data(buf);
1758
1759 WMITLV_SET_HDR(cmd, WMITLV_TAG_ARRAY_BYTE, OEM_DATA_REQ_SIZE);
1760 cmd += WMI_TLV_HDR_SIZE;
1761 cdf_mem_copy(cmd, &startOemDataReq->oemDataReq[0], OEM_DATA_REQ_SIZE);
1762
1763 WMA_LOGI("%s: Sending OEM Data Request to target, data len (%d)",
1764 __func__, OEM_DATA_REQ_SIZE);
1765
1766 ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
1767 (OEM_DATA_REQ_SIZE +
1768 WMI_TLV_HDR_SIZE), WMI_OEM_REQ_CMDID);
1769
1770 if (ret != EOK) {
1771 WMA_LOGE("%s:wmi cmd send failed", __func__);
1772 cdf_nbuf_free(buf);
1773 }
1774
1775out:
1776 /* free oem data req buffer received from UMAC */
1777 if (startOemDataReq)
1778 cdf_mem_free(startOemDataReq);
1779
1780 /* Now send data resp back to PE/SME with message sub-type of
1781 * WMI_OEM_INTERNAL_RSP. This is required so that PE/SME clears
1782 * up pending active command. Later when desired oem response(s)
1783 * comes as wmi event from target then those shall be passed
1784 * to oem application
1785 */
1786 pStartOemDataRsp = cdf_mem_malloc(sizeof(*pStartOemDataRsp));
1787 if (!pStartOemDataRsp) {
1788 WMA_LOGE("%s:failed to allocate memory for OEM Data Resp to PE",
1789 __func__);
1790 return;
1791 }
1792 cdf_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp));
1793 msg_subtype = (uint32_t *) (&pStartOemDataRsp->oemDataRsp[0]);
1794 *msg_subtype = WMI_OEM_INTERNAL_RSP;
1795
1796 WMA_LOGI("%s: Sending WMA_START_OEM_DATA_RSP to clear up PE/SME pending cmd",
1797 __func__);
1798
1799 wma_send_msg(wma_handle, WMA_START_OEM_DATA_RSP,
1800 (void *)pStartOemDataRsp, 0);
1801
1802 return;
1803}
1804#endif /* FEATURE_OEM_DATA_SUPPORT */
1805
1806
1807/**
1808 * wma_unified_dfs_radar_rx_event_handler() - dfs radar rx event handler
1809 * @handle: wma handle
1810 * @data: data buffer
1811 * @datalen: data length
1812 *
1813 * WMI handler for WMI_DFS_RADAR_EVENTID
1814 * This handler is registered for handling
1815 * filtered DFS Phyerror. This handler is
1816 * will be invoked only when DFS Phyerr
1817 * filtering offload is enabled.
1818 *
1819 * Return: 1 for Success and 0 for error
1820 */
1821static int wma_unified_dfs_radar_rx_event_handler(void *handle,
1822 uint8_t *data,
1823 uint32_t datalen)
1824{
1825 tp_wma_handle wma = (tp_wma_handle) handle;
1826 struct ieee80211com *ic;
1827 struct ath_dfs *dfs;
1828 struct dfs_event *event;
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +05301829 struct dfs_ieee80211_channel *chan;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830 int empty;
1831 int do_check_chirp = 0;
1832 int is_hw_chirp = 0;
1833 int is_sw_chirp = 0;
1834 int is_pri = 0;
1835
1836 WMI_DFS_RADAR_EVENTID_param_tlvs *param_tlvs;
1837 wmi_dfs_radar_event_fixed_param *radar_event;
1838
1839 ic = wma->dfs_ic;
1840 if (NULL == ic) {
1841 WMA_LOGE("%s: dfs_ic is NULL ", __func__);
1842 return 0;
1843 }
1844
1845 dfs = (struct ath_dfs *)ic->ic_dfs;
1846 param_tlvs = (WMI_DFS_RADAR_EVENTID_param_tlvs *) data;
1847
1848 if (NULL == dfs) {
1849 WMA_LOGE("%s: dfs is NULL ", __func__);
1850 return 0;
1851 }
1852 /*
1853 * This parameter holds the number
1854 * of phyerror interrupts to the host
1855 * after the phyerrors have passed through
1856 * false detect filters in the firmware.
1857 */
1858 dfs->dfs_phyerr_count++;
1859
1860 if (!param_tlvs) {
1861 WMA_LOGE("%s: Received NULL data from FW", __func__);
1862 return 0;
1863 }
1864
1865 radar_event = param_tlvs->fixed_param;
1866
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05301867 cdf_spin_lock_bh(&ic->chan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001868 chan = ic->ic_curchan;
Edhar, Mahesh Kumar35d9b2e2015-10-26 17:06:23 +05301869 if (ic->disable_phy_err_processing) {
1870 WMA_LOGD("%s: radar indication done,drop phyerror event",
1871 __func__);
1872 cdf_spin_unlock_bh(&ic->chan_lock);
1873 return 0;
1874 }
1875
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 if (CHANNEL_STATE_DFS != cds_get_channel_state(chan->ic_ieee)) {
1877 WMA_LOGE
1878 ("%s: Invalid DFS Phyerror event. Channel=%d is Non-DFS",
1879 __func__, chan->ic_ieee);
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05301880 cdf_spin_unlock_bh(&ic->chan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881 return 0;
1882 }
1883
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05301884 cdf_spin_unlock_bh(&ic->chan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885 dfs->ath_dfs_stats.total_phy_errors++;
1886
1887 if (dfs->dfs_caps.ath_chip_is_bb_tlv) {
1888 do_check_chirp = 1;
1889 is_pri = 1;
1890 is_hw_chirp = radar_event->pulse_is_chirp;
1891
1892 if ((uint32_t) dfs->dfs_phyerr_freq_min >
1893 radar_event->pulse_center_freq) {
1894 dfs->dfs_phyerr_freq_min =
1895 (int)radar_event->pulse_center_freq;
1896 }
1897
1898 if (dfs->dfs_phyerr_freq_max <
1899 (int)radar_event->pulse_center_freq) {
1900 dfs->dfs_phyerr_freq_max =
1901 (int)radar_event->pulse_center_freq;
1902 }
1903 }
1904
1905 /*
1906 * Now, add the parsed, checked and filtered
1907 * radar phyerror event radar pulse event list.
1908 * This event will then be processed by
1909 * dfs_radar_processevent() to see if the pattern
1910 * of pulses in radar pulse list match any radar
1911 * singnature in the current regulatory domain.
1912 */
1913
1914 ATH_DFSEVENTQ_LOCK(dfs);
1915 empty = STAILQ_EMPTY(&(dfs->dfs_eventq));
1916 ATH_DFSEVENTQ_UNLOCK(dfs);
1917 if (empty) {
1918 return 0;
1919 }
1920 /*
1921 * Add the event to the list, if there's space.
1922 */
1923 ATH_DFSEVENTQ_LOCK(dfs);
1924 event = STAILQ_FIRST(&(dfs->dfs_eventq));
1925 if (event == NULL) {
1926 ATH_DFSEVENTQ_UNLOCK(dfs);
1927 WMA_LOGE("%s: No more space left for queuing DFS Phyerror events",
1928 __func__);
1929 return 0;
1930 }
1931 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list);
1932 ATH_DFSEVENTQ_UNLOCK(dfs);
1933 dfs->dfs_phyerr_queued_count++;
1934 dfs->dfs_phyerr_w53_counter++;
1935 event->re_dur = (uint8_t) radar_event->pulse_duration;
1936 event->re_rssi = radar_event->rssi;
1937 event->re_ts = radar_event->pulse_detect_ts & DFS_TSMASK;
1938 event->re_full_ts = (((uint64_t) radar_event->upload_fullts_high) << 32)
1939 | radar_event->upload_fullts_low;
1940
1941 /*
1942 * Index of peak magnitude
1943 */
1944 event->sidx = radar_event->peak_sidx;
1945
1946 /*
1947 * Handle chirp flags.
1948 */
1949 if (do_check_chirp) {
1950 event->re_flags |= DFS_EVENT_CHECKCHIRP;
1951 if (is_hw_chirp) {
1952 event->re_flags |= DFS_EVENT_HW_CHIRP;
1953 }
1954 if (is_sw_chirp) {
1955 event->re_flags |= DFS_EVENT_SW_CHIRP;
1956 }
1957 }
1958 /*
1959 * Correctly set which channel is being reported on
1960 */
1961 if (is_pri) {
1962 event->re_chanindex = (uint8_t) dfs->dfs_curchan_radindex;
1963 } else {
1964 if (dfs->dfs_extchan_radindex == -1) {
1965 WMA_LOGI("%s phyerr on ext channel", __func__);
1966 }
1967 event->re_chanindex = (uint8_t) dfs->dfs_extchan_radindex;
1968 WMA_LOGI("%s:New extension channel event is added to queue",
1969 __func__);
1970 }
1971
1972 ATH_DFSQ_LOCK(dfs);
1973
1974 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list);
1975
1976 empty = STAILQ_EMPTY(&dfs->dfs_radarq);
1977
1978 ATH_DFSQ_UNLOCK(dfs);
1979
1980 if (!empty && !dfs->ath_radar_tasksched) {
1981 dfs->ath_radar_tasksched = 1;
1982 OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0);
1983 }
1984
1985 return 1;
1986
1987}
1988
1989/**
1990 * wma_unified_phyerr_rx_event_handler() - phyerr event handler
1991 * @handle: wma handle
1992 * @data: data buffer
1993 * @datalen: buffer length
1994 *
1995 * WMI Handler for WMI_PHYERR_EVENTID event from firmware.
1996 * This handler is currently handling only DFS phy errors.
1997 * This handler will be invoked only when the DFS phyerror
1998 * filtering offload is disabled.
1999 *
2000 * Return: 1:Success, 0:Failure
2001 */
2002static int wma_unified_phyerr_rx_event_handler(void *handle,
2003 uint8_t *data, uint32_t datalen)
2004{
2005 tp_wma_handle wma = (tp_wma_handle) handle;
2006 WMI_PHYERR_EVENTID_param_tlvs *param_tlvs;
2007 wmi_comb_phyerr_rx_hdr *pe_hdr;
2008 uint8_t *bufp;
2009 wmi_single_phyerr_rx_event *ev;
2010 struct ieee80211com *ic = wma->dfs_ic;
2011 cdf_size_t n;
2012 A_UINT64 tsf64 = 0;
2013 int phy_err_code = 0;
2014 int error = 0;
2015 tpAniSirGlobal mac_ctx =
2016 (tpAniSirGlobal)cds_get_context(CDF_MODULE_ID_PE);
2017 bool enable_log = false;
2018
2019 if (NULL == mac_ctx) {
2020 WMA_LOGE("%s: mac_ctx is NULL", __func__);
2021 return 0;
2022 }
2023 enable_log = mac_ctx->sap.enable_dfs_phy_error_logs;
2024
2025 param_tlvs = (WMI_PHYERR_EVENTID_param_tlvs *) data;
2026
2027 if (!param_tlvs) {
2028 WMA_LOGE("%s: Received NULL data from FW", __func__);
2029 return 0;
2030 }
2031
2032 pe_hdr = param_tlvs->hdr;
2033 if (pe_hdr == NULL) {
2034 WMA_LOGE("%s: Received Data PE Header is NULL", __func__);
2035 return 0;
2036 }
2037
2038 /* Ensure it's at least the size of the header */
2039 if (datalen < sizeof(*pe_hdr)) {
2040 WMA_LOGE("%s: Expected minimum size %zu, received %d",
2041 __func__, sizeof(*pe_hdr), datalen);
2042 return 0;
2043 }
2044 if (pe_hdr->buf_len > DFS_MAX_BUF_LENGHT) {
2045 WMA_LOGE("%s: Received Invalid Phyerror event buffer length = %d"
2046 "Maximum allowed buf length = %d", __func__,
2047 pe_hdr->buf_len, DFS_MAX_BUF_LENGHT);
2048
2049 return 0;
2050 }
2051
2052 /*
2053 * Reconstruct the 64 bit event TSF. This isn't from the MAC, it's
2054 * at the time the event was sent to us, the TSF value will be
2055 * in the future.
2056 */
2057 tsf64 = pe_hdr->tsf_l32;
2058 tsf64 |= (((uint64_t) pe_hdr->tsf_u32) << 32);
2059
2060 /*
2061 * Loop over the bufp, extracting out phyerrors
2062 * wmi_unified_comb_phyerr_rx_event.bufp is a char pointer,
2063 * which isn't correct here - what we have received here
2064 * is an array of TLV-style PHY errors.
2065 */
2066 n = 0; /* Start just after the header */
2067 bufp = param_tlvs->bufp;
2068 while (n < pe_hdr->buf_len) {
2069 /* ensure there's at least space for the header */
2070 if ((pe_hdr->buf_len - n) < sizeof(ev->hdr)) {
2071 WMA_LOGE("%s: Not enough space.(datalen=%d, n=%zu, hdr=%zu bytes",
2072 __func__, pe_hdr->buf_len, n, sizeof(ev->hdr));
2073 error = 1;
2074 break;
2075 }
2076 /*
2077 * Obtain a pointer to the beginning of the current event.
2078 * data[0] is the beginning of the WMI payload.
2079 */
2080 ev = (wmi_single_phyerr_rx_event *) &bufp[n];
2081
2082 /*
2083 * Sanity check the buffer length of the event against
2084 * what we currently have.
2085 * Since buf_len is 32 bits, we check if it overflows
2086 * a large 32 bit value. It's not 0x7fffffff because
2087 * we increase n by (buf_len + sizeof(hdr)), which would
2088 * in itself cause n to overflow.
2089 * If "int" is 64 bits then this becomes a moot point.
2090 */
2091 if (ev->hdr.buf_len > 0x7f000000) {
2092 WMA_LOGE("%s:buf_len is garbage (0x%x)", __func__,
2093 ev->hdr.buf_len);
2094 error = 1;
2095 break;
2096 }
2097 if (n + ev->hdr.buf_len > pe_hdr->buf_len) {
2098 WMA_LOGE("%s: buf_len exceeds available space n=%zu,"
2099 "buf_len=%d, datalen=%d",
2100 __func__, n, ev->hdr.buf_len, pe_hdr->buf_len);
2101 error = 1;
2102 break;
2103 }
2104 phy_err_code = WMI_UNIFIED_PHYERRCODE_GET(&ev->hdr);
2105
2106 /*
2107 * If the phyerror category matches,
2108 * pass radar events to the dfs pattern matching code.
2109 * Don't pass radar events with no buffer payload.
2110 */
2111 if (phy_err_code == 0x5 || phy_err_code == 0x24) {
2112 if (ev->hdr.buf_len > 0) {
2113 /* Calling in to the DFS module to process the phyerr */
2114 dfs_process_phyerr(ic, &ev->bufp[0],
2115 ev->hdr.buf_len,
2116 WMI_UNIFIED_RSSI_COMB_GET
2117 (&ev->hdr) & 0xff,
2118 /* Extension RSSI */
2119 WMI_UNIFIED_RSSI_COMB_GET
2120 (&ev->hdr) & 0xff,
2121 ev->hdr.tsf_timestamp,
2122 tsf64, enable_log);
2123 }
2124 }
2125
2126 /*
2127 * Advance the buffer pointer to the next PHY error.
2128 * buflen is the length of this payload, so we need to
2129 * advance past the current header _AND_ the payload.
2130 */
2131 n += sizeof(*ev) + ev->hdr.buf_len;
2132
2133 } /*end while() */
2134 if (error)
2135 return 0;
2136 else
2137 return 1;
2138}
2139
2140/**
2141 * wma_register_dfs_event_handler() - register dfs event handler
2142 * @wma_handle: wma handle
2143 *
2144 * Register appropriate dfs phyerror event handler
2145 * based on phyerror filtering offload is enabled
2146 * or disabled.
2147 *
2148 * Return: none
2149 */
2150void wma_register_dfs_event_handler(tp_wma_handle wma_handle)
2151{
2152 if (NULL == wma_handle) {
2153 WMA_LOGE("%s:wma_handle is NULL", __func__);
2154 return;
2155 }
2156
2157 if (false == wma_handle->dfs_phyerr_filter_offload) {
2158 /*
2159 * Register the wma_unified_phyerr_rx_event_handler
2160 * for filtering offload disabled case to handle
2161 * the DFS phyerrors.
2162 */
2163 WMA_LOGD("%s:Phyerror Filtering offload is Disabled in ini",
2164 __func__);
2165 wmi_unified_register_event_handler(wma_handle->wmi_handle,
2166 WMI_PHYERR_EVENTID,
2167 wma_unified_phyerr_rx_event_handler);
2168 WMA_LOGD("%s: WMI_PHYERR_EVENTID event handler registered",
2169 __func__);
2170 } else {
2171 WMA_LOGD("%s:Phyerror Filtering offload is Enabled in ini",
2172 __func__);
2173 wmi_unified_register_event_handler(wma_handle->wmi_handle,
2174 WMI_DFS_RADAR_EVENTID,
2175 wma_unified_dfs_radar_rx_event_handler);
2176 WMA_LOGD("%s:WMI_DFS_RADAR_EVENTID event handler registered",
2177 __func__);
2178 }
2179
2180 return;
2181}
2182
2183
2184/**
2185 * wma_unified_dfs_phyerr_filter_offload_enable() - enable dfs phyerr filter
2186 * @wma_handle: wma handle
2187 *
2188 * Send WMI_DFS_PHYERR_FILTER_ENA_CMDID or
2189 * WMI_DFS_PHYERR_FILTER_DIS_CMDID command
2190 * to firmware based on phyerr filtering
2191 * offload status.
2192 *
2193 * Return: 1 success, 0 failure
2194 */
2195int
2196wma_unified_dfs_phyerr_filter_offload_enable(tp_wma_handle wma_handle)
2197{
2198 wmi_dfs_phyerr_filter_ena_cmd_fixed_param *enable_phyerr_offload_cmd;
2199 wmi_dfs_phyerr_filter_dis_cmd_fixed_param *disable_phyerr_offload_cmd;
2200 wmi_buf_t buf;
2201 uint16_t len;
2202 int ret;
2203
2204 if (NULL == wma_handle) {
2205 WMA_LOGE("%s:wma_handle is NULL", __func__);
2206 return 0;
2207 }
2208
2209 if (false == wma_handle->dfs_phyerr_filter_offload) {
2210 WMA_LOGD("%s:Phyerror Filtering offload is Disabled in ini",
2211 __func__);
2212 len = sizeof(*disable_phyerr_offload_cmd);
2213 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
2214 if (!buf) {
2215 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
2216 return 0;
2217 }
2218 disable_phyerr_offload_cmd =
2219 (wmi_dfs_phyerr_filter_dis_cmd_fixed_param *)
2220 wmi_buf_data(buf);
2221
2222 WMITLV_SET_HDR(&disable_phyerr_offload_cmd->tlv_header,
2223 WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param,
2224 WMITLV_GET_STRUCT_TLVLEN
2225 (wmi_dfs_phyerr_filter_dis_cmd_fixed_param));
2226
2227 /*
2228 * Send WMI_DFS_PHYERR_FILTER_DIS_CMDID
2229 * to the firmware to disable the phyerror
2230 * filtering offload.
2231 */
2232 ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
2233 WMI_DFS_PHYERR_FILTER_DIS_CMDID);
2234 if (ret < 0) {
2235 WMA_LOGE("%s: Failed to send WMI_DFS_PHYERR_FILTER_DIS_CMDID ret=%d",
2236 __func__, ret);
2237 wmi_buf_free(buf);
2238 return 0;
2239 }
2240 WMA_LOGD("%s: WMI_DFS_PHYERR_FILTER_DIS_CMDID Send Success",
2241 __func__);
2242 } else {
2243 WMA_LOGD("%s:Phyerror Filtering offload is Enabled in ini",
2244 __func__);
2245
2246 len = sizeof(*enable_phyerr_offload_cmd);
2247 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
2248 if (!buf) {
2249 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
2250 return 0;
2251 }
2252
2253 enable_phyerr_offload_cmd =
2254 (wmi_dfs_phyerr_filter_ena_cmd_fixed_param *)
2255 wmi_buf_data(buf);
2256
2257 WMITLV_SET_HDR(&enable_phyerr_offload_cmd->tlv_header,
2258 WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param,
2259 WMITLV_GET_STRUCT_TLVLEN
2260 (wmi_dfs_phyerr_filter_ena_cmd_fixed_param));
2261
2262 /*
2263 * Send a WMI_DFS_PHYERR_FILTER_ENA_CMDID
2264 * to the firmware to enable the phyerror
2265 * filtering offload.
2266 */
2267 ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
2268 WMI_DFS_PHYERR_FILTER_ENA_CMDID);
2269
2270 if (ret < 0) {
2271 WMA_LOGE("%s: Failed to send WMI_DFS_PHYERR_FILTER_ENA_CMDID ret=%d",
2272 __func__, ret);
2273 wmi_buf_free(buf);
2274 return 0;
2275 }
2276 WMA_LOGD("%s: WMI_DFS_PHYERR_FILTER_ENA_CMDID Send Success",
2277 __func__);
2278 }
2279
2280 return 1;
2281}
2282
2283#if !defined(REMOVE_PKT_LOG)
2284/**
2285 * wma_pktlog_wmi_send_cmd() - send pktlog enable/disable command to target
2286 * @handle: wma handle
2287 * @params: pktlog params
2288 *
2289 * Return: CDF status
2290 */
2291CDF_STATUS wma_pktlog_wmi_send_cmd(WMA_HANDLE handle,
2292 struct ath_pktlog_wmi_params *params)
2293{
2294 tp_wma_handle wma_handle = (tp_wma_handle) handle;
2295 WMI_PKTLOG_EVENT PKTLOG_EVENT;
2296 WMI_CMD_ID CMD_ID;
2297 wmi_pdev_pktlog_enable_cmd_fixed_param *cmd;
2298 wmi_pdev_pktlog_disable_cmd_fixed_param *disable_cmd;
2299 int len = 0;
2300 wmi_buf_t buf;
2301
2302 /*Check if packet log is enabled in cfg.ini */
2303 if (!cds_is_packet_log_enabled()) {
2304 WMA_LOGE("%s:pkt log is not enabled in cfg.ini", __func__);
2305 return CDF_STATUS_E_FAILURE;
2306 }
2307
2308 PKTLOG_EVENT = params->pktlog_event;
2309 CMD_ID = params->cmd_id;
2310
2311 switch (CMD_ID) {
2312 case WMI_PDEV_PKTLOG_ENABLE_CMDID:
2313 len = sizeof(*cmd);
2314 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
2315 if (!buf) {
2316 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
2317 return CDF_STATUS_E_NOMEM;
2318 }
2319 cmd = (wmi_pdev_pktlog_enable_cmd_fixed_param *)
2320 wmi_buf_data(buf);
2321 WMITLV_SET_HDR(&cmd->tlv_header,
2322 WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param,
2323 WMITLV_GET_STRUCT_TLVLEN
2324 (wmi_pdev_pktlog_enable_cmd_fixed_param));
2325 cmd->evlist = PKTLOG_EVENT;
2326 if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
2327 WMI_PDEV_PKTLOG_ENABLE_CMDID)) {
2328 WMA_LOGE("failed to send pktlog enable cmdid");
2329 goto wmi_send_failed;
2330 }
2331 break;
2332 case WMI_PDEV_PKTLOG_DISABLE_CMDID:
2333 len = sizeof(*disable_cmd);
2334 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
2335 if (!buf) {
2336 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
2337 return CDF_STATUS_E_NOMEM;
2338 }
2339 disable_cmd = (wmi_pdev_pktlog_disable_cmd_fixed_param *)
2340 wmi_buf_data(buf);
2341 WMITLV_SET_HDR(&disable_cmd->tlv_header,
2342 WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param,
2343 WMITLV_GET_STRUCT_TLVLEN
2344 (wmi_pdev_pktlog_disable_cmd_fixed_param));
2345 disable_cmd->reserved0 = 0;
2346 if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
2347 WMI_PDEV_PKTLOG_DISABLE_CMDID)) {
2348 WMA_LOGE("failed to send pktlog disable cmdid");
2349 goto wmi_send_failed;
2350 }
2351 break;
2352 default:
2353 WMA_LOGD("%s: invalid PKTLOG command", __func__);
2354 break;
2355 }
2356
2357 return CDF_STATUS_SUCCESS;
2358
2359wmi_send_failed:
2360 wmi_buf_free(buf);
2361 return CDF_STATUS_E_FAILURE;
2362}
2363#endif /* REMOVE_PKT_LOG */
2364
2365static void wma_send_status_to_suspend_ind(tp_wma_handle wma, bool suspended)
2366{
2367 tSirReadyToSuspendInd *ready_to_suspend;
2368 CDF_STATUS status;
2369 cds_msg_t cds_msg;
2370 uint8_t len;
2371
2372 WMA_LOGD("Posting ready to suspend indication to umac");
2373
2374 len = sizeof(tSirReadyToSuspendInd);
2375 ready_to_suspend = (tSirReadyToSuspendInd *) cdf_mem_malloc(len);
2376
2377 if (NULL == ready_to_suspend) {
2378 WMA_LOGE("%s: Memory allocation failure", __func__);
2379 return;
2380 }
2381
2382 ready_to_suspend->mesgType = eWNI_SME_READY_TO_SUSPEND_IND;
2383 ready_to_suspend->mesgLen = len;
2384 ready_to_suspend->suspended = suspended;
2385
2386 cds_msg.type = eWNI_SME_READY_TO_SUSPEND_IND;
2387 cds_msg.bodyptr = (void *)ready_to_suspend;
2388 cds_msg.bodyval = 0;
2389
2390 status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg);
2391 if (status != CDF_STATUS_SUCCESS) {
2392 WMA_LOGE("Failed to post ready to suspend");
2393 cdf_mem_free(ready_to_suspend);
2394 }
2395}
2396
2397/**
2398 * wma_wow_wake_reason_str() - Converts wow wakeup reason code to text format
2399 * @wake_reason - WOW wake reason
2400 *
2401 * Return: reason code in string format
2402 */
2403static const u8 *wma_wow_wake_reason_str(A_INT32 wake_reason)
2404{
2405 switch (wake_reason) {
2406 case WOW_REASON_UNSPECIFIED:
2407 return "UNSPECIFIED";
2408 case WOW_REASON_NLOD:
2409 return "NLOD";
2410 case WOW_REASON_AP_ASSOC_LOST:
2411 return "AP_ASSOC_LOST";
2412 case WOW_REASON_LOW_RSSI:
2413 return "LOW_RSSI";
2414 case WOW_REASON_DEAUTH_RECVD:
2415 return "DEAUTH_RECVD";
2416 case WOW_REASON_DISASSOC_RECVD:
2417 return "DISASSOC_RECVD";
2418 case WOW_REASON_GTK_HS_ERR:
2419 return "GTK_HS_ERR";
2420 case WOW_REASON_EAP_REQ:
2421 return "EAP_REQ";
2422 case WOW_REASON_FOURWAY_HS_RECV:
2423 return "FOURWAY_HS_RECV";
2424 case WOW_REASON_TIMER_INTR_RECV:
2425 return "TIMER_INTR_RECV";
2426 case WOW_REASON_PATTERN_MATCH_FOUND:
2427 return "PATTERN_MATCH_FOUND";
2428 case WOW_REASON_RECV_MAGIC_PATTERN:
2429 return "RECV_MAGIC_PATTERN";
2430 case WOW_REASON_P2P_DISC:
2431 return "P2P_DISC";
2432#ifdef FEATURE_WLAN_LPHB
2433 case WOW_REASON_WLAN_HB:
2434 return "WLAN_HB";
2435#endif /* FEATURE_WLAN_LPHB */
2436
2437 case WOW_REASON_CSA_EVENT:
2438 return "CSA_EVENT";
2439 case WOW_REASON_PROBE_REQ_WPS_IE_RECV:
2440 return "PROBE_REQ_RECV";
2441 case WOW_REASON_AUTH_REQ_RECV:
2442 return "AUTH_REQ_RECV";
2443 case WOW_REASON_ASSOC_REQ_RECV:
2444 return "ASSOC_REQ_RECV";
2445 case WOW_REASON_HTT_EVENT:
2446 return "WOW_REASON_HTT_EVENT";
2447#ifdef FEATURE_WLAN_RA_FILTERING
2448 case WOW_REASON_RA_MATCH:
2449 return "WOW_REASON_RA_MATCH";
2450#endif /* FEATURE_WLAN_RA_FILTERING */
2451 case WOW_REASON_BEACON_RECV:
2452 return "WOW_REASON_IBSS_BEACON_RECV";
2453#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
2454 case WOW_REASON_HOST_AUTO_SHUTDOWN:
2455 return "WOW_REASON_HOST_AUTO_SHUTDOWN";
2456#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */
2457#ifdef WLAN_FEATURE_ROAM_OFFLOAD
2458 case WOW_REASON_ROAM_HO:
2459 return "WOW_REASON_ROAM_HO";
2460#endif /* WLAN_FEATURE_ROAM_OFFLOAD */
2461#ifdef FEATURE_WLAN_EXTSCAN
2462 case WOW_REASON_EXTSCAN:
2463 return "WOW_REASON_EXTSCAN";
2464#endif
2465 case WOW_REASON_RSSI_BREACH_EVENT:
2466 return "WOW_REASON_RSSI_BREACH_EVENT";
2467 }
2468 return "unknown";
2469}
2470
2471/**
2472 * wma_wow_wake_up_stats_display() - display wow wake up stats
2473 * @wma: Pointer to wma handle
2474 *
2475 * Return: none
2476 */
2477static void wma_wow_wake_up_stats_display(tp_wma_handle wma)
2478{
2479 WMA_LOGA("uc %d bc %d v4_mc %d v6_mc %d ra %d ns %d na %d pno_match %d pno_complete %d gscan %d low_rssi %d rssi_breach %d",
2480 wma->wow_ucast_wake_up_count,
2481 wma->wow_bcast_wake_up_count,
2482 wma->wow_ipv4_mcast_wake_up_count,
2483 wma->wow_ipv6_mcast_wake_up_count,
2484 wma->wow_ipv6_mcast_ra_stats,
2485 wma->wow_ipv6_mcast_ns_stats,
2486 wma->wow_ipv6_mcast_na_stats,
2487 wma->wow_pno_match_wake_up_count,
2488 wma->wow_pno_complete_wake_up_count,
2489 wma->wow_gscan_wake_up_count,
2490 wma->wow_low_rssi_wake_up_count,
2491 wma->wow_rssi_breach_wake_up_count);
2492
2493 return;
2494}
2495
2496/**
2497 * wma_wow_ipv6_mcast_stats() - ipv6 mcast wake up stats
2498 * @wma: Pointer to wma handle
2499 * @data: Pointer to pattern match data
2500 *
2501 * Return: none
2502 */
2503static void wma_wow_ipv6_mcast_stats(tp_wma_handle wma, uint8_t *data)
2504{
2505 static const uint8_t ipv6_mcast[] = {0x86, 0xDD};
2506
2507 if (!memcmp(ipv6_mcast, (data + WMA_ETHER_TYPE_OFFSET),
2508 sizeof(ipv6_mcast))) {
2509 if (WMA_ICMP_V6_HEADER_TYPE ==
2510 *(data + WMA_ICMP_V6_HEADER_OFFSET)) {
2511 if (WMA_ICMP_V6_RA_TYPE ==
2512 *(data + WMA_ICMP_V6_TYPE_OFFSET))
2513 wma->wow_ipv6_mcast_ra_stats++;
2514 else if (WMA_ICMP_V6_NS_TYPE ==
2515 *(data + WMA_ICMP_V6_TYPE_OFFSET))
2516 wma->wow_ipv6_mcast_ns_stats++;
2517 else if (WMA_ICMP_V6_NA_TYPE ==
2518 *(data + WMA_ICMP_V6_TYPE_OFFSET))
2519 wma->wow_ipv6_mcast_na_stats++;
2520 else
2521 WMA_LOGA("ICMP V6 type : 0x%x",
2522 *(data + WMA_ICMP_V6_TYPE_OFFSET));
2523 } else {
2524 WMA_LOGA("ICMP_V6 header 0x%x",
2525 *(data + WMA_ICMP_V6_HEADER_OFFSET));
2526 }
2527 } else {
2528 WMA_LOGA("Ethertype x%x:0x%x",
2529 *(data + WMA_ETHER_TYPE_OFFSET),
2530 *(data + WMA_ETHER_TYPE_OFFSET + 1));
2531 }
2532
2533 return;
2534}
2535
2536/**
2537 * wma_wow_wake_up_stats() - maintain wow pattern match wake up stats
2538 * @wma: Pointer to wma handle
2539 * @data: Pointer to pattern match data
2540 * @len: Pattern match data length
2541 * @event: Wake up event
2542 *
2543 * Return: none
2544 */
2545static void wma_wow_wake_up_stats(tp_wma_handle wma, uint8_t *data,
2546 int32_t len, WOW_WAKE_REASON_TYPE event)
2547{
2548 switch (event) {
2549
2550 case WOW_REASON_PATTERN_MATCH_FOUND:
2551 if (WMA_BCAST_MAC_ADDR == *data) {
2552 wma->wow_bcast_wake_up_count++;
2553 } else if (WMA_MCAST_IPV4_MAC_ADDR == *data) {
2554 wma->wow_ipv4_mcast_wake_up_count++;
2555 } else if (WMA_MCAST_IPV6_MAC_ADDR == *data) {
2556 wma->wow_ipv6_mcast_wake_up_count++;
2557 if (len > WMA_ICMP_V6_TYPE_OFFSET)
2558 wma_wow_ipv6_mcast_stats(wma, data);
2559 else
2560 WMA_LOGA("ICMP_V6 data len %d", len);
2561 } else {
2562 wma->wow_ucast_wake_up_count++;
2563 }
2564 break;
2565
2566 case WOW_REASON_RA_MATCH:
2567 wma->wow_ipv6_mcast_ra_stats++;
2568 break;
2569
2570 case WOW_REASON_NLOD:
2571 wma->wow_pno_match_wake_up_count++;
2572 break;
2573
2574 case WOW_REASON_NLO_SCAN_COMPLETE:
2575 wma->wow_pno_complete_wake_up_count++;
2576 break;
2577
2578 case WOW_REASON_LOW_RSSI:
2579 wma->wow_low_rssi_wake_up_count++;
2580 break;
2581
2582 case WOW_REASON_EXTSCAN:
2583 wma->wow_gscan_wake_up_count++;
2584 break;
2585
2586 case WOW_REASON_RSSI_BREACH_EVENT:
2587 wma->wow_rssi_breach_wake_up_count++;
2588 break;
2589
2590 default:
2591 WMA_LOGE("Unknown wake up reason");
2592 break;
2593 }
2594
2595 wma_wow_wake_up_stats_display(wma);
2596 return;
2597}
2598
2599/**
2600 * wma_wow_wakeup_host_event() - wakeup host event handler
2601 * @handle: wma handle
2602 * @event: event data
2603 * @len: buffer length
2604 *
2605 * Handler to catch wow wakeup host event. This event will have
2606 * reason why the firmware has woken the host.
2607 *
2608 * Return: 0 for success or error
2609 */
2610int wma_wow_wakeup_host_event(void *handle, uint8_t *event,
2611 uint32_t len)
2612{
2613 tp_wma_handle wma = (tp_wma_handle) handle;
2614 WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *param_buf;
2615 WOW_EVENT_INFO_fixed_param *wake_info;
2616#ifdef FEATURE_WLAN_SCAN_PNO
2617 struct wma_txrx_node *node;
2618#endif /* FEATURE_WLAN_SCAN_PNO */
2619 uint32_t wake_lock_duration = 0;
2620 uint32_t wow_buf_pkt_len = 0;
2621
2622 param_buf = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *) event;
2623 if (!param_buf) {
2624 WMA_LOGE("Invalid wow wakeup host event buf");
2625 return -EINVAL;
2626 }
2627
2628 wake_info = param_buf->fixed_param;
2629
2630 WMA_LOGA("WOW wakeup host event received (reason: %s(%d)) for vdev %d",
2631 wma_wow_wake_reason_str(wake_info->wake_reason),
2632 wake_info->wake_reason, wake_info->vdev_id);
2633
2634 cdf_event_set(&wma->wma_resume_event);
2635
2636 switch (wake_info->wake_reason) {
2637 case WOW_REASON_AUTH_REQ_RECV:
2638 wake_lock_duration = WMA_AUTH_REQ_RECV_WAKE_LOCK_TIMEOUT;
2639 break;
2640
2641 case WOW_REASON_ASSOC_REQ_RECV:
2642 wake_lock_duration = WMA_ASSOC_REQ_RECV_WAKE_LOCK_DURATION;
2643 break;
2644
2645 case WOW_REASON_DEAUTH_RECVD:
2646 wake_lock_duration = WMA_DEAUTH_RECV_WAKE_LOCK_DURATION;
2647 break;
2648
2649 case WOW_REASON_DISASSOC_RECVD:
2650 wake_lock_duration = WMA_DISASSOC_RECV_WAKE_LOCK_DURATION;
2651 break;
2652
2653 case WOW_REASON_AP_ASSOC_LOST:
2654 wake_lock_duration = WMA_BMISS_EVENT_WAKE_LOCK_DURATION;
2655 WMA_LOGA("Beacon miss indication on vdev %x",
2656 wake_info->vdev_id);
2657 wma_beacon_miss_handler(wma, wake_info->vdev_id);
2658 break;
2659#ifdef FEATURE_WLAN_RA_FILTERING
2660 case WOW_REASON_RA_MATCH:
2661 wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_RA_MATCH);
2662 break;
2663#endif /* FEATURE_WLAN_RA_FILTERING */
2664#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
2665 case WOW_REASON_HOST_AUTO_SHUTDOWN:
2666 wake_lock_duration = WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION;
2667 WMA_LOGA("Received WOW Auto Shutdown trigger in suspend");
2668 if (wma_post_auto_shutdown_msg())
2669 return -EINVAL;
2670 break;
2671#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */
2672#ifdef FEATURE_WLAN_SCAN_PNO
2673 case WOW_REASON_NLOD:
2674 wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_NLOD);
2675 node = &wma->interfaces[wake_info->vdev_id];
2676 if (node) {
2677 WMA_LOGD("NLO match happened");
2678 node->nlo_match_evt_received = true;
2679 cdf_wake_lock_timeout_acquire(&wma->pno_wake_lock,
2680 WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT,
2681 WIFI_POWER_EVENT_WAKELOCK_PNO);
2682 }
2683 break;
2684#endif /* FEATURE_WLAN_SCAN_PNO */
2685
2686 case WOW_REASON_CSA_EVENT:
2687 {
2688 WMI_CSA_HANDLING_EVENTID_param_tlvs param;
2689 WMA_LOGD("Host woken up because of CSA IE");
2690 param.fixed_param = (wmi_csa_event_fixed_param *)
2691 (((uint8_t *) wake_info)
2692 + sizeof(WOW_EVENT_INFO_fixed_param)
2693 + WOW_CSA_EVENT_OFFSET);
2694 wma_csa_offload_handler(handle, (uint8_t *) &param,
2695 sizeof(param));
2696 }
2697 break;
2698
2699#ifdef FEATURE_WLAN_LPHB
2700 case WOW_REASON_WLAN_HB:
2701 wma_lphb_handler(wma, (uint8_t *) param_buf->hb_indevt);
2702 break;
2703#endif /* FEATURE_WLAN_LPHB */
2704
2705 case WOW_REASON_HTT_EVENT:
2706 break;
2707 case WOW_REASON_PATTERN_MATCH_FOUND:
2708 wma_wow_wake_up_stats_display(wma);
2709 WMA_LOGD("Wake up for Rx packet, dump starting from ethernet hdr");
2710 if (param_buf->wow_packet_buffer) {
2711 /* First 4-bytes of wow_packet_buffer is the length */
2712 cdf_mem_copy((uint8_t *) &wow_buf_pkt_len,
2713 param_buf->wow_packet_buffer, 4);
2714 wma_wow_wake_up_stats(wma,
2715 param_buf->wow_packet_buffer + 4,
2716 wow_buf_pkt_len,
2717 WOW_REASON_PATTERN_MATCH_FOUND);
2718 cdf_trace_hex_dump(CDF_MODULE_ID_WMA,
2719 CDF_TRACE_LEVEL_DEBUG,
2720 param_buf->wow_packet_buffer + 4,
2721 wow_buf_pkt_len);
2722 } else {
2723 WMA_LOGE("No wow packet buffer present");
2724 }
2725 break;
2726
2727 case WOW_REASON_LOW_RSSI:
2728 {
2729 /* WOW_REASON_LOW_RSSI is used for all roaming events.
2730 * WMI_ROAM_REASON_BETTER_AP, WMI_ROAM_REASON_BMISS,
2731 * WMI_ROAM_REASON_SUITABLE_AP will be handled by
2732 * wma_roam_event_callback().
2733 */
2734 WMI_ROAM_EVENTID_param_tlvs param;
2735 wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_LOW_RSSI);
2736 if (param_buf->wow_packet_buffer) {
2737 /* Roam event is embedded in wow_packet_buffer */
2738 WMA_LOGD("Host woken up because of roam event");
2739 cdf_mem_copy((uint8_t *) &wow_buf_pkt_len,
2740 param_buf->wow_packet_buffer, 4);
2741 WMA_LOGD("wow_packet_buffer dump");
2742 cdf_trace_hex_dump(CDF_MODULE_ID_WMA,
2743 CDF_TRACE_LEVEL_DEBUG,
2744 param_buf->wow_packet_buffer,
2745 wow_buf_pkt_len);
2746 if (wow_buf_pkt_len >= sizeof(param)) {
2747 param.fixed_param =
2748 (wmi_roam_event_fixed_param *)
2749 (param_buf->wow_packet_buffer + 4);
2750 wma_roam_event_callback(handle,
2751 (uint8_t *) &
2752 param,
2753 sizeof(param));
2754 } else {
2755 WMA_LOGE("Wrong length for roam event = %d bytes",
2756 wow_buf_pkt_len);
2757 }
2758 } else {
2759 /* No wow_packet_buffer means a better AP beacon
2760 * will follow in a later event.
2761 */
2762 WMA_LOGD("Host woken up because of better AP beacon");
2763 }
2764 break;
2765 }
2766 case WOW_REASON_CLIENT_KICKOUT_EVENT:
2767 {
2768 WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs param;
2769 if (param_buf->wow_packet_buffer) {
2770 /* station kickout event embedded in wow_packet_buffer */
2771 WMA_LOGD("Host woken up because of sta_kickout event");
2772 cdf_mem_copy((u_int8_t *) &wow_buf_pkt_len,
2773 param_buf->wow_packet_buffer, 4);
2774 WMA_LOGD("wow_packet_buffer dump");
2775 cdf_trace_hex_dump(CDF_MODULE_ID_WMA,
2776 CDF_TRACE_LEVEL_DEBUG,
2777 param_buf->wow_packet_buffer, wow_buf_pkt_len);
2778 if (wow_buf_pkt_len >= sizeof(param)) {
2779 param.fixed_param = (wmi_peer_sta_kickout_event_fixed_param *)
2780 (param_buf->wow_packet_buffer + 4);
2781 wma_peer_sta_kickout_event_handler(handle,
2782 (u_int8_t *)&param, sizeof(param));
2783 } else {
2784 WMA_LOGE("Wrong length for sta_kickout event = %d bytes",
2785 wow_buf_pkt_len);
2786 }
2787 } else {
2788 WMA_LOGD("No wow_packet_buffer present");
2789 }
2790 break;
2791 }
2792#ifdef FEATURE_WLAN_EXTSCAN
2793 case WOW_REASON_EXTSCAN:
2794 WMA_LOGD("Host woken up because of extscan reason");
2795 wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_EXTSCAN);
2796 if (param_buf->wow_packet_buffer) {
2797 wow_buf_pkt_len =
2798 *(uint32_t *)param_buf->wow_packet_buffer;
2799 wma_extscan_wow_event_callback(handle,
2800 (u_int8_t *)(param_buf->wow_packet_buffer + 4),
2801 wow_buf_pkt_len);
2802 } else
2803 WMA_LOGE("wow_packet_buffer is empty");
2804 break;
2805#endif
2806 case WOW_REASON_RSSI_BREACH_EVENT:
2807 {
2808 WMI_RSSI_BREACH_EVENTID_param_tlvs param;
2809
2810 wma_wow_wake_up_stats(wma, NULL, 0,
2811 WOW_REASON_RSSI_BREACH_EVENT);
2812 WMA_LOGD("Host woken up because of rssi breach reason");
2813 /* rssi breach event is embedded in wow_packet_buffer */
2814 if (param_buf->wow_packet_buffer) {
2815 cdf_mem_copy((u_int8_t *) &wow_buf_pkt_len,
2816 param_buf->wow_packet_buffer, 4);
2817 if (wow_buf_pkt_len >= sizeof(param)) {
2818 param.fixed_param =
2819 (wmi_rssi_breach_event_fixed_param *)
2820 (param_buf->wow_packet_buffer + 4);
2821 wma_rssi_breached_event_handler(handle,
2822 (u_int8_t *)&param,
2823 sizeof(param));
2824 } else {
2825 WMA_LOGE("%s: Wrong length: %d bytes",
2826 __func__, wow_buf_pkt_len);
2827 }
2828 } else
2829 WMA_LOGD("No wow_packet_buffer present");
2830 }
2831 break;
2832 default:
2833 break;
2834 }
2835
2836 if (wake_lock_duration) {
2837 cdf_wake_lock_timeout_acquire(&wma->wow_wake_lock,
2838 wake_lock_duration,
2839 WIFI_POWER_EVENT_WAKELOCK_WOW);
2840 WMA_LOGA("Holding %d msec wake_lock", wake_lock_duration);
2841 }
2842
2843 return 0;
2844}
2845
2846/**
2847 * wma_pdev_resume_event_handler() - PDEV resume event handler
2848 * @handle: wma handle
2849 * @event: event data
2850 * @len: buffer length
2851 *
2852 * Return: 0 for success or error
2853 */
2854int wma_pdev_resume_event_handler(void *handle, uint8_t *event, uint32_t len)
2855{
2856 tp_wma_handle wma = (tp_wma_handle) handle;
2857
2858 WMA_LOGA("Received PDEV resume event");
2859
2860 cdf_event_set(&wma->wma_resume_event);
2861
2862 return 0;
2863}
2864/**
2865 * wma_set_wow_bus_suspend() - set suspend flag
2866 * @wma: wma handle
2867 * @val: value
2868 *
2869 * Return: none
2870 */
2871static inline void wma_set_wow_bus_suspend(tp_wma_handle wma, int val)
2872{
2873
2874 cdf_atomic_set(&wma->is_wow_bus_suspended, val);
2875}
2876
2877
2878
2879/**
2880 * wma_add_wow_wakeup_event() - Configures wow wakeup events.
2881 * @wma: wma handle
2882 * @vdev_id: vdev id
2883 * @bitmap: Event bitmap
2884 * @enable: enable/disable
2885 *
2886 * Return: CDF status
2887 */
2888static CDF_STATUS wma_add_wow_wakeup_event(tp_wma_handle wma,
2889 uint32_t vdev_id,
2890 uint32_t bitmap,
2891 bool enable)
2892{
2893 WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *cmd;
2894 uint16_t len;
2895 wmi_buf_t buf;
2896 int ret;
2897
2898 len = sizeof(WMI_WOW_ADD_DEL_EVT_CMD_fixed_param);
2899 buf = wmi_buf_alloc(wma->wmi_handle, len);
2900 if (!buf) {
2901 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
2902 return CDF_STATUS_E_NOMEM;
2903 }
2904 cmd = (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *) wmi_buf_data(buf);
2905 WMITLV_SET_HDR(&cmd->tlv_header,
2906 WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param,
2907 WMITLV_GET_STRUCT_TLVLEN
2908 (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param));
2909 cmd->vdev_id = vdev_id;
2910 cmd->is_add = enable;
2911 cmd->event_bitmap = bitmap;
2912
2913 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
2914 WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID);
2915 if (ret) {
2916 WMA_LOGE("Failed to config wow wakeup event");
2917 wmi_buf_free(buf);
2918 return CDF_STATUS_E_FAILURE;
2919 }
2920
2921 WMA_LOGD("Wakeup pattern 0x%x %s in fw", bitmap,
2922 enable ? "enabled" : "disabled");
2923
2924 return CDF_STATUS_SUCCESS;
2925}
2926
2927/**
2928 * wma_send_wow_patterns_to_fw() - Sends WOW patterns to FW.
2929 * @wma: wma handle
2930 * @vdev_id: vdev id
2931 * @ptrn_id: pattern id
2932 * @ptrn: pattern
2933 * @ptrn_len: pattern length
2934 * @ptrn_offset: pattern offset
2935 * @mask: mask
2936 * @mask_len: mask length
2937 * @user: true for user configured pattern and false for default pattern
2938 *
2939 * Return: CDF status
2940 */
2941static CDF_STATUS wma_send_wow_patterns_to_fw(tp_wma_handle wma,
2942 uint8_t vdev_id, uint8_t ptrn_id,
2943 const uint8_t *ptrn, uint8_t ptrn_len,
2944 uint8_t ptrn_offset, const uint8_t *mask,
2945 uint8_t mask_len, bool user)
2946{
2947 WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd;
2948 WOW_BITMAP_PATTERN_T *bitmap_pattern;
2949 struct wma_txrx_node *iface;
2950 wmi_buf_t buf;
2951 uint8_t *buf_ptr;
2952 int32_t len;
2953 int ret;
2954
2955 iface = &wma->interfaces[vdev_id];
2956
2957 len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) +
2958 WMI_TLV_HDR_SIZE +
2959 1 * sizeof(WOW_BITMAP_PATTERN_T) +
2960 WMI_TLV_HDR_SIZE +
2961 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) +
2962 WMI_TLV_HDR_SIZE +
2963 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) +
2964 WMI_TLV_HDR_SIZE +
2965 0 * sizeof(WOW_MAGIC_PATTERN_CMD) +
2966 WMI_TLV_HDR_SIZE +
2967 0 * sizeof(A_UINT32) + WMI_TLV_HDR_SIZE + 1 * sizeof(A_UINT32);
2968
2969 buf = wmi_buf_alloc(wma->wmi_handle, len);
2970 if (!buf) {
2971 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
2972 return CDF_STATUS_E_NOMEM;
2973 }
2974
2975 cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf);
2976 buf_ptr = (uint8_t *) cmd;
2977
2978 WMITLV_SET_HDR(&cmd->tlv_header,
2979 WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param,
2980 WMITLV_GET_STRUCT_TLVLEN
2981 (WMI_WOW_ADD_PATTERN_CMD_fixed_param));
2982 cmd->vdev_id = vdev_id;
2983 /*
2984 * For user configured wow pattern use pattern id sent by HDD
2985 * and for default wow patterns generate pattern id internally
2986 */
2987 if (user)
2988 cmd->pattern_id = ptrn_id;
2989 else
2990 cmd->pattern_id = iface->num_wow_default_patterns++;
2991
2992 cmd->pattern_type = WOW_BITMAP_PATTERN;
2993 buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param);
2994
2995 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
2996 sizeof(WOW_BITMAP_PATTERN_T));
2997 buf_ptr += WMI_TLV_HDR_SIZE;
2998 bitmap_pattern = (WOW_BITMAP_PATTERN_T *) buf_ptr;
2999
3000 WMITLV_SET_HDR(&bitmap_pattern->tlv_header,
3001 WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T,
3002 WMITLV_GET_STRUCT_TLVLEN(WOW_BITMAP_PATTERN_T));
3003
3004 cdf_mem_copy(&bitmap_pattern->patternbuf[0], ptrn, ptrn_len);
3005 cdf_mem_copy(&bitmap_pattern->bitmaskbuf[0], mask, mask_len);
3006
3007 bitmap_pattern->pattern_offset = ptrn_offset;
3008 bitmap_pattern->pattern_len = ptrn_len;
3009
3010 if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMAP_PATTERN_SIZE)
3011 bitmap_pattern->pattern_len = WOW_DEFAULT_BITMAP_PATTERN_SIZE;
3012
3013 if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMASK_SIZE)
3014 bitmap_pattern->pattern_len = WOW_DEFAULT_BITMASK_SIZE;
3015
3016 bitmap_pattern->bitmask_len = bitmap_pattern->pattern_len;
3017 bitmap_pattern->pattern_id = ptrn_id;
3018
3019 WMA_LOGI("vdev id : %d, ptrn id: %d, ptrn len: %d, ptrn offset: %d user %d",
3020 cmd->vdev_id, cmd->pattern_id, bitmap_pattern->pattern_len,
3021 bitmap_pattern->pattern_offset, user);
3022
3023 WMA_LOGI("Pattern : ");
3024 CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_INFO,
3025 &bitmap_pattern->patternbuf[0], bitmap_pattern->pattern_len);
3026
3027 WMA_LOGI("Mask : ");
3028 CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_INFO,
3029 &bitmap_pattern->bitmaskbuf[0], bitmap_pattern->pattern_len);
3030
3031 buf_ptr += sizeof(WOW_BITMAP_PATTERN_T);
3032
3033 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */
3034 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
3035 buf_ptr += WMI_TLV_HDR_SIZE;
3036
3037 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */
3038 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
3039 buf_ptr += WMI_TLV_HDR_SIZE;
3040
3041 /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */
3042 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
3043 buf_ptr += WMI_TLV_HDR_SIZE;
3044
3045 /* Fill TLV for pattern_info_timeout but no data. */
3046 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
3047 buf_ptr += WMI_TLV_HDR_SIZE;
3048
3049 /* Fill TLV for ra_ratelimit_interval with dummy data as this fix elem */
3050 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 1 * sizeof(A_UINT32));
3051 buf_ptr += WMI_TLV_HDR_SIZE;
3052 *(A_UINT32 *) buf_ptr = 0;
3053
3054 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
3055 WMI_WOW_ADD_WAKE_PATTERN_CMDID);
3056 if (ret) {
3057 WMA_LOGE("%s: Failed to send wow ptrn to fw", __func__);
3058 wmi_buf_free(buf);
3059 if (!user)
3060 iface->num_wow_default_patterns--;
3061 return CDF_STATUS_E_FAILURE;
3062 }
3063
3064 if (user)
3065 iface->num_wow_user_patterns++;
3066
3067 return CDF_STATUS_SUCCESS;
3068}
3069
3070/**
3071 * wma_wow_ap() - set WOW patterns in ap mode
3072 * @wma: wma handle
3073 * @vdev_id: vdev id
3074 *
3075 * Configures default WOW pattern for the given vdev_id which is in AP mode.
3076 *
3077 * Return: CDF status
3078 */
3079static CDF_STATUS wma_wow_ap(tp_wma_handle wma, uint8_t vdev_id)
3080{
3081 CDF_STATUS ret;
3082 uint8_t arp_offset = 20;
3083 uint8_t mac_mask[IEEE80211_ADDR_LEN];
3084
3085 /* Setup unicast pkt pattern */
3086 cdf_mem_set(&mac_mask, IEEE80211_ADDR_LEN, 0xFF);
3087 ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0,
3088 wma->interfaces[vdev_id].addr,
3089 IEEE80211_ADDR_LEN, 0, mac_mask,
3090 IEEE80211_ADDR_LEN, false);
3091 if (ret != CDF_STATUS_SUCCESS) {
3092 WMA_LOGE("Failed to add WOW unicast pattern ret %d", ret);
3093 return ret;
3094 }
3095
3096 /*
3097 * Setup all ARP pkt pattern. This is dummy pattern hence the length
3098 * is zero
3099 */
3100 ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0,
3101 arp_ptrn, 0, arp_offset, arp_mask, 0, false);
3102 if (ret != CDF_STATUS_SUCCESS) {
3103 WMA_LOGE("Failed to add WOW ARP pattern ret %d", ret);
3104 return ret;
3105 }
3106
3107 return ret;
3108}
3109
3110/**
3111 * wma_wow_sta() - set WOW patterns in sta mode
3112 * @wma: wma handle
3113 * @vdev_id: vdev id
3114 *
3115 * Configures default WOW pattern for the given vdev_id which is in sta mode.
3116 *
3117 * Return: CDF status
3118 */
3119static CDF_STATUS wma_wow_sta(tp_wma_handle wma, uint8_t vdev_id)
3120{
3121 uint8_t arp_offset = 12;
3122 uint8_t discvr_offset = 30;
3123 uint8_t mac_mask[IEEE80211_ADDR_LEN];
3124 CDF_STATUS ret = CDF_STATUS_SUCCESS;
3125
3126 /* Setup unicast pkt pattern */
3127 cdf_mem_set(&mac_mask, IEEE80211_ADDR_LEN, 0xFF);
3128 ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0,
3129 wma->interfaces[vdev_id].addr,
3130 IEEE80211_ADDR_LEN, 0, mac_mask,
3131 IEEE80211_ADDR_LEN, false);
3132 if (ret != CDF_STATUS_SUCCESS) {
3133 WMA_LOGE("Failed to add WOW unicast pattern ret %d", ret);
3134 return ret;
3135 }
3136
3137 /*
3138 * Setup multicast pattern for mDNS 224.0.0.251,
3139 * SSDP 239.255.255.250 and LLMNR 224.0.0.252
3140 */
3141 if (wma->ssdp) {
3142 ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0,
3143 discvr_ptrn, sizeof(discvr_ptrn), discvr_offset,
3144 discvr_mask, sizeof(discvr_ptrn), false);
3145 if (ret != CDF_STATUS_SUCCESS) {
3146 WMA_LOGE("Failed to add WOW mDNS/SSDP/LLMNR pattern");
3147 return ret;
3148 }
3149 } else
3150 WMA_LOGD("mDNS, SSDP, LLMNR patterns are disabled from ini");
3151
3152 /* when arp offload or ns offloaded is disabled
3153 * from ini file, configure broad cast arp pattern
3154 * to fw, so that host can wake up
3155 */
3156 if (!(wma->ol_ini_info & 0x1)) {
3157 /* Setup all ARP pkt pattern */
3158 ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0,
3159 arp_ptrn, sizeof(arp_ptrn), arp_offset,
3160 arp_mask, sizeof(arp_mask), false);
3161 if (ret != CDF_STATUS_SUCCESS) {
3162 WMA_LOGE("Failed to add WOW ARP pattern");
3163 return ret;
3164 }
3165 }
3166
3167 /* for NS or NDP offload packets */
3168 if (!(wma->ol_ini_info & 0x2)) {
3169 /* Setup all NS pkt pattern */
3170 ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0,
3171 ns_ptrn, sizeof(arp_ptrn), arp_offset,
3172 arp_mask, sizeof(arp_mask), false);
3173 if (ret != CDF_STATUS_SUCCESS) {
3174 WMA_LOGE("Failed to add WOW NS pattern");
3175 return ret;
3176 }
3177 }
3178
3179 return ret;
3180}
3181
3182/**
3183 * wma_register_wow_default_patterns() - register default wow patterns with fw
3184 * @handle: Pointer to wma handle
3185 * @vdev_id: vdev id
3186 *
3187 * WoW default wake up pattern rule is:
3188 * - For STA & P2P CLI mode register for same STA specific wow patterns
3189 * - For SAP/P2P GO & IBSS mode register for same SAP specific wow patterns
3190 *
3191 * Return: none
3192 */
3193void wma_register_wow_default_patterns(WMA_HANDLE handle, uint8_t vdev_id)
3194{
3195 tp_wma_handle wma = handle;
3196 struct wma_txrx_node *iface;
3197
3198 if (vdev_id > wma->max_bssid) {
3199 WMA_LOGE("Invalid vdev id %d", vdev_id);
3200 return;
3201 }
3202 iface = &wma->interfaces[vdev_id];
3203
3204 if (iface->ptrn_match_enable) {
3205 if (wma_is_vdev_in_ap_mode(wma, vdev_id)
3206#ifdef QCA_IBSS_SUPPORT
3207 ||
3208 wma_is_vdev_in_ibss_mode(wma, vdev_id)
3209#endif
3210 ) {
3211 /* Configure SAP/GO/IBSS mode default wow patterns */
3212 WMA_LOGI("Config SAP specific default wow patterns vdev_id %d",
3213 vdev_id);
3214 wma_wow_ap(wma, vdev_id);
3215 } else {
3216 /* Configure STA/P2P CLI mode default wow patterns */
3217 WMA_LOGI("Config STA specific default wow patterns vdev_id %d",
3218 vdev_id);
3219 wma_wow_sta(wma, vdev_id);
3220 if (wma->IsRArateLimitEnabled) {
3221 WMA_LOGI("Config STA RA limit wow patterns vdev_id %d",
3222 vdev_id);
3223 wma_wow_sta_ra_filter(wma, vdev_id);
3224 }
3225 }
3226 }
3227
3228 return;
3229}
3230
3231/**
3232 * wma_register_wow_wakeup_events() - register vdev specific wake events with fw
3233 * @handle: Pointer to wma handle
3234 * @vdev_id: vdev Id
3235 * @vdev_type: vdev type
3236 * @vdev_subtype: vdev sub type
3237 *
3238 * WoW wake up event rule is following:
3239 * 1) STA mode and P2P CLI mode wake up events are same
3240 * 2) SAP mode and P2P GO mode wake up events are same
3241 * 3) IBSS mode wake events are same as STA mode plus WOW_BEACON_EVENT
3242 *
3243 * Return: none
3244 */
3245void wma_register_wow_wakeup_events(WMA_HANDLE handle,
3246 uint8_t vdev_id,
3247 uint8_t vdev_type,
3248 uint8_t vdev_subtype)
3249{
3250 tp_wma_handle wma = handle;
3251 uint32_t event_bitmap;
3252
3253 WMA_LOGI("vdev_type %d vdev_subtype %d vdev_id %d", vdev_type,
3254 vdev_subtype, vdev_id);
3255
3256 if ((WMI_VDEV_TYPE_STA == vdev_type) ||
3257 ((WMI_VDEV_TYPE_AP == vdev_type) &&
3258 (WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE == vdev_subtype))) {
3259 /* Configure STA/P2P CLI mode specific default wake up events */
3260 event_bitmap = WMA_WOW_STA_WAKE_UP_EVENTS;
3261 WMA_LOGI("STA specific default wake up event 0x%x vdev id %d",
3262 event_bitmap, vdev_id);
3263 } else if (WMI_VDEV_TYPE_IBSS == vdev_type) {
3264 /* Configure IBSS mode specific default wake up events */
3265 event_bitmap = (WMA_WOW_STA_WAKE_UP_EVENTS |
3266 (1 << WOW_BEACON_EVENT));
3267 WMA_LOGI("IBSS specific default wake up event 0x%x vdev id %d",
3268 event_bitmap, vdev_id);
3269 } else if (WMI_VDEV_TYPE_AP == vdev_type) {
3270 /* Configure SAP/GO mode specific default wake up events */
3271 event_bitmap = WMA_WOW_SAP_WAKE_UP_EVENTS;
3272 WMA_LOGI("SAP specific default wake up event 0x%x vdev id %d",
3273 event_bitmap, vdev_id);
3274 } else {
3275 WMA_LOGE("unknown type %d subtype %d", vdev_type, vdev_subtype);
3276 return;
3277 }
3278
3279 wma_add_wow_wakeup_event(wma, vdev_id, event_bitmap, true);
3280
3281 return;
3282}
3283
3284/**
3285 * wma_enable_disable_wakeup_event() - Configures wow wakeup events
3286 * @wma: wma handle
3287 * @vdev_id: vdev id
3288 * @bitmap: Event bitmap
3289 * @enable: enable/disable
3290 *
3291 * Return: none
3292 */
3293void wma_enable_disable_wakeup_event(WMA_HANDLE handle,
3294 uint32_t vdev_id,
3295 uint32_t bitmap,
3296 bool enable)
3297{
3298 tp_wma_handle wma = handle;
3299
3300 WMA_LOGI("vdev_id %d wake up event 0x%x enable %d",
3301 vdev_id, bitmap, enable);
3302 wma_add_wow_wakeup_event(wma, vdev_id, bitmap, enable);
3303}
3304
3305/**
3306 * wma_enable_wow_in_fw() - wnable wow in fw
3307 * @wma: wma handle
3308 *
3309 * Return: CDF status
3310 */
3311CDF_STATUS wma_enable_wow_in_fw(WMA_HANDLE handle)
3312{
3313 tp_wma_handle wma = handle;
3314 wmi_wow_enable_cmd_fixed_param *cmd;
3315 wmi_buf_t buf;
3316 int32_t len;
3317 int ret;
3318 struct ol_softc *scn;
3319 int host_credits;
3320 int wmi_pending_cmds;
3321#ifdef CONFIG_CNSS
3322 tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE);
3323
3324 if (NULL == pMac) {
3325 WMA_LOGE("%s: Unable to get PE context", __func__);
3326 return CDF_STATUS_E_FAILURE;
3327 }
3328#endif /* CONFIG_CNSS */
3329
3330 len = sizeof(wmi_wow_enable_cmd_fixed_param);
3331
3332 buf = wmi_buf_alloc(wma->wmi_handle, len);
3333 if (!buf) {
3334 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
3335 return CDF_STATUS_E_NOMEM;
3336 }
3337
3338 cmd = (wmi_wow_enable_cmd_fixed_param *) wmi_buf_data(buf);
3339 WMITLV_SET_HDR(&cmd->tlv_header,
3340 WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param,
3341 WMITLV_GET_STRUCT_TLVLEN
3342 (wmi_wow_enable_cmd_fixed_param));
3343 cmd->enable = true;
3344 if (hif_can_suspend_link())
3345 cmd->pause_iface_config = WOW_IFACE_PAUSE_ENABLED;
3346 else
3347 cmd->pause_iface_config = WOW_IFACE_PAUSE_DISABLED;
3348
3349 WMA_LOGI("suspend type: %s",
3350 cmd->pause_iface_config == WOW_IFACE_PAUSE_ENABLED ?
3351 "WOW_IFACE_PAUSE_ENABLED" : "WOW_IFACE_PAUSE_DISABLED");
3352
3353 cdf_event_reset(&wma->target_suspend);
3354 wma->wow_nack = 0;
3355
3356 host_credits = wmi_get_host_credits(wma->wmi_handle);
3357 wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle);
3358
3359 WMA_LOGD("Credits:%d; Pending_Cmds: %d",
3360 host_credits, wmi_pending_cmds);
3361
3362 if (host_credits < WMI_WOW_REQUIRED_CREDITS) {
3363 WMA_LOGE("%s: Host Doesn't have enough credits to Post WMI_WOW_ENABLE_CMDID! "
3364 "Credits:%d, pending_cmds:%d\n", __func__, host_credits,
3365 wmi_pending_cmds);
3366#ifndef QCA_WIFI_3_0_EMU
3367 goto error;
3368#endif
3369 }
3370
3371 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
3372 WMI_WOW_ENABLE_CMDID);
3373 if (ret) {
3374 WMA_LOGE("Failed to enable wow in fw");
3375 goto error;
3376 }
3377
3378 wmi_set_target_suspend(wma->wmi_handle, true);
3379
3380 if (cdf_wait_single_event(&wma->target_suspend,
3381 WMA_TGT_SUSPEND_COMPLETE_TIMEOUT)
3382 != CDF_STATUS_SUCCESS) {
3383 WMA_LOGE("Failed to receive WoW Enable Ack from FW");
3384 WMA_LOGE("Credits:%d; Pending_Cmds: %d",
3385 wmi_get_host_credits(wma->wmi_handle),
3386 wmi_get_pending_cmds(wma->wmi_handle));
Yue Ma455aff62015-10-20 18:29:16 -07003387 if (!cds_is_logp_in_progress()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003388#ifdef CONFIG_CNSS
Yue Ma455aff62015-10-20 18:29:16 -07003389 if (pMac->sme.enableSelfRecovery) {
3390 cds_trigger_recovery();
3391 } else {
3392 CDF_BUG(0);
3393 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003394#else
Yue Ma455aff62015-10-20 18:29:16 -07003395 CDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003396#endif /* CONFIG_CNSS */
Yue Ma455aff62015-10-20 18:29:16 -07003397 } else {
3398 WMA_LOGE("%s: LOGP is in progress, ignore!", __func__);
3399 }
3400
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003401 wmi_set_target_suspend(wma->wmi_handle, false);
3402 return CDF_STATUS_E_FAILURE;
3403 }
3404
3405 if (wma->wow_nack) {
3406 WMA_LOGE("FW not ready to WOW");
3407 wmi_set_target_suspend(wma->wmi_handle, false);
3408 return CDF_STATUS_E_AGAIN;
3409 }
3410
3411 host_credits = wmi_get_host_credits(wma->wmi_handle);
3412 wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle);
3413
3414 if (host_credits < WMI_WOW_REQUIRED_CREDITS) {
3415 WMA_LOGE("%s: No Credits after HTC ACK:%d, pending_cmds:%d, "
3416 "cannot resume back", __func__, host_credits,
3417 wmi_pending_cmds);
3418 htc_dump_counter_info(wma->htc_handle);
3419 if (!cds_is_logp_in_progress())
3420 CDF_BUG(0);
3421 else
3422 WMA_LOGE("%s: SSR in progress, ignore no credit issue",
3423 __func__);
3424 }
3425
3426 WMA_LOGD("WOW enabled successfully in fw: credits:%d"
3427 "pending_cmds: %d", host_credits, wmi_pending_cmds);
3428
3429 scn = cds_get_context(CDF_MODULE_ID_HIF);
3430
3431 if (scn == NULL) {
3432 WMA_LOGE("%s: Failed to get HIF context", __func__);
3433 CDF_ASSERT(0);
3434 return CDF_STATUS_E_FAULT;
3435 }
3436
3437 htc_cancel_deferred_target_sleep(scn);
3438
3439 wma->wow.wow_enable_cmd_sent = true;
3440
3441 return CDF_STATUS_SUCCESS;
3442
3443error:
3444 wmi_buf_free(buf);
3445 return CDF_STATUS_E_FAILURE;
3446}
3447
3448/**
3449 * wma_resume_req() - clear configured wow patterns in fw
3450 * @wma: wma handle
3451 *
3452 * Return: CDF status
3453 */
3454CDF_STATUS wma_resume_req(tp_wma_handle wma)
3455{
3456 wma->no_of_resume_ind++;
3457
3458 if (wma->no_of_resume_ind < wma_get_vdev_count(wma))
3459 return CDF_STATUS_SUCCESS;
3460
3461 wma->no_of_resume_ind = 0;
3462
3463 /* Reset the DTIM Parameters */
3464 wma_set_resume_dtim(wma);
3465 /* need to reset if hif_pci_suspend_fails */
3466 wma_set_wow_bus_suspend(wma, 0);
3467 /* unpause the vdev if left paused and hif_pci_suspend fails */
3468 wma_unpause_vdev(wma);
3469
3470 return CDF_STATUS_SUCCESS;
3471}
3472
3473/**
3474 * wma_wow_delete_pattern() - delete wow pattern in target
3475 * @wma: wma handle
3476 * @ptrn_id: pattern id
3477 * @vdev_id: vdev id
3478 * @user: true for user pattern and false for default pattern
3479 *
3480 * Return: CDF status
3481 */
3482static CDF_STATUS wma_wow_delete_pattern(tp_wma_handle wma, uint8_t ptrn_id,
3483 uint8_t vdev_id, bool user)
3484{
3485 WMI_WOW_DEL_PATTERN_CMD_fixed_param *cmd;
3486 struct wma_txrx_node *iface;
3487 wmi_buf_t buf;
3488 int32_t len;
3489 int ret;
3490
3491 len = sizeof(WMI_WOW_DEL_PATTERN_CMD_fixed_param);
3492
3493 iface = &wma->interfaces[vdev_id];
3494
3495 buf = wmi_buf_alloc(wma->wmi_handle, len);
3496 if (!buf) {
3497 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
3498 return CDF_STATUS_E_NOMEM;
3499 }
3500
3501 cmd = (WMI_WOW_DEL_PATTERN_CMD_fixed_param *) wmi_buf_data(buf);
3502
3503 WMITLV_SET_HDR(&cmd->tlv_header,
3504 WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param,
3505 WMITLV_GET_STRUCT_TLVLEN(
3506 WMI_WOW_DEL_PATTERN_CMD_fixed_param));
3507 cmd->vdev_id = vdev_id;
3508 cmd->pattern_id = ptrn_id;
3509 cmd->pattern_type = WOW_BITMAP_PATTERN;
3510
3511 WMA_LOGI("Deleting pattern id: %d vdev id %d in fw",
3512 cmd->pattern_id, vdev_id);
3513
3514 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
3515 WMI_WOW_DEL_WAKE_PATTERN_CMDID);
3516 if (ret) {
3517 WMA_LOGE("%s: Failed to delete wow ptrn from fw", __func__);
3518 wmi_buf_free(buf);
3519 return CDF_STATUS_E_FAILURE;
3520 }
3521
3522 if (user)
3523 iface->num_wow_user_patterns--;
3524
3525 return CDF_STATUS_SUCCESS;
3526}
3527
3528/**
3529 * wma_wow_add_pattern() - add wow pattern in target
3530 * @wma: wma handle
3531 * @ptrn: wow pattern
3532 *
3533 * This function does following:
3534 * 1) Delete all default patterns of the vdev
3535 * 2) Add received wow patterns for given vdev in target.
3536 *
3537 * Target is responsible for caching wow patterns accross multiple
3538 * suspend/resumes until the pattern is deleted by user
3539 *
3540 * Return: CDF status
3541 */
3542CDF_STATUS wma_wow_add_pattern(tp_wma_handle wma, struct wow_add_pattern *ptrn)
3543{
3544 uint8_t id;
3545 uint8_t bit_to_check, pos;
3546 struct wma_txrx_node *iface;
3547 CDF_STATUS ret = CDF_STATUS_SUCCESS;
3548 uint8_t new_mask[SIR_WOWL_BCAST_PATTERN_MAX_SIZE];
3549
3550 if (ptrn->session_id > wma->max_bssid) {
3551 WMA_LOGE("Invalid vdev id (%d)", ptrn->session_id);
3552 return CDF_STATUS_E_INVAL;
3553 }
3554
3555 iface = &wma->interfaces[ptrn->session_id];
3556
3557 /* clear all default patterns cofigured by wma */
3558 for (id = 0; id < iface->num_wow_default_patterns; id++)
3559 wma_wow_delete_pattern(wma, id, ptrn->session_id, false);
3560
3561 iface->num_wow_default_patterns = 0;
3562
3563 WMA_LOGI("Add user passed wow pattern id %d vdev id %d",
3564 ptrn->pattern_id, ptrn->session_id);
3565 /*
3566 * Convert received pattern mask value from bit representation
3567 * to byte representation.
3568 *
3569 * For example, received value from umac,
3570 *
3571 * Mask value : A1 (equivalent binary is "1010 0001")
3572 * Pattern value : 12:00:13:00:00:00:00:44
3573 *
3574 * The value which goes to FW after the conversion from this
3575 * function (1 in mask value will become FF and 0 will
3576 * become 00),
3577 *
3578 * Mask value : FF:00:FF:00:0:00:00:FF
3579 * Pattern value : 12:00:13:00:00:00:00:44
3580 */
3581 cdf_mem_zero(new_mask, sizeof(new_mask));
3582 for (pos = 0; pos < ptrn->pattern_size; pos++) {
3583 bit_to_check = (WMA_NUM_BITS_IN_BYTE - 1) -
3584 (pos % WMA_NUM_BITS_IN_BYTE);
3585 bit_to_check = 0x1 << bit_to_check;
3586 if (ptrn->pattern_mask[pos / WMA_NUM_BITS_IN_BYTE] &
3587 bit_to_check)
3588 new_mask[pos] = WMA_WOW_PTRN_MASK_VALID;
3589 }
3590
3591 ret = wma_send_wow_patterns_to_fw(wma, ptrn->session_id,
3592 ptrn->pattern_id,
3593 ptrn->pattern, ptrn->pattern_size,
3594 ptrn->pattern_byte_offset, new_mask,
3595 ptrn->pattern_size, true);
3596 if (ret != CDF_STATUS_SUCCESS)
3597 WMA_LOGE("Failed to add wow pattern %d", ptrn->pattern_id);
3598
3599 return ret;
3600}
3601
3602/**
3603 * wma_wow_delete_user_pattern() - delete user configured wow pattern in target
3604 * @wma: wma handle
3605 * @ptrn: wow pattern
3606 *
3607 * This function does following:
3608 * 1) Deletes a particular user configured wow pattern in target
3609 * 2) After deleting all user wow patterns add default wow patterns
3610 * specific to that vdev.
3611 *
3612 * Return: CDF status
3613 */
3614CDF_STATUS wma_wow_delete_user_pattern(tp_wma_handle wma,
3615 struct wow_delete_pattern *pattern)
3616{
3617 struct wma_txrx_node *iface;
3618
3619 if (pattern->session_id > wma->max_bssid) {
3620 WMA_LOGE("Invalid vdev id %d", pattern->session_id);
3621 return CDF_STATUS_E_INVAL;
3622 }
3623
3624 iface = &wma->interfaces[pattern->session_id];
3625 if (iface->num_wow_user_patterns <= 0) {
3626 WMA_LOGE("No valid user pattern. Num user pattern %u vdev %d",
3627 iface->num_wow_user_patterns, pattern->session_id);
3628 return CDF_STATUS_E_INVAL;
3629 }
3630
3631 WMA_LOGI("Delete user passed wow pattern id %d total user pattern %d",
3632 pattern->pattern_id, iface->num_wow_user_patterns);
3633
3634 wma_wow_delete_pattern(wma, pattern->pattern_id,
3635 pattern->session_id, true);
3636
3637 /* configure default patterns once all user patterns are deleted */
3638 if (!iface->num_wow_user_patterns)
3639 wma_register_wow_default_patterns(wma, pattern->session_id);
3640
3641 return CDF_STATUS_SUCCESS;
3642}
3643
3644/**
3645 * wma_wow_enter() - store enable/disable status for pattern
3646 * @wma: wma handle
3647 * @info: wow parameters
3648 *
3649 * Records pattern enable/disable status locally. This choice will
3650 * take effect when the driver enter into suspend state.
3651 *
3652 * Return: CDF status
3653 */
3654CDF_STATUS wma_wow_enter(tp_wma_handle wma, tpSirHalWowlEnterParams info)
3655{
3656 struct wma_txrx_node *iface;
3657
3658 WMA_LOGD("wow enable req received for vdev id: %d", info->sessionId);
3659
3660 if (info->sessionId > wma->max_bssid) {
3661 WMA_LOGE("Invalid vdev id (%d)", info->sessionId);
3662 cdf_mem_free(info);
3663 return CDF_STATUS_E_INVAL;
3664 }
3665
3666 iface = &wma->interfaces[info->sessionId];
3667 iface->ptrn_match_enable = info->ucPatternFilteringEnable ?
3668 true : false;
3669 wma->wow.magic_ptrn_enable = info->ucMagicPktEnable ? true : false;
3670 wma->wow.deauth_enable = info->ucWowDeauthRcv ? true : false;
3671 wma->wow.disassoc_enable = info->ucWowDeauthRcv ? true : false;
3672 wma->wow.bmiss_enable = info->ucWowMaxMissedBeacons ? true : false;
3673
3674 cdf_mem_free(info);
3675
3676 return CDF_STATUS_SUCCESS;
3677}
3678
3679/**
3680 * wma_wow_exit() - clear all wma states
3681 * @wma: wma handle
3682 * @info: wow params
3683 *
3684 * Return: CDF status
3685 */
3686CDF_STATUS wma_wow_exit(tp_wma_handle wma, tpSirHalWowlExitParams info)
3687{
3688 struct wma_txrx_node *iface;
3689
3690 WMA_LOGD("wow disable req received for vdev id: %d", info->sessionId);
3691
3692 if (info->sessionId > wma->max_bssid) {
3693 WMA_LOGE("Invalid vdev id (%d)", info->sessionId);
3694 cdf_mem_free(info);
3695 return CDF_STATUS_E_INVAL;
3696 }
3697
3698 iface = &wma->interfaces[info->sessionId];
3699 iface->ptrn_match_enable = false;
3700 wma->wow.magic_ptrn_enable = false;
3701 cdf_mem_free(info);
3702
3703 return CDF_STATUS_SUCCESS;
3704}
3705
3706/**
3707 * wma_suspend_req() - Handles suspend indication request received from umac.
3708 * @wma: wma handle
3709 * @info: suspend params
3710 *
3711 * Return: CDF status
3712 */
3713CDF_STATUS wma_suspend_req(tp_wma_handle wma, tpSirWlanSuspendParam info)
3714{
3715 struct wma_txrx_node *iface;
3716 bool connected = false, pno_in_progress = false;
3717 uint8_t i;
3718 bool extscan_in_progress = false;
3719
3720 wma->no_of_suspend_ind++;
3721
3722 if (info->sessionId > wma->max_bssid) {
3723 WMA_LOGE("Invalid vdev id (%d)", info->sessionId);
3724 cdf_mem_free(info);
3725 return CDF_STATUS_E_INVAL;
3726 }
3727
3728 iface = &wma->interfaces[info->sessionId];
3729 if (!iface) {
3730 WMA_LOGD("vdev %d node is not found", info->sessionId);
3731 cdf_mem_free(info);
3732 return CDF_STATUS_SUCCESS;
3733 }
3734
3735 if (!wma->wow.magic_ptrn_enable && !iface->ptrn_match_enable) {
3736 cdf_mem_free(info);
3737
3738 if (wma->no_of_suspend_ind == wma_get_vdev_count(wma)) {
3739 WMA_LOGD("Both magic and pattern byte match are disabled");
3740 wma->no_of_suspend_ind = 0;
3741 goto send_ready_to_suspend;
3742 }
3743
3744 return CDF_STATUS_SUCCESS;
3745 }
3746
3747 iface->conn_state = (info->connectedState) ? true : false;
3748
3749 /*
3750 * Once WOW is enabled in FW, host can't send anymore
3751 * data to fw. umac sends suspend indication on each
3752 * vdev during platform suspend. WMA has to wait until
3753 * suspend indication received on last vdev before
3754 * enabling wow in fw.
3755 */
3756 if (wma->no_of_suspend_ind < wma_get_vdev_count(wma)) {
3757 cdf_mem_free(info);
3758 return CDF_STATUS_SUCCESS;
3759 }
3760
3761 wma->no_of_suspend_ind = 0;
3762 wma->wow.gtk_pdev_enable = 0;
3763 /*
3764 * Enable WOW if any one of the condition meets,
3765 * 1) Is any one of vdev in beaconning mode (in AP mode) ?
3766 * 2) Is any one of vdev in connected state (in STA mode) ?
3767 * 3) Is PNO in progress in any one of vdev ?
3768 * 4) Is Extscan in progress in any one of vdev ?
3769 */
3770 for (i = 0; i < wma->max_bssid; i++) {
3771 if ((wma_is_vdev_in_ap_mode(wma, i)
3772#ifdef QCA_IBSS_SUPPORT
3773 || wma_is_vdev_in_ibss_mode(wma, i)
3774#endif /* QCA_IBSS_SUPPORT */
3775 ) && wma->interfaces[i].vdev_up &&
3776 WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
3777 WMI_SERVICE_BEACON_OFFLOAD)) {
3778 WMA_LOGD("vdev %d is in beaconning mode, enabling wow",
3779 i);
3780 goto enable_wow;
3781 }
3782 }
3783 for (i = 0; i < wma->max_bssid; i++) {
3784 if (wma->interfaces[i].conn_state) {
3785 connected = true;
3786 break;
3787 }
3788#ifdef FEATURE_WLAN_SCAN_PNO
3789 if (wma->interfaces[i].pno_in_progress) {
3790 WMA_LOGD("PNO is in progress, enabling wow");
3791 pno_in_progress = true;
3792 break;
3793 }
3794#endif /* FEATURE_WLAN_SCAN_PNO */
3795#ifdef FEATURE_WLAN_EXTSCAN
3796 if (wma->interfaces[i].extscan_in_progress) {
3797 WMA_LOGD("Extscan is in progress, enabling wow");
3798 extscan_in_progress = true;
3799 break;
3800 }
3801#endif
3802 }
3803 for (i = 0; i < wma->max_bssid; i++) {
3804 wma->wow.gtk_pdev_enable |= wma->wow.gtk_err_enable[i];
3805 WMA_LOGD("VDEV_ID:%d, gtk_err_enable[%d]:%d, gtk_pdev_enable:%d", i,
3806 i, wma->wow.gtk_err_enable[i], wma->wow.gtk_pdev_enable);
3807 }
3808
3809 if (!connected && !pno_in_progress && !extscan_in_progress) {
3810 WMA_LOGD("All vdev are in disconnected state and pno/extscan is not in progress, skipping wow");
3811 cdf_mem_free(info);
3812 goto send_ready_to_suspend;
3813 }
3814
3815enable_wow:
3816 WMA_LOGE("WOW Suspend");
3817
3818 /*
3819 * At this point, suspend indication is received on
3820 * last vdev. It's the time to enable wow in fw.
3821 */
3822#ifdef FEATURE_WLAN_LPHB
3823 /* LPHB cache, if any item was enabled, should be
3824 * applied.
3825 */
3826 WMA_LOGD("%s: checking LPHB cache", __func__);
3827 for (i = 0; i < 2; i++) {
3828 if (wma->wow.lphb_cache[i].params.lphbEnableReq.enable) {
3829 WMA_LOGD("%s: LPHB cache for item %d is marked as enable",
3830 __func__, i + 1);
3831 wma_lphb_conf_hbenable(wma, &(wma->wow.lphb_cache[i]),
3832 false);
3833 }
3834 }
3835#endif /* FEATURE_WLAN_LPHB */
3836
3837 wma->wow.wow_enable = true;
3838 wma->wow.wow_enable_cmd_sent = false;
3839
3840 cdf_mem_free(info);
3841
3842send_ready_to_suspend:
3843 /* Set the Suspend DTIM Parameters */
3844 wma_set_suspend_dtim(wma);
3845 wma_send_status_to_suspend_ind(wma, true);
3846
3847 /* to handle race between hif_pci_suspend and
3848 * unpause/pause tx handler
3849 */
3850 wma_set_wow_bus_suspend(wma, 1);
3851
3852 return CDF_STATUS_SUCCESS;
3853}
3854
3855/**
3856 * wma_send_host_wakeup_ind_to_fw() - send wakeup ind to fw
3857 * @wma: wma handle
3858 *
3859 * Sends host wakeup indication to FW. On receiving this indication,
3860 * FW will come out of WOW.
3861 *
3862 * Return: CDF status
3863 */
3864static CDF_STATUS wma_send_host_wakeup_ind_to_fw(tp_wma_handle wma)
3865{
3866 wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *cmd;
3867 wmi_buf_t buf;
3868 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
3869 int32_t len;
3870 int ret;
3871#ifdef CONFIG_CNSS
3872 tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE);
3873 if (NULL == pMac) {
3874 WMA_LOGE("%s: Unable to get PE context", __func__);
3875 return CDF_STATUS_E_FAILURE;
3876 }
3877#endif /* CONFIG_CNSS */
3878
3879 len = sizeof(wmi_wow_hostwakeup_from_sleep_cmd_fixed_param);
3880
3881 buf = wmi_buf_alloc(wma->wmi_handle, len);
3882 if (!buf) {
3883 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
3884 return CDF_STATUS_E_NOMEM;
3885 }
3886
3887 cmd = (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *)
3888 wmi_buf_data(buf);
3889 WMITLV_SET_HDR(&cmd->tlv_header,
3890 WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param,
3891 WMITLV_GET_STRUCT_TLVLEN
3892 (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param));
3893
3894 cdf_event_reset(&wma->wma_resume_event);
3895
3896 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
3897 WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID);
3898 if (ret) {
3899 WMA_LOGE("Failed to send host wakeup indication to fw");
3900 wmi_buf_free(buf);
3901 return CDF_STATUS_E_FAILURE;
3902 }
3903
3904 WMA_LOGD("Host wakeup indication sent to fw");
3905
3906 cdf_status = cdf_wait_single_event(&(wma->wma_resume_event),
3907 WMA_RESUME_TIMEOUT);
3908 if (CDF_STATUS_SUCCESS != cdf_status) {
3909 WMA_LOGP("%s: Timeout waiting for resume event from FW",
3910 __func__);
3911 WMA_LOGP("%s: Pending commands %d credits %d", __func__,
3912 wmi_get_pending_cmds(wma->wmi_handle),
3913 wmi_get_host_credits(wma->wmi_handle));
3914 if (!cds_is_logp_in_progress()) {
3915#ifdef CONFIG_CNSS
3916 if (pMac->sme.enableSelfRecovery) {
3917 cds_trigger_recovery();
3918 } else {
3919 CDF_BUG(0);
3920 }
3921#else
3922 CDF_BUG(0);
3923#endif /* CONFIG_CNSS */
3924 } else {
3925 WMA_LOGE("%s: SSR in progress, ignore resume timeout",
3926 __func__);
3927 }
3928 } else {
3929 WMA_LOGD("Host wakeup received");
3930 }
3931
3932 if (CDF_STATUS_SUCCESS == cdf_status)
3933 wmi_set_target_suspend(wma->wmi_handle, false);
3934
3935 return cdf_status;
3936}
3937
3938/**
3939 * wma_disable_wow_in_fw() - Disable wow in PCIe resume context.
3940 * @handle: wma handle
3941 *
3942 * Return: 0 for success or error code
3943 */
3944CDF_STATUS wma_disable_wow_in_fw(WMA_HANDLE handle)
3945{
3946 tp_wma_handle wma = handle;
3947 CDF_STATUS ret;
3948
3949 if (!wma->wow.wow_enable || !wma->wow.wow_enable_cmd_sent)
3950 return CDF_STATUS_SUCCESS;
3951
3952 ret = wma_send_host_wakeup_ind_to_fw(wma);
3953
3954 if (ret != CDF_STATUS_SUCCESS)
3955 return ret;
3956
3957 wma->wow.wow_enable = false;
3958 wma->wow.wow_enable_cmd_sent = false;
3959
3960 /* To allow the tx pause/unpause events */
3961 wma_set_wow_bus_suspend(wma, 0);
3962 /* Unpause the vdev as we are resuming */
3963 wma_unpause_vdev(wma);
3964
3965 return ret;
3966}
3967
3968#ifdef WLAN_FEATURE_LPSS
3969/**
3970 * wma_is_lpass_enabled() - check if lpass is enabled
3971 * @handle: Pointer to wma handle
3972 *
3973 * WoW is needed if LPASS or NaN feature is enabled in INI because
3974 * target can't wake up itself if its put in PDEV suspend when LPASS
3975 * or NaN features are supported
3976 *
3977 * Return: true if lpass is enabled else false
3978 */
3979bool static wma_is_lpass_enabled(tp_wma_handle wma)
3980{
3981 if (wma->is_lpass_enabled)
3982 return true;
3983 else
3984 return false;
3985}
3986#else
3987bool static wma_is_lpass_enabled(tp_wma_handle wma)
3988{
3989 return false;
3990}
3991#endif
3992
3993#ifdef WLAN_FEATURE_NAN
3994/**
3995 * wma_is_nan_enabled() - check if NaN is enabled
3996 * @handle: Pointer to wma handle
3997 *
3998 * WoW is needed if LPASS or NaN feature is enabled in INI because
3999 * target can't wake up itself if its put in PDEV suspend when LPASS
4000 * or NaN features are supported
4001 *
4002 * Return: true if NaN is enabled else false
4003 */
4004bool static wma_is_nan_enabled(tp_wma_handle wma)
4005{
4006 if (wma->is_nan_enabled)
4007 return true;
4008 else
4009 return false;
4010}
4011#else
4012bool static wma_is_nan_enabled(tp_wma_handle wma)
4013{
4014 return false;
4015}
4016#endif
4017
4018/**
4019 * wma_is_wow_mode_selected() - check if wow needs to be enabled in fw
4020 * @handle: Pointer to wma handle
4021 *
4022 * If lpass is enabled then always do wow else check wow_enable config
4023 *
4024 * Return: true is wow mode is needed else false
4025 */
4026int wma_is_wow_mode_selected(WMA_HANDLE handle)
4027{
4028 tp_wma_handle wma = (tp_wma_handle) handle;
4029
4030 if (wma_is_lpass_enabled(wma)) {
4031 WMA_LOGD("LPASS is enabled select WoW");
4032 return true;
4033 } else if (wma_is_nan_enabled(wma)) {
4034 WMA_LOGD("NAN is enabled select WoW");
4035 return true;
4036 } else {
4037 WMA_LOGD("WoW enable %d", wma->wow.wow_enable);
4038 return wma->wow.wow_enable;
4039 }
4040}
4041
4042/**
4043 * wma_del_ts_req() - send DELTS request to fw
4044 * @wma: wma handle
4045 * @msg: delts params
4046 *
4047 * Return: none
4048 */
4049void wma_del_ts_req(tp_wma_handle wma, tDelTsParams *msg)
4050{
4051 wmi_vdev_wmm_delts_cmd_fixed_param *cmd;
4052 wmi_buf_t buf;
4053 int32_t len = sizeof(*cmd);
4054
4055 buf = wmi_buf_alloc(wma->wmi_handle, len);
4056 if (!buf) {
4057 WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
4058 goto err;
4059 }
4060 cmd = (wmi_vdev_wmm_delts_cmd_fixed_param *) wmi_buf_data(buf);
4061 WMITLV_SET_HDR(&cmd->tlv_header,
4062 WMITLV_TAG_STRUC_wmi_vdev_wmm_delts_cmd_fixed_param,
4063 WMITLV_GET_STRUCT_TLVLEN
4064 (wmi_vdev_wmm_delts_cmd_fixed_param));
4065 cmd->vdev_id = msg->sessionId;
4066 cmd->ac = TID_TO_WME_AC(msg->userPrio);
4067
4068 WMA_LOGD("Delts vdev:%d, ac:%d, %s:%d",
4069 cmd->vdev_id, cmd->ac, __FUNCTION__, __LINE__);
4070 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
4071 WMI_VDEV_WMM_DELTS_CMDID)) {
4072 WMA_LOGP("%s: Failed to send vdev DELTS command", __func__);
4073 cdf_nbuf_free(buf);
4074 }
4075#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4076 if (msg->setRICparams == true)
4077 wma_set_ric_req(wma, msg, false);
4078#endif /* WLAN_FEATURE_ROAM_OFFLOAD */
4079
4080err:
4081 cdf_mem_free(msg);
4082}
4083
4084/**
4085 * wma_aggr_qos_req() - send aggr qos request to fw
4086 * @wma: handle to wma
4087 * @pAggrQosRspMsg - combined struct for all ADD_TS requests.
4088 *
4089 * A function to handle WMA_AGGR_QOS_REQ. This will send out
4090 * ADD_TS requestes to firmware in loop for all the ACs with
4091 * active flow.
4092 *
4093 * Return: none
4094 */
4095void wma_aggr_qos_req(tp_wma_handle wma,
4096 tAggrAddTsParams *pAggrQosRspMsg)
4097{
4098 int i = 0;
4099 wmi_vdev_wmm_addts_cmd_fixed_param *cmd;
4100 wmi_buf_t buf;
4101 int32_t len = sizeof(*cmd);
4102
4103 for (i = 0; i < HAL_QOS_NUM_AC_MAX; i++) {
4104 /* if flow in this AC is active */
4105 if (((1 << i) & pAggrQosRspMsg->tspecIdx)) {
4106 /*
4107 * as per implementation of wma_add_ts_req() we
4108 * are not waiting any response from firmware so
4109 * apart from sending ADDTS to firmware just send
4110 * success to upper layers
4111 */
4112 pAggrQosRspMsg->status[i] = CDF_STATUS_SUCCESS;
4113
4114 buf = wmi_buf_alloc(wma->wmi_handle, len);
4115 if (!buf) {
4116 WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
4117 goto aggr_qos_exit;
4118 }
4119 cmd = (wmi_vdev_wmm_addts_cmd_fixed_param *)
4120 wmi_buf_data(buf);
4121 WMITLV_SET_HDR(&cmd->tlv_header,
4122 WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param,
4123 WMITLV_GET_STRUCT_TLVLEN
4124 (wmi_vdev_wmm_addts_cmd_fixed_param));
4125 cmd->vdev_id = pAggrQosRspMsg->sessionId;
4126 cmd->ac =
4127 TID_TO_WME_AC(pAggrQosRspMsg->tspec[i].tsinfo.
4128 traffic.userPrio);
4129 cmd->medium_time_us =
4130 pAggrQosRspMsg->tspec[i].mediumTime * 32;
4131 cmd->downgrade_type = WMM_AC_DOWNGRADE_DEPRIO;
4132 WMA_LOGD("%s:%d: Addts vdev:%d, ac:%d, mediumTime:%d downgrade_type:%d",
4133 __func__, __LINE__, cmd->vdev_id, cmd->ac,
4134 cmd->medium_time_us, cmd->downgrade_type);
4135 if (wmi_unified_cmd_send
4136 (wma->wmi_handle, buf, len,
4137 WMI_VDEV_WMM_ADDTS_CMDID)) {
4138 WMA_LOGP("%s: Failed to send vdev ADDTS command",
4139 __func__);
4140 pAggrQosRspMsg->status[i] =
4141 CDF_STATUS_E_FAILURE;
4142 cdf_nbuf_free(buf);
4143 }
4144 }
4145 }
4146
4147aggr_qos_exit:
4148 /* send reponse to upper layers from here only. */
4149 wma_send_msg(wma, WMA_AGGR_QOS_RSP, pAggrQosRspMsg, 0);
4150}
4151
4152/**
4153 * wma_add_ts_req() - send ADDTS request to fw
4154 * @wma: wma handle
4155 * @msg: ADDTS params
4156 *
4157 * Return: none
4158 */
4159void wma_add_ts_req(tp_wma_handle wma, tAddTsParams *msg)
4160{
4161 wmi_vdev_wmm_addts_cmd_fixed_param *cmd;
4162 wmi_buf_t buf;
4163 int32_t len = sizeof(*cmd);
4164
4165#ifdef FEATURE_WLAN_ESE
4166 /*
4167 * msmt_interval is in unit called TU (1 TU = 1024 us)
4168 * max value of msmt_interval cannot make resulting
4169 * interval_miliseconds overflow 32 bit
4170 */
4171 uint32_t intervalMiliseconds;
4172 ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX);
4173 if (NULL == pdev) {
4174 WMA_LOGE("%s: Failed to get pdev", __func__);
4175 goto err;
4176 }
4177
4178 intervalMiliseconds = (msg->tsm_interval * 1024) / 1000;
4179
4180 ol_tx_set_compute_interval(pdev, intervalMiliseconds);
4181#endif /* FEATURE_WLAN_ESE */
4182 msg->status = CDF_STATUS_SUCCESS;
4183
4184 buf = wmi_buf_alloc(wma->wmi_handle, len);
4185 if (!buf) {
4186 WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
4187 goto err;
4188 }
4189 cmd = (wmi_vdev_wmm_addts_cmd_fixed_param *) wmi_buf_data(buf);
4190 WMITLV_SET_HDR(&cmd->tlv_header,
4191 WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param,
4192 WMITLV_GET_STRUCT_TLVLEN
4193 (wmi_vdev_wmm_addts_cmd_fixed_param));
4194 cmd->vdev_id = msg->sme_session_id;
4195 cmd->ac = TID_TO_WME_AC(msg->tspec.tsinfo.traffic.userPrio);
4196 cmd->medium_time_us = msg->tspec.mediumTime * 32;
4197 cmd->downgrade_type = WMM_AC_DOWNGRADE_DROP;
4198 WMA_LOGD("Addts vdev:%d, ac:%d, mediumTime:%d, downgrade_type:%d %s:%d",
4199 cmd->vdev_id, cmd->ac, cmd->medium_time_us,
4200 cmd->downgrade_type, __func__, __LINE__);
4201 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
4202 WMI_VDEV_WMM_ADDTS_CMDID)) {
4203 WMA_LOGP("%s: Failed to send vdev ADDTS command", __func__);
4204 msg->status = CDF_STATUS_E_FAILURE;
4205 cdf_nbuf_free(buf);
4206 }
4207#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4208 if (msg->setRICparams == true)
4209 wma_set_ric_req(wma, msg, true);
4210#endif /* WLAN_FEATURE_ROAM_OFFLOAD */
4211
4212err:
4213 wma_send_msg(wma, WMA_ADD_TS_RSP, msg, 0);
4214}
4215
4216/**
4217 * wma_enable_disable_packet_filter() - enable/disable packet filter in target
4218 * @wma: Pointer to wma handle
4219 * @vdev_id: vdev id
4220 * @enable: Flag to enable/disable packet filter
4221 *
4222 * Return: 0 for success or error code
4223 */
4224static int wma_enable_disable_packet_filter(tp_wma_handle wma,
4225 uint8_t vdev_id, bool enable)
4226{
4227 int32_t len;
4228 int ret = 0;
4229 wmi_buf_t buf;
4230 WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *cmd;
4231
4232 len = sizeof(WMI_PACKET_FILTER_ENABLE_CMD_fixed_param);
4233
4234 buf = wmi_buf_alloc(wma->wmi_handle, len);
4235 if (!buf) {
4236 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
4237 return -ENOMEM;
4238 }
4239
4240 cmd = (WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *) wmi_buf_data(buf);
4241 WMITLV_SET_HDR(&cmd->tlv_header,
4242 WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param,
4243 WMITLV_GET_STRUCT_TLVLEN(
4244 WMI_PACKET_FILTER_ENABLE_CMD_fixed_param));
4245
4246 cmd->vdev_id = vdev_id;
4247 if (enable)
4248 cmd->enable = PACKET_FILTER_SET_ENABLE;
4249 else
4250 cmd->enable = PACKET_FILTER_SET_DISABLE;
4251
4252 WMA_LOGE("%s: Packet filter enable %d for vdev_id %d",
4253 __func__, cmd->enable, vdev_id);
4254
4255 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
4256 WMI_PACKET_FILTER_ENABLE_CMDID);
4257 if (ret)
4258 WMA_LOGE("Failed to send packet filter wmi cmd to fw");
4259
4260 return ret;
4261}
4262
4263/**
4264 * wma_config_packet_filter() - configure packet filter in target
4265 * @wma: Pointer to wma handle
4266 * @vdev_id: vdev id
4267 * @rcv_filter_param: Packet filter parameters
4268 * @filter_id: Filter id
4269 * @enable: Flag to add/delete packet filter configuration
4270 *
4271 * Return: 0 for success or error code
4272 */
4273static int wma_config_packet_filter(tp_wma_handle wma,
4274 uint8_t vdev_id, tSirRcvPktFilterCfgType *rcv_filter_param,
4275 uint8_t filter_id, bool enable)
4276{
4277 int len, i;
4278 int err = 0;
4279 wmi_buf_t buf;
4280 WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *cmd;
4281
4282
4283 /* allocate the memory */
4284 len = sizeof(*cmd);
4285 buf = wmi_buf_alloc(wma->wmi_handle, len);
4286 if (!buf) {
4287 WMA_LOGE("Failed to allocate buffer to send set_param cmd");
4288 return -ENOMEM;
4289 }
4290
4291 cmd = (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *)wmi_buf_data(buf);
4292 WMITLV_SET_HDR(&cmd->tlv_header,
4293 WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param,
4294 WMITLV_GET_STRUCT_TLVLEN
4295 (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param));
4296
4297 cmd->vdev_id = vdev_id;
4298 cmd->filter_id = filter_id;
4299 if (enable)
4300 cmd->filter_action = PACKET_FILTER_SET_ACTIVE;
4301 else
4302 cmd->filter_action = PACKET_FILTER_SET_INACTIVE;
4303
4304 if (enable) {
4305 cmd->num_params = CDF_MIN(
4306 WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER,
4307 rcv_filter_param->numFieldParams);
4308 cmd->filter_type = rcv_filter_param->filterType;
4309 cmd->coalesce_time = rcv_filter_param->coalesceTime;
4310
4311 for (i = 0; i < cmd->num_params; i++) {
4312 cmd->paramsData[i].proto_type =
4313 rcv_filter_param->paramsData[i].protocolLayer;
4314 cmd->paramsData[i].cmp_type =
4315 rcv_filter_param->paramsData[i].cmpFlag;
4316 cmd->paramsData[i].data_length =
4317 rcv_filter_param->paramsData[i].dataLength;
4318 cmd->paramsData[i].data_offset =
4319 rcv_filter_param->paramsData[i].dataOffset;
4320 memcpy(&cmd->paramsData[i].compareData,
4321 rcv_filter_param->paramsData[i].compareData,
4322 sizeof(cmd->paramsData[i].compareData));
4323 memcpy(&cmd->paramsData[i].dataMask,
4324 rcv_filter_param->paramsData[i].dataMask,
4325 sizeof(cmd->paramsData[i].dataMask));
4326 }
4327 }
4328
4329 WMA_LOGE("Packet filter action %d filter with id: %d, num_params=%d",
4330 cmd->filter_action, cmd->filter_id, cmd->num_params);
4331 /* send the command along with data */
4332 err = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
4333 WMI_PACKET_FILTER_CONFIG_CMDID);
4334 if (err) {
4335 WMA_LOGE("Failed to send pkt_filter cmd");
4336 wmi_buf_free(buf);
4337 return -EIO;
4338 }
4339
4340 /* Enable packet filter */
4341 if (enable)
4342 wma_enable_disable_packet_filter(wma, vdev_id, true);
4343
4344 return 0;
4345}
4346
4347/**
4348 * wma_process_receive_filter_set_filter_req() - enable packet filter
4349 * @wma_handle: wma handle
4350 * @rcv_filter_param: filter params
4351 *
4352 * Return: 0 for success or error code
4353 */
4354int wma_process_receive_filter_set_filter_req(tp_wma_handle wma,
4355 tSirRcvPktFilterCfgType *rcv_filter_param)
4356{
4357 int ret = 0;
4358 uint8_t vdev_id;
4359
4360 /* Get the vdev id */
4361 if (!wma_find_vdev_by_bssid(wma, rcv_filter_param->bssId, &vdev_id)) {
4362 WMA_LOGE("vdev handle is invalid for %pM",
4363 rcv_filter_param->bssId);
4364 return -EINVAL;
4365 }
4366
4367 ret = wma_config_packet_filter(wma, vdev_id, rcv_filter_param,
4368 rcv_filter_param->filterId, true);
4369
4370 return ret;
4371}
4372
4373/**
4374 * wma_process_receive_filter_clear_filter_req() - disable packet filter
4375 * @wma_handle: wma handle
4376 * @rcv_clear_param: filter params
4377 *
4378 * Return: 0 for success or error code
4379 */
4380int wma_process_receive_filter_clear_filter_req(tp_wma_handle wma,
4381 tSirRcvFltPktClearParam *rcv_clear_param)
4382{
4383 int ret = 0;
4384 uint8_t vdev_id;
4385
4386 /* Get the vdev id */
4387 if (!wma_find_vdev_by_bssid(wma, rcv_clear_param->bssId, &vdev_id)) {
4388 WMA_LOGE("vdev handle is invalid for %pM", rcv_clear_param->bssId);
4389 return -EINVAL;
4390 }
4391
4392 ret = wma_config_packet_filter(wma, vdev_id, NULL,
4393 rcv_clear_param->filterId, false);
4394
4395 return ret;
4396}
4397
4398#ifdef FEATURE_WLAN_ESE
4399
4400#define TSM_DELAY_HISTROGRAM_BINS 4
4401/**
4402 * wma_process_tsm_stats_req() - process tsm stats request
4403 * @wma_handler - handle to wma
4404 * @pTsmStatsMsg - TSM stats struct that needs to be populated and
4405 * passed in message.
4406 *
4407 * A parallel function to WMA_ProcessTsmStatsReq for pronto. This
4408 * function fetches stats from data path APIs and post
4409 * WMA_TSM_STATS_RSP msg back to LIM.
4410 *
4411 * Return: CDF status
4412 */
4413CDF_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler,
4414 void *pTsmStatsMsg)
4415{
4416 uint8_t counter;
4417 uint32_t queue_delay_microsec = 0;
4418 uint32_t tx_delay_microsec = 0;
4419 uint16_t packet_count = 0;
4420 uint16_t packet_loss_count = 0;
4421 tpAniTrafStrmMetrics pTsmMetric = NULL;
4422#ifdef FEATURE_WLAN_ESE_UPLOAD
4423 tpAniGetTsmStatsReq pStats = (tpAniGetTsmStatsReq) pTsmStatsMsg;
4424 tpAniGetTsmStatsRsp pTsmRspParams = NULL;
4425#else
4426 tpTSMStats pStats = (tpTSMStats) pTsmStatsMsg;
4427#endif /* FEATURE_WLAN_ESE_UPLOAD */
4428 int tid = pStats->tid;
4429 /*
4430 * The number of histrogram bin report by data path api are different
4431 * than required by TSM, hence different (6) size array used
4432 */
4433 uint16_t bin_values[QCA_TX_DELAY_HIST_REPORT_BINS] = { 0, };
4434
4435 ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX);
4436
4437 if (NULL == pdev) {
4438 WMA_LOGE("%s: Failed to get pdev", __func__);
4439 cdf_mem_free(pTsmStatsMsg);
4440 return CDF_STATUS_E_INVAL;
4441 }
4442
4443 /* get required values from data path APIs */
4444 ol_tx_delay(pdev, &queue_delay_microsec, &tx_delay_microsec, tid);
4445 ol_tx_delay_hist(pdev, bin_values, tid);
4446 ol_tx_packet_count(pdev, &packet_count, &packet_loss_count, tid);
4447
4448#ifdef FEATURE_WLAN_ESE_UPLOAD
4449 pTsmRspParams =
4450 (tpAniGetTsmStatsRsp) cdf_mem_malloc(sizeof(tAniGetTsmStatsRsp));
4451 if (NULL == pTsmRspParams) {
4452 CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR,
4453 "%s: CDF MEM Alloc Failure", __func__);
4454 CDF_ASSERT(0);
4455 cdf_mem_free(pTsmStatsMsg);
4456 return CDF_STATUS_E_NOMEM;
4457 }
4458 pTsmRspParams->staId = pStats->staId;
4459 pTsmRspParams->rc = eSIR_FAILURE;
4460 pTsmRspParams->tsmStatsReq = pStats;
4461 pTsmMetric = &pTsmRspParams->tsmMetrics;
4462#else
4463 pTsmMetric = (tpAniTrafStrmMetrics)&(pStats->tsmMetrics);
4464#endif /* FEATURE_WLAN_ESE_UPLOAD */
4465 /* populate pTsmMetric */
4466 pTsmMetric->UplinkPktQueueDly = queue_delay_microsec;
4467 /* store only required number of bin values */
4468 for (counter = 0; counter < TSM_DELAY_HISTROGRAM_BINS; counter++) {
4469 pTsmMetric->UplinkPktQueueDlyHist[counter] =
4470 bin_values[counter];
4471 }
4472 pTsmMetric->UplinkPktTxDly = tx_delay_microsec;
4473 pTsmMetric->UplinkPktLoss = packet_loss_count;
4474 pTsmMetric->UplinkPktCount = packet_count;
4475
4476 /*
4477 * No need to populate roaming delay and roaming count as they are
4478 * being populated just before sending IAPP frame out
4479 */
4480 /* post this message to LIM/PE */
4481#ifdef FEATURE_WLAN_ESE_UPLOAD
4482 wma_send_msg(wma_handler, WMA_TSM_STATS_RSP, (void *)pTsmRspParams, 0);
4483#else
4484 wma_send_msg(wma_handler, WMA_TSM_STATS_RSP, (void *)pTsmStatsMsg, 0);
4485#endif /* FEATURE_WLAN_ESE_UPLOAD */
4486 return CDF_STATUS_SUCCESS;
4487}
4488
4489#endif /* FEATURE_WLAN_ESE */
4490
4491/**
4492 * wma_add_clear_mcbc_filter() - set mcast filter command to fw
4493 * @wma_handle: wma handle
4494 * @vdev_id: vdev id
4495 * @multicastAddr: mcast address
4496 * @clearList: clear list flag
4497 *
4498 * Return: 0 for success or error code
4499 */
4500static int wma_add_clear_mcbc_filter(tp_wma_handle wma_handle, uint8_t vdev_id,
4501 tSirMacAddr multicastAddr, bool clearList)
4502{
4503 WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *cmd;
4504 wmi_buf_t buf;
4505 int err;
4506
4507 buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
4508 if (!buf) {
4509 WMA_LOGE("Failed to allocate buffer to send set_param cmd");
4510 return -ENOMEM;
4511 }
4512
4513 cmd = (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *) wmi_buf_data(buf);
4514 cdf_mem_zero(cmd, sizeof(*cmd));
4515
4516 WMITLV_SET_HDR(&cmd->tlv_header,
4517 WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param,
4518 WMITLV_GET_STRUCT_TLVLEN
4519 (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param));
4520 cmd->action =
4521 (clearList ? WMI_MCAST_FILTER_DELETE : WMI_MCAST_FILTER_SET);
4522 cmd->vdev_id = vdev_id;
4523 WMI_CHAR_ARRAY_TO_MAC_ADDR(multicastAddr, &cmd->mcastbdcastaddr);
4524 err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
4525 sizeof(*cmd),
4526 WMI_SET_MCASTBCAST_FILTER_CMDID);
4527 if (err) {
4528 WMA_LOGE("Failed to send set_param cmd");
4529 cdf_mem_free(buf);
4530 return -EIO;
4531 }
4532 WMA_LOGD("Action:%d; vdev_id:%d; clearList:%d\n",
4533 cmd->action, vdev_id, clearList);
4534 WMA_LOGD("MCBC MAC Addr: %0x:%0x:%0x:%0x:%0x:%0x\n",
4535 multicastAddr[0], multicastAddr[1], multicastAddr[2],
4536 multicastAddr[3], multicastAddr[4], multicastAddr[5]);
4537 return 0;
4538}
4539
4540/**
4541 * wma_process_mcbc_set_filter_req() - process mcbc set filter request
4542 * @wma_handle: wma handle
4543 * @mcbc_param: mcbc params
4544 *
4545 * Return: CDF status
4546 */
4547CDF_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle,
4548 tSirRcvFltMcAddrList * mcbc_param)
4549{
4550 uint8_t vdev_id = 0;
4551 int i;
4552
4553 if (mcbc_param->ulMulticastAddrCnt <= 0) {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08004554 WMA_LOGW("Number of multicast addresses is 0");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004555 return CDF_STATUS_E_FAILURE;
4556 }
4557
4558 if (!wma_find_vdev_by_addr
4559 (wma_handle, mcbc_param->selfMacAddr, &vdev_id)) {
4560 WMA_LOGE("%s: Failed to find vdev id for %pM", __func__,
4561 mcbc_param->bssId);
4562 return CDF_STATUS_E_FAILURE;
4563 }
4564 /* set mcbc_param->action to clear MCList and reset
4565 * to configure the MCList in FW
4566 */
4567
4568 for (i = 0; i < mcbc_param->ulMulticastAddrCnt; i++) {
4569 wma_add_clear_mcbc_filter(wma_handle, vdev_id,
4570 mcbc_param->multicastAddr[i],
4571 (mcbc_param->action == 0));
4572 }
4573 return CDF_STATUS_SUCCESS;
4574}
4575
4576#ifdef WLAN_FEATURE_GTK_OFFLOAD
4577#define GTK_OFFLOAD_ENABLE 0
4578#define GTK_OFFLOAD_DISABLE 1
4579
4580/**
4581 * wma_gtk_offload_status_event() - GTK offload status event handler
4582 * @handle: wma handle
4583 * @event: event buffer
4584 * @len: buffer length
4585 *
4586 * Return: 0 for success or error code
4587 */
4588int wma_gtk_offload_status_event(void *handle, uint8_t *event,
4589 uint32_t len)
4590{
4591 tp_wma_handle wma = (tp_wma_handle) handle;
4592 WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *status;
4593 WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *param_buf;
4594 tpSirGtkOffloadGetInfoRspParams resp;
4595 cds_msg_t cds_msg;
4596 uint8_t *bssid;
4597
4598 WMA_LOGD("%s Enter", __func__);
4599
4600 param_buf = (WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *) event;
4601 if (!param_buf) {
4602 WMA_LOGE("param_buf is NULL");
4603 return -EINVAL;
4604 }
4605
4606 status = (WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *) param_buf->fixed_param;
4607
4608 if (len < sizeof(WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param)) {
4609 WMA_LOGE("Invalid length for GTK status");
4610 return -EINVAL;
4611 }
4612 bssid = wma_find_bssid_by_vdev_id(wma, status->vdev_id);
4613 if (!bssid) {
4614 WMA_LOGE("invalid bssid for vdev id %d", status->vdev_id);
4615 return -ENOENT;
4616 }
4617
4618 resp = cdf_mem_malloc(sizeof(*resp));
4619 if (!resp) {
4620 WMA_LOGE("%s: Failed to alloc response", __func__);
4621 return -ENOMEM;
4622 }
4623 cdf_mem_zero(resp, sizeof(*resp));
4624 resp->mesgType = eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP;
4625 resp->mesgLen = sizeof(*resp);
4626 resp->ulStatus = CDF_STATUS_SUCCESS;
4627 resp->ulTotalRekeyCount = status->refresh_cnt;
4628 /* TODO: Is the total rekey count and GTK rekey count same? */
4629 resp->ulGTKRekeyCount = status->refresh_cnt;
4630
4631 cdf_mem_copy(&resp->ullKeyReplayCounter, &status->replay_counter,
4632 GTK_REPLAY_COUNTER_BYTES);
4633
4634 cdf_mem_copy(resp->bssId, bssid, IEEE80211_ADDR_LEN);
4635
4636#ifdef IGTK_OFFLOAD
4637 /* TODO: Is the refresh count same for GTK and IGTK? */
4638 resp->ulIGTKRekeyCount = status->refresh_cnt;
4639#endif /* IGTK_OFFLOAD */
4640
4641 cds_msg.type = eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP;
4642 cds_msg.bodyptr = (void *)resp;
4643 cds_msg.bodyval = 0;
4644
4645 if (cds_mq_post_message(CDS_MQ_ID_SME, (cds_msg_t *) &cds_msg)
4646 != CDF_STATUS_SUCCESS) {
4647 WMA_LOGE("Failed to post GTK response to SME");
4648 cdf_mem_free(resp);
4649 return -EINVAL;
4650 }
4651
4652 WMA_LOGD("GTK: got target status with replay counter "
4653 "%02x%02x%02x%02x%02x%02x%02x%02x. vdev %d "
4654 "Refresh GTK %d times exchanges since last set operation",
4655 status->replay_counter[0],
4656 status->replay_counter[1],
4657 status->replay_counter[2],
4658 status->replay_counter[3],
4659 status->replay_counter[4],
4660 status->replay_counter[5],
4661 status->replay_counter[6],
4662 status->replay_counter[7],
4663 status->vdev_id, status->refresh_cnt);
4664
4665 WMA_LOGD("%s Exit", __func__);
4666
4667 return 0;
4668}
4669
4670/**
4671 * wma_send_gtk_offload_req() - send GTK offload command to fw
4672 * @wma: wma handle
4673 * @vdev_id: vdev id
4674 * @params: GTK offload parameters
4675 *
4676 * Return: CDF status
4677 */
4678static CDF_STATUS wma_send_gtk_offload_req(tp_wma_handle wma, uint8_t vdev_id,
4679 tpSirGtkOffloadParams params)
4680{
4681 int len;
4682 wmi_buf_t buf;
4683 WMI_GTK_OFFLOAD_CMD_fixed_param *cmd;
4684 CDF_STATUS status = CDF_STATUS_SUCCESS;
4685
4686 WMA_LOGD("%s Enter", __func__);
4687
4688 len = sizeof(*cmd);
4689
4690 /* alloc wmi buffer */
4691 buf = wmi_buf_alloc(wma->wmi_handle, len);
4692 if (!buf) {
4693 WMA_LOGE("wmi_buf_alloc failed for WMI_GTK_OFFLOAD_CMD");
4694 status = CDF_STATUS_E_NOMEM;
4695 goto out;
4696 }
4697
4698 cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf);
4699 WMITLV_SET_HDR(&cmd->tlv_header,
4700 WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param,
4701 WMITLV_GET_STRUCT_TLVLEN
4702 (WMI_GTK_OFFLOAD_CMD_fixed_param));
4703
4704 cmd->vdev_id = vdev_id;
4705
4706 /* Request target to enable GTK offload */
4707 if (params->ulFlags == GTK_OFFLOAD_ENABLE) {
4708 cmd->flags = GTK_OFFLOAD_ENABLE_OPCODE;
4709 wma->wow.gtk_err_enable[vdev_id] = true;
4710
4711 /* Copy the keys and replay counter */
4712 cdf_mem_copy(cmd->KCK, params->aKCK, GTK_OFFLOAD_KCK_BYTES);
4713 cdf_mem_copy(cmd->KEK, params->aKEK, GTK_OFFLOAD_KEK_BYTES);
4714 cdf_mem_copy(cmd->replay_counter, &params->ullKeyReplayCounter,
4715 GTK_REPLAY_COUNTER_BYTES);
4716 } else {
4717 wma->wow.gtk_err_enable[vdev_id] = false;
4718 cmd->flags = GTK_OFFLOAD_DISABLE_OPCODE;
4719 }
4720
4721 /* send the wmi command */
4722 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
4723 WMI_GTK_OFFLOAD_CMDID)) {
4724 WMA_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID");
4725 wmi_buf_free(buf);
4726 status = CDF_STATUS_E_FAILURE;
4727 }
4728
4729 WMA_LOGD("VDEVID: %d, GTK_FLAGS: x%x", vdev_id, cmd->flags);
4730out:
4731 WMA_LOGD("%s Exit", __func__);
4732 return status;
4733}
4734
4735/**
4736 * wma_process_gtk_offload_req() - process GTK offload req from umac
4737 * @handle: wma handle
4738 * @params: GTK offload params
4739 *
4740 * Return: CDF status
4741 */
4742CDF_STATUS wma_process_gtk_offload_req(tp_wma_handle wma,
4743 tpSirGtkOffloadParams params)
4744{
4745 uint8_t vdev_id;
4746 CDF_STATUS status = CDF_STATUS_SUCCESS;
4747
4748 WMA_LOGD("%s Enter", __func__);
4749
4750 /* Get the vdev id */
4751 if (!wma_find_vdev_by_bssid(wma, params->bssId, &vdev_id)) {
4752 WMA_LOGE("vdev handle is invalid for %pM", params->bssId);
4753 status = CDF_STATUS_E_INVAL;
4754 goto out;
4755 }
4756
4757 /* Validate vdev id */
4758 if (vdev_id >= wma->max_bssid) {
4759 WMA_LOGE("invalid vdev_id %d for %pM", vdev_id, params->bssId);
4760 status = CDF_STATUS_E_INVAL;
4761 goto out;
4762 }
4763
4764 if ((params->ulFlags == GTK_OFFLOAD_ENABLE) &&
4765 (wma->wow.gtk_err_enable[vdev_id] == true)) {
4766 WMA_LOGE("%s GTK Offload already enabled. Disable it first "
4767 "vdev_id %d", __func__, vdev_id);
4768 params->ulFlags = GTK_OFFLOAD_DISABLE;
4769 status = wma_send_gtk_offload_req(wma, vdev_id, params);
4770 if (status != CDF_STATUS_SUCCESS) {
4771 WMA_LOGE("%s Failed to disable GTK Offload", __func__);
4772 goto out;
4773 }
4774 WMA_LOGD("%s Enable GTK Offload again with updated inputs",
4775 __func__);
4776 params->ulFlags = GTK_OFFLOAD_ENABLE;
4777 }
4778 status = wma_send_gtk_offload_req(wma, vdev_id, params);
4779out:
4780 cdf_mem_free(params);
4781 WMA_LOGD("%s Exit", __func__);
4782 return status;
4783}
4784
4785/**
4786 * wma_process_gtk_offload_getinfo_req() - send GTK offload cmd to fw
4787 * @wma: wma handle
4788 * @params: GTK offload params
4789 *
4790 * Return: CDF status
4791 */
4792CDF_STATUS wma_process_gtk_offload_getinfo_req(tp_wma_handle wma,
4793 tpSirGtkOffloadGetInfoRspParams params)
4794{
4795 uint8_t vdev_id;
4796 int len;
4797 wmi_buf_t buf;
4798 WMI_GTK_OFFLOAD_CMD_fixed_param *cmd;
4799 CDF_STATUS status = CDF_STATUS_SUCCESS;
4800
4801 WMA_LOGD("%s Enter", __func__);
4802
4803 /* Get the vdev id */
4804 if (!wma_find_vdev_by_bssid(wma, params->bssId, &vdev_id)) {
4805 WMA_LOGE("vdev handle is invalid for %pM", params->bssId);
4806 status = CDF_STATUS_E_INVAL;
4807 goto out;
4808 }
4809
4810 len = sizeof(*cmd);
4811
4812 /* alloc wmi buffer */
4813 buf = wmi_buf_alloc(wma->wmi_handle, len);
4814 if (!buf) {
4815 WMA_LOGE("wmi_buf_alloc failed for WMI_GTK_OFFLOAD_CMD");
4816 status = CDF_STATUS_E_NOMEM;
4817 goto out;
4818 }
4819
4820 cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf);
4821 WMITLV_SET_HDR(&cmd->tlv_header,
4822 WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param,
4823 WMITLV_GET_STRUCT_TLVLEN
4824 (WMI_GTK_OFFLOAD_CMD_fixed_param));
4825
4826 /* Request for GTK offload status */
4827 cmd->flags = GTK_OFFLOAD_REQUEST_STATUS_OPCODE;
4828 cmd->vdev_id = vdev_id;
4829
4830 /* send the wmi command */
4831 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
4832 WMI_GTK_OFFLOAD_CMDID)) {
4833 WMA_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID for req info");
4834 wmi_buf_free(buf);
4835 status = CDF_STATUS_E_FAILURE;
4836 }
4837out:
4838 cdf_mem_free(params);
4839 WMA_LOGD("%s Exit", __func__);
4840 return status;
4841}
4842#endif /* WLAN_FEATURE_GTK_OFFLOAD */
4843
4844/**
4845 * wma_enable_arp_ns_offload() - enable ARP NS offload
4846 * @wma: wma handle
4847 * @tpSirHostOffloadReq: offload request
4848 * @bArpOnly: flag
4849 *
4850 * To configure ARP NS off load data to firmware
4851 * when target goes to wow mode.
4852 *
4853 * Return: CDF Status
4854 */
4855CDF_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma,
4856 tpSirHostOffloadReq
4857 pHostOffloadParams, bool bArpOnly)
4858{
4859 int32_t i;
4860 int32_t res;
4861 WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *cmd;
4862 WMI_NS_OFFLOAD_TUPLE *ns_tuple;
4863 WMI_ARP_OFFLOAD_TUPLE *arp_tuple;
4864 A_UINT8 *buf_ptr;
4865 wmi_buf_t buf;
4866 int32_t len;
4867 uint8_t vdev_id;
4868 uint32_t count = 0, num_ns_ext_tuples = 0;
4869
4870 /* Get the vdev id */
4871 if (!wma_find_vdev_by_bssid(wma, pHostOffloadParams->bssId, &vdev_id)) {
4872 WMA_LOGE("vdev handle is invalid for %pM",
4873 pHostOffloadParams->bssId);
4874 cdf_mem_free(pHostOffloadParams);
4875 return CDF_STATUS_E_INVAL;
4876 }
4877
4878 if (!wma->interfaces[vdev_id].vdev_up) {
4879
4880 WMA_LOGE("vdev %d is not up skipping arp/ns offload", vdev_id);
4881 cdf_mem_free(pHostOffloadParams);
4882 return CDF_STATUS_E_FAILURE;
4883 }
4884
4885 if (!bArpOnly)
4886 count = pHostOffloadParams->num_ns_offload_count;
4887
4888
4889 len = sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param) + WMI_TLV_HDR_SIZE + /* TLV place holder size for array of NS tuples */
4890 WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE) + WMI_TLV_HDR_SIZE + /* TLV place holder size for array of ARP tuples */
4891 WMI_MAX_ARP_OFFLOADS * sizeof(WMI_ARP_OFFLOAD_TUPLE);
4892
4893 /*
4894 * If there are more than WMI_MAX_NS_OFFLOADS addresses then allocate
4895 * extra length for extended NS offload tuples which follows ARP offload
4896 * tuples. Host needs to fill this structure in following format:
4897 * 2 NS ofload tuples
4898 * 2 ARP offload tuples
4899 * N numbers of extended NS offload tuples if HDD has given more than
4900 * 2 NS offload addresses
4901 */
4902 if (!bArpOnly && count > WMI_MAX_NS_OFFLOADS) {
4903 num_ns_ext_tuples = count - WMI_MAX_NS_OFFLOADS;
4904 len += WMI_TLV_HDR_SIZE + num_ns_ext_tuples *
4905 sizeof(WMI_NS_OFFLOAD_TUPLE);
4906 }
4907
4908 buf = wmi_buf_alloc(wma->wmi_handle, len);
4909 if (!buf) {
4910 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
4911 cdf_mem_free(pHostOffloadParams);
4912 return CDF_STATUS_E_NOMEM;
4913 }
4914
4915 buf_ptr = (A_UINT8 *) wmi_buf_data(buf);
4916 cmd = (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *) buf_ptr;
4917 WMITLV_SET_HDR(&cmd->tlv_header,
4918 WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param,
4919 WMITLV_GET_STRUCT_TLVLEN
4920 (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param));
4921 cmd->flags = 0;
4922 cmd->vdev_id = vdev_id;
4923 if (!bArpOnly)
4924 cmd->num_ns_ext_tuples = num_ns_ext_tuples;
4925
4926 WMA_LOGD("ARP NS Offload vdev_id: %d", cmd->vdev_id);
4927
4928 /* Have copy of arp info to send along with NS, Since FW expects
4929 * both ARP and NS info in single cmd */
4930 if (bArpOnly)
4931 cdf_mem_copy(&wma->mArpInfo, pHostOffloadParams,
4932 sizeof(tSirHostOffloadReq));
4933
4934 buf_ptr += sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param);
4935 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
4936 (WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE)));
4937 buf_ptr += WMI_TLV_HDR_SIZE;
4938 for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) {
4939 ns_tuple = (WMI_NS_OFFLOAD_TUPLE *) buf_ptr;
4940 WMITLV_SET_HDR(&ns_tuple->tlv_header,
4941 WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE,
4942 (sizeof(WMI_NS_OFFLOAD_TUPLE) -
4943 WMI_TLV_HDR_SIZE));
4944
4945 /* Fill data only for NS offload in the first ARP tuple for LA */
4946 if (!bArpOnly &&
4947 ((pHostOffloadParams->enableOrDisable & SIR_OFFLOAD_ENABLE))) {
4948 ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID;
4949
4950#ifdef WLAN_NS_OFFLOAD
4951 /*Copy the target/solicitation/remote ip addr */
4952 if (pHostOffloadParams->nsOffloadInfo.
4953 targetIPv6AddrValid[i])
4954 A_MEMCPY(&ns_tuple->target_ipaddr[0],
4955 &pHostOffloadParams->nsOffloadInfo.
4956 targetIPv6Addr[i],
4957 sizeof(WMI_IPV6_ADDR));
4958 A_MEMCPY(&ns_tuple->solicitation_ipaddr,
4959 &pHostOffloadParams->nsOffloadInfo.
4960 selfIPv6Addr[i], sizeof(WMI_IPV6_ADDR));
4961 WMA_LOGD("NS solicitedIp: %pI6, targetIp: %pI6",
4962 &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i],
4963 &pHostOffloadParams->nsOffloadInfo.
4964 targetIPv6Addr[i]);
4965
4966 /* target MAC is optional, check if it is valid,
4967 * if this is not valid, the target will use the known
4968 * local MAC address rather than the tuple
4969 */
4970 WMI_CHAR_ARRAY_TO_MAC_ADDR(pHostOffloadParams->
4971 nsOffloadInfo.selfMacAddr,
4972 &ns_tuple->target_mac);
4973#endif /* WLAN_NS_OFFLOAD */
4974 if ((ns_tuple->target_mac.mac_addr31to0 != 0) ||
4975 (ns_tuple->target_mac.mac_addr47to32 != 0)) {
4976 ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID;
4977 }
4978 }
4979 buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE);
4980 }
4981
4982 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
4983 (WMI_MAX_ARP_OFFLOADS * sizeof(WMI_ARP_OFFLOAD_TUPLE)));
4984 buf_ptr += WMI_TLV_HDR_SIZE;
4985 for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) {
4986 arp_tuple = (WMI_ARP_OFFLOAD_TUPLE *) buf_ptr;
4987 WMITLV_SET_HDR(&arp_tuple->tlv_header,
4988 WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE,
4989 WMITLV_GET_STRUCT_TLVLEN(WMI_ARP_OFFLOAD_TUPLE));
4990
4991 /* Fill data for ARP and NS in the first tupple for LA */
4992 if ((wma->mArpInfo.enableOrDisable & SIR_OFFLOAD_ENABLE)
4993 && (i == 0)) {
4994 /*Copy the target ip addr and flags */
4995 arp_tuple->flags = WMI_ARPOFF_FLAGS_VALID;
4996 A_MEMCPY(&arp_tuple->target_ipaddr,
4997 wma->mArpInfo.params.hostIpv4Addr,
4998 SIR_IPV4_ADDR_LEN);
4999 WMA_LOGD("ARPOffload IP4 address: %pI4",
5000 wma->mArpInfo.params.hostIpv4Addr);
5001 }
5002 buf_ptr += sizeof(WMI_ARP_OFFLOAD_TUPLE);
5003 }
5004
5005 /* Populate extended NS offload tuples */
5006 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
5007 (num_ns_ext_tuples*sizeof(WMI_NS_OFFLOAD_TUPLE)));
5008 buf_ptr += WMI_TLV_HDR_SIZE;
5009
5010 if (num_ns_ext_tuples) {
5011 for (i = WMI_MAX_NS_OFFLOADS; i < count; i++) {
5012 ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)buf_ptr;
5013 WMITLV_SET_HDR(&ns_tuple->tlv_header,
5014 WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE,
5015 (sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE));
5016
5017 /* Fill data only for NS offload in the first ARP tuple for LA */
5018 if (!bArpOnly &&
5019 ((pHostOffloadParams->enableOrDisable & SIR_OFFLOAD_ENABLE))) {
5020 ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID;
5021#ifdef WLAN_NS_OFFLOAD
5022 /*Copy the target/solicitation/remote ip addr */
5023 if (pHostOffloadParams->nsOffloadInfo.targetIPv6AddrValid[i])
5024 A_MEMCPY(&ns_tuple->target_ipaddr[0],
5025 &pHostOffloadParams->nsOffloadInfo.targetIPv6Addr[i],
5026 sizeof(WMI_IPV6_ADDR));
5027 A_MEMCPY(&ns_tuple->solicitation_ipaddr,
5028 &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i],
5029 sizeof(WMI_IPV6_ADDR));
5030 WMA_LOGD("Index %d NS solicitedIp: %pI6, targetIp: %pI6", i,
5031 &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i],
5032 &pHostOffloadParams->nsOffloadInfo.targetIPv6Addr[i]);
5033
5034 /* target MAC is optional, check if it is valid, if this is not valid,
5035 * the target will use the known local MAC address rather than the tuple */
5036 WMI_CHAR_ARRAY_TO_MAC_ADDR(pHostOffloadParams->nsOffloadInfo.selfMacAddr,
5037 &ns_tuple->target_mac);
5038#endif
5039 if ((ns_tuple->target_mac.mac_addr31to0 != 0) ||
5040 (ns_tuple->target_mac.mac_addr47to32 != 0)) {
5041 ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID;
5042 }
5043 }
5044 buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE);
5045 }
5046 }
5047
5048 res = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
5049 WMI_SET_ARP_NS_OFFLOAD_CMDID);
5050 if (res) {
5051 WMA_LOGE("Failed to enable ARP NDP/NSffload");
5052 wmi_buf_free(buf);
5053 cdf_mem_free(pHostOffloadParams);
5054 return CDF_STATUS_E_FAILURE;
5055 }
5056
5057 cdf_mem_free(pHostOffloadParams);
5058 return CDF_STATUS_SUCCESS;
5059}
5060
5061/**
5062 * wma_process_add_periodic_tx_ptrn_ind - add periodic tx ptrn
5063 * @handle: wma handle
5064 * @pAddPeriodicTxPtrnParams: tx ptrn params
5065 *
5066 * Retrun: CDF status
5067 */
5068CDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle,
5069 tSirAddPeriodicTxPtrn *
5070 pAddPeriodicTxPtrnParams)
5071{
5072 tp_wma_handle wma_handle = (tp_wma_handle) handle;
5073 WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *cmd;
5074 wmi_buf_t wmi_buf;
5075 uint32_t len;
5076 uint8_t vdev_id;
5077 uint8_t *buf_ptr;
5078 uint32_t ptrn_len, ptrn_len_aligned;
5079 int j;
5080
5081 if (!wma_handle || !wma_handle->wmi_handle) {
5082 WMA_LOGE("%s: WMA is closed, can not issue fw add pattern cmd",
5083 __func__);
5084 return CDF_STATUS_E_INVAL;
5085 }
5086 ptrn_len = pAddPeriodicTxPtrnParams->ucPtrnSize;
5087 ptrn_len_aligned = roundup(ptrn_len, sizeof(uint32_t));
5088 len = sizeof(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param) +
5089 WMI_TLV_HDR_SIZE + ptrn_len_aligned;
5090
5091 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
5092 if (!wmi_buf) {
5093 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
5094 return CDF_STATUS_E_NOMEM;
5095 }
5096 if (!wma_find_vdev_by_addr(wma_handle,
5097 pAddPeriodicTxPtrnParams->macAddress,
5098 &vdev_id)) {
5099 WMA_LOGE("%s: Failed to find vdev id for %pM", __func__,
5100 pAddPeriodicTxPtrnParams->macAddress);
5101 cdf_nbuf_free(wmi_buf);
5102 return CDF_STATUS_E_INVAL;
5103 }
5104 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
5105
5106 cmd = (WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *) buf_ptr;
5107 WMITLV_SET_HDR(&cmd->tlv_header,
5108 WMITLV_TAG_STRUC_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param,
5109 WMITLV_GET_STRUCT_TLVLEN
5110 (WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param));
5111
5112 /* Pass the pattern id to delete for the corresponding vdev id */
5113 cmd->vdev_id = vdev_id;
5114 cmd->pattern_id = pAddPeriodicTxPtrnParams->ucPtrnId;
5115 cmd->timeout = pAddPeriodicTxPtrnParams->usPtrnIntervalMs;
5116 cmd->length = pAddPeriodicTxPtrnParams->ucPtrnSize;
5117
5118 /* Pattern info */
5119 buf_ptr += sizeof(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param);
5120 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ptrn_len_aligned);
5121 buf_ptr += WMI_TLV_HDR_SIZE;
5122 cdf_mem_copy(buf_ptr, pAddPeriodicTxPtrnParams->ucPattern, ptrn_len);
5123 for (j = 0; j < pAddPeriodicTxPtrnParams->ucPtrnSize; j++) {
5124 WMA_LOGD("%s: Add Ptrn: %02x", __func__, buf_ptr[j] & 0xff);
5125 }
5126 WMA_LOGD("%s: Add ptrn id: %d vdev_id: %d",
5127 __func__, cmd->pattern_id, cmd->vdev_id);
5128
5129 if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
5130 WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID)) {
5131 WMA_LOGE("%s: failed to add pattern set state command",
5132 __func__);
5133 cdf_nbuf_free(wmi_buf);
5134 return CDF_STATUS_E_FAILURE;
5135 }
5136 return CDF_STATUS_SUCCESS;
5137}
5138
5139/**
5140 * wma_process_del_periodic_tx_ptrn_ind - del periodic tx ptrn
5141 * @handle: wma handle
5142 * @pDelPeriodicTxPtrnParams: tx ptrn params
5143 *
5144 * Retrun: CDF status
5145 */
5146CDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle,
5147 tSirDelPeriodicTxPtrn *
5148 pDelPeriodicTxPtrnParams)
5149{
5150 tp_wma_handle wma_handle = (tp_wma_handle) handle;
5151 WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *cmd;
5152 wmi_buf_t wmi_buf;
5153 uint8_t vdev_id;
5154 uint32_t len =
5155 sizeof(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param);
5156
5157 if (!wma_handle || !wma_handle->wmi_handle) {
5158 WMA_LOGE("%s: WMA is closed, can not issue Del Pattern cmd",
5159 __func__);
5160 return CDF_STATUS_E_INVAL;
5161 }
5162 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
5163 if (!wmi_buf) {
5164 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
5165 return CDF_STATUS_E_NOMEM;
5166 }
5167 if (!wma_find_vdev_by_addr(wma_handle,
5168 pDelPeriodicTxPtrnParams->macAddress,
5169 &vdev_id)) {
5170 WMA_LOGE("%s: Failed to find vdev id for %pM", __func__,
5171 pDelPeriodicTxPtrnParams->macAddress);
5172 cdf_nbuf_free(wmi_buf);
5173 return CDF_STATUS_E_INVAL;
5174 }
5175 cmd = (WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *)
5176 wmi_buf_data(wmi_buf);
5177 WMITLV_SET_HDR(&cmd->tlv_header,
5178 WMITLV_TAG_STRUC_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param,
5179 WMITLV_GET_STRUCT_TLVLEN
5180 (WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param));
5181
5182 /* Pass the pattern id to delete for the corresponding vdev id */
5183 cmd->vdev_id = vdev_id;
5184 cmd->pattern_id = pDelPeriodicTxPtrnParams->ucPtrnId;
5185 WMA_LOGD("%s: Del ptrn id: %d vdev_id: %d",
5186 __func__, cmd->pattern_id, cmd->vdev_id);
5187
5188 if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
5189 WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID)) {
5190 WMA_LOGE("%s: failed to send del pattern command", __func__);
5191 cdf_nbuf_free(wmi_buf);
5192 return CDF_STATUS_E_FAILURE;
5193 }
5194 return CDF_STATUS_SUCCESS;
5195}
5196
5197#ifdef WLAN_FEATURE_STATS_EXT
5198/**
5199 * wma_stats_ext_req() - request ext stats from fw
5200 * @wma_ptr: wma handle
5201 * @preq: stats ext params
5202 *
5203 * Return: CDF status
5204 */
5205CDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq)
5206{
5207 int32_t ret;
5208 tp_wma_handle wma = (tp_wma_handle) wma_ptr;
5209 wmi_req_stats_ext_cmd_fixed_param *cmd;
5210 wmi_buf_t buf;
5211 uint16_t len;
5212 uint8_t *buf_ptr;
5213
5214 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + preq->request_data_len;
5215
5216 buf = wmi_buf_alloc(wma->wmi_handle, len);
5217 if (!buf) {
5218 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
5219 return -ENOMEM;
5220 }
5221
5222 buf_ptr = (uint8_t *) wmi_buf_data(buf);
5223 cmd = (wmi_req_stats_ext_cmd_fixed_param *) buf_ptr;
5224
5225 WMITLV_SET_HDR(&cmd->tlv_header,
5226 WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param,
5227 WMITLV_GET_STRUCT_TLVLEN
5228 (wmi_req_stats_ext_cmd_fixed_param));
5229 cmd->vdev_id = preq->vdev_id;
5230 cmd->data_len = preq->request_data_len;
5231
5232 WMA_LOGD("%s: The data len value is %u and vdev id set is %u ",
5233 __func__, preq->request_data_len, preq->vdev_id);
5234
5235 buf_ptr += sizeof(wmi_req_stats_ext_cmd_fixed_param);
5236 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, cmd->data_len);
5237
5238 buf_ptr += WMI_TLV_HDR_SIZE;
5239 cdf_mem_copy(buf_ptr, preq->request_data, cmd->data_len);
5240
5241 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
5242 WMI_REQUEST_STATS_EXT_CMDID);
5243 if (ret != EOK) {
5244 WMA_LOGE("%s: Failed to send notify cmd ret = %d", __func__,
5245 ret);
5246 wmi_buf_free(buf);
5247 }
5248
5249 return ret;
5250}
5251
5252#endif /* WLAN_FEATURE_STATS_EXT */
5253
5254#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
5255/**
5256 * wma_send_status_of_ext_wow() - send ext wow status to SME
5257 * @wma: wma handle
5258 * @status: status
5259 *
5260 * Return: none
5261 */
5262static void wma_send_status_of_ext_wow(tp_wma_handle wma, bool status)
5263{
5264 tSirReadyToExtWoWInd *ready_to_extwow;
5265 CDF_STATUS vstatus;
5266 cds_msg_t cds_msg;
5267 uint8_t len;
5268
5269 WMA_LOGD("Posting ready to suspend indication to umac");
5270
5271 len = sizeof(tSirReadyToExtWoWInd);
5272 ready_to_extwow = (tSirReadyToExtWoWInd *) cdf_mem_malloc(len);
5273
5274 if (NULL == ready_to_extwow) {
5275 WMA_LOGE("%s: Memory allocation failure", __func__);
5276 return;
5277 }
5278
5279 ready_to_extwow->mesgType = eWNI_SME_READY_TO_EXTWOW_IND;
5280 ready_to_extwow->mesgLen = len;
5281 ready_to_extwow->status = status;
5282
5283 cds_msg.type = eWNI_SME_READY_TO_EXTWOW_IND;
5284 cds_msg.bodyptr = (void *)ready_to_extwow;
5285 cds_msg.bodyval = 0;
5286
5287 vstatus = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg);
5288 if (vstatus != CDF_STATUS_SUCCESS) {
5289 WMA_LOGE("Failed to post ready to suspend");
5290 cdf_mem_free(ready_to_extwow);
5291 }
5292}
5293
5294/**
5295 * wma_enable_ext_wow() - enable ext wow in fw
5296 * @wma: wma handle
5297 * @params: ext wow params
5298 *
5299 * Return:0 for success or error code
5300 */
5301int wma_enable_ext_wow(tp_wma_handle wma, tpSirExtWoWParams params)
5302{
5303 wmi_extwow_enable_cmd_fixed_param *cmd;
5304 wmi_buf_t buf;
5305 int32_t len;
5306 int ret;
5307
5308 len = sizeof(wmi_extwow_enable_cmd_fixed_param);
5309 buf = wmi_buf_alloc(wma->wmi_handle, len);
5310 if (!buf) {
5311 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
5312 return CDF_STATUS_E_NOMEM;
5313 }
5314
5315 cmd = (wmi_extwow_enable_cmd_fixed_param *) wmi_buf_data(buf);
5316
5317 WMITLV_SET_HDR(&cmd->tlv_header,
5318 WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param,
5319 WMITLV_GET_STRUCT_TLVLEN
5320 (wmi_extwow_enable_cmd_fixed_param));
5321
5322 cmd->vdev_id = params->vdev_id;
5323 cmd->type = params->type;
5324 cmd->wakeup_pin_num = params->wakeup_pin_num;
5325
5326 WMA_LOGD("%s: vdev_id %d type %d Wakeup_pin_num %x",
5327 __func__, cmd->vdev_id, cmd->type, cmd->wakeup_pin_num);
5328
5329 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
5330 WMI_EXTWOW_ENABLE_CMDID);
5331 if (ret) {
5332 WMA_LOGE("%s: Failed to set EXTWOW Enable", __func__);
5333 wmi_buf_free(buf);
5334 wma_send_status_of_ext_wow(wma, false);
5335 return CDF_STATUS_E_FAILURE;
5336 }
5337
5338 wma_send_status_of_ext_wow(wma, true);
5339 return CDF_STATUS_SUCCESS;
5340
5341}
5342
5343/**
5344 * wma_set_app_type1_params_in_fw() - set app type1 params in fw
5345 * @wma: wma handle
5346 * @appType1Params: app type1 params
5347 *
5348 * Return: CDF status
5349 */
5350int wma_set_app_type1_params_in_fw(tp_wma_handle wma,
5351 tpSirAppType1Params appType1Params)
5352{
5353 wmi_extwow_set_app_type1_params_cmd_fixed_param *cmd;
5354 wmi_buf_t buf;
5355 int32_t len;
5356 int ret;
5357
5358 len = sizeof(wmi_extwow_set_app_type1_params_cmd_fixed_param);
5359 buf = wmi_buf_alloc(wma->wmi_handle, len);
5360 if (!buf) {
5361 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
5362 return CDF_STATUS_E_NOMEM;
5363 }
5364
5365 cmd = (wmi_extwow_set_app_type1_params_cmd_fixed_param *)
5366 wmi_buf_data(buf);
5367
5368 WMITLV_SET_HDR(&cmd->tlv_header,
5369 WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param,
5370 WMITLV_GET_STRUCT_TLVLEN
5371 (wmi_extwow_set_app_type1_params_cmd_fixed_param));
5372
5373 cmd->vdev_id = appType1Params->vdev_id;
5374 WMI_CHAR_ARRAY_TO_MAC_ADDR(appType1Params->wakee_mac_addr,
5375 &cmd->wakee_mac);
5376 cdf_mem_copy(cmd->ident, appType1Params->identification_id, 8);
5377 cmd->ident_len = appType1Params->id_length;
5378 cdf_mem_copy(cmd->passwd, appType1Params->password, 16);
5379 cmd->passwd_len = appType1Params->pass_length;
5380
5381 WMA_LOGD("%s: vdev_id %d wakee_mac_addr %pM "
5382 "identification_id %.8s id_length %u "
5383 "password %.16s pass_length %u",
5384 __func__, cmd->vdev_id, appType1Params->wakee_mac_addr,
5385 cmd->ident, cmd->ident_len, cmd->passwd, cmd->passwd_len);
5386
5387 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
5388 WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID);
5389 if (ret) {
5390 WMA_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__);
5391 wmi_buf_free(buf);
5392 return CDF_STATUS_E_FAILURE;
5393 }
5394
5395 return CDF_STATUS_SUCCESS;
5396}
5397
5398/**
5399 * wma_set_app_type2_params_in_fw() - set app type2 params in fw
5400 * @wma: wma handle
5401 * @appType2Params: app type2 params
5402 *
5403 * Return: CDF status
5404 */
5405int wma_set_app_type2_params_in_fw(tp_wma_handle wma,
5406 tpSirAppType2Params appType2Params)
5407{
5408 wmi_extwow_set_app_type2_params_cmd_fixed_param *cmd;
5409 wmi_buf_t buf;
5410 int32_t len;
5411 int ret;
5412
5413 len = sizeof(wmi_extwow_set_app_type2_params_cmd_fixed_param);
5414 buf = wmi_buf_alloc(wma->wmi_handle, len);
5415 if (!buf) {
5416 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
5417 return CDF_STATUS_E_NOMEM;
5418 }
5419
5420 cmd = (wmi_extwow_set_app_type2_params_cmd_fixed_param *)
5421 wmi_buf_data(buf);
5422
5423 WMITLV_SET_HDR(&cmd->tlv_header,
5424 WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param,
5425 WMITLV_GET_STRUCT_TLVLEN
5426 (wmi_extwow_set_app_type2_params_cmd_fixed_param));
5427
5428 cmd->vdev_id = appType2Params->vdev_id;
5429
5430 cdf_mem_copy(cmd->rc4_key, appType2Params->rc4_key, 16);
5431 cmd->rc4_key_len = appType2Params->rc4_key_len;
5432
5433 cmd->ip_id = appType2Params->ip_id;
5434 cmd->ip_device_ip = appType2Params->ip_device_ip;
5435 cmd->ip_server_ip = appType2Params->ip_server_ip;
5436
5437 cmd->tcp_src_port = appType2Params->tcp_src_port;
5438 cmd->tcp_dst_port = appType2Params->tcp_dst_port;
5439 cmd->tcp_seq = appType2Params->tcp_seq;
5440 cmd->tcp_ack_seq = appType2Params->tcp_ack_seq;
5441
5442 cmd->keepalive_init = appType2Params->keepalive_init;
5443 cmd->keepalive_min = appType2Params->keepalive_min;
5444 cmd->keepalive_max = appType2Params->keepalive_max;
5445 cmd->keepalive_inc = appType2Params->keepalive_inc;
5446
5447 WMI_CHAR_ARRAY_TO_MAC_ADDR(appType2Params->gateway_mac,
5448 &cmd->gateway_mac);
5449 cmd->tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val;
5450 cmd->tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val;
5451
5452 WMA_LOGD("%s: vdev_id %d gateway_mac %pM "
5453 "rc4_key %.16s rc4_key_len %u "
5454 "ip_id %x ip_device_ip %x ip_server_ip %x "
5455 "tcp_src_port %u tcp_dst_port %u tcp_seq %u "
5456 "tcp_ack_seq %u keepalive_init %u keepalive_min %u "
5457 "keepalive_max %u keepalive_inc %u "
5458 "tcp_tx_timeout_val %u tcp_rx_timeout_val %u",
5459 __func__, cmd->vdev_id, appType2Params->gateway_mac,
5460 cmd->rc4_key, cmd->rc4_key_len,
5461 cmd->ip_id, cmd->ip_device_ip, cmd->ip_server_ip,
5462 cmd->tcp_src_port, cmd->tcp_dst_port, cmd->tcp_seq,
5463 cmd->tcp_ack_seq, cmd->keepalive_init, cmd->keepalive_min,
5464 cmd->keepalive_max, cmd->keepalive_inc,
5465 cmd->tcp_tx_timeout_val, cmd->tcp_rx_timeout_val);
5466
5467 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
5468 WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID);
5469 if (ret) {
5470 WMA_LOGE("%s: Failed to set APP TYPE2 PARAMS", __func__);
5471 wmi_buf_free(buf);
5472 return CDF_STATUS_E_FAILURE;
5473 }
5474
5475 return CDF_STATUS_SUCCESS;
5476
5477}
5478#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5479
5480#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
5481/**
5482 * wma_auto_shutdown_event_handler() - process auto shutdown timer trigger
5483 * @handle: wma handle
5484 * @event: event buffer
5485 * @len: buffer length
5486 *
5487 * Return: 0 for success or error code
5488 */
5489int wma_auto_shutdown_event_handler(void *handle, uint8_t *event,
5490 uint32_t len)
5491{
5492 wmi_host_auto_shutdown_event_fixed_param *wmi_auto_sh_evt;
5493 WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *param_buf =
5494 (WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *)
5495 event;
5496
5497 if (!param_buf || !param_buf->fixed_param) {
5498 WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__,
5499 __LINE__);
5500 return -EINVAL;
5501 }
5502
5503 wmi_auto_sh_evt = param_buf->fixed_param;
5504
5505 if (wmi_auto_sh_evt->shutdown_reason
5506 != WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY) {
5507 WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__,
5508 __LINE__);
5509 return -EINVAL;
5510 }
5511
5512 WMA_LOGD("%s:%d: Auto Shutdown Evt: %d", __func__, __LINE__,
5513 wmi_auto_sh_evt->shutdown_reason);
5514 return wma_post_auto_shutdown_msg();
5515}
5516
5517/**
5518 * wma_set_auto_shutdown_timer_req() - sets auto shutdown timer in firmware
5519 * @wma: wma handle
5520 * @auto_sh_cmd: auto shutdown timer value
5521 *
5522 * Return: CDF status
5523 */
5524CDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle,
5525 tSirAutoShutdownCmdParams *
5526 auto_sh_cmd)
5527{
5528 int status = 0;
5529 wmi_buf_t buf = NULL;
5530 uint8_t *buf_ptr;
5531 wmi_host_auto_shutdown_cfg_cmd_fixed_param *wmi_auto_sh_cmd;
5532 int len = sizeof(wmi_host_auto_shutdown_cfg_cmd_fixed_param);
5533
5534 if (auto_sh_cmd == NULL) {
5535 WMA_LOGE("%s : Invalid Autoshutdown cfg cmd", __func__);
5536 return CDF_STATUS_E_FAILURE;
5537 }
5538
5539 WMA_LOGD("%s: Set WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID:TIMER_VAL=%d",
5540 __func__, auto_sh_cmd->timer_val);
5541
5542 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
5543 if (!buf) {
5544 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
5545 return CDF_STATUS_E_NOMEM;
5546 }
5547
5548 buf_ptr = (uint8_t *) wmi_buf_data(buf);
5549 wmi_auto_sh_cmd =
5550 (wmi_host_auto_shutdown_cfg_cmd_fixed_param *) buf_ptr;
5551 wmi_auto_sh_cmd->timer_value = auto_sh_cmd->timer_val;
5552
5553 WMITLV_SET_HDR(&wmi_auto_sh_cmd->tlv_header,
5554 WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param,
5555 WMITLV_GET_STRUCT_TLVLEN
5556 (wmi_host_auto_shutdown_cfg_cmd_fixed_param));
5557
5558 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
5559 len, WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID);
5560 if (status != EOK) {
5561 WMA_LOGE("%s: WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID Err %d",
5562 __func__, status);
5563 wmi_buf_free(buf);
5564 return CDF_STATUS_E_FAILURE;
5565 }
5566
5567 return CDF_STATUS_SUCCESS;
5568}
5569#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */
5570
5571#ifdef WLAN_FEATURE_NAN
5572/**
5573 * wma_nan_req() - to send nan request to target
5574 * @wma: wma_handle
5575 * @nan_req: request data which will be non-null
5576 *
5577 * Return: CDF status
5578 */
5579CDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req)
5580{
5581 int ret;
5582 tp_wma_handle wma_handle = (tp_wma_handle) wma_ptr;
5583 wmi_nan_cmd_param *cmd;
5584 wmi_buf_t buf;
5585 uint16_t len = sizeof(*cmd);
5586 uint16_t nan_data_len, nan_data_len_aligned;
5587 uint8_t *buf_ptr;
5588
5589 /*
5590 * <----- cmd ------------><-- WMI_TLV_HDR_SIZE --><--- data ---->
5591 * +------------+----------+-----------------------+--------------+
5592 * | tlv_header | data_len | WMITLV_TAG_ARRAY_BYTE | nan_req_data |
5593 * +------------+----------+-----------------------+--------------+
5594 */
5595 if (!nan_req) {
5596 WMA_LOGE("%s:nan req is not valid", __func__);
5597 return CDF_STATUS_E_FAILURE;
5598 }
5599 nan_data_len = nan_req->request_data_len;
5600 nan_data_len_aligned = roundup(nan_req->request_data_len,
5601 sizeof(uint32_t));
5602 len += WMI_TLV_HDR_SIZE + nan_data_len_aligned;
5603 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
5604 if (!buf) {
5605 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
5606 return CDF_STATUS_E_NOMEM;
5607 }
5608 buf_ptr = (uint8_t *) wmi_buf_data(buf);
5609 cmd = (wmi_nan_cmd_param *) buf_ptr;
5610 WMITLV_SET_HDR(&cmd->tlv_header,
5611 WMITLV_TAG_STRUC_wmi_nan_cmd_param,
5612 WMITLV_GET_STRUCT_TLVLEN(wmi_nan_cmd_param));
5613 cmd->data_len = nan_req->request_data_len;
5614 WMA_LOGD("%s: The data len value is %u",
5615 __func__, nan_req->request_data_len);
5616 buf_ptr += sizeof(wmi_nan_cmd_param);
5617 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, nan_data_len_aligned);
5618 buf_ptr += WMI_TLV_HDR_SIZE;
5619 cdf_mem_copy(buf_ptr, nan_req->request_data, cmd->data_len);
5620
5621 ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
5622 WMI_NAN_CMDID);
5623 if (ret != EOK) {
5624 WMA_LOGE("%s Failed to send set param command ret = %d",
5625 __func__, ret);
5626 wmi_buf_free(buf);
5627 }
5628 return ret;
5629}
5630#endif /* WLAN_FEATURE_NAN */
5631
5632#ifdef DHCP_SERVER_OFFLOAD
5633/**
5634 * wma_process_dhcpserver_offload() - enable DHCP server offload
5635 * @wma_handle: wma handle
5636 * @pDhcpSrvOffloadInfo: DHCP server offload info
5637 *
5638 * Return: 0 for success or error code
5639 */
5640int wma_process_dhcpserver_offload(tp_wma_handle wma_handle,
5641 tSirDhcpSrvOffloadInfo *
5642 pDhcpSrvOffloadInfo)
5643{
5644 wmi_set_dhcp_server_offload_cmd_fixed_param *cmd;
5645 wmi_buf_t buf;
5646 int err;
5647
5648 buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
5649 if (!buf) {
5650 WMA_LOGE("Failed to allocate buffer to send "
5651 "set_dhcp_server_offload cmd");
5652 return -ENOMEM;
5653 }
5654
5655 cmd = (wmi_set_dhcp_server_offload_cmd_fixed_param *) wmi_buf_data(buf);
5656 cdf_mem_zero(cmd, sizeof(*cmd));
5657
5658 WMITLV_SET_HDR(&cmd->tlv_header,
5659 WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param,
5660 WMITLV_GET_STRUCT_TLVLEN
5661 (wmi_set_dhcp_server_offload_cmd_fixed_param));
5662 cmd->vdev_id = pDhcpSrvOffloadInfo->vdev_id;
5663 cmd->enable = pDhcpSrvOffloadInfo->dhcpSrvOffloadEnabled;
5664 cmd->num_client = pDhcpSrvOffloadInfo->dhcpClientNum;
5665 cmd->srv_ipv4 = pDhcpSrvOffloadInfo->dhcpSrvIP;
5666 cmd->start_lsb = 0;
5667 err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
5668 sizeof(*cmd),
5669 WMI_SET_DHCP_SERVER_OFFLOAD_CMDID);
5670 if (err) {
5671 WMA_LOGE("Failed to send set_dhcp_server_offload cmd");
5672 wmi_buf_free(buf);
5673 return -EIO;
5674 }
5675 WMA_LOGD("Set dhcp server offload to vdevId %d",
5676 pDhcpSrvOffloadInfo->vdev_id);
5677 return 0;
5678}
5679#endif /* DHCP_SERVER_OFFLOAD */
5680
5681#ifdef WLAN_FEATURE_GPIO_LED_FLASHING
5682/**
5683 * wma_set_led_flashing() - set led flashing in fw
5684 * @wma_handle: wma handle
5685 * @flashing: flashing request
5686 *
5687 * Return: CDF status
5688 */
5689CDF_STATUS wma_set_led_flashing(tp_wma_handle wma_handle,
5690 tSirLedFlashingReq *flashing)
5691{
5692 wmi_set_led_flashing_cmd_fixed_param *cmd;
5693 int status = 0;
5694 wmi_buf_t buf;
5695 uint8_t *buf_ptr;
5696 int32_t len = sizeof(wmi_set_led_flashing_cmd_fixed_param);
5697
5698 if (!wma_handle || !wma_handle->wmi_handle) {
5699 WMA_LOGE(FL("WMA is closed, can not issue cmd"));
5700 return CDF_STATUS_E_INVAL;
5701 }
5702 if (!flashing) {
5703 WMA_LOGE(FL("invalid parameter: flashing"));
5704 return CDF_STATUS_E_INVAL;
5705 }
5706
5707 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
5708 if (!buf) {
5709 WMA_LOGP(FL("wmi_buf_alloc failed"));
5710 return -ENOMEM;
5711 }
5712 buf_ptr = (uint8_t *) wmi_buf_data(buf);
5713 cmd = (wmi_set_led_flashing_cmd_fixed_param *) buf_ptr;
5714 WMITLV_SET_HDR(&cmd->tlv_header,
5715 WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param,
5716 WMITLV_GET_STRUCT_TLVLEN
5717 (wmi_set_led_flashing_cmd_fixed_param));
5718 cmd->pattern_id = flashing->pattern_id;
5719 cmd->led_x0 = flashing->led_x0;
5720 cmd->led_x1 = flashing->led_x1;
5721
5722 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
5723 WMI_PDEV_SET_LED_FLASHING_CMDID);
5724 if (status != EOK) {
5725 WMA_LOGE("%s: wmi_unified_cmd_send WMI_PEER_SET_PARAM_CMD"
5726 " returned Error %d", __func__, status);
5727 return CDF_STATUS_E_FAILURE;
5728 }
5729 return CDF_STATUS_SUCCESS;
5730}
5731#endif /* WLAN_FEATURE_GPIO_LED_FLASHING */
5732
5733#ifdef FEATURE_WLAN_CH_AVOID
5734/**
5735 * wma_channel_avoid_evt_handler() - process channel to avoid event from FW.
5736 * @handle: wma handle
5737 * @event: event buffer
5738 * @len: buffer length
5739 *
5740 * Return: 0 for success or error code
5741 */
5742int wma_channel_avoid_evt_handler(void *handle, uint8_t *event,
5743 uint32_t len)
5744{
5745 wmi_avoid_freq_ranges_event_fixed_param *afr_fixed_param;
5746 wmi_avoid_freq_range_desc *afr_desc;
5747 uint32_t num_freq_ranges, freq_range_idx;
5748 tSirChAvoidIndType *sca_indication;
5749 CDF_STATUS cdf_status;
5750 cds_msg_t sme_msg = { 0 };
5751 WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *param_buf =
5752 (WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *) event;
5753
5754 if (!param_buf) {
5755 WMA_LOGE("Invalid channel avoid event buffer");
5756 return -EINVAL;
5757 }
5758
5759 afr_fixed_param = param_buf->fixed_param;
5760 if (!afr_fixed_param) {
5761 WMA_LOGE("Invalid channel avoid event fixed param buffer");
5762 return -EINVAL;
5763 }
5764
5765 num_freq_ranges =
5766 (afr_fixed_param->num_freq_ranges >
5767 SIR_CH_AVOID_MAX_RANGE) ? SIR_CH_AVOID_MAX_RANGE :
5768 afr_fixed_param->num_freq_ranges;
5769
5770 WMA_LOGD("Channel avoid event received with %d ranges",
5771 num_freq_ranges);
5772 for (freq_range_idx = 0; freq_range_idx < num_freq_ranges;
5773 freq_range_idx++) {
5774 afr_desc = (wmi_avoid_freq_range_desc *)
5775 ((void *)param_buf->avd_freq_range +
5776 freq_range_idx * sizeof(wmi_avoid_freq_range_desc));
5777
5778 WMA_LOGD("range %d: tlv id = %u, start freq = %u, end freq = %u",
5779 freq_range_idx, afr_desc->tlv_header, afr_desc->start_freq,
5780 afr_desc->end_freq);
5781 }
5782
5783 sca_indication = (tSirChAvoidIndType *)
5784 cdf_mem_malloc(sizeof(tSirChAvoidIndType));
5785 if (!sca_indication) {
5786 WMA_LOGE("Invalid channel avoid indication buffer");
5787 return -EINVAL;
5788 }
5789
5790 sca_indication->avoid_range_count = num_freq_ranges;
5791 for (freq_range_idx = 0; freq_range_idx < num_freq_ranges;
5792 freq_range_idx++) {
5793 afr_desc = (wmi_avoid_freq_range_desc *)
5794 ((void *)param_buf->avd_freq_range +
5795 freq_range_idx * sizeof(wmi_avoid_freq_range_desc));
5796 sca_indication->avoid_freq_range[freq_range_idx].start_freq =
5797 afr_desc->start_freq;
5798 sca_indication->avoid_freq_range[freq_range_idx].end_freq =
5799 afr_desc->end_freq;
5800 }
5801
5802 sme_msg.type = eWNI_SME_CH_AVOID_IND;
5803 sme_msg.bodyptr = sca_indication;
5804 sme_msg.bodyval = 0;
5805
5806 cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg);
5807 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
5808 WMA_LOGE("Fail to post eWNI_SME_CH_AVOID_IND msg to SME");
5809 cdf_mem_free(sca_indication);
5810 return -EINVAL;
5811 }
5812
5813 return 0;
5814}
5815
5816/**
5817 * wma_process_ch_avoid_update_req() - handles channel avoid update request
5818 * @wma_handle: wma handle
5819 * @ch_avoid_update_req: channel avoid update params
5820 *
5821 * Return: CDF status
5822 */
5823CDF_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle,
5824 tSirChAvoidUpdateReq *
5825 ch_avoid_update_req)
5826{
5827 int status = 0;
5828 wmi_buf_t buf = NULL;
5829 uint8_t *buf_ptr;
5830 wmi_chan_avoid_update_cmd_param *ch_avoid_update_fp;
5831 int len = sizeof(wmi_chan_avoid_update_cmd_param);
5832
5833 if (ch_avoid_update_req == NULL) {
5834 WMA_LOGE("%s : ch_avoid_update_req is NULL", __func__);
5835 return CDF_STATUS_E_FAILURE;
5836 }
5837
5838 WMA_LOGI("%s: WMA --> WMI_CHAN_AVOID_UPDATE", __func__);
5839
5840 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
5841 if (!buf) {
5842 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
5843 return CDF_STATUS_E_NOMEM;
5844 }
5845
5846 buf_ptr = (uint8_t *) wmi_buf_data(buf);
5847 ch_avoid_update_fp = (wmi_chan_avoid_update_cmd_param *) buf_ptr;
5848 WMITLV_SET_HDR(&ch_avoid_update_fp->tlv_header,
5849 WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param,
5850 WMITLV_GET_STRUCT_TLVLEN
5851 (wmi_chan_avoid_update_cmd_param));
5852
5853 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
5854 len, WMI_CHAN_AVOID_UPDATE_CMDID);
5855 if (status != EOK) {
5856 WMA_LOGE("wmi_unified_cmd_send"
5857 " WMITLV_TABLE_WMI_CHAN_AVOID_UPDATE"
5858 " returned Error %d", status);
5859 wmi_buf_free(buf);
5860 return CDF_STATUS_E_FAILURE;
5861 }
5862
5863 WMA_LOGI("%s: WMA --> WMI_CHAN_AVOID_UPDATE sent through WMI",
5864 __func__);
5865 return CDF_STATUS_SUCCESS;
5866}
5867#endif /* FEATURE_WLAN_CH_AVOID */
5868
5869/**
5870 * wma_set_reg_domain() - set reg domain
5871 * @clientCtxt: client context
5872 * @regId: reg id
5873 *
5874 * Return: CDF status
5875 */
5876CDF_STATUS wma_set_reg_domain(void *clientCtxt, v_REGDOMAIN_t regId)
5877{
5878 if (CDF_STATUS_SUCCESS !=
5879 cds_set_reg_domain(clientCtxt, regId))
5880 return CDF_STATUS_E_INVAL;
5881
5882 return CDF_STATUS_SUCCESS;
5883}
5884
5885/**
5886 * wma_send_regdomain_info_to_fw() - send regdomain info to fw
5887 * @reg_dmn: reg domain
5888 * @regdmn2G: 2G reg domain
5889 * @regdmn5G: 5G reg domain
5890 * @ctl2G: 2G test limit
5891 * @ctl5G: 5G test limit
5892 *
5893 * Return: none
5894 */
5895void wma_send_regdomain_info_to_fw(uint32_t reg_dmn, uint16_t regdmn2G,
5896 uint16_t regdmn5G, int8_t ctl2G,
5897 int8_t ctl5G)
5898{
5899 wmi_buf_t buf;
5900 wmi_pdev_set_regdomain_cmd_fixed_param *cmd;
5901 int32_t len = sizeof(*cmd);
5902 tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA);
5903 int32_t cck_mask_val = 0;
5904 int ret = 0;
5905
5906 if (NULL == wma) {
5907 WMA_LOGE("%s: wma context is NULL", __func__);
5908 return;
5909 }
5910
5911 buf = wmi_buf_alloc(wma->wmi_handle, len);
5912 if (!buf) {
5913 WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
5914 return;
5915 }
5916 cmd = (wmi_pdev_set_regdomain_cmd_fixed_param *) wmi_buf_data(buf);
5917 WMITLV_SET_HDR(&cmd->tlv_header,
5918 WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param,
5919 WMITLV_GET_STRUCT_TLVLEN
5920 (wmi_pdev_set_regdomain_cmd_fixed_param));
5921 cmd->reg_domain = reg_dmn;
5922 cmd->reg_domain_2G = regdmn2G;
5923 cmd->reg_domain_5G = regdmn5G;
5924 cmd->conformance_test_limit_2G = ctl2G;
5925 cmd->conformance_test_limit_5G = ctl5G;
5926
5927 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
5928 WMI_PDEV_SET_REGDOMAIN_CMDID)) {
5929 WMA_LOGP("%s: Failed to send pdev set regdomain command",
5930 __func__);
5931 cdf_nbuf_free(buf);
5932 }
5933
5934 if ((((reg_dmn & ~COUNTRY_ERD_FLAG) == CTRY_JAPAN) ||
5935 ((reg_dmn & ~COUNTRY_ERD_FLAG) == CTRY_KOREA_ROC)) &&
5936 (true == wma->tx_chain_mask_cck))
5937 cck_mask_val = 1;
5938
5939 cck_mask_val |= (wma->self_gen_frm_pwr << 16);
5940 ret = wmi_unified_pdev_set_param(wma->wmi_handle,
5941 WMI_PDEV_PARAM_TX_CHAIN_MASK_CCK,
5942 cck_mask_val);
5943 if (ret)
5944 WMA_LOGE("failed to set PDEV tx_chain_mask_cck %d",
5945 ret);
5946
5947 return;
5948}
5949
5950/**
5951 * wma_bus_suspend() - handles bus suspend request from hdd
5952 *
5953 * Calls the appropriate handler based on configuration and event
5954 *
5955 * Return: 0 for success or error code
5956 */
5957int wma_bus_suspend(void)
5958{
5959 WMA_HANDLE handle = cds_get_context(CDF_MODULE_ID_WMA);
5960 if (NULL == handle) {
5961 WMA_LOGE("%s: wma context is NULL", __func__);
5962 return -EFAULT;
5963 }
5964
5965 WMA_LOGE("%s: wow mode selected %d", __func__,
5966 wma_is_wow_mode_selected(handle));
5967
5968 if (wma_check_scan_in_progress(handle)) {
5969 WMA_LOGE("%s: Scan in progress. Aborting suspend", __func__);
5970 return -EBUSY;
5971 }
5972
5973 if (wma_is_wow_mode_selected(handle))
5974 return cdf_status_to_os_return(wma_enable_wow_in_fw(handle));
5975
5976 return wma_suspend_target(handle, 0);
5977}
5978
5979/**
5980 * wma_bus_resume() - handles bus resume request from hdd
5981 * @handle: valid wma handle
5982 *
5983 * Calls the appropriate handler based on configuration
5984 *
5985 * Return: 0 for success or error code
5986 */
5987int wma_bus_resume(void)
5988{
5989 WMA_HANDLE handle = cds_get_context(CDF_MODULE_ID_WMA);
5990 int wow_mode;
5991 if (NULL == handle) {
5992 WMA_LOGE("%s: wma context is NULL", __func__);
5993 return -EFAULT;
5994 }
5995
5996 wow_mode = wma_is_wow_mode_selected(handle);
5997 WMA_LOGE("%s: wow mode %d", __func__, wow_mode);
5998
5999 if (!wow_mode)
6000 return wma_resume_target(handle);
6001
6002 return cdf_status_to_os_return(wma_disable_wow_in_fw(handle));
6003}
6004
6005/**
6006 * wma_suspend_target() - suspend target
6007 * @handle: wma handle
6008 * @disable_target_intr: disable target interrupt
6009 *
6010 * Return: 0 for success or error code
6011 */
6012int wma_suspend_target(WMA_HANDLE handle, int disable_target_intr)
6013{
6014 tp_wma_handle wma_handle = (tp_wma_handle) handle;
6015 wmi_pdev_suspend_cmd_fixed_param *cmd;
6016 wmi_buf_t wmibuf;
6017 uint32_t len = sizeof(*cmd);
6018 struct ol_softc *scn;
6019 int ret;
Yue Mae1a85f32015-10-20 18:12:45 -07006020#ifdef CONFIG_CNSS
6021 tpAniSirGlobal pmac = cds_get_context(CDF_MODULE_ID_PE);
6022#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006023
6024 if (!wma_handle || !wma_handle->wmi_handle) {
6025 WMA_LOGE("WMA is closed. can not issue suspend cmd");
6026 return -EINVAL;
6027 }
Yue Mae1a85f32015-10-20 18:12:45 -07006028
6029#ifdef CONFIG_CNSS
6030 if (NULL == pmac) {
6031 WMA_LOGE("%s: Unable to get PE context", __func__);
6032 return -EINVAL;
6033 }
6034#endif
6035
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006036 /*
6037 * send the comand to Target to ignore the
6038 * PCIE reset so as to ensure that Host and target
6039 * states are in sync
6040 */
6041 wmibuf = wmi_buf_alloc(wma_handle->wmi_handle, len);
6042 if (wmibuf == NULL)
6043 return -ENOMEM;
6044
6045 cmd = (wmi_pdev_suspend_cmd_fixed_param *) wmi_buf_data(wmibuf);
6046 WMITLV_SET_HDR(&cmd->tlv_header,
6047 WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param,
6048 WMITLV_GET_STRUCT_TLVLEN
6049 (wmi_pdev_suspend_cmd_fixed_param));
6050 if (disable_target_intr) {
6051 cmd->suspend_opt = WMI_PDEV_SUSPEND_AND_DISABLE_INTR;
6052 } else {
6053 cmd->suspend_opt = WMI_PDEV_SUSPEND;
6054 }
6055 cdf_event_reset(&wma_handle->target_suspend);
6056 ret = wmi_unified_cmd_send(wma_handle->wmi_handle, wmibuf, len,
6057 WMI_PDEV_SUSPEND_CMDID);
6058 if (ret < 0) {
6059 cdf_nbuf_free(wmibuf);
6060 return ret;
6061 }
6062
6063 wmi_set_target_suspend(wma_handle->wmi_handle, true);
6064
6065 if (cdf_wait_single_event(&wma_handle->target_suspend,
6066 WMA_TGT_SUSPEND_COMPLETE_TIMEOUT)
6067 != CDF_STATUS_SUCCESS) {
6068 WMA_LOGE("Failed to get ACK from firmware for pdev suspend");
6069 wmi_set_target_suspend(wma_handle->wmi_handle, false);
Yue Mae1a85f32015-10-20 18:12:45 -07006070#ifdef CONFIG_CNSS
Yue Ma455aff62015-10-20 18:29:16 -07006071 if (!cds_is_logp_in_progress()) {
6072 if (pmac->sme.enableSelfRecovery) {
6073 cds_trigger_recovery();
6074 } else {
6075 CDF_BUG(0);
6076 }
Yue Mae1a85f32015-10-20 18:12:45 -07006077 } else {
Yue Ma455aff62015-10-20 18:29:16 -07006078 WMA_LOGE("%s: LOGP is in progress, ignore!", __func__);
Yue Mae1a85f32015-10-20 18:12:45 -07006079 }
6080#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006081 return -EFAULT;
6082 }
6083
6084 scn = cds_get_context(CDF_MODULE_ID_HIF);
6085
6086 if (scn == NULL) {
6087 WMA_LOGE("%s: Failed to get HIF context", __func__);
6088 CDF_ASSERT(0);
6089 return -EFAULT;
6090 }
6091
6092 htc_cancel_deferred_target_sleep(scn);
6093
6094 return 0;
6095}
6096
6097/**
6098 * wma_target_suspend_acknowledge() - update target susspend status
6099 * @context: wma context
6100 *
6101 * Return: none
6102 */
6103void wma_target_suspend_acknowledge(void *context)
6104{
6105 tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA);
6106 int wow_nack = *((int *)context);
6107
6108 if (NULL == wma) {
6109 WMA_LOGE("%s: wma is NULL", __func__);
6110 return;
6111 }
6112
6113 wma->wow_nack = wow_nack;
6114 cdf_event_set(&wma->target_suspend);
6115 if (wow_nack)
6116 cdf_wake_lock_timeout_acquire(&wma->wow_wake_lock,
6117 WMA_WAKE_LOCK_TIMEOUT,
6118 WIFI_POWER_EVENT_WAKELOCK_WOW);
6119}
6120
6121/**
6122 * wma_resume_target() - resume target
6123 * @handle: wma handle
6124 *
6125 * Return: 0 for success or error code
6126 */
6127int wma_resume_target(WMA_HANDLE handle)
6128{
6129 int ret;
6130 tp_wma_handle wma = (tp_wma_handle) handle;
6131 wmi_buf_t wmibuf;
6132 wmi_pdev_resume_cmd_fixed_param *cmd;
6133 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
6134#ifdef CONFIG_CNSS
6135 tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE);
6136 if (NULL == pMac) {
6137 WMA_LOGE("%s: Unable to get PE context", __func__);
6138 return -EINVAL;
6139 }
6140#endif /* CONFIG_CNSS */
6141
6142 wmibuf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd));
6143 if (wmibuf == NULL) {
6144 return -ENOMEM;
6145 }
6146 cmd = (wmi_pdev_resume_cmd_fixed_param *) wmi_buf_data(wmibuf);
6147 WMITLV_SET_HDR(&cmd->tlv_header,
6148 WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param,
6149 WMITLV_GET_STRUCT_TLVLEN
6150 (wmi_pdev_resume_cmd_fixed_param));
6151 cmd->reserved0 = 0;
6152 cdf_event_reset(&wma->wma_resume_event);
6153 ret = wmi_unified_cmd_send(wma->wmi_handle, wmibuf, sizeof(*cmd),
6154 WMI_PDEV_RESUME_CMDID);
6155 if (ret != EOK) {
6156 WMA_LOGE("Failed to send WMI_PDEV_RESUME_CMDID command");
6157 wmi_buf_free(wmibuf);
6158 }
6159
6160 cdf_status = cdf_wait_single_event(&(wma->wma_resume_event),
6161 WMA_RESUME_TIMEOUT);
6162 if (CDF_STATUS_SUCCESS != cdf_status) {
6163 WMA_LOGP("%s: Timeout waiting for resume event from FW",
6164 __func__);
6165 WMA_LOGP("%s: Pending commands %d credits %d", __func__,
6166 wmi_get_pending_cmds(wma->wmi_handle),
6167 wmi_get_host_credits(wma->wmi_handle));
6168 if (!cds_is_logp_in_progress()) {
6169#ifdef CONFIG_CNSS
6170 if (pMac->sme.enableSelfRecovery) {
6171 cds_trigger_recovery();
6172 } else {
6173 CDF_BUG(0);
6174 }
6175#else
6176 CDF_BUG(0);
6177#endif /* CONFIG_CNSS */
6178 } else {
6179 WMA_LOGE("%s: SSR in progress, ignore resume timeout",
6180 __func__);
6181 }
6182 } else {
6183 WMA_LOGD("Host wakeup received");
6184 }
6185
6186 if (CDF_STATUS_SUCCESS == cdf_status)
6187 wmi_set_target_suspend(wma->wmi_handle, false);
6188
6189 return ret;
6190}
6191
6192/**
6193 * wma_get_modeselect() - get modeSelect flag based on phy_capability
6194 * @wma: wma handle
6195 * @modeSelect: mode Select
6196 *
6197 * Return: none
6198 */
6199void wma_get_modeselect(tp_wma_handle wma, uint32_t *modeSelect)
6200{
6201
6202 switch (wma->phy_capability) {
6203 case WMI_11G_CAPABILITY:
6204 case WMI_11NG_CAPABILITY:
6205 *modeSelect &= ~(REGDMN_MODE_11A | REGDMN_MODE_TURBO |
6206 REGDMN_MODE_108A | REGDMN_MODE_11A_HALF_RATE |
6207 REGDMN_MODE_11A_QUARTER_RATE |
6208 REGDMN_MODE_11NA_HT20 |
6209 REGDMN_MODE_11NA_HT40PLUS |
6210 REGDMN_MODE_11NA_HT40MINUS |
6211 REGDMN_MODE_11AC_VHT20 |
6212 REGDMN_MODE_11AC_VHT40PLUS |
6213 REGDMN_MODE_11AC_VHT40MINUS |
6214 REGDMN_MODE_11AC_VHT80);
6215 break;
6216 case WMI_11A_CAPABILITY:
6217 case WMI_11NA_CAPABILITY:
6218 case WMI_11AC_CAPABILITY:
6219 *modeSelect &= ~(REGDMN_MODE_11B | REGDMN_MODE_11G |
6220 REGDMN_MODE_108G | REGDMN_MODE_11NG_HT20 |
6221 REGDMN_MODE_11NG_HT40PLUS |
6222 REGDMN_MODE_11NG_HT40MINUS |
6223 REGDMN_MODE_11AC_VHT20_2G |
6224 REGDMN_MODE_11AC_VHT40_2G |
6225 REGDMN_MODE_11AC_VHT80_2G);
6226 break;
6227 }
6228}
6229
6230
6231#ifdef FEATURE_WLAN_TDLS
6232/**
6233 * wma_tdls_event_handler() - handle TDLS event
6234 * @handle: wma handle
6235 * @event: event buffer
6236 * @len: buffer length
6237 *
6238 * Return: 0 for success or error code
6239 */
6240int wma_tdls_event_handler(void *handle, uint8_t *event, uint32_t len)
6241{
6242 tp_wma_handle wma = (tp_wma_handle) handle;
6243 WMI_TDLS_PEER_EVENTID_param_tlvs *param_buf = NULL;
6244 wmi_tdls_peer_event_fixed_param *peer_event = NULL;
6245 tSirTdlsEventnotify *tdls_event;
6246
6247 if (!event) {
6248 WMA_LOGE("%s: event param null", __func__);
6249 return -EINVAL;
6250 }
6251
6252 param_buf = (WMI_TDLS_PEER_EVENTID_param_tlvs *) event;
6253 if (!param_buf) {
6254 WMA_LOGE("%s: received null buf from target", __func__);
6255 return -EINVAL;
6256 }
6257
6258 peer_event = param_buf->fixed_param;
6259 if (!peer_event) {
6260 WMA_LOGE("%s: received null event data from target", __func__);
6261 return -EINVAL;
6262 }
6263
6264 tdls_event = (tSirTdlsEventnotify *)
6265 cdf_mem_malloc(sizeof(*tdls_event));
6266 if (!tdls_event) {
6267 WMA_LOGE("%s: failed to allocate memory for tdls_event",
6268 __func__);
6269 return -ENOMEM;
6270 }
6271
6272 tdls_event->sessionId = peer_event->vdev_id;
6273 WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_event->peer_macaddr,
6274 tdls_event->peerMac);
6275
6276 switch (peer_event->peer_status) {
6277 case WMI_TDLS_SHOULD_DISCOVER:
6278 tdls_event->messageType = WMA_TDLS_SHOULD_DISCOVER_CMD;
6279 break;
6280 case WMI_TDLS_SHOULD_TEARDOWN:
6281 tdls_event->messageType = WMA_TDLS_SHOULD_TEARDOWN_CMD;
6282 break;
6283 case WMI_TDLS_PEER_DISCONNECTED:
6284 tdls_event->messageType = WMA_TDLS_PEER_DISCONNECTED_CMD;
6285 break;
6286 default:
6287 WMA_LOGE("%s: Discarding unknown tdls event(%d) from target",
6288 __func__, peer_event->peer_status);
6289 return -EINVAL;
6290 }
6291
6292 switch (peer_event->peer_reason) {
6293 case WMI_TDLS_TEARDOWN_REASON_TX:
6294 tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_TX;
6295 break;
6296 case WMI_TDLS_TEARDOWN_REASON_RSSI:
6297 tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_RSSI;
6298 break;
6299 case WMI_TDLS_TEARDOWN_REASON_SCAN:
6300 tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_SCAN;
6301 break;
6302 case WMI_TDLS_DISCONNECTED_REASON_PEER_DELETE:
6303 tdls_event->peer_reason =
6304 eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE;
6305 break;
6306 case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT:
6307 tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT;
6308 break;
6309 case WMI_TDLS_TEARDOWN_REASON_BAD_PTR:
6310 tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_BAD_PTR;
6311 break;
6312 case WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE:
6313 tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE;
6314 break;
6315 default:
6316 WMA_LOGE("%s: unknown reason(%d) in tdls event(%d) from target",
6317 __func__, peer_event->peer_reason,
6318 peer_event->peer_status);
6319 return -EINVAL;
6320 }
6321
6322 WMA_LOGD("%s: sending msg to umac, messageType: 0x%x, "
6323 "for peer: %pM, reason: %d, smesessionId: %d",
6324 __func__, tdls_event->messageType, tdls_event->peerMac,
6325 tdls_event->peer_reason, tdls_event->sessionId);
6326
6327 wma_send_msg(wma, tdls_event->messageType, (void *)tdls_event, 0);
6328 return 0;
6329}
6330
6331/**
6332 * wma_set_tdls_offchan_mode() - set tdls off channel mode
6333 * @handle: wma handle
6334 * @chan_switch_params: Pointer to tdls channel switch parameter structure
6335 *
6336 * This function sets tdls off channel mode
6337 *
6338 * Return: 0 on success; Negative errno otherwise
6339 */
6340int wma_set_tdls_offchan_mode(WMA_HANDLE handle,
6341 tdls_chan_switch_params *chan_switch_params)
6342{
6343 tp_wma_handle wma_handle = (tp_wma_handle) handle;
6344 wmi_tdls_set_offchan_mode_cmd_fixed_param *cmd;
6345 wmi_buf_t wmi_buf;
6346 u_int16_t len = sizeof(wmi_tdls_set_offchan_mode_cmd_fixed_param);
6347 int ret = 0;
6348
6349 if (!wma_handle || !wma_handle->wmi_handle) {
6350 WMA_LOGE(FL(
6351 "WMA is closed, can not issue tdls off channel cmd"
6352 ));
6353 ret = -EINVAL;
6354 goto end;
6355 }
6356 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
6357 if (!wmi_buf) {
6358 WMA_LOGE(FL("wmi_buf_alloc failed"));
6359 ret = -ENOMEM;
6360 goto end;
6361 }
6362 cmd = (wmi_tdls_set_offchan_mode_cmd_fixed_param *)
6363 wmi_buf_data(wmi_buf);
6364 WMITLV_SET_HDR(&cmd->tlv_header,
6365 WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param,
6366 WMITLV_GET_STRUCT_TLVLEN(
6367 wmi_tdls_set_offchan_mode_cmd_fixed_param));
6368
6369 WMI_CHAR_ARRAY_TO_MAC_ADDR(chan_switch_params->peer_mac_addr,
6370 &cmd->peer_macaddr);
6371 cmd->vdev_id = chan_switch_params->vdev_id;
6372 cmd->offchan_mode = chan_switch_params->tdls_sw_mode;
6373 cmd->is_peer_responder = chan_switch_params->is_responder;
6374 cmd->offchan_num = chan_switch_params->tdls_off_ch;
6375 cmd->offchan_bw_bitmap = chan_switch_params->tdls_off_ch_bw_offset;
6376 cmd->offchan_oper_class = chan_switch_params->oper_class;
6377
6378 WMA_LOGD(FL("Peer MAC Addr mac_addr31to0: 0x%x, mac_addr47to32: 0x%x"),
6379 cmd->peer_macaddr.mac_addr31to0,
6380 cmd->peer_macaddr.mac_addr47to32);
6381
6382 WMA_LOGD(FL(
6383 "vdev_id: %d, off channel mode: %d, off channel Num: %d, off channel offset: 0x%x, is_peer_responder: %d, operating class: %d"
6384 ),
6385 cmd->vdev_id,
6386 cmd->offchan_mode,
6387 cmd->offchan_num,
6388 cmd->offchan_bw_bitmap,
6389 cmd->is_peer_responder,
6390 cmd->offchan_oper_class);
6391
6392 if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
6393 WMI_TDLS_SET_OFFCHAN_MODE_CMDID)) {
6394 WMA_LOGP(FL("failed to send tdls off chan command"));
6395 cdf_nbuf_free(wmi_buf);
6396 ret = -EIO;
6397 }
6398
6399end:
6400 if (chan_switch_params)
6401 cdf_mem_free(chan_switch_params);
6402 return ret;
6403}
6404
6405/**
6406 * wma_update_fw_tdls_state() - send enable/disable tdls for a vdev
6407 * @wma: wma handle
6408 * @pwmaTdlsparams: TDLS params
6409 *
6410 * Return: 0 for sucess or error code
6411 */
6412int wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams)
6413{
6414 tp_wma_handle wma_handle = (tp_wma_handle) handle;
6415 wmi_tdls_set_state_cmd_fixed_param *cmd;
6416 wmi_buf_t wmi_buf;
6417 t_wma_tdls_mode tdls_mode;
6418 t_wma_tdls_params *wma_tdls = (t_wma_tdls_params *) pwmaTdlsparams;
6419 uint16_t len = sizeof(wmi_tdls_set_state_cmd_fixed_param);
6420 int ret = 0;
6421
6422 if (!wma_handle || !wma_handle->wmi_handle) {
6423 WMA_LOGE("%s: WMA is closed, can not issue fw tdls state cmd",
6424 __func__);
6425 ret = -EINVAL;
6426 goto end_fw_tdls_state;
6427 }
6428
6429 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
6430 if (!wmi_buf) {
6431 WMA_LOGE("%s: wmai_buf_alloc failed", __func__);
6432 ret = ENOMEM;
6433 goto end_fw_tdls_state;
6434 }
6435 tdls_mode = wma_tdls->tdls_state;
6436 cmd = (wmi_tdls_set_state_cmd_fixed_param *) wmi_buf_data(wmi_buf);
6437 WMITLV_SET_HDR(&cmd->tlv_header,
6438 WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param,
6439 WMITLV_GET_STRUCT_TLVLEN
6440 (wmi_tdls_set_state_cmd_fixed_param));
6441 cmd->vdev_id = wma_tdls->vdev_id;
6442
6443 if (WMA_TDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == tdls_mode) {
6444 cmd->state = WMI_TDLS_ENABLE_PASSIVE;
6445 } else if (WMA_TDLS_SUPPORT_ENABLED == tdls_mode) {
6446 cmd->state = WMI_TDLS_ENABLE_ACTIVE;
6447 } else {
6448 cmd->state = WMI_TDLS_DISABLE;
6449 }
6450
6451 cmd->notification_interval_ms = wma_tdls->notification_interval_ms;
6452 cmd->tx_discovery_threshold = wma_tdls->tx_discovery_threshold;
6453 cmd->tx_teardown_threshold = wma_tdls->tx_teardown_threshold;
6454 cmd->rssi_teardown_threshold = wma_tdls->rssi_teardown_threshold;
6455 cmd->rssi_delta = wma_tdls->rssi_delta;
6456 cmd->tdls_options = wma_tdls->tdls_options;
6457 cmd->tdls_peer_traffic_ind_window = wma_tdls->peer_traffic_ind_window;
6458 cmd->tdls_peer_traffic_response_timeout_ms =
6459 wma_tdls->peer_traffic_response_timeout;
6460 cmd->tdls_puapsd_mask = wma_tdls->puapsd_mask;
6461 cmd->tdls_puapsd_inactivity_time_ms = wma_tdls->puapsd_inactivity_time;
6462 cmd->tdls_puapsd_rx_frame_threshold =
6463 wma_tdls->puapsd_rx_frame_threshold;
6464
6465 WMA_LOGD("%s: tdls_mode: %d, state: %d, "
6466 "notification_interval_ms: %d, "
6467 "tx_discovery_threshold: %d, "
6468 "tx_teardown_threshold: %d, "
6469 "rssi_teardown_threshold: %d, "
6470 "rssi_delta: %d, "
6471 "tdls_options: 0x%x, "
6472 "tdls_peer_traffic_ind_window: %d, "
6473 "tdls_peer_traffic_response_timeout: %d, "
6474 "tdls_puapsd_mask: 0x%x, "
6475 "tdls_puapsd_inactivity_time: %d, "
6476 "tdls_puapsd_rx_frame_threshold: %d ",
6477 __func__, tdls_mode, cmd->state,
6478 cmd->notification_interval_ms,
6479 cmd->tx_discovery_threshold,
6480 cmd->tx_teardown_threshold,
6481 cmd->rssi_teardown_threshold,
6482 cmd->rssi_delta,
6483 cmd->tdls_options,
6484 cmd->tdls_peer_traffic_ind_window,
6485 cmd->tdls_peer_traffic_response_timeout_ms,
6486 cmd->tdls_puapsd_mask,
6487 cmd->tdls_puapsd_inactivity_time_ms,
6488 cmd->tdls_puapsd_rx_frame_threshold);
6489
6490 if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
6491 WMI_TDLS_SET_STATE_CMDID)) {
6492 WMA_LOGP("%s: failed to send tdls set state command", __func__);
6493 cdf_nbuf_free(wmi_buf);
6494 ret = -EIO;
6495 goto end_fw_tdls_state;
6496 }
6497 WMA_LOGD("%s: vdev_id %d", __func__, wma_tdls->vdev_id);
6498
6499end_fw_tdls_state:
6500 if (pwmaTdlsparams)
6501 cdf_mem_free(pwmaTdlsparams);
6502 return ret;
6503}
6504
6505/**
6506 * wma_update_tdls_peer_state() - update TDLS peer state
6507 * @handle: wma handle
6508 * @peerStateParams: TDLS peer state params
6509 *
6510 * Return: 0 for success or error code
6511 */
6512int wma_update_tdls_peer_state(WMA_HANDLE handle,
6513 tTdlsPeerStateParams *peerStateParams)
6514{
6515 tp_wma_handle wma_handle = (tp_wma_handle) handle;
6516 wmi_tdls_peer_update_cmd_fixed_param *cmd;
6517 wmi_tdls_peer_capabilities *peer_cap;
6518 wmi_channel *chan_info;
6519 wmi_buf_t wmi_buf;
6520 uint8_t *buf_ptr;
6521 uint32_t i;
6522 ol_txrx_pdev_handle pdev;
6523 uint8_t peer_id;
6524 struct ol_txrx_peer_t *peer;
6525 int32_t len = sizeof(wmi_tdls_peer_update_cmd_fixed_param) +
6526 sizeof(wmi_tdls_peer_capabilities);
6527 int ret = 0;
6528
6529 if (!wma_handle || !wma_handle->wmi_handle) {
6530 WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__);
6531 ret = -EINVAL;
6532 goto end_tdls_peer_state;
6533 }
6534
6535 /* peer capability info is valid only when peer state is connected */
6536 if (WMA_TDLS_PEER_STATE_CONNECTED != peerStateParams->peerState) {
6537 cdf_mem_zero(&peerStateParams->peerCap,
6538 sizeof(tTdlsPeerCapParams));
6539 }
6540
6541 len += WMI_TLV_HDR_SIZE +
6542 sizeof(wmi_channel) * peerStateParams->peerCap.peerChanLen;
6543
6544 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
6545 if (!wmi_buf) {
6546 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
6547 ret = ENOMEM;
6548 goto end_tdls_peer_state;
6549 }
6550
6551 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
6552 cmd = (wmi_tdls_peer_update_cmd_fixed_param *) buf_ptr;
6553 WMITLV_SET_HDR(&cmd->tlv_header,
6554 WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param,
6555 WMITLV_GET_STRUCT_TLVLEN
6556 (wmi_tdls_peer_update_cmd_fixed_param));
6557
6558 cmd->vdev_id = peerStateParams->vdevId;
6559 WMI_CHAR_ARRAY_TO_MAC_ADDR(peerStateParams->peerMacAddr,
6560 &cmd->peer_macaddr);
6561
6562 switch (peerStateParams->peerState) {
6563 case WMA_TDLS_PEER_STATE_PEERING:
6564 cmd->peer_state = WMI_TDLS_PEER_STATE_PEERING;
6565 break;
6566 case WMA_TDLS_PEER_STATE_CONNECTED:
6567 cmd->peer_state = WMI_TDLS_PEER_STATE_CONNECTED;
6568 break;
6569 case WMA_TDLS_PEER_STATE_TEARDOWN:
6570 cmd->peer_state = WMI_TDLS_PEER_STATE_TEARDOWN;
6571 break;
6572 }
6573
6574 WMA_LOGD("%s: vdev_id: %d, peerStateParams->peerMacAddr: %pM, "
6575 "peer_macaddr.mac_addr31to0: 0x%x, "
6576 "peer_macaddr.mac_addr47to32: 0x%x, peer_state: %d",
6577 __func__, cmd->vdev_id, peerStateParams->peerMacAddr,
6578 cmd->peer_macaddr.mac_addr31to0,
6579 cmd->peer_macaddr.mac_addr47to32, cmd->peer_state);
6580
6581 buf_ptr += sizeof(wmi_tdls_peer_update_cmd_fixed_param);
6582 peer_cap = (wmi_tdls_peer_capabilities *) buf_ptr;
6583 WMITLV_SET_HDR(&peer_cap->tlv_header,
6584 WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities,
6585 WMITLV_GET_STRUCT_TLVLEN(wmi_tdls_peer_capabilities));
6586
6587 if ((peerStateParams->peerCap.peerUapsdQueue & 0x08) >> 3)
6588 WMI_SET_TDLS_PEER_VO_UAPSD(peer_cap);
6589 if ((peerStateParams->peerCap.peerUapsdQueue & 0x04) >> 2)
6590 WMI_SET_TDLS_PEER_VI_UAPSD(peer_cap);
6591 if ((peerStateParams->peerCap.peerUapsdQueue & 0x02) >> 1)
6592 WMI_SET_TDLS_PEER_BK_UAPSD(peer_cap);
6593 if (peerStateParams->peerCap.peerUapsdQueue & 0x01)
6594 WMI_SET_TDLS_PEER_BE_UAPSD(peer_cap);
6595
6596 /* Ack and More Data Ack are sent as 0, so no need to set
6597 * but fill SP
6598 */
6599 WMI_SET_TDLS_PEER_SP_UAPSD(peer_cap,
6600 peerStateParams->peerCap.peerMaxSp);
6601
6602 peer_cap->buff_sta_support =
6603 peerStateParams->peerCap.peerBuffStaSupport;
6604 peer_cap->off_chan_support =
6605 peerStateParams->peerCap.peerOffChanSupport;
6606 peer_cap->peer_curr_operclass =
6607 peerStateParams->peerCap.peerCurrOperClass;
6608 /* self curr operclass is not being used and so pass op class for
6609 * preferred off chan in it.
6610 */
6611 peer_cap->self_curr_operclass =
6612 peerStateParams->peerCap.opClassForPrefOffChan;
6613 peer_cap->peer_chan_len = peerStateParams->peerCap.peerChanLen;
6614 peer_cap->peer_operclass_len =
6615 peerStateParams->peerCap.peerOperClassLen;
6616
6617 WMA_LOGD("%s: peer_operclass_len: %d",
6618 __func__, peer_cap->peer_operclass_len);
6619 for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++) {
6620 peer_cap->peer_operclass[i] =
6621 peerStateParams->peerCap.peerOperClass[i];
6622 WMA_LOGD("%s: peer_operclass[%d]: %d",
6623 __func__, i, peer_cap->peer_operclass[i]);
6624 }
6625
6626 peer_cap->is_peer_responder = peerStateParams->peerCap.isPeerResponder;
6627 peer_cap->pref_offchan_num = peerStateParams->peerCap.prefOffChanNum;
6628 peer_cap->pref_offchan_bw =
6629 peerStateParams->peerCap.prefOffChanBandwidth;
6630
6631 WMA_LOGD
6632 ("%s: peer_qos: 0x%x, buff_sta_support: %d, off_chan_support: %d, peer_curr_operclass: %d, self_curr_operclass: %d, peer_chan_len: %d, peer_operclass_len: %d, is_peer_responder: %d, pref_offchan_num: %d, pref_offchan_bw: %d",
6633 __func__, peer_cap->peer_qos, peer_cap->buff_sta_support,
6634 peer_cap->off_chan_support, peer_cap->peer_curr_operclass,
6635 peer_cap->self_curr_operclass, peer_cap->peer_chan_len,
6636 peer_cap->peer_operclass_len, peer_cap->is_peer_responder,
6637 peer_cap->pref_offchan_num, peer_cap->pref_offchan_bw);
6638
6639 /* next fill variable size array of peer chan info */
6640 buf_ptr += sizeof(wmi_tdls_peer_capabilities);
6641 WMITLV_SET_HDR(buf_ptr,
6642 WMITLV_TAG_ARRAY_STRUC,
6643 sizeof(wmi_channel) *
6644 peerStateParams->peerCap.peerChanLen);
6645 chan_info = (wmi_channel *) (buf_ptr + WMI_TLV_HDR_SIZE);
6646
6647 for (i = 0; i < peerStateParams->peerCap.peerChanLen; ++i) {
6648 WMITLV_SET_HDR(&chan_info->tlv_header,
6649 WMITLV_TAG_STRUC_wmi_channel,
6650 WMITLV_GET_STRUCT_TLVLEN(wmi_channel));
6651 chan_info->mhz =
6652 cds_chan_to_freq(peerStateParams->peerCap.peerChan[i].
6653 chanId);
6654 chan_info->band_center_freq1 = chan_info->mhz;
6655 chan_info->band_center_freq2 = 0;
6656
6657 WMA_LOGD("%s: chan[%d] = %u", __func__, i, chan_info->mhz);
6658
6659 if (peerStateParams->peerCap.peerChan[i].dfsSet) {
6660 WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_PASSIVE);
6661 WMA_LOGI("chan[%d] DFS[%d]\n",
6662 peerStateParams->peerCap.peerChan[i].chanId,
6663 peerStateParams->peerCap.peerChan[i].dfsSet);
6664 }
6665
6666 if (chan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) {
6667 WMI_SET_CHANNEL_MODE(chan_info, MODE_11G);
6668 } else {
6669 WMI_SET_CHANNEL_MODE(chan_info, MODE_11A);
6670 }
6671
6672 WMI_SET_CHANNEL_MAX_TX_POWER(chan_info,
6673 peerStateParams->peerCap.
6674 peerChan[i].pwr);
6675
6676 WMI_SET_CHANNEL_REG_POWER(chan_info,
6677 peerStateParams->peerCap.peerChan[i].
6678 pwr);
6679 WMA_LOGD("Channel TX power[%d] = %u: %d", i, chan_info->mhz,
6680 peerStateParams->peerCap.peerChan[i].pwr);
6681
6682 chan_info++;
6683 }
6684
6685 if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
6686 WMI_TDLS_PEER_UPDATE_CMDID)) {
6687 WMA_LOGE("%s: failed to send tdls peer update state command",
6688 __func__);
6689 cdf_nbuf_free(wmi_buf);
6690 ret = -EIO;
6691 goto end_tdls_peer_state;
6692 }
6693
6694 /* in case of teardown, remove peer from fw */
6695 if (WMA_TDLS_PEER_STATE_TEARDOWN == peerStateParams->peerState) {
6696 pdev = cds_get_context(CDF_MODULE_ID_TXRX);
6697 if (!pdev) {
6698 WMA_LOGE("%s: Failed to find pdev", __func__);
6699 ret = -EIO;
6700 goto end_tdls_peer_state;
6701 }
6702
6703 peer = ol_txrx_find_peer_by_addr(pdev,
6704 peerStateParams->peerMacAddr,
6705 &peer_id);
6706 if (!peer) {
6707 WMA_LOGE("%s: Failed to get peer handle using peer mac %pM",
6708 __func__, peerStateParams->peerMacAddr);
6709 ret = -EIO;
6710 goto end_tdls_peer_state;
6711 }
6712
6713 WMA_LOGD("%s: calling wma_remove_peer for peer " MAC_ADDRESS_STR
6714 " vdevId: %d", __func__,
6715 MAC_ADDR_ARRAY(peer->mac_addr.raw),
6716 peerStateParams->vdevId);
6717 wma_remove_peer(wma_handle, peer->mac_addr.raw,
6718 peerStateParams->vdevId, peer, false);
6719 }
6720
6721end_tdls_peer_state:
6722 if (peerStateParams)
6723 cdf_mem_free(peerStateParams);
6724 return ret;
6725}
6726#endif /* FEATURE_WLAN_TDLS */
6727
6728
6729/**
6730 * wma_dfs_attach() - Attach DFS methods to the umac state.
6731 * @dfs_ic: ieee80211com ptr
6732 *
6733 * Return: Return ieee80211com ptr with updated info
6734 */
6735struct ieee80211com *wma_dfs_attach(struct ieee80211com *dfs_ic)
6736{
6737 /*Allocate memory for dfs_ic before passing it up to dfs_attach() */
6738 dfs_ic = (struct ieee80211com *)
6739 os_malloc(NULL, sizeof(struct ieee80211com), GFP_ATOMIC);
6740 if (dfs_ic == NULL) {
6741 WMA_LOGE("%s:Allocation of dfs_ic failed %zu",
6742 __func__, sizeof(struct ieee80211com));
6743 return NULL;
6744 }
6745 OS_MEMZERO(dfs_ic, sizeof(struct ieee80211com));
6746 /* DFS pattern matching hooks */
6747 dfs_ic->ic_dfs_attach = ol_if_dfs_attach;
6748 dfs_ic->ic_dfs_disable = ol_if_dfs_disable;
6749 dfs_ic->ic_find_channel = ieee80211_find_channel;
6750 dfs_ic->ic_dfs_enable = ol_if_dfs_enable;
6751 dfs_ic->ic_ieee2mhz = ieee80211_ieee2mhz;
6752
6753 /* Hardware facing hooks */
6754 dfs_ic->ic_get_ext_busy = ol_if_dfs_get_ext_busy;
6755 dfs_ic->ic_get_mib_cycle_counts_pct =
6756 ol_if_dfs_get_mib_cycle_counts_pct;
6757 dfs_ic->ic_get_TSF64 = ol_if_get_tsf64;
6758
6759 /* NOL related hooks */
6760 dfs_ic->ic_dfs_usenol = ol_if_dfs_usenol;
6761 /*
6762 * Hooks from wma/dfs/ back
6763 * into the PE/SME
6764 * and shared DFS code
6765 */
6766 dfs_ic->ic_dfs_notify_radar = ieee80211_mark_dfs;
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05306767 cdf_spinlock_init(&dfs_ic->chan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006768 /* Initializes DFS Data Structures and queues */
6769 dfs_attach(dfs_ic);
6770
6771 return dfs_ic;
6772}
6773
6774/**
6775 * wma_dfs_detach() - Detach DFS methods
6776 * @dfs_ic: ieee80211com ptr
6777 *
6778 * Return: none
6779 */
6780void wma_dfs_detach(struct ieee80211com *dfs_ic)
6781{
6782 dfs_detach(dfs_ic);
6783
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05306784 cdf_spinlock_destroy(&dfs_ic->chan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006785 if (NULL != dfs_ic->ic_curchan) {
6786 OS_FREE(dfs_ic->ic_curchan);
6787 dfs_ic->ic_curchan = NULL;
6788 }
6789
6790 OS_FREE(dfs_ic);
6791}
6792
6793/**
6794 * wma_dfs_configure() - configure dfs
6795 * @ic: ieee80211com ptr
6796 *
6797 * Configures Radar Filters during
6798 * vdev start/channel change/regulatory domain
6799 * change.This Configuration enables to program
6800 * the DFS pattern matching module.
6801 *
6802 * Return: none
6803 */
6804void wma_dfs_configure(struct ieee80211com *ic)
6805{
6806 struct ath_dfs_radar_tab_info rinfo;
6807 int dfsdomain;
6808 int radar_enabled_status = 0;
6809 if (ic == NULL) {
6810 WMA_LOGE("%s: DFS ic is Invalid", __func__);
6811 return;
6812 }
6813
6814 dfsdomain = ic->current_dfs_regdomain;
6815
6816 /* Fetch current radar patterns from the lmac */
6817 OS_MEMZERO(&rinfo, sizeof(rinfo));
6818
6819 /*
6820 * Look up the current DFS
6821 * regulatory domain and decide
6822 * which radar pulses to use.
6823 */
6824 switch (dfsdomain) {
6825 case DFS_FCC_DOMAIN:
6826 WMA_LOGI("%s: DFS-FCC domain", __func__);
6827 rinfo.dfsdomain = DFS_FCC_DOMAIN;
6828 rinfo.dfs_radars = dfs_fcc_radars;
6829 rinfo.numradars = CDF_ARRAY_SIZE(dfs_fcc_radars);
6830 rinfo.b5pulses = dfs_fcc_bin5pulses;
6831 rinfo.numb5radars = CDF_ARRAY_SIZE(dfs_fcc_bin5pulses);
6832 break;
6833 case DFS_ETSI_DOMAIN:
6834 WMA_LOGI("%s: DFS-ETSI domain", __func__);
6835 rinfo.dfsdomain = DFS_ETSI_DOMAIN;
6836 rinfo.dfs_radars = dfs_etsi_radars;
6837 rinfo.numradars = CDF_ARRAY_SIZE(dfs_etsi_radars);
6838 rinfo.b5pulses = NULL;
6839 rinfo.numb5radars = 0;
6840 break;
6841 case DFS_MKK4_DOMAIN:
6842 WMA_LOGI("%s: DFS-MKK4 domain", __func__);
6843 rinfo.dfsdomain = DFS_MKK4_DOMAIN;
6844 rinfo.dfs_radars = dfs_mkk4_radars;
6845 rinfo.numradars = CDF_ARRAY_SIZE(dfs_mkk4_radars);
6846 rinfo.b5pulses = dfs_jpn_bin5pulses;
6847 rinfo.numb5radars = CDF_ARRAY_SIZE(dfs_jpn_bin5pulses);
6848 break;
6849 default:
6850 WMA_LOGI("%s: DFS-UNINT domain", __func__);
6851 rinfo.dfsdomain = DFS_UNINIT_DOMAIN;
6852 rinfo.dfs_radars = NULL;
6853 rinfo.numradars = 0;
6854 rinfo.b5pulses = NULL;
6855 rinfo.numb5radars = 0;
6856 break;
6857 }
6858
6859 rinfo.dfs_pri_multiplier = ic->dfs_pri_multiplier;
6860
6861 /*
6862 * Set the regulatory domain,
6863 * radar pulse table and enable
6864 * radar events if required.
6865 * dfs_radar_enable() returns
6866 * 0 on success and non-zero
6867 * failure.
6868 */
6869 radar_enabled_status = dfs_radar_enable(ic, &rinfo);
6870 if (radar_enabled_status != DFS_STATUS_SUCCESS) {
6871 WMA_LOGE("%s[%d]: DFS- Radar Detection Enabling Failed",
6872 __func__, __LINE__);
6873 }
6874}
6875
6876/**
6877 * wma_dfs_configure_channel() - configure DFS channel
6878 * @dfs_ic: ieee80211com ptr
6879 * @chan: wmi channel
6880 * @chanmode: channel mode
6881 * @ req: vdev start request
6882 *
6883 * Set the Channel parameters in to DFS module
6884 * Also,configure the DFS radar filters for
6885 * matching the DFS phyerrors.
6886 *
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +05306887 * Return: dfs_ieee80211_channel / NULL for error
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006888 */
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +05306889struct dfs_ieee80211_channel *wma_dfs_configure_channel(
6890 struct ieee80211com *dfs_ic,
6891 wmi_channel *chan,
6892 WLAN_PHY_MODE chanmode,
6893 struct wma_vdev_start_req
6894 *req)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006895{
6896 if (dfs_ic == NULL) {
6897 WMA_LOGE("%s: DFS ic is Invalid", __func__);
6898 return NULL;
6899 }
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05306900
6901 if (!dfs_ic->ic_curchan) {
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +05306902 dfs_ic->ic_curchan = (struct dfs_ieee80211_channel *)os_malloc(
6903 NULL,
6904 sizeof(struct dfs_ieee80211_channel),
6905 GFP_ATOMIC);
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05306906 if (dfs_ic->ic_curchan == NULL) {
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +05306907 WMA_LOGE(
6908 "%s: allocation of dfs_ic->ic_curchan failed %zu",
6909 __func__, sizeof(struct dfs_ieee80211_channel));
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05306910 return NULL;
6911 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006912 }
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05306913
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +05306914 OS_MEMZERO(dfs_ic->ic_curchan, sizeof(struct dfs_ieee80211_channel));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006915
6916 dfs_ic->ic_curchan->ic_ieee = req->chan;
6917 dfs_ic->ic_curchan->ic_freq = chan->mhz;
6918 dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1 = chan->band_center_freq1;
6919 dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg2 = chan->band_center_freq2;
6920 dfs_ic->ic_curchan->ic_pri_freq_center_freq_mhz_separation =
6921 dfs_ic->ic_curchan->ic_freq -
6922 dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1;
6923
6924 if ((dfs_ic->ic_curchan->ic_ieee >= WMA_11A_CHANNEL_BEGIN) &&
6925 (dfs_ic->ic_curchan->ic_ieee <= WMA_11A_CHANNEL_END)) {
6926 dfs_ic->ic_curchan->ic_flags |= IEEE80211_CHAN_5GHZ;
6927 }
6928 if (CH_WIDTH_80MHZ == req->chan_width) {
6929 dfs_ic->ic_curchan->ic_flags |= IEEE80211_CHAN_VHT80;
6930 }
6931 if (CH_WIDTH_40MHZ == req->chan_width) {
6932 if (req->chan < req->ch_center_freq_seg0)
6933 dfs_ic->ic_curchan->ic_flags |= (req->vht_capable ?
6934 IEEE80211_CHAN_VHT40PLUS :
6935 IEEE80211_CHAN_HT40PLUS);
6936 else
6937 dfs_ic->ic_curchan->ic_flags |= (req->vht_capable ?
6938 IEEE80211_CHAN_VHT40MINUS :
6939 IEEE80211_CHAN_HT40MINUS);
6940 } else if (CH_WIDTH_20MHZ == req->chan_width) {
6941 dfs_ic->ic_curchan->ic_flags |=
6942 (req->vht_capable ? IEEE80211_CHAN_VHT20 :
6943 IEEE80211_CHAN_HT20);
6944 }
6945 dfs_ic->ic_curchan->ic_flagext |= IEEE80211_CHAN_DFS;
6946
6947 if (req->oper_mode == BSS_OPERATIONAL_MODE_AP) {
6948 dfs_ic->ic_opmode = IEEE80211_M_HOSTAP;
6949 dfs_ic->vdev_id = req->vdev_id;
6950 }
6951
6952 dfs_ic->dfs_pri_multiplier = req->dfs_pri_multiplier;
6953
6954 /*
6955 * Configuring the DFS with current channel and the radar filters
6956 */
6957 wma_dfs_configure(dfs_ic);
6958 WMA_LOGI("%s: DFS- CHANNEL CONFIGURED", __func__);
6959 return dfs_ic->ic_curchan;
6960}
6961
6962
6963/**
6964 * wma_set_dfs_region() - set DFS region
6965 * @wma: wma handle
6966 *
6967 * Configure the DFS region for DFS radar filter initialization
6968 *
6969 * Return: none
6970 */
6971void wma_set_dfs_region(tp_wma_handle wma, uint8_t dfs_region)
6972{
6973 /* dfs information is passed */
6974 if (dfs_region > DFS_MKK4_DOMAIN || dfs_region == DFS_UNINIT_DOMAIN)
6975 /* assign DFS_FCC_DOMAIN as default domain*/
6976 wma->dfs_ic->current_dfs_regdomain = DFS_FCC_DOMAIN;
6977 else
6978 wma->dfs_ic->current_dfs_regdomain = dfs_region;
6979
6980 WMA_LOGI("%s: DFS Region Domain: %d", __func__,
6981 wma->dfs_ic->current_dfs_regdomain);
6982}
6983
6984/**
6985 * wma_get_channels() - prepare dfs radar channel list
6986 * @ichan: channel
6987 * @chan_list: return channel list
6988 *
6989 * Return: return number of channels
6990 */
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +05306991int wma_get_channels(struct dfs_ieee80211_channel *ichan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006992 struct wma_dfs_radar_channel_list *chan_list)
6993{
6994 uint8_t center_chan = cds_freq_to_chan(ichan->ic_vhtop_ch_freq_seg1);
6995
6996 chan_list->nchannels = 0;
6997
6998 if (IEEE80211_IS_CHAN_11AC_VHT80(ichan)) {
6999 chan_list->nchannels = 4;
7000 chan_list->channels[0] = center_chan - 6;
7001 chan_list->channels[1] = center_chan - 2;
7002 chan_list->channels[2] = center_chan + 2;
7003 chan_list->channels[3] = center_chan + 6;
7004 } else if (IEEE80211_IS_CHAN_11N_HT40(ichan) ||
7005 IEEE80211_IS_CHAN_11AC_VHT40(ichan)) {
7006 chan_list->nchannels = 2;
7007 chan_list->channels[0] = center_chan - 2;
7008 chan_list->channels[1] = center_chan + 2;
7009 } else {
7010 chan_list->nchannels = 1;
7011 chan_list->channels[0] = center_chan;
7012 }
7013
7014 return chan_list->nchannels;
7015}
7016
7017
7018/**
7019 * wma_dfs_indicate_radar() - Indicate Radar to SAP/HDD
7020 * @ic: ieee80211com ptr
7021 * @ichan: ieee 80211 channel
7022 *
7023 * Return: 0 for success or error code
7024 */
7025int wma_dfs_indicate_radar(struct ieee80211com *ic,
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +05307026 struct dfs_ieee80211_channel *ichan)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007027{
7028 tp_wma_handle wma;
7029 void *hdd_ctx;
7030 struct wma_dfs_radar_indication *radar_event;
7031 struct wma_dfs_radar_ind wma_radar_event;
7032 tpAniSirGlobal pmac = NULL;
Edhar, Mahesh Kumar695468e2015-10-19 12:06:20 +05307033 bool indication_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007034
7035 wma = cds_get_context(CDF_MODULE_ID_WMA);
7036 if (wma == NULL) {
7037 WMA_LOGE("%s: DFS- Invalid wma", __func__);
7038 return -ENOENT;
7039 }
7040
7041 hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
7042 pmac = (tpAniSirGlobal)
7043 cds_get_context(CDF_MODULE_ID_PE);
7044
7045 if (!pmac) {
7046 WMA_LOGE("%s: Invalid MAC handle", __func__);
7047 return -ENOENT;
7048 }
7049
7050 if (wma->dfs_ic != ic) {
7051 WMA_LOGE("%s:DFS- Invalid WMA handle", __func__);
7052 return -ENOENT;
7053 }
7054 radar_event = (struct wma_dfs_radar_indication *)
7055 cdf_mem_malloc(sizeof(struct wma_dfs_radar_indication));
7056 if (radar_event == NULL) {
7057 WMA_LOGE("%s:DFS- Invalid radar_event", __func__);
7058 return -ENOMEM;
7059 }
7060
7061 /*
7062 * Do not post multiple Radar events on the same channel.
7063 * But, when DFS test mode is enabled, allow multiple dfs
7064 * radar events to be posted on the same channel.
7065 */
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05307066 cdf_spin_lock_bh(&ic->chan_lock);
Edhar, Mahesh Kumar35d9b2e2015-10-26 17:06:23 +05307067 if (!pmac->sap.SapDfsInfo.disable_dfs_ch_switch)
7068 wma->dfs_ic->disable_phy_err_processing = true;
7069
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007070 if ((ichan->ic_ieee != (wma->dfs_ic->last_radar_found_chan)) ||
7071 (pmac->sap.SapDfsInfo.disable_dfs_ch_switch == true)) {
7072 wma->dfs_ic->last_radar_found_chan = ichan->ic_ieee;
7073 /* Indicate the radar event to HDD to stop the netif Tx queues */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007074 wma_radar_event.chan_freq = ichan->ic_freq;
7075 wma_radar_event.dfs_radar_status = WMA_DFS_RADAR_FOUND;
Edhar, Mahesh Kumar695468e2015-10-19 12:06:20 +05307076 indication_status =
7077 wma->dfs_radar_indication_cb(hdd_ctx, &wma_radar_event);
7078 if (indication_status == false) {
7079 WMA_LOGE("%s:Application triggered channel switch in progress!.. drop radar event indiaction to SAP",
7080 __func__);
7081 cdf_mem_free(radar_event);
7082 cdf_spin_unlock_bh(&ic->chan_lock);
7083 return 0;
7084 }
7085
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007086 WMA_LOGE("%s:DFS- RADAR INDICATED TO HDD", __func__);
7087
Edhar, Mahesh Kumar695468e2015-10-19 12:06:20 +05307088 wma_radar_event.ieee_chan_number = ichan->ic_ieee;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007089 /*
7090 * Indicate to the radar event to SAP to
7091 * select a new channel and set CSA IE
7092 */
7093 radar_event->vdev_id = ic->vdev_id;
7094 wma_get_channels(ichan, &radar_event->chan_list);
7095 radar_event->dfs_radar_status = WMA_DFS_RADAR_FOUND;
7096 radar_event->use_nol = ic->ic_dfs_usenol(ic);
7097 wma_send_msg(wma, WMA_DFS_RADAR_IND, (void *)radar_event, 0);
7098 WMA_LOGE("%s:DFS- WMA_DFS_RADAR_IND Message Posted", __func__);
7099 }
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +05307100 cdf_spin_unlock_bh(&ic->chan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007101
7102 return 0;
7103}
7104
7105#ifdef WLAN_FEATURE_MEMDUMP
7106/*
7107 * wma_process_fw_mem_dump_req() - Function to request fw memory dump from
7108 * firmware
7109 * @wma: Pointer to WMA handle
7110 * @mem_dump_req: Pointer for mem_dump_req
7111 *
7112 * This function sends memory dump request to firmware
7113 *
7114 * Return: CDF_STATUS_SUCCESS for success otherwise failure
7115 *
7116 */
7117CDF_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma,
7118 struct fw_dump_req *mem_dump_req)
7119{
7120 wmi_get_fw_mem_dump_fixed_param *cmd;
7121 wmi_fw_mem_dump *dump_params;
7122 struct fw_dump_seg_req *seg_req;
7123 int32_t len;
7124 wmi_buf_t buf;
7125 u_int8_t *buf_ptr;
7126 int ret, loop;
7127
7128 if (!mem_dump_req || !wma) {
7129 WMA_LOGE(FL("input pointer is NULL"));
7130 return CDF_STATUS_E_FAILURE;
7131 }
7132
7133 /*
7134 * len = sizeof(fixed param) that includes tlv header +
7135 * tlv header for array of struc +
7136 * sizeof (each struct)
7137 */
7138 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
7139 len += mem_dump_req->num_seg * sizeof(wmi_fw_mem_dump);
7140 buf = wmi_buf_alloc(wma->wmi_handle, len);
7141
7142 if (!buf) {
7143 WMA_LOGE(FL("Failed allocate wmi buffer"));
7144 return CDF_STATUS_E_NOMEM;
7145 }
7146
7147 buf_ptr = (u_int8_t *) wmi_buf_data(buf);
7148 cdf_mem_zero(buf_ptr, len);
7149 cmd = (wmi_get_fw_mem_dump_fixed_param *) buf_ptr;
7150
7151 WMITLV_SET_HDR(&cmd->tlv_header,
7152 WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param,
7153 WMITLV_GET_STRUCT_TLVLEN(wmi_get_fw_mem_dump_fixed_param));
7154
7155 cmd->request_id = mem_dump_req->request_id;
7156 cmd->num_fw_mem_dump_segs = mem_dump_req->num_seg;
7157
7158 /* TLV indicating array of structures to follow */
7159 buf_ptr += sizeof(wmi_get_fw_mem_dump_fixed_param);
7160 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
7161 sizeof(wmi_fw_mem_dump) *
7162 cmd->num_fw_mem_dump_segs);
7163
7164 buf_ptr += WMI_TLV_HDR_SIZE;
7165 dump_params = (wmi_fw_mem_dump *) buf_ptr;
7166
7167 WMA_LOGI(FL("request_id:%d num_seg:%d"),
7168 mem_dump_req->request_id, mem_dump_req->num_seg);
7169 for (loop = 0; loop < cmd->num_fw_mem_dump_segs; loop++) {
7170 seg_req = (struct fw_dump_seg_req *)
7171 ((uint8_t *)(mem_dump_req->segment) +
7172 loop * sizeof(*seg_req));
7173 WMITLV_SET_HDR(&dump_params->tlv_header,
7174 WMITLV_TAG_STRUC_wmi_fw_mem_dump_params,
7175 WMITLV_GET_STRUCT_TLVLEN(wmi_fw_mem_dump));
7176 dump_params->seg_id = seg_req->seg_id;
7177 dump_params->seg_start_addr_lo = seg_req->seg_start_addr_lo;
7178 dump_params->seg_start_addr_hi = seg_req->seg_start_addr_hi;
7179 dump_params->seg_length = seg_req->seg_length;
7180 dump_params->dest_addr_lo = seg_req->dst_addr_lo;
7181 dump_params->dest_addr_hi = seg_req->dst_addr_hi;
7182 WMA_LOGI(FL("seg_number:%d"), loop);
7183 WMA_LOGI(FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"),
7184 dump_params->seg_id, dump_params->seg_start_addr_lo,
7185 dump_params->seg_start_addr_hi);
7186 WMA_LOGI(FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"),
7187 dump_params->seg_length, dump_params->dest_addr_lo,
7188 dump_params->dest_addr_hi);
7189 dump_params++;
7190 }
7191
7192 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
7193 WMI_GET_FW_MEM_DUMP_CMDID);
7194 if (ret) {
7195 WMA_LOGE(FL("Failed to send get firmware mem dump request"));
7196 wmi_buf_free(buf);
7197 return CDF_STATUS_E_FAILURE;
7198 }
7199
7200 WMA_LOGI(FL("Get firmware mem dump request sent successfully"));
7201 return CDF_STATUS_SUCCESS;
7202}
7203
7204/**
7205 * wma_fw_mem_dump_rsp() - send fw mem dump response to SME
7206 *
7207 * @req_id - request id.
7208 * @status - copy status from the firmware.
7209 *
7210 * This function is called by the memory dump response handler to
7211 * indicate SME that firmware dump copy is complete
7212 *
7213 * Return: CDF_STATUS
7214 */
7215static CDF_STATUS wma_fw_mem_dump_rsp(uint32_t req_id, uint32_t status)
7216{
7217 struct fw_dump_rsp *dump_rsp;
7218 cds_msg_t sme_msg = {0};
7219 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
7220
7221 dump_rsp = cdf_mem_malloc(sizeof(*dump_rsp));
7222
7223 if (!dump_rsp) {
7224 WMA_LOGE(FL("Memory allocation failed."));
7225 cdf_status = CDF_STATUS_E_NOMEM;
7226 return cdf_status;
7227 }
7228
7229 WMA_LOGI(FL("FW memory dump copy complete status: %d for request: %d"),
7230 status, req_id);
7231
7232 dump_rsp->request_id = req_id;
7233 dump_rsp->dump_complete = status;
7234
7235 sme_msg.type = eWNI_SME_FW_DUMP_IND;
7236 sme_msg.bodyptr = dump_rsp;
7237 sme_msg.bodyval = 0;
7238
7239 cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg);
7240 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
7241 WMA_LOGE(FL("Fail to post fw mem dump ind msg"));
7242 cdf_mem_free(dump_rsp);
7243 }
7244
7245 return cdf_status;
7246}
7247
7248/**
7249 * wma_fw_mem_dump_event_handler() - handles fw memory dump event
7250 *
7251 * @handle: pointer to wma handle.
7252 * @cmd_param_info: pointer to TLV info received in the event.
7253 * @len: length of data in @cmd_param_info
7254 *
7255 * This function is a handler for firmware memory dump event.
7256 *
7257 * Return: integer (0 for success and error code otherwise)
7258 */
7259int wma_fw_mem_dump_event_handler(void *handle, u_int8_t *cmd_param_info,
7260 u_int32_t len)
7261{
7262 WMI_UPDATE_FW_MEM_DUMP_EVENTID_param_tlvs *param_buf;
7263 wmi_update_fw_mem_dump_fixed_param *event;
7264 CDF_STATUS status;
7265
7266 param_buf =
7267 (WMI_UPDATE_FW_MEM_DUMP_EVENTID_param_tlvs *) cmd_param_info;
7268 if (!param_buf) {
7269 WMA_LOGA("%s: Invalid stats event", __func__);
7270 return -EINVAL;
7271 }
7272
7273 event = param_buf->fixed_param;
7274
7275 status = wma_fw_mem_dump_rsp(event->request_id,
7276 event->fw_mem_dump_complete);
7277 if (CDF_STATUS_SUCCESS != status) {
7278 WMA_LOGE("Error posting FW MEM DUMP RSP.");
7279 return -EINVAL;
7280 }
7281
7282 WMA_LOGI("FW MEM DUMP RSP posted successfully");
7283 return 0;
7284}
7285#endif /* WLAN_FEATURE_MEMDUMP */
7286
7287/*
7288 * wma_process_set_ie_info() - Function to send IE info to firmware
7289 * @wma: Pointer to WMA handle
7290 * @ie_data: Pointer for ie data
7291 *
7292 * This function sends IE information to firmware
7293 *
7294 * Return: CDF_STATUS_SUCCESS for success otherwise failure
7295 *
7296 */
7297CDF_STATUS wma_process_set_ie_info(tp_wma_handle wma,
7298 struct vdev_ie_info *ie_info)
7299{
7300 wmi_vdev_set_ie_cmd_fixed_param *cmd;
7301 wmi_buf_t buf;
7302 uint8_t *buf_ptr;
7303 uint32_t len, ie_len_aligned;
7304 int ret;
7305
7306 if (!ie_info || !wma) {
7307 WMA_LOGE(FL("input pointer is NULL"));
7308 return CDF_STATUS_E_FAILURE;
7309 }
7310
7311 /* Validate the input */
7312 if (ie_info->length <= 0) {
7313 WMA_LOGE(FL("Invalid IE length"));
7314 return CDF_STATUS_E_INVAL;
7315 }
7316
7317 ie_len_aligned = roundup(ie_info->length, sizeof(uint32_t));
7318 /* Allocate memory for the WMI command */
7319 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + ie_len_aligned;
7320
7321 buf = wmi_buf_alloc(wma->wmi_handle, len);
7322 if (!buf) {
7323 WMA_LOGE(FL("wmi_buf_alloc failed"));
7324 return CDF_STATUS_E_NOMEM;
7325 }
7326
7327 buf_ptr = wmi_buf_data(buf);
7328 cdf_mem_zero(buf_ptr, len);
7329
7330 /* Populate the WMI command */
7331 cmd = (wmi_vdev_set_ie_cmd_fixed_param *)buf_ptr;
7332
7333 WMITLV_SET_HDR(&cmd->tlv_header,
7334 WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param,
7335 WMITLV_GET_STRUCT_TLVLEN(
7336 wmi_vdev_set_ie_cmd_fixed_param));
7337 cmd->vdev_id = ie_info->vdev_id;
7338 cmd->ie_id = ie_info->ie_id;
7339 cmd->ie_len = ie_info->length;
7340
7341 WMA_LOGD(FL("IE:%d of size:%d sent for vdev:%d"), ie_info->ie_id,
7342 ie_info->length, ie_info->vdev_id);
7343
7344 buf_ptr += sizeof(*cmd);
7345 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned);
7346 buf_ptr += WMI_TLV_HDR_SIZE;
7347
7348 cdf_mem_copy(buf_ptr, ie_info->data, cmd->ie_len);
7349
7350 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
7351 WMI_VDEV_SET_IE_CMDID);
7352 if (ret != EOK) {
7353 WMA_LOGE(FL("Failed to send set IE command ret = %d"), ret);
7354 wmi_buf_free(buf);
7355 }
7356
7357 return ret;
7358}
7359