blob: 78544bcfd459a0680aaf9128c73c19c7c20dd8e7 [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
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530183struct wlan_ipa_priv *wlan_ipa_get_obj_context(void)
184{
185 return gp_ipa;
186}
187
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530188#ifdef CONFIG_IPA_WDI_UNIFIED_API
189
190/*
191 * TODO: Get WDI version through FW capabilities
192 */
193#ifdef CONFIG_LITHIUM
194static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
195{
196 ipa_ctx->wdi_version = IPA_WDI_3;
197}
198#elif defined(QCA_WIFI_3_0)
199static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
200{
201 ipa_ctx->wdi_version = IPA_WDI_2;
202}
203#else
204static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
205{
206 ipa_ctx->wdi_version = IPA_WDI_1;
207}
208#endif
209
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530210#ifdef FEATURE_METERING
211/**
212 * wlan_ipa_wdi_init_metering() - IPA WDI metering init
213 * @ipa_ctx: IPA context
214 * @in: IPA WDI in param
215 *
216 * Return: QDF_STATUS
217 */
218static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
219 qdf_ipa_wdi_init_in_params_t *in)
220{
221 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(in) =
222 wlan_ipa_wdi_meter_notifier_cb;
223}
224#else
225static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
226 qdf_ipa_wdi_init_in_params_t *in)
227{
228}
229#endif
230
231/**
232 * wlan_ipa_wdi_init() - IPA WDI init
233 * @ipa_ctx: IPA context
234 *
235 * Return: QDF_STATUS
236 */
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530237static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
238{
239 qdf_ipa_wdi_init_in_params_t in;
240 qdf_ipa_wdi_init_out_params_t out;
241 int ret;
242
243 ipa_ctx->uc_loaded = false;
244
245 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version;
246 QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb;
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530247 QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = ipa_ctx;
248 wlan_ipa_wdi_init_metering(ipa_ctx, &in);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530249
250 ret = qdf_ipa_wdi_init(&in, &out);
251 if (ret) {
252 ipa_err("ipa_wdi_init failed with ret=%d", ret);
253 return QDF_STATUS_E_FAILURE;
254 }
255
256 if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
257 ipa_info("IPA uC READY");
258 ipa_ctx->uc_loaded = true;
259 ipa_ctx->is_smmu_enabled =
260 QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
261 ipa_info("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled);
262 } else {
263 return QDF_STATUS_E_BUSY;
264 }
265
266 return QDF_STATUS_SUCCESS;
267}
268
269static inline int wlan_ipa_wdi_cleanup(void)
270{
271 int ret;
272
273 ret = qdf_ipa_wdi_cleanup();
274 if (ret)
275 ipa_info("ipa_wdi_cleanup failed ret=%d", ret);
276 return ret;
277}
278
279static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
280 struct ipa_sys_connect_params *sys,
281 uint32_t *handle)
282{
283 return 0;
284}
285
286static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
287 uint32_t handle)
288{
289 return 0;
290}
291
292#else /* CONFIG_IPA_WDI_UNIFIED_API */
293
294static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
295{
296}
297
298static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
299{
300 struct ipa_wdi_uc_ready_params uc_ready_param;
301
302 ipa_ctx->uc_loaded = false;
303 uc_ready_param.priv = (void *)ipa_ctx;
304 uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb;
305 if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) {
306 ipa_info("UC Ready CB register fail");
307 return QDF_STATUS_E_FAILURE;
308 }
309
310 if (true == uc_ready_param.is_uC_ready) {
311 ipa_info("UC Ready");
312 ipa_ctx->uc_loaded = true;
313 } else {
314 return QDF_STATUS_E_BUSY;
315 }
316
317 return QDF_STATUS_SUCCESS;
318}
319
320static inline int wlan_ipa_wdi_cleanup(void)
321{
322 int ret;
323
324 ret = qdf_ipa_uc_dereg_rdyCB();
325 if (ret)
326 ipa_info("UC Ready CB deregister fail");
327 return ret;
328}
329
330static inline int wlan_ipa_wdi_setup_sys_pipe(
331 struct wlan_ipa_priv *ipa_ctx,
332 struct ipa_sys_connect_params *sys, uint32_t *handle)
333{
334 return qdf_ipa_setup_sys_pipe(sys, handle);
335}
336
337static inline int wlan_ipa_wdi_teardown_sys_pipe(
338 struct wlan_ipa_priv *ipa_ctx,
339 uint32_t handle)
340{
341 return qdf_ipa_teardown_sys_pipe(handle);
342}
343
344#endif /* CONFIG_IPA_WDI_UNIFIED_API */
345
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530346QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx)
347{
348 int result;
349
350 ipa_debug("enter");
351
352 if (!ipa_ctx->ipa_pipes_down) {
353 /*
354 * IPA WDI Pipes are already activated due to
355 * rm deferred resources grant
356 */
357 ipa_warn("IPA WDI Pipes are already activated");
358 goto end;
359 }
360
361 result = cdp_ipa_enable_pipes(ipa_ctx->dp_soc,
362 ipa_ctx->dp_pdev);
363 if (result) {
364 ipa_err("Enable IPA WDI PIPE failed: ret=%d", result);
365 return QDF_STATUS_E_FAILURE;
366 }
367
368 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
369 ipa_ctx->ipa_pipes_down = false;
370
371 cdp_ipa_enable_autonomy(ipa_ctx->dp_soc,
372 ipa_ctx->dp_pdev);
373
374end:
375 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
376
377 return QDF_STATUS_SUCCESS;
378}
379
380QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx)
381{
382 int result;
383
384 ipa_debug("enter");
385
386 if (ipa_ctx->ipa_pipes_down) {
387 /*
388 * This shouldn't happen :
389 * IPA WDI Pipes are already deactivated
390 */
391 QDF_ASSERT(0);
392 ipa_warn("IPA WDI Pipes are already deactivated");
393 goto end;
394 }
395
396 cdp_ipa_disable_autonomy(ipa_ctx->dp_soc,
397 ipa_ctx->dp_pdev);
398
399 result = cdp_ipa_disable_pipes(ipa_ctx->dp_soc,
400 ipa_ctx->dp_pdev);
401 if (result) {
402 ipa_err("Disable IPA WDI PIPE failed: ret=%d", result);
403 return QDF_STATUS_E_FAILURE;
404 }
405
406 ipa_ctx->ipa_pipes_down = true;
407
408end:
409 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
410
411 return QDF_STATUS_SUCCESS;
412}
413
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530414/**
415 * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
416 * @ipa_ctx: IPA context
417 *
418 * Return: QDF_STATUS
419 */
420static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
421{
422 int i;
423 uint32_t max_desc_cnt;
424 struct wlan_ipa_tx_desc *tmp_desc;
425
426 max_desc_cnt = ipa_ctx->config->txbuf_count;
427
428 qdf_list_create(&ipa_ctx->tx_desc_list, max_desc_cnt);
429
430 qdf_spin_lock_bh(&ipa_ctx->q_lock);
431 for (i = 0; i < max_desc_cnt; i++) {
432 tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc));
433 tmp_desc->id = i;
434 tmp_desc->ipa_tx_desc_ptr = NULL;
435 qdf_list_insert_back(&ipa_ctx->tx_desc_list,
436 &tmp_desc->node);
437 tmp_desc++;
438 }
439
440 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
441 ipa_ctx->stats.num_tx_desc_error = 0;
442
443 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
444
445 return QDF_STATUS_SUCCESS;
446}
447
448#ifndef QCA_LL_TX_FLOW_CONTROL_V2
449/**
450 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
451 * @ipa_ctx: Global IPA IPA context
452 * @desc_fifo_sz: Number of descriptors
453 *
454 * Return: 0 on success, negative errno on error
455 */
456static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
457 int32_t desc_fifo_sz)
458{
459 int i, ret = 0;
460 qdf_ipa_sys_connect_params_t *ipa;
461
462 /*setup TX pipes */
463 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
464 ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params;
465
466 ipa->client = wlan_ipa_iface_2_client[i].cons_client;
467 ipa->desc_fifo_sz = desc_fifo_sz;
468 ipa->priv = &ipa_ctx->iface_context[i];
469 ipa->notify = NULL;
470
471 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
472 ipa->ipa_ep_cfg.hdr.hdr_len =
473 WLAN_IPA_UC_WLAN_TX_HDR_LEN;
474 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
475 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
476 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
477 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
478 WLAN_IPA_UC_WLAN_8023_HDR_SIZE;
479 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
480 } else {
481 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN;
482 }
483 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
484
485 ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa,
486 &ipa_ctx->sys_pipe[i].conn_hdl);
487 if (ret) {
488 ipa_err("Failed for pipe %d ret: %d", i, ret);
489 return ret;
490 }
491 ipa_ctx->sys_pipe[i].conn_hdl_valid = 1;
492 }
493
494 return ret;
495}
496#else
497/**
498 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
499 * @ipa_ctx: Global IPA IPA context
500 * @desc_fifo_sz: Number of descriptors
501 *
502 * Return: 0 on success, negative errno on error
503 */
504static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
505 int32_t desc_fifo_sz)
506{
507 /*
508 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
509 * is enabled, where per vdev descriptors are supported in firmware.
510 */
511 return 0;
512}
513#endif
514
515/**
516 * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
517 * @ipa_ctx: Global IPA IPA context
518 * @desc_fifo_sz: Number of descriptors
519 *
520 * Return: 0 on success, negative errno on error
521 */
522static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
523 int32_t desc_fifo_sz)
524{
525 int ret = 0;
526 qdf_ipa_sys_connect_params_t *ipa;
527
528 /*
529 * Hard code it here, this can be extended if in case
530 * PROD pipe is also per interface.
531 * Right now there is no advantage of doing this.
532 */
533 ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params;
534
535 ipa->client = IPA_CLIENT_WLAN1_PROD;
536
537 ipa->desc_fifo_sz = desc_fifo_sz;
538 ipa->priv = ipa_ctx;
539 ipa->notify = NULL;
540
541 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
542 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN;
543 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
544 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
545
546 ret = qdf_ipa_setup_sys_pipe(ipa,
547 &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl);
548 if (ret) {
549 ipa_err("Failed for RX pipe: %d", ret);
550 return ret;
551 }
552 ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1;
553
554 return ret;
555}
556
557/**
558 * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
559 * @ipa_ctx: Global IPA IPA context
560 *
561 * Return: 0 on success, negative errno on error
562 */
563static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
564{
565 int i = WLAN_IPA_MAX_IFACE, ret = 0;
566 uint32_t desc_fifo_sz;
567
568 /* The maximum number of descriptors that can be provided to a BAM at
569 * once is one less than the total number of descriptors that the buffer
570 * can contain.
571 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
572 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
573 * be provided at once.
574 * Because of above requirement, one extra descriptor will be added to
575 * make sure hardware always has one descriptor.
576 */
577 desc_fifo_sz = ipa_ctx->config->desc_size
578 + SPS_DESC_SIZE;
579
580 ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz);
581 if (ret) {
582 ipa_err("Failed for TX pipe: %d", ret);
583 goto setup_sys_pipe_fail;
584 }
585
586 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
587 ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz);
588 if (ret) {
589 ipa_err("Failed for RX pipe: %d", ret);
590 goto setup_sys_pipe_fail;
591 }
592 }
593
594 /* Allocate free Tx desc list */
595 ret = wlan_ipa_alloc_tx_desc_list(ipa_ctx);
596 if (ret)
597 goto setup_sys_pipe_fail;
598
599 return ret;
600
601setup_sys_pipe_fail:
602
603 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
604 if (ipa_ctx->sys_pipe[i].conn_hdl_valid)
605 qdf_ipa_teardown_sys_pipe(
606 ipa_ctx->sys_pipe[i].conn_hdl);
607 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
608 sizeof(struct wlan_ipa_sys_pipe));
609 }
610
611 return ret;
612}
613
614/**
615 * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
616 * @ipa_ctx: Global IPA IPA context
617 *
618 * Return: None
619 */
620static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
621{
622 int ret = 0, i;
623 struct wlan_ipa_tx_desc *tmp_desc;
624 qdf_ipa_rx_data_t *ipa_tx_desc;
625 qdf_list_node_t *node;
626
627 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
628 if (ipa_ctx->sys_pipe[i].conn_hdl_valid) {
629 ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx,
630 ipa_ctx->sys_pipe[i].conn_hdl);
631 if (ret)
632 ipa_err("Failed:%d", ret);
633
634 ipa_ctx->sys_pipe[i].conn_hdl_valid = 0;
635 }
636 }
637
638 while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) ==
639 QDF_STATUS_SUCCESS) {
640 tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc,
641 node);
642 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
643 if (ipa_tx_desc)
644 qdf_ipa_free_skb(ipa_tx_desc);
645
646 qdf_mem_free(tmp_desc);
647 }
648}
649
650/**
651 * wlan_ipa_setup() - IPA initialization function
652 * @ipa_ctx: IPA context
653 * @ipa_cfg: IPA config
654 *
655 * Allocate ipa_ctx resources, ipa pipe resource and register
656 * wlan interface with IPA module.
657 *
658 * Return: QDF_STATUS enumeration
659 */
660QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
661 struct wlan_ipa_config *ipa_cfg)
662{
663 int ret, i;
664 struct wlan_ipa_iface_context *iface_context = NULL;
665 QDF_STATUS status;
666
667 ipa_debug("enter");
668
669 gp_ipa = ipa_ctx;
670 ipa_ctx->num_iface = 0;
671 ipa_ctx->config = ipa_cfg;
672
673 wlan_ipa_wdi_get_wdi_version(ipa_ctx);
674
675 /* Create the interface context */
676 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
677 iface_context = &ipa_ctx->iface_context[i];
678 iface_context->ipa_ctx = ipa_ctx;
679 iface_context->cons_client =
680 wlan_ipa_iface_2_client[i].cons_client;
681 iface_context->prod_client =
682 wlan_ipa_iface_2_client[i].prod_client;
683 iface_context->iface_id = i;
684 iface_context->dev = NULL;
685 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
686 iface_context->tl_context = NULL;
687 qdf_spinlock_create(&iface_context->interface_lock);
688 }
689
690 qdf_spinlock_create(&ipa_ctx->pm_lock);
691 qdf_spinlock_create(&ipa_ctx->q_lock);
692 qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head);
693 qdf_list_create(&ipa_ctx->pending_event, 1000);
694 qdf_mutex_create(&ipa_ctx->event_lock);
695 qdf_mutex_create(&ipa_ctx->ipa_lock);
696
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530697 status = wlan_ipa_wdi_setup_rm(ipa_ctx);
698 if (status != QDF_STATUS_SUCCESS)
699 goto fail_setup_rm;
700
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530701 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++)
702 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
703 sizeof(struct wlan_ipa_sys_pipe));
704
705 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
706 qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats));
707 ipa_ctx->sap_num_connected_sta = 0;
708 ipa_ctx->ipa_tx_packets_diff = 0;
709 ipa_ctx->ipa_rx_packets_diff = 0;
710 ipa_ctx->ipa_p_tx_packets = 0;
711 ipa_ctx->ipa_p_rx_packets = 0;
712 ipa_ctx->resource_loading = false;
713 ipa_ctx->resource_unloading = false;
714 ipa_ctx->sta_connected = 0;
715 ipa_ctx->ipa_pipes_down = true;
716 ipa_ctx->wdi_enabled = false;
717 /* Setup IPA system pipes */
718 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
719 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
720 if (ret)
721 goto fail_create_sys_pipe;
722 }
723
724 status = wlan_ipa_wdi_init(ipa_ctx);
725 if (status == QDF_STATUS_E_BUSY)
726 status = wlan_ipa_uc_send_wdi_control_msg(false);
727 if (status != QDF_STATUS_SUCCESS) {
728 ipa_err("IPA WDI init failed: ret=%d", ret);
729 goto fail_create_sys_pipe;
730 }
731 } else {
732 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
733 if (ret)
734 goto fail_create_sys_pipe;
735 }
736
737 qdf_event_create(&ipa_ctx->ipa_resource_comp);
738
739 ipa_debug("exit: success");
740
741 return QDF_STATUS_SUCCESS;
742
743fail_create_sys_pipe:
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530744 wlan_ipa_wdi_destroy_rm(ipa_ctx);
745
746fail_setup_rm:
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530747 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530748 qdf_spinlock_destroy(&ipa_ctx->q_lock);
749 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
750 iface_context = &ipa_ctx->iface_context[i];
751 qdf_spinlock_destroy(&iface_context->interface_lock);
752 }
753 qdf_mutex_destroy(&ipa_ctx->event_lock);
754 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
755 qdf_list_destroy(&ipa_ctx->pending_event);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530756 gp_ipa = NULL;
757 ipa_debug("exit: fail");
758
759 return QDF_STATUS_E_FAILURE;
760}
761
762QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx)
763{
764 struct wlan_ipa_iface_context *iface_context = NULL;
765 int i;
766
767 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
768 wlan_ipa_teardown_sys_pipe(ipa_ctx);
769
770 /* Teardown IPA sys_pipe for MCC */
771 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
772 wlan_ipa_teardown_sys_pipe(ipa_ctx);
773
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530774 wlan_ipa_wdi_destroy_rm(ipa_ctx);
775
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530776 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
777 qdf_spinlock_destroy(&ipa_ctx->q_lock);
778
779 /* destroy the interface lock */
780 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
781 iface_context = &ipa_ctx->iface_context[i];
782 qdf_spinlock_destroy(&iface_context->interface_lock);
783 }
784
785 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
786 wlan_ipa_wdi_cleanup();
787 qdf_mutex_destroy(&ipa_ctx->event_lock);
788 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
789 qdf_list_destroy(&ipa_ctx->pending_event);
790
791 }
792
793 gp_ipa = NULL;
794
795 return QDF_STATUS_SUCCESS;
796}
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530797
798struct wlan_ipa_iface_context
799*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode)
800{
801 struct wlan_ipa_iface_context *iface_ctx = NULL;
802 int i;
803
804 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
805 iface_ctx = &ipa_ctx->iface_context[i];
806
807 if (iface_ctx->device_mode == mode)
808 return iface_ctx;
809 }
810
811 return NULL;
812}