blob: 340eecdf742ee3f56329f0b2d4d0d3aa6d35e3c3 [file] [log] [blame]
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301/*
2 * Copyright (c) 2013-2018 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/* Include Files */
29#include "wlan_ipa_core.h"
30#include "wlan_ipa_main.h"
31#include <ol_txrx.h>
32#include "cdp_txrx_ipa.h"
33#include "wal_rx_desc.h"
34
35static struct wlan_ipa_priv *gp_ipa;
36
37static struct wlan_ipa_iface_2_client {
38 qdf_ipa_client_type_t cons_client;
39 qdf_ipa_client_type_t prod_client;
40} wlan_ipa_iface_2_client[WLAN_IPA_MAX_IFACE] = {
41 {
42 QDF_IPA_CLIENT_WLAN2_CONS, QDF_IPA_CLIENT_WLAN1_PROD
43 }, {
44 QDF_IPA_CLIENT_WLAN3_CONS, QDF_IPA_CLIENT_WLAN1_PROD
45 }, {
46 QDF_IPA_CLIENT_WLAN4_CONS, QDF_IPA_CLIENT_WLAN1_PROD
47 }
48};
49
50/**
51 * wlan_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
52 * @ipa_cfg: IPA config
53 *
54 * Return: true if STA mode IPA uC offload is enabled, false otherwise
55 */
56static inline bool wlan_ipa_uc_sta_is_enabled(struct wlan_ipa_config *ipa_cfg)
57{
58 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_STA_ENABLE_MASK);
59}
60
61/**
62 * wlan_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
63 * @ipa_cfg: IPA config
64 *
65 * Return: true if pre-filter is enabled, otherwise false
66 */
67static inline
68bool wlan_ipa_is_pre_filter_enabled(struct wlan_ipa_config *ipa_cfg)
69{
70 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg,
71 WLAN_IPA_PRE_FILTER_ENABLE_MASK);
72}
73
74/**
75 * wlan_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
76 * @ipa_cfg: IPA config
77 *
78 * Return: true if IPv6 is enabled, otherwise false
79 */
80static inline bool wlan_ipa_is_ipv6_enabled(struct wlan_ipa_config *ipa_cfg)
81{
82 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_IPV6_ENABLE_MASK);
83}
84
85/**
86 * wlan_ipa_msg_free_fn() - Free an IPA message
87 * @buff: pointer to the IPA message
88 * @len: length of the IPA message
89 * @type: type of IPA message
90 *
91 * Return: None
92 */
93static void wlan_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
94{
95 ipa_debug("msg type:%d, len:%d", type, len);
96 qdf_mem_free(buff);
97}
98
99/**
100 * wlan_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
101 * @priv_ctxt: IPA context
102 *
103 * Will be called by IPA context.
104 * It's atomic context, then should be scheduled to kworker thread
105 *
106 * Return: None
107 */
108static void wlan_ipa_uc_loaded_uc_cb(void *priv_ctxt)
109{
110 struct wlan_ipa_priv *ipa_ctx;
111 struct op_msg_type *msg;
112 struct uc_op_work_struct *uc_op_work;
113
114 if (!priv_ctxt) {
115 ipa_err("Invalid IPA context");
116 return;
117 }
118
119 ipa_ctx = priv_ctxt;
120
121 msg = qdf_mem_malloc(sizeof(*msg));
122 if (!msg) {
123 ipa_err("op_msg allocation fails");
124 return;
125 }
126
127 msg->op_code = WLAN_IPA_UC_OPCODE_UC_READY;
128
129 uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
130
131 /* When the same uC OPCODE is already pended, just return */
132 if (uc_op_work->msg)
133 goto done;
134
135 uc_op_work->msg = msg;
136 qdf_sched_work(0, &uc_op_work->work);
137 /* work handler will free the msg buffer */
138 return;
139
140done:
141 qdf_mem_free(msg);
142}
143
144/**
145 * wlan_ipa_uc_send_wdi_control_msg() - Set WDI control message
146 * @ctrl: WDI control value
147 *
148 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
149 *
150 * Return: QDF_STATUS
151 */
152static QDF_STATUS wlan_ipa_uc_send_wdi_control_msg(bool ctrl)
153{
154 qdf_ipa_msg_meta_t meta;
155 qdf_ipa_wlan_msg_t *ipa_msg;
156 int ret = 0;
157
158 /* WDI enable message to IPA */
159 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
160 ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
161 if (!ipa_msg) {
162 ipa_err("msg allocation failed");
163 return QDF_STATUS_E_NOMEM;
164 }
165
166 if (ctrl)
167 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_ENABLE);
168 else
169 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_DISABLE);
170
171 ipa_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
172 ret = qdf_ipa_send_msg(&meta, ipa_msg, wlan_ipa_msg_free_fn);
173 if (ret) {
174 ipa_err("ipa_send_msg(Evt:%d)-fail=%d",
175 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
176 qdf_mem_free(ipa_msg);
177 return QDF_STATUS_E_FAILURE;
178 }
179
180 return QDF_STATUS_SUCCESS;
181}
182
183#ifdef CONFIG_IPA_WDI_UNIFIED_API
184
185/*
186 * TODO: Get WDI version through FW capabilities
187 */
188#ifdef CONFIG_LITHIUM
189static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
190{
191 ipa_ctx->wdi_version = IPA_WDI_3;
192}
193#elif defined(QCA_WIFI_3_0)
194static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
195{
196 ipa_ctx->wdi_version = IPA_WDI_2;
197}
198#else
199static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
200{
201 ipa_ctx->wdi_version = IPA_WDI_1;
202}
203#endif
204
205static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
206{
207 qdf_ipa_wdi_init_in_params_t in;
208 qdf_ipa_wdi_init_out_params_t out;
209 int ret;
210
211 ipa_ctx->uc_loaded = false;
212
213 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version;
214 QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb;
215 QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = (void *)ipa_ctx;
216
217 ret = qdf_ipa_wdi_init(&in, &out);
218 if (ret) {
219 ipa_err("ipa_wdi_init failed with ret=%d", ret);
220 return QDF_STATUS_E_FAILURE;
221 }
222
223 if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
224 ipa_info("IPA uC READY");
225 ipa_ctx->uc_loaded = true;
226 ipa_ctx->is_smmu_enabled =
227 QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
228 ipa_info("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled);
229 } else {
230 return QDF_STATUS_E_BUSY;
231 }
232
233 return QDF_STATUS_SUCCESS;
234}
235
236static inline int wlan_ipa_wdi_cleanup(void)
237{
238 int ret;
239
240 ret = qdf_ipa_wdi_cleanup();
241 if (ret)
242 ipa_info("ipa_wdi_cleanup failed ret=%d", ret);
243 return ret;
244}
245
246static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
247 struct ipa_sys_connect_params *sys,
248 uint32_t *handle)
249{
250 return 0;
251}
252
253static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
254 uint32_t handle)
255{
256 return 0;
257}
258
259#else /* CONFIG_IPA_WDI_UNIFIED_API */
260
261static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
262{
263}
264
265static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
266{
267 struct ipa_wdi_uc_ready_params uc_ready_param;
268
269 ipa_ctx->uc_loaded = false;
270 uc_ready_param.priv = (void *)ipa_ctx;
271 uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb;
272 if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) {
273 ipa_info("UC Ready CB register fail");
274 return QDF_STATUS_E_FAILURE;
275 }
276
277 if (true == uc_ready_param.is_uC_ready) {
278 ipa_info("UC Ready");
279 ipa_ctx->uc_loaded = true;
280 } else {
281 return QDF_STATUS_E_BUSY;
282 }
283
284 return QDF_STATUS_SUCCESS;
285}
286
287static inline int wlan_ipa_wdi_cleanup(void)
288{
289 int ret;
290
291 ret = qdf_ipa_uc_dereg_rdyCB();
292 if (ret)
293 ipa_info("UC Ready CB deregister fail");
294 return ret;
295}
296
297static inline int wlan_ipa_wdi_setup_sys_pipe(
298 struct wlan_ipa_priv *ipa_ctx,
299 struct ipa_sys_connect_params *sys, uint32_t *handle)
300{
301 return qdf_ipa_setup_sys_pipe(sys, handle);
302}
303
304static inline int wlan_ipa_wdi_teardown_sys_pipe(
305 struct wlan_ipa_priv *ipa_ctx,
306 uint32_t handle)
307{
308 return qdf_ipa_teardown_sys_pipe(handle);
309}
310
311#endif /* CONFIG_IPA_WDI_UNIFIED_API */
312
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530313QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx)
314{
315 int result;
316
317 ipa_debug("enter");
318
319 if (!ipa_ctx->ipa_pipes_down) {
320 /*
321 * IPA WDI Pipes are already activated due to
322 * rm deferred resources grant
323 */
324 ipa_warn("IPA WDI Pipes are already activated");
325 goto end;
326 }
327
328 result = cdp_ipa_enable_pipes(ipa_ctx->dp_soc,
329 ipa_ctx->dp_pdev);
330 if (result) {
331 ipa_err("Enable IPA WDI PIPE failed: ret=%d", result);
332 return QDF_STATUS_E_FAILURE;
333 }
334
335 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
336 ipa_ctx->ipa_pipes_down = false;
337
338 cdp_ipa_enable_autonomy(ipa_ctx->dp_soc,
339 ipa_ctx->dp_pdev);
340
341end:
342 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
343
344 return QDF_STATUS_SUCCESS;
345}
346
347QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx)
348{
349 int result;
350
351 ipa_debug("enter");
352
353 if (ipa_ctx->ipa_pipes_down) {
354 /*
355 * This shouldn't happen :
356 * IPA WDI Pipes are already deactivated
357 */
358 QDF_ASSERT(0);
359 ipa_warn("IPA WDI Pipes are already deactivated");
360 goto end;
361 }
362
363 cdp_ipa_disable_autonomy(ipa_ctx->dp_soc,
364 ipa_ctx->dp_pdev);
365
366 result = cdp_ipa_disable_pipes(ipa_ctx->dp_soc,
367 ipa_ctx->dp_pdev);
368 if (result) {
369 ipa_err("Disable IPA WDI PIPE failed: ret=%d", result);
370 return QDF_STATUS_E_FAILURE;
371 }
372
373 ipa_ctx->ipa_pipes_down = true;
374
375end:
376 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
377
378 return QDF_STATUS_SUCCESS;
379}
380
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530381/**
382 * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
383 * @ipa_ctx: IPA context
384 *
385 * Return: QDF_STATUS
386 */
387static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
388{
389 int i;
390 uint32_t max_desc_cnt;
391 struct wlan_ipa_tx_desc *tmp_desc;
392
393 max_desc_cnt = ipa_ctx->config->txbuf_count;
394
395 qdf_list_create(&ipa_ctx->tx_desc_list, max_desc_cnt);
396
397 qdf_spin_lock_bh(&ipa_ctx->q_lock);
398 for (i = 0; i < max_desc_cnt; i++) {
399 tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc));
400 tmp_desc->id = i;
401 tmp_desc->ipa_tx_desc_ptr = NULL;
402 qdf_list_insert_back(&ipa_ctx->tx_desc_list,
403 &tmp_desc->node);
404 tmp_desc++;
405 }
406
407 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
408 ipa_ctx->stats.num_tx_desc_error = 0;
409
410 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
411
412 return QDF_STATUS_SUCCESS;
413}
414
415#ifndef QCA_LL_TX_FLOW_CONTROL_V2
416/**
417 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
418 * @ipa_ctx: Global IPA IPA context
419 * @desc_fifo_sz: Number of descriptors
420 *
421 * Return: 0 on success, negative errno on error
422 */
423static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
424 int32_t desc_fifo_sz)
425{
426 int i, ret = 0;
427 qdf_ipa_sys_connect_params_t *ipa;
428
429 /*setup TX pipes */
430 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
431 ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params;
432
433 ipa->client = wlan_ipa_iface_2_client[i].cons_client;
434 ipa->desc_fifo_sz = desc_fifo_sz;
435 ipa->priv = &ipa_ctx->iface_context[i];
436 ipa->notify = NULL;
437
438 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
439 ipa->ipa_ep_cfg.hdr.hdr_len =
440 WLAN_IPA_UC_WLAN_TX_HDR_LEN;
441 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
442 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
443 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
444 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
445 WLAN_IPA_UC_WLAN_8023_HDR_SIZE;
446 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
447 } else {
448 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN;
449 }
450 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
451
452 ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa,
453 &ipa_ctx->sys_pipe[i].conn_hdl);
454 if (ret) {
455 ipa_err("Failed for pipe %d ret: %d", i, ret);
456 return ret;
457 }
458 ipa_ctx->sys_pipe[i].conn_hdl_valid = 1;
459 }
460
461 return ret;
462}
463#else
464/**
465 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
466 * @ipa_ctx: Global IPA IPA context
467 * @desc_fifo_sz: Number of descriptors
468 *
469 * Return: 0 on success, negative errno on error
470 */
471static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
472 int32_t desc_fifo_sz)
473{
474 /*
475 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
476 * is enabled, where per vdev descriptors are supported in firmware.
477 */
478 return 0;
479}
480#endif
481
482/**
483 * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
484 * @ipa_ctx: Global IPA IPA context
485 * @desc_fifo_sz: Number of descriptors
486 *
487 * Return: 0 on success, negative errno on error
488 */
489static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
490 int32_t desc_fifo_sz)
491{
492 int ret = 0;
493 qdf_ipa_sys_connect_params_t *ipa;
494
495 /*
496 * Hard code it here, this can be extended if in case
497 * PROD pipe is also per interface.
498 * Right now there is no advantage of doing this.
499 */
500 ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params;
501
502 ipa->client = IPA_CLIENT_WLAN1_PROD;
503
504 ipa->desc_fifo_sz = desc_fifo_sz;
505 ipa->priv = ipa_ctx;
506 ipa->notify = NULL;
507
508 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
509 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN;
510 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
511 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
512
513 ret = qdf_ipa_setup_sys_pipe(ipa,
514 &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl);
515 if (ret) {
516 ipa_err("Failed for RX pipe: %d", ret);
517 return ret;
518 }
519 ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1;
520
521 return ret;
522}
523
524/**
525 * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
526 * @ipa_ctx: Global IPA IPA context
527 *
528 * Return: 0 on success, negative errno on error
529 */
530static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
531{
532 int i = WLAN_IPA_MAX_IFACE, ret = 0;
533 uint32_t desc_fifo_sz;
534
535 /* The maximum number of descriptors that can be provided to a BAM at
536 * once is one less than the total number of descriptors that the buffer
537 * can contain.
538 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
539 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
540 * be provided at once.
541 * Because of above requirement, one extra descriptor will be added to
542 * make sure hardware always has one descriptor.
543 */
544 desc_fifo_sz = ipa_ctx->config->desc_size
545 + SPS_DESC_SIZE;
546
547 ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz);
548 if (ret) {
549 ipa_err("Failed for TX pipe: %d", ret);
550 goto setup_sys_pipe_fail;
551 }
552
553 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
554 ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz);
555 if (ret) {
556 ipa_err("Failed for RX pipe: %d", ret);
557 goto setup_sys_pipe_fail;
558 }
559 }
560
561 /* Allocate free Tx desc list */
562 ret = wlan_ipa_alloc_tx_desc_list(ipa_ctx);
563 if (ret)
564 goto setup_sys_pipe_fail;
565
566 return ret;
567
568setup_sys_pipe_fail:
569
570 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
571 if (ipa_ctx->sys_pipe[i].conn_hdl_valid)
572 qdf_ipa_teardown_sys_pipe(
573 ipa_ctx->sys_pipe[i].conn_hdl);
574 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
575 sizeof(struct wlan_ipa_sys_pipe));
576 }
577
578 return ret;
579}
580
581/**
582 * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
583 * @ipa_ctx: Global IPA IPA context
584 *
585 * Return: None
586 */
587static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
588{
589 int ret = 0, i;
590 struct wlan_ipa_tx_desc *tmp_desc;
591 qdf_ipa_rx_data_t *ipa_tx_desc;
592 qdf_list_node_t *node;
593
594 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
595 if (ipa_ctx->sys_pipe[i].conn_hdl_valid) {
596 ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx,
597 ipa_ctx->sys_pipe[i].conn_hdl);
598 if (ret)
599 ipa_err("Failed:%d", ret);
600
601 ipa_ctx->sys_pipe[i].conn_hdl_valid = 0;
602 }
603 }
604
605 while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) ==
606 QDF_STATUS_SUCCESS) {
607 tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc,
608 node);
609 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
610 if (ipa_tx_desc)
611 qdf_ipa_free_skb(ipa_tx_desc);
612
613 qdf_mem_free(tmp_desc);
614 }
615}
616
617/**
618 * wlan_ipa_setup() - IPA initialization function
619 * @ipa_ctx: IPA context
620 * @ipa_cfg: IPA config
621 *
622 * Allocate ipa_ctx resources, ipa pipe resource and register
623 * wlan interface with IPA module.
624 *
625 * Return: QDF_STATUS enumeration
626 */
627QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
628 struct wlan_ipa_config *ipa_cfg)
629{
630 int ret, i;
631 struct wlan_ipa_iface_context *iface_context = NULL;
632 QDF_STATUS status;
633
634 ipa_debug("enter");
635
636 gp_ipa = ipa_ctx;
637 ipa_ctx->num_iface = 0;
638 ipa_ctx->config = ipa_cfg;
639
640 wlan_ipa_wdi_get_wdi_version(ipa_ctx);
641
642 /* Create the interface context */
643 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
644 iface_context = &ipa_ctx->iface_context[i];
645 iface_context->ipa_ctx = ipa_ctx;
646 iface_context->cons_client =
647 wlan_ipa_iface_2_client[i].cons_client;
648 iface_context->prod_client =
649 wlan_ipa_iface_2_client[i].prod_client;
650 iface_context->iface_id = i;
651 iface_context->dev = NULL;
652 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
653 iface_context->tl_context = NULL;
654 qdf_spinlock_create(&iface_context->interface_lock);
655 }
656
657 qdf_spinlock_create(&ipa_ctx->pm_lock);
658 qdf_spinlock_create(&ipa_ctx->q_lock);
659 qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head);
660 qdf_list_create(&ipa_ctx->pending_event, 1000);
661 qdf_mutex_create(&ipa_ctx->event_lock);
662 qdf_mutex_create(&ipa_ctx->ipa_lock);
663
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530664 status = wlan_ipa_wdi_setup_rm(ipa_ctx);
665 if (status != QDF_STATUS_SUCCESS)
666 goto fail_setup_rm;
667
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530668 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++)
669 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
670 sizeof(struct wlan_ipa_sys_pipe));
671
672 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
673 qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats));
674 ipa_ctx->sap_num_connected_sta = 0;
675 ipa_ctx->ipa_tx_packets_diff = 0;
676 ipa_ctx->ipa_rx_packets_diff = 0;
677 ipa_ctx->ipa_p_tx_packets = 0;
678 ipa_ctx->ipa_p_rx_packets = 0;
679 ipa_ctx->resource_loading = false;
680 ipa_ctx->resource_unloading = false;
681 ipa_ctx->sta_connected = 0;
682 ipa_ctx->ipa_pipes_down = true;
683 ipa_ctx->wdi_enabled = false;
684 /* Setup IPA system pipes */
685 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
686 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
687 if (ret)
688 goto fail_create_sys_pipe;
689 }
690
691 status = wlan_ipa_wdi_init(ipa_ctx);
692 if (status == QDF_STATUS_E_BUSY)
693 status = wlan_ipa_uc_send_wdi_control_msg(false);
694 if (status != QDF_STATUS_SUCCESS) {
695 ipa_err("IPA WDI init failed: ret=%d", ret);
696 goto fail_create_sys_pipe;
697 }
698 } else {
699 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
700 if (ret)
701 goto fail_create_sys_pipe;
702 }
703
704 qdf_event_create(&ipa_ctx->ipa_resource_comp);
705
706 ipa_debug("exit: success");
707
708 return QDF_STATUS_SUCCESS;
709
710fail_create_sys_pipe:
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530711 wlan_ipa_wdi_destroy_rm(ipa_ctx);
712
713fail_setup_rm:
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530714 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530715 qdf_spinlock_destroy(&ipa_ctx->q_lock);
716 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
717 iface_context = &ipa_ctx->iface_context[i];
718 qdf_spinlock_destroy(&iface_context->interface_lock);
719 }
720 qdf_mutex_destroy(&ipa_ctx->event_lock);
721 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
722 qdf_list_destroy(&ipa_ctx->pending_event);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530723 gp_ipa = NULL;
724 ipa_debug("exit: fail");
725
726 return QDF_STATUS_E_FAILURE;
727}
728
729QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx)
730{
731 struct wlan_ipa_iface_context *iface_context = NULL;
732 int i;
733
734 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
735 wlan_ipa_teardown_sys_pipe(ipa_ctx);
736
737 /* Teardown IPA sys_pipe for MCC */
738 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
739 wlan_ipa_teardown_sys_pipe(ipa_ctx);
740
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530741 wlan_ipa_wdi_destroy_rm(ipa_ctx);
742
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530743 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
744 qdf_spinlock_destroy(&ipa_ctx->q_lock);
745
746 /* destroy the interface lock */
747 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
748 iface_context = &ipa_ctx->iface_context[i];
749 qdf_spinlock_destroy(&iface_context->interface_lock);
750 }
751
752 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
753 wlan_ipa_wdi_cleanup();
754 qdf_mutex_destroy(&ipa_ctx->event_lock);
755 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
756 qdf_list_destroy(&ipa_ctx->pending_event);
757
758 }
759
760 gp_ipa = NULL;
761
762 return QDF_STATUS_SUCCESS;
763}