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