blob: c9be3aaac7790eb7f46299139e213e34fd6ccc37 [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
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +053050/* Local Function Prototypes */
51static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
52 unsigned long data);
53static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
54 unsigned long data);
55
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +053056/**
57 * wlan_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
58 * @ipa_cfg: IPA config
59 *
60 * Return: true if STA mode IPA uC offload is enabled, false otherwise
61 */
62static inline bool wlan_ipa_uc_sta_is_enabled(struct wlan_ipa_config *ipa_cfg)
63{
64 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_STA_ENABLE_MASK);
65}
66
67/**
68 * wlan_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
69 * @ipa_cfg: IPA config
70 *
71 * Return: true if pre-filter is enabled, otherwise false
72 */
73static inline
74bool wlan_ipa_is_pre_filter_enabled(struct wlan_ipa_config *ipa_cfg)
75{
76 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg,
77 WLAN_IPA_PRE_FILTER_ENABLE_MASK);
78}
79
80/**
81 * wlan_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
82 * @ipa_cfg: IPA config
83 *
84 * Return: true if IPv6 is enabled, otherwise false
85 */
86static inline bool wlan_ipa_is_ipv6_enabled(struct wlan_ipa_config *ipa_cfg)
87{
88 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_IPV6_ENABLE_MASK);
89}
90
91/**
92 * wlan_ipa_msg_free_fn() - Free an IPA message
93 * @buff: pointer to the IPA message
94 * @len: length of the IPA message
95 * @type: type of IPA message
96 *
97 * Return: None
98 */
99static void wlan_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
100{
101 ipa_debug("msg type:%d, len:%d", type, len);
102 qdf_mem_free(buff);
103}
104
105/**
106 * wlan_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
107 * @priv_ctxt: IPA context
108 *
109 * Will be called by IPA context.
110 * It's atomic context, then should be scheduled to kworker thread
111 *
112 * Return: None
113 */
114static void wlan_ipa_uc_loaded_uc_cb(void *priv_ctxt)
115{
116 struct wlan_ipa_priv *ipa_ctx;
117 struct op_msg_type *msg;
118 struct uc_op_work_struct *uc_op_work;
119
120 if (!priv_ctxt) {
121 ipa_err("Invalid IPA context");
122 return;
123 }
124
125 ipa_ctx = priv_ctxt;
126
127 msg = qdf_mem_malloc(sizeof(*msg));
128 if (!msg) {
129 ipa_err("op_msg allocation fails");
130 return;
131 }
132
133 msg->op_code = WLAN_IPA_UC_OPCODE_UC_READY;
134
135 uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
136
137 /* When the same uC OPCODE is already pended, just return */
138 if (uc_op_work->msg)
139 goto done;
140
141 uc_op_work->msg = msg;
142 qdf_sched_work(0, &uc_op_work->work);
143 /* work handler will free the msg buffer */
144 return;
145
146done:
147 qdf_mem_free(msg);
148}
149
150/**
151 * wlan_ipa_uc_send_wdi_control_msg() - Set WDI control message
152 * @ctrl: WDI control value
153 *
154 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
155 *
156 * Return: QDF_STATUS
157 */
158static QDF_STATUS wlan_ipa_uc_send_wdi_control_msg(bool ctrl)
159{
160 qdf_ipa_msg_meta_t meta;
161 qdf_ipa_wlan_msg_t *ipa_msg;
162 int ret = 0;
163
164 /* WDI enable message to IPA */
165 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
166 ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
167 if (!ipa_msg) {
168 ipa_err("msg allocation failed");
169 return QDF_STATUS_E_NOMEM;
170 }
171
172 if (ctrl)
173 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_ENABLE);
174 else
175 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_DISABLE);
176
177 ipa_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
178 ret = qdf_ipa_send_msg(&meta, ipa_msg, wlan_ipa_msg_free_fn);
179 if (ret) {
180 ipa_err("ipa_send_msg(Evt:%d)-fail=%d",
181 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
182 qdf_mem_free(ipa_msg);
183 return QDF_STATUS_E_FAILURE;
184 }
185
186 return QDF_STATUS_SUCCESS;
187}
188
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530189struct wlan_ipa_priv *wlan_ipa_get_obj_context(void)
190{
191 return gp_ipa;
192}
193
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530194#ifdef CONFIG_IPA_WDI_UNIFIED_API
195
196/*
197 * TODO: Get WDI version through FW capabilities
198 */
199#ifdef CONFIG_LITHIUM
200static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
201{
202 ipa_ctx->wdi_version = IPA_WDI_3;
203}
204#elif defined(QCA_WIFI_3_0)
205static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
206{
207 ipa_ctx->wdi_version = IPA_WDI_2;
208}
209#else
210static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
211{
212 ipa_ctx->wdi_version = IPA_WDI_1;
213}
214#endif
215
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530216static inline bool wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx,
217 qdf_device_t osdev)
218{
219 /* TODO: Need to check if SMMU is supported on cld_3.2 */
220 /* return hdd_ipa->is_smmu_enabled && qdf_mem_smmu_s1_enabled(osdev); */
221 return 0;
222}
223
224static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx,
225 qdf_device_t osdev)
226{
227 qdf_ipa_sys_connect_params_t sys_in[WLAN_IPA_MAX_IFACE];
228 int i;
229
230 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++)
231 qdf_mem_copy(&sys_in[i],
232 &ipa_ctx->sys_pipe[i].ipa_sys_params,
233 sizeof(qdf_ipa_sys_connect_params_t));
234
235 return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
236 wlan_ipa_i2w_cb, wlan_ipa_w2i_cb,
237 wlan_ipa_wdi_meter_notifier_cb,
238 ipa_ctx->config->desc_size,
239 ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config),
240 &ipa_ctx->tx_pipe_handle,
241 &ipa_ctx->rx_pipe_handle,
242 wlan_ipa_wdi_is_smmu_enabled(ipa_ctx, osdev),
243 sys_in);
244}
245
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530246#ifdef FEATURE_METERING
247/**
248 * wlan_ipa_wdi_init_metering() - IPA WDI metering init
249 * @ipa_ctx: IPA context
250 * @in: IPA WDI in param
251 *
252 * Return: QDF_STATUS
253 */
254static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
255 qdf_ipa_wdi_init_in_params_t *in)
256{
257 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(in) =
258 wlan_ipa_wdi_meter_notifier_cb;
259}
260#else
261static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
262 qdf_ipa_wdi_init_in_params_t *in)
263{
264}
265#endif
266
267/**
268 * wlan_ipa_wdi_init() - IPA WDI init
269 * @ipa_ctx: IPA context
270 *
271 * Return: QDF_STATUS
272 */
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530273static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
274{
275 qdf_ipa_wdi_init_in_params_t in;
276 qdf_ipa_wdi_init_out_params_t out;
277 int ret;
278
279 ipa_ctx->uc_loaded = false;
280
281 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version;
282 QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb;
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530283 QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = ipa_ctx;
284 wlan_ipa_wdi_init_metering(ipa_ctx, &in);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530285
286 ret = qdf_ipa_wdi_init(&in, &out);
287 if (ret) {
288 ipa_err("ipa_wdi_init failed with ret=%d", ret);
289 return QDF_STATUS_E_FAILURE;
290 }
291
292 if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
293 ipa_info("IPA uC READY");
294 ipa_ctx->uc_loaded = true;
295 ipa_ctx->is_smmu_enabled =
296 QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
297 ipa_info("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled);
298 } else {
299 return QDF_STATUS_E_BUSY;
300 }
301
302 return QDF_STATUS_SUCCESS;
303}
304
305static inline int wlan_ipa_wdi_cleanup(void)
306{
307 int ret;
308
309 ret = qdf_ipa_wdi_cleanup();
310 if (ret)
311 ipa_info("ipa_wdi_cleanup failed ret=%d", ret);
312 return ret;
313}
314
315static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
316 struct ipa_sys_connect_params *sys,
317 uint32_t *handle)
318{
319 return 0;
320}
321
322static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
323 uint32_t handle)
324{
325 return 0;
326}
327
328#else /* CONFIG_IPA_WDI_UNIFIED_API */
329
330static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
331{
332}
333
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530334static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx,
335 qdf_device_t osdev)
336{
337 return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
338 wlan_ipa_i2w_cb, wlan_ipa_w2i_cb,
339 wlan_ipa_wdi_meter_notifier_cb,
340 ipa_ctx->config->desc_size,
341 ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config),
342 &ipa_ctx->tx_pipe_handle,
343 &ipa_ctx->rx_pipe_handle);
344}
345
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530346static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
347{
348 struct ipa_wdi_uc_ready_params uc_ready_param;
349
350 ipa_ctx->uc_loaded = false;
351 uc_ready_param.priv = (void *)ipa_ctx;
352 uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb;
353 if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) {
354 ipa_info("UC Ready CB register fail");
355 return QDF_STATUS_E_FAILURE;
356 }
357
358 if (true == uc_ready_param.is_uC_ready) {
359 ipa_info("UC Ready");
360 ipa_ctx->uc_loaded = true;
361 } else {
362 return QDF_STATUS_E_BUSY;
363 }
364
365 return QDF_STATUS_SUCCESS;
366}
367
368static inline int wlan_ipa_wdi_cleanup(void)
369{
370 int ret;
371
372 ret = qdf_ipa_uc_dereg_rdyCB();
373 if (ret)
374 ipa_info("UC Ready CB deregister fail");
375 return ret;
376}
377
378static inline int wlan_ipa_wdi_setup_sys_pipe(
379 struct wlan_ipa_priv *ipa_ctx,
380 struct ipa_sys_connect_params *sys, uint32_t *handle)
381{
382 return qdf_ipa_setup_sys_pipe(sys, handle);
383}
384
385static inline int wlan_ipa_wdi_teardown_sys_pipe(
386 struct wlan_ipa_priv *ipa_ctx,
387 uint32_t handle)
388{
389 return qdf_ipa_teardown_sys_pipe(handle);
390}
391
392#endif /* CONFIG_IPA_WDI_UNIFIED_API */
393
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530394/**
395 * wlan_ipa_send_skb_to_network() - Send skb to kernel
396 * @skb: network buffer
397 * @iface_ctx: IPA interface context
398 *
399 * Called when a network buffer is received which should not be routed
400 * to the IPA module.
401 *
402 * Return: None
403 */
404static void
405wlan_ipa_send_skb_to_network(qdf_nbuf_t skb,
406 struct wlan_ipa_iface_context *iface_ctx)
407{
408 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
409
410 if (!iface_ctx->dev) {
411 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid interface");
412 ipa_ctx->ipa_rx_internal_drop_count++;
413 qdf_nbuf_free(skb);
414 return;
415 }
416
417 skb->destructor = wlan_ipa_uc_rt_debug_destructor;
418
419 if (ipa_ctx->send_to_nw)
420 ipa_ctx->send_to_nw(skb, iface_ctx->dev);
421
422 ipa_ctx->ipa_rx_net_send_count++;
423}
424
425/**
426 * wlan_ipa_forward() - handle packet forwarding to wlan tx
427 * @ipa_ctx: pointer to ipa ipa context
428 * @iface_ctx: interface context
429 * @skb: data pointer
430 *
431 * if exception packet has set forward bit, copied new packet should be
432 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
433 * put into pm queue and tx procedure will be differed
434 *
435 * Return: None
436 */
437static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx,
438 struct wlan_ipa_iface_context *iface_ctx,
439 qdf_nbuf_t skb)
440{
441 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
442
443 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
444
445 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
446 qdf_nbuf_ipa_owned_set(skb);
447
448 /* WLAN subsystem is in suspend, put in queue */
449 if (ipa_ctx->suspended) {
450 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
451 WLAN_IPA_LOG(QDF_TRACE_LEVEL_INFO,
452 "Tx in suspend, put in queue");
453 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
454 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
455 pm_tx_cb->exception = true;
456 pm_tx_cb->iface_context = iface_ctx;
457 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
458 qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
459 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
460 ipa_ctx->stats.num_tx_queued++;
461 } else {
462 /* Resume, put packet into WLAN TX */
463 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
464
465 if (ipa_ctx->softap_xmit) {
466 if (ipa_ctx->softap_xmit(skb, iface_ctx->dev)) {
467 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
468 "packet Tx fail");
469 ipa_ctx->stats.num_tx_fwd_err++;
470 } else {
471 ipa_ctx->stats.num_tx_fwd_ok++;
472 }
473 } else {
474 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
475 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
476 }
477 }
478}
479
480/**
481 * wlan_ipa_intrabss_forward() - Forward intra bss packets.
482 * @ipa_ctx: pointer to IPA IPA struct
483 * @iface_ctx: ipa interface context
484 * @desc: Firmware descriptor
485 * @skb: Data buffer
486 *
487 * Return:
488 * WLAN_IPA_FORWARD_PKT_NONE
489 * WLAN_IPA_FORWARD_PKT_DISCARD
490 * WLAN_IPA_FORWARD_PKT_LOCAL_STACK
491 *
492 */
493
494static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward(
495 struct wlan_ipa_priv *ipa_ctx,
496 struct wlan_ipa_iface_context *iface_ctx,
497 uint8_t desc,
498 qdf_nbuf_t skb)
499{
500 int ret = WLAN_IPA_FORWARD_PKT_NONE;
501 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
502 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
503
504 if ((desc & FW_RX_DESC_FORWARD_M)) {
505 if (!ol_txrx_fwd_desc_thresh_check(
506 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
507 (struct cdp_pdev *)pdev,
508 iface_ctx->session_id))) {
509 /* Drop the packet*/
510 ipa_ctx->stats.num_tx_fwd_err++;
511 kfree_skb(skb);
512 ret = WLAN_IPA_FORWARD_PKT_DISCARD;
513 return ret;
514 }
515 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
516 "Forward packet to Tx (fw_desc=%d)", desc);
517 ipa_ctx->ipa_tx_forward++;
518
519 if ((desc & FW_RX_DESC_DISCARD_M)) {
520 wlan_ipa_forward(ipa_ctx, iface_ctx, skb);
521 ipa_ctx->ipa_rx_internal_drop_count++;
522 ipa_ctx->ipa_rx_discard++;
523 ret = WLAN_IPA_FORWARD_PKT_DISCARD;
524 } else {
525 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
526
527 if (cloned_skb)
528 wlan_ipa_forward(ipa_ctx, iface_ctx,
529 cloned_skb);
530 else
531 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
532 "tx skb alloc failed");
533 ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK;
534 }
535 }
536
537 return ret;
538}
539
540/**
541 * wlan_ipa_w2i_cb() - WLAN to IPA callback handler
542 * @priv: pointer to private data registered with IPA (we register a
543 * pointer to the global IPA context)
544 * @evt: the IPA event which triggered the callback
545 * @data: data associated with the event
546 *
547 * Return: None
548 */
549static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
550 unsigned long data)
551{
552 struct wlan_ipa_priv *ipa_ctx = NULL;
553 qdf_nbuf_t skb;
554 uint8_t iface_id;
555 uint8_t session_id;
556 struct wlan_ipa_iface_context *iface_context;
557 uint8_t fw_desc;
558
559 ipa_ctx = (struct wlan_ipa_priv *)priv;
560
561 if (!ipa_ctx)
562 return;
563
564 switch (evt) {
565 case IPA_RECEIVE:
566 skb = (qdf_nbuf_t) data;
567
568 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
569 session_id = (uint8_t)skb->cb[0];
570 iface_id = ipa_ctx->vdev_to_iface[session_id];
571 ipa_debug("IPA_RECEIVE: session_id=%u, iface_id=%u",
572 session_id, iface_id);
573 } else {
574 iface_id = WLAN_IPA_GET_IFACE_ID(skb->data);
575 }
576 if (iface_id >= WLAN_IPA_MAX_IFACE) {
577 ipa_err("IPA_RECEIVE: Invalid iface_id: %u",
578 iface_id);
579 ipa_ctx->ipa_rx_internal_drop_count++;
580 qdf_nbuf_free(skb);
581 return;
582 }
583
584 iface_context = &ipa_ctx->iface_context[iface_id];
585 if (!iface_context->tl_context) {
586 ipa_err("IPA_RECEIVE: TL context is NULL");
587 ipa_ctx->ipa_rx_internal_drop_count++;
588 qdf_nbuf_free(skb);
589 return;
590 }
591
592 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
593 ipa_ctx->stats.num_rx_excep++;
594 qdf_nbuf_pull_head(skb, WLAN_IPA_UC_WLAN_CLD_HDR_LEN);
595 } else {
596 qdf_nbuf_pull_head(skb, WLAN_IPA_WLAN_CLD_HDR_LEN);
597 }
598
599 iface_context->stats.num_rx_ipa_excep++;
600
601 /* Disable to forward Intra-BSS Rx packets when
602 * ap_isolate=1 in hostapd.conf
603 */
604 if (!ipa_ctx->ap_intrabss_fwd) {
605 /*
606 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
607 * all Rx packets to IPA uC, which need to be forwarded
608 * to other interface.
609 * And, IPA driver will send back to WLAN host driver
610 * through exception pipe with fw_desc field set by FW.
611 * Here we are checking fw_desc field for FORWARD bit
612 * set, and forward to Tx. Then copy to kernel stack
613 * only when DISCARD bit is not set.
614 */
615 fw_desc = (uint8_t)skb->cb[1];
616 if (WLAN_IPA_FORWARD_PKT_DISCARD ==
617 wlan_ipa_intrabss_forward(ipa_ctx, iface_context,
618 fw_desc, skb))
619 break;
620 } else {
621 ipa_debug("Intra-BSS FWD is disabled-skip forward to Tx");
622 }
623
624 wlan_ipa_send_skb_to_network(skb, iface_context);
625 break;
626
627 default:
628 ipa_err("w2i cb wrong event: 0x%x", evt);
629 return;
630 }
631}
632
633/**
634 * wlan_ipa_send_pkt_to_tl() - Send an IPA packet to TL
635 * @iface_context: interface-specific IPA context
636 * @ipa_tx_desc: packet data descriptor
637 *
638 * Return: None
639 */
640static void wlan_ipa_send_pkt_to_tl(
641 struct wlan_ipa_iface_context *iface_context,
642 qdf_ipa_rx_data_t *ipa_tx_desc)
643{
644 struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
645 qdf_nbuf_t skb;
646 struct wlan_ipa_tx_desc *tx_desc;
647
648 qdf_spin_lock_bh(&iface_context->interface_lock);
649 /*
650 * During CAC period, data packets shouldn't be sent over the air so
651 * drop all the packets here
652 */
653 if (iface_context->device_mode == QDF_SAP_MODE ||
654 iface_context->device_mode == QDF_P2P_GO_MODE) {
655 if (ipa_ctx->dfs_cac_block_tx) {
656 ipa_free_skb(ipa_tx_desc);
657 qdf_spin_unlock_bh(&iface_context->interface_lock);
658 iface_context->stats.num_tx_cac_drop++;
659 wlan_ipa_wdi_rm_try_release(ipa_ctx);
660 return;
661 }
662 }
663 qdf_spin_unlock_bh(&iface_context->interface_lock);
664
665 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
666
667 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
668
669 /* Store IPA Tx buffer ownership into SKB CB */
670 qdf_nbuf_ipa_owned_set(skb);
671 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
672 qdf_nbuf_mapped_paddr_set(skb,
673 QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
674 + WLAN_IPA_WLAN_FRAG_HEADER
675 + WLAN_IPA_WLAN_IPA_HEADER);
676 QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
677 WLAN_IPA_WLAN_FRAG_HEADER + WLAN_IPA_WLAN_IPA_HEADER;
678 } else
679 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
680
681 qdf_spin_lock_bh(&ipa_ctx->q_lock);
682 /* get free Tx desc and assign ipa_tx_desc pointer */
683 if (qdf_list_remove_front(&ipa_ctx->tx_desc_list,
684 (qdf_list_node_t **)&tx_desc) ==
685 QDF_STATUS_SUCCESS) {
686 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
687 ipa_ctx->stats.num_tx_desc_q_cnt++;
688 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
689 /* Store Tx Desc index into SKB CB */
690 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
691 } else {
692 ipa_ctx->stats.num_tx_desc_error++;
693 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
694 qdf_ipa_free_skb(ipa_tx_desc);
695 wlan_ipa_wdi_rm_try_release(ipa_ctx);
696 return;
697 }
698
699 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
700 (struct cdp_vdev *)iface_context->tl_context,
701 QDF_IPA_RX_DATA_SKB(ipa_tx_desc));
702 if (skb) {
703 qdf_nbuf_free(skb);
704 iface_context->stats.num_tx_err++;
705 return;
706 }
707
708 atomic_inc(&ipa_ctx->tx_ref_cnt);
709
710 iface_context->stats.num_tx++;
711}
712
713/**
714 * wlan_ipa_i2w_cb() - IPA to WLAN callback
715 * @priv: pointer to private data registered with IPA (we register a
716 * pointer to the interface-specific IPA context)
717 * @evt: the IPA event which triggered the callback
718 * @data: data associated with the event
719 *
720 * Return: None
721 */
722static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
723 unsigned long data)
724{
725 struct wlan_ipa_priv *ipa_ctx = NULL;
726 qdf_ipa_rx_data_t *ipa_tx_desc;
727 struct wlan_ipa_iface_context *iface_context;
728 qdf_nbuf_t skb;
729 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
730
731 iface_context = (struct wlan_ipa_iface_context *)priv;
732 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
733 ipa_ctx = iface_context->ipa_ctx;
734
735 if (evt != IPA_RECEIVE) {
736 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
737 ipa_free_skb(ipa_tx_desc);
738 iface_context->stats.num_tx_drop++;
739 return;
740 }
741
742 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
743
744 /*
745 * If PROD resource is not requested here then there may be cases where
746 * IPA hardware may be clocked down because of not having proper
747 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
748 * workaround to request PROD resource while data is going over CONS
749 * pipe to prevent the IPA hardware clockdown.
750 */
751 wlan_ipa_wdi_rm_request(ipa_ctx);
752
753 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
754 /*
755 * If host is still suspended then queue the packets and these will be
756 * drained later when resume completes. When packet is arrived here and
757 * host is suspended, this means that there is already resume is in
758 * progress.
759 */
760 if (ipa_ctx->suspended) {
761 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
762 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
763 pm_tx_cb->iface_context = iface_context;
764 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
765 qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
766 ipa_ctx->stats.num_tx_queued++;
767
768 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
769 return;
770 }
771
772 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
773
774 /*
775 * If we are here means, host is not suspended, wait for the work queue
776 * to finish.
777 */
778 qdf_flush_work(&ipa_ctx->pm_work);
779
780 return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
781}
782
783QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx)
784{
785 /*
786 * Check if IPA is ready for suspend, If we are here means, there is
787 * high chance that suspend would go through but just to avoid any race
788 * condition after suspend started, these checks are conducted before
789 * allowing to suspend.
790 */
791 if (atomic_read(&ipa_ctx->tx_ref_cnt))
792 return QDF_STATUS_E_AGAIN;
793
794 qdf_spin_lock_bh(&ipa_ctx->rm_lock);
795
796 if (ipa_ctx->rm_state != WLAN_IPA_RM_RELEASED) {
797 qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
798 return QDF_STATUS_E_AGAIN;
799 }
800 qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
801
802 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
803 ipa_ctx->suspended = true;
804 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
805
806 return QDF_STATUS_SUCCESS;
807}
808
809QDF_STATUS wlan_ipa_resume(struct wlan_ipa_priv *ipa_ctx)
810{
811 qdf_sched_work(0, &ipa_ctx->pm_work);
812
813 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
814 ipa_ctx->suspended = false;
815 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
816
817 return QDF_STATUS_SUCCESS;
818}
819
820/**
821 * wlan_ipa_pm_flush() - flush queued packets
822 * @work: pointer to the scheduled work
823 *
824 * Called during PM resume to send packets to TL which were queued
825 * while host was in the process of suspending.
826 *
827 * Return: None
828 */
829static void wlan_ipa_pm_flush(void *data)
830{
831 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
832 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
833 qdf_nbuf_t skb;
834 uint32_t dequeued = 0;
835
836 qdf_wake_lock_acquire(&ipa_ctx->wake_lock,
837 WIFI_POWER_EVENT_WAKELOCK_IPA);
838 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
839 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) !=
840 NULL)) {
841 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
842
843 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
844 dequeued++;
845
846 wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
847 pm_tx_cb->ipa_tx_desc);
848
849 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
850 }
851 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
852 qdf_wake_lock_release(&ipa_ctx->wake_lock,
853 WIFI_POWER_EVENT_WAKELOCK_IPA);
854
855 ipa_ctx->stats.num_tx_dequeued += dequeued;
856 if (dequeued > ipa_ctx->stats.num_max_pm_queue)
857 ipa_ctx->stats.num_max_pm_queue = dequeued;
858}
859
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530860QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx)
861{
862 int result;
863
864 ipa_debug("enter");
865
866 if (!ipa_ctx->ipa_pipes_down) {
867 /*
868 * IPA WDI Pipes are already activated due to
869 * rm deferred resources grant
870 */
871 ipa_warn("IPA WDI Pipes are already activated");
872 goto end;
873 }
874
875 result = cdp_ipa_enable_pipes(ipa_ctx->dp_soc,
876 ipa_ctx->dp_pdev);
877 if (result) {
878 ipa_err("Enable IPA WDI PIPE failed: ret=%d", result);
879 return QDF_STATUS_E_FAILURE;
880 }
881
882 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
883 ipa_ctx->ipa_pipes_down = false;
884
885 cdp_ipa_enable_autonomy(ipa_ctx->dp_soc,
886 ipa_ctx->dp_pdev);
887
888end:
889 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
890
891 return QDF_STATUS_SUCCESS;
892}
893
894QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx)
895{
896 int result;
897
898 ipa_debug("enter");
899
900 if (ipa_ctx->ipa_pipes_down) {
901 /*
902 * This shouldn't happen :
903 * IPA WDI Pipes are already deactivated
904 */
905 QDF_ASSERT(0);
906 ipa_warn("IPA WDI Pipes are already deactivated");
907 goto end;
908 }
909
910 cdp_ipa_disable_autonomy(ipa_ctx->dp_soc,
911 ipa_ctx->dp_pdev);
912
913 result = cdp_ipa_disable_pipes(ipa_ctx->dp_soc,
914 ipa_ctx->dp_pdev);
915 if (result) {
916 ipa_err("Disable IPA WDI PIPE failed: ret=%d", result);
917 return QDF_STATUS_E_FAILURE;
918 }
919
920 ipa_ctx->ipa_pipes_down = true;
921
922end:
923 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
924
925 return QDF_STATUS_SUCCESS;
926}
927
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530928/**
929 * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
930 * @ipa_ctx: IPA context
931 *
932 * Return: QDF_STATUS
933 */
934static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
935{
936 int i;
937 uint32_t max_desc_cnt;
938 struct wlan_ipa_tx_desc *tmp_desc;
939
940 max_desc_cnt = ipa_ctx->config->txbuf_count;
941
942 qdf_list_create(&ipa_ctx->tx_desc_list, max_desc_cnt);
943
944 qdf_spin_lock_bh(&ipa_ctx->q_lock);
945 for (i = 0; i < max_desc_cnt; i++) {
946 tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc));
947 tmp_desc->id = i;
948 tmp_desc->ipa_tx_desc_ptr = NULL;
949 qdf_list_insert_back(&ipa_ctx->tx_desc_list,
950 &tmp_desc->node);
951 tmp_desc++;
952 }
953
954 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
955 ipa_ctx->stats.num_tx_desc_error = 0;
956
957 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
958
959 return QDF_STATUS_SUCCESS;
960}
961
962#ifndef QCA_LL_TX_FLOW_CONTROL_V2
963/**
964 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
965 * @ipa_ctx: Global IPA IPA context
966 * @desc_fifo_sz: Number of descriptors
967 *
968 * Return: 0 on success, negative errno on error
969 */
970static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
971 int32_t desc_fifo_sz)
972{
973 int i, ret = 0;
974 qdf_ipa_sys_connect_params_t *ipa;
975
976 /*setup TX pipes */
977 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
978 ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params;
979
980 ipa->client = wlan_ipa_iface_2_client[i].cons_client;
981 ipa->desc_fifo_sz = desc_fifo_sz;
982 ipa->priv = &ipa_ctx->iface_context[i];
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530983 ipa->notify = wlan_ipa_i2w_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530984
985 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
986 ipa->ipa_ep_cfg.hdr.hdr_len =
987 WLAN_IPA_UC_WLAN_TX_HDR_LEN;
988 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
989 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
990 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
991 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
992 WLAN_IPA_UC_WLAN_8023_HDR_SIZE;
993 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
994 } else {
995 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN;
996 }
997 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
998
999 ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa,
1000 &ipa_ctx->sys_pipe[i].conn_hdl);
1001 if (ret) {
1002 ipa_err("Failed for pipe %d ret: %d", i, ret);
1003 return ret;
1004 }
1005 ipa_ctx->sys_pipe[i].conn_hdl_valid = 1;
1006 }
1007
1008 return ret;
1009}
1010#else
1011/**
1012 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
1013 * @ipa_ctx: Global IPA IPA context
1014 * @desc_fifo_sz: Number of descriptors
1015 *
1016 * Return: 0 on success, negative errno on error
1017 */
1018static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
1019 int32_t desc_fifo_sz)
1020{
1021 /*
1022 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
1023 * is enabled, where per vdev descriptors are supported in firmware.
1024 */
1025 return 0;
1026}
1027#endif
1028
1029/**
1030 * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
1031 * @ipa_ctx: Global IPA IPA context
1032 * @desc_fifo_sz: Number of descriptors
1033 *
1034 * Return: 0 on success, negative errno on error
1035 */
1036static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
1037 int32_t desc_fifo_sz)
1038{
1039 int ret = 0;
1040 qdf_ipa_sys_connect_params_t *ipa;
1041
1042 /*
1043 * Hard code it here, this can be extended if in case
1044 * PROD pipe is also per interface.
1045 * Right now there is no advantage of doing this.
1046 */
1047 ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params;
1048
1049 ipa->client = IPA_CLIENT_WLAN1_PROD;
1050
1051 ipa->desc_fifo_sz = desc_fifo_sz;
1052 ipa->priv = ipa_ctx;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301053 ipa->notify = wlan_ipa_w2i_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301054
1055 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
1056 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN;
1057 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
1058 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
1059
1060 ret = qdf_ipa_setup_sys_pipe(ipa,
1061 &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl);
1062 if (ret) {
1063 ipa_err("Failed for RX pipe: %d", ret);
1064 return ret;
1065 }
1066 ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1;
1067
1068 return ret;
1069}
1070
1071/**
1072 * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
1073 * @ipa_ctx: Global IPA IPA context
1074 *
1075 * Return: 0 on success, negative errno on error
1076 */
1077static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
1078{
1079 int i = WLAN_IPA_MAX_IFACE, ret = 0;
1080 uint32_t desc_fifo_sz;
1081
1082 /* The maximum number of descriptors that can be provided to a BAM at
1083 * once is one less than the total number of descriptors that the buffer
1084 * can contain.
1085 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
1086 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
1087 * be provided at once.
1088 * Because of above requirement, one extra descriptor will be added to
1089 * make sure hardware always has one descriptor.
1090 */
1091 desc_fifo_sz = ipa_ctx->config->desc_size
1092 + SPS_DESC_SIZE;
1093
1094 ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz);
1095 if (ret) {
1096 ipa_err("Failed for TX pipe: %d", ret);
1097 goto setup_sys_pipe_fail;
1098 }
1099
1100 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
1101 ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz);
1102 if (ret) {
1103 ipa_err("Failed for RX pipe: %d", ret);
1104 goto setup_sys_pipe_fail;
1105 }
1106 }
1107
1108 /* Allocate free Tx desc list */
1109 ret = wlan_ipa_alloc_tx_desc_list(ipa_ctx);
1110 if (ret)
1111 goto setup_sys_pipe_fail;
1112
1113 return ret;
1114
1115setup_sys_pipe_fail:
1116
1117 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
1118 if (ipa_ctx->sys_pipe[i].conn_hdl_valid)
1119 qdf_ipa_teardown_sys_pipe(
1120 ipa_ctx->sys_pipe[i].conn_hdl);
1121 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
1122 sizeof(struct wlan_ipa_sys_pipe));
1123 }
1124
1125 return ret;
1126}
1127
1128/**
1129 * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
1130 * @ipa_ctx: Global IPA IPA context
1131 *
1132 * Return: None
1133 */
1134static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
1135{
1136 int ret = 0, i;
1137 struct wlan_ipa_tx_desc *tmp_desc;
1138 qdf_ipa_rx_data_t *ipa_tx_desc;
1139 qdf_list_node_t *node;
1140
1141 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
1142 if (ipa_ctx->sys_pipe[i].conn_hdl_valid) {
1143 ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx,
1144 ipa_ctx->sys_pipe[i].conn_hdl);
1145 if (ret)
1146 ipa_err("Failed:%d", ret);
1147
1148 ipa_ctx->sys_pipe[i].conn_hdl_valid = 0;
1149 }
1150 }
1151
1152 while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) ==
1153 QDF_STATUS_SUCCESS) {
1154 tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc,
1155 node);
1156 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
1157 if (ipa_tx_desc)
1158 qdf_ipa_free_skb(ipa_tx_desc);
1159
1160 qdf_mem_free(tmp_desc);
1161 }
1162}
1163
1164/**
1165 * wlan_ipa_setup() - IPA initialization function
1166 * @ipa_ctx: IPA context
1167 * @ipa_cfg: IPA config
1168 *
1169 * Allocate ipa_ctx resources, ipa pipe resource and register
1170 * wlan interface with IPA module.
1171 *
1172 * Return: QDF_STATUS enumeration
1173 */
1174QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
1175 struct wlan_ipa_config *ipa_cfg)
1176{
1177 int ret, i;
1178 struct wlan_ipa_iface_context *iface_context = NULL;
1179 QDF_STATUS status;
1180
1181 ipa_debug("enter");
1182
1183 gp_ipa = ipa_ctx;
1184 ipa_ctx->num_iface = 0;
1185 ipa_ctx->config = ipa_cfg;
1186
1187 wlan_ipa_wdi_get_wdi_version(ipa_ctx);
1188
1189 /* Create the interface context */
1190 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1191 iface_context = &ipa_ctx->iface_context[i];
1192 iface_context->ipa_ctx = ipa_ctx;
1193 iface_context->cons_client =
1194 wlan_ipa_iface_2_client[i].cons_client;
1195 iface_context->prod_client =
1196 wlan_ipa_iface_2_client[i].prod_client;
1197 iface_context->iface_id = i;
1198 iface_context->dev = NULL;
1199 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
1200 iface_context->tl_context = NULL;
1201 qdf_spinlock_create(&iface_context->interface_lock);
1202 }
1203
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301204 qdf_create_work(0, &ipa_ctx->pm_work, wlan_ipa_pm_flush, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301205 qdf_spinlock_create(&ipa_ctx->pm_lock);
1206 qdf_spinlock_create(&ipa_ctx->q_lock);
1207 qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head);
1208 qdf_list_create(&ipa_ctx->pending_event, 1000);
1209 qdf_mutex_create(&ipa_ctx->event_lock);
1210 qdf_mutex_create(&ipa_ctx->ipa_lock);
1211
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05301212 status = wlan_ipa_wdi_setup_rm(ipa_ctx);
1213 if (status != QDF_STATUS_SUCCESS)
1214 goto fail_setup_rm;
1215
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301216 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++)
1217 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
1218 sizeof(struct wlan_ipa_sys_pipe));
1219
1220 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1221 qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats));
1222 ipa_ctx->sap_num_connected_sta = 0;
1223 ipa_ctx->ipa_tx_packets_diff = 0;
1224 ipa_ctx->ipa_rx_packets_diff = 0;
1225 ipa_ctx->ipa_p_tx_packets = 0;
1226 ipa_ctx->ipa_p_rx_packets = 0;
1227 ipa_ctx->resource_loading = false;
1228 ipa_ctx->resource_unloading = false;
1229 ipa_ctx->sta_connected = 0;
1230 ipa_ctx->ipa_pipes_down = true;
1231 ipa_ctx->wdi_enabled = false;
1232 /* Setup IPA system pipes */
1233 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
1234 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
1235 if (ret)
1236 goto fail_create_sys_pipe;
1237 }
1238
1239 status = wlan_ipa_wdi_init(ipa_ctx);
1240 if (status == QDF_STATUS_E_BUSY)
1241 status = wlan_ipa_uc_send_wdi_control_msg(false);
1242 if (status != QDF_STATUS_SUCCESS) {
1243 ipa_err("IPA WDI init failed: ret=%d", ret);
1244 goto fail_create_sys_pipe;
1245 }
1246 } else {
1247 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
1248 if (ret)
1249 goto fail_create_sys_pipe;
1250 }
1251
1252 qdf_event_create(&ipa_ctx->ipa_resource_comp);
1253
1254 ipa_debug("exit: success");
1255
1256 return QDF_STATUS_SUCCESS;
1257
1258fail_create_sys_pipe:
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05301259 wlan_ipa_wdi_destroy_rm(ipa_ctx);
1260
1261fail_setup_rm:
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301262 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05301263 qdf_spinlock_destroy(&ipa_ctx->q_lock);
1264 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1265 iface_context = &ipa_ctx->iface_context[i];
1266 qdf_spinlock_destroy(&iface_context->interface_lock);
1267 }
1268 qdf_mutex_destroy(&ipa_ctx->event_lock);
1269 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
1270 qdf_list_destroy(&ipa_ctx->pending_event);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301271 gp_ipa = NULL;
1272 ipa_debug("exit: fail");
1273
1274 return QDF_STATUS_E_FAILURE;
1275}
1276
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301277void wlan_ipa_flush(struct wlan_ipa_priv *ipa_ctx)
1278{
1279 qdf_nbuf_t skb;
1280 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
1281
1282 if (!wlan_ipa_is_enabled(ipa_ctx->config))
1283 return;
1284
1285 qdf_cancel_work(&ipa_ctx->pm_work);
1286
1287 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
1288
1289 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head))
1290 != NULL)) {
1291 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
1292
1293 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
1294 if (pm_tx_cb->ipa_tx_desc)
1295 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
1296
1297 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
1298 }
1299 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
1300}
1301
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301302QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx)
1303{
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301304 struct wlan_ipa_iface_context *iface_context;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301305 int i;
1306
1307 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
1308 wlan_ipa_teardown_sys_pipe(ipa_ctx);
1309
1310 /* Teardown IPA sys_pipe for MCC */
1311 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
1312 wlan_ipa_teardown_sys_pipe(ipa_ctx);
1313
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05301314 wlan_ipa_wdi_destroy_rm(ipa_ctx);
1315
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301316 wlan_ipa_flush(ipa_ctx);
1317
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301318 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
1319 qdf_spinlock_destroy(&ipa_ctx->q_lock);
1320
1321 /* destroy the interface lock */
1322 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1323 iface_context = &ipa_ctx->iface_context[i];
1324 qdf_spinlock_destroy(&iface_context->interface_lock);
1325 }
1326
1327 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1328 wlan_ipa_wdi_cleanup();
1329 qdf_mutex_destroy(&ipa_ctx->event_lock);
1330 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
1331 qdf_list_destroy(&ipa_ctx->pending_event);
1332
1333 }
1334
1335 gp_ipa = NULL;
1336
1337 return QDF_STATUS_SUCCESS;
1338}
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +05301339
1340struct wlan_ipa_iface_context
1341*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode)
1342{
1343 struct wlan_ipa_iface_context *iface_ctx = NULL;
1344 int i;
1345
1346 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1347 iface_ctx = &ipa_ctx->iface_context[i];
1348
1349 if (iface_ctx->device_mode == mode)
1350 return iface_ctx;
1351 }
1352
1353 return NULL;
1354}
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301355
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05301356#ifndef QCA_LL_TX_FLOW_CONTROL_V2
1357QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
1358 bool mcc_mode)
1359{
1360 qdf_ipa_msg_meta_t meta;
1361 qdf_ipa_wlan_msg_t *msg;
1362 int ret;
1363
1364 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
1365 return QDF_STATUS_SUCCESS;
1366
1367 /* Send SCC/MCC Switching event to IPA */
1368 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
1369 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1370 if (msg == NULL) {
1371 ipa_err("msg allocation failed");
1372 return QDF_STATUS_E_NOMEM;
1373 }
1374
1375 QDF_IPA_MSG_META_MSG_TYPE(&meta) = mcc_mode ?
1376 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
1377 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
1378 "ipa_send_msg(Evt:%d)",
1379 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1380
1381 ret = qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn);
1382
1383 if (ret) {
1384 ipa_err("ipa_send_msg(Evt:%d) - fail=%d",
1385 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
1386 qdf_mem_free(msg);
1387 return QDF_STATUS_E_FAILURE;
1388 }
1389
1390 return QDF_STATUS_SUCCESS;
1391}
1392#endif
1393
1394/**
1395 * wlan_ipa_uc_loaded_handler() - Process IPA uC loaded indication
1396 * @ipa_ctx: ipa ipa local context
1397 *
1398 * Will handle IPA UC image loaded indication comes from IPA kernel
1399 *
1400 * Return: None
1401 */
1402static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx)
1403{
1404 struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
1405 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
1406 qdf_device_t qdf_dev = wlan_psoc_get_qdf_dev(psoc);
1407 QDF_STATUS status;
1408
1409 ipa_info("UC READY");
1410 if (true == ipa_ctx->uc_loaded) {
1411 ipa_info("UC already loaded");
1412 return;
1413 }
1414
1415 ipa_ctx->uc_loaded = true;
1416
1417 /* Connect pipe */
1418 status = wlan_ipa_wdi_setup(ipa_ctx, qdf_dev);
1419 if (status) {
1420 ipa_err("Failure to setup IPA pipes (status=%d)",
1421 status);
1422 return;
1423 }
1424
1425 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
1426}
1427
1428/**
1429 * wlan_ipa_uc_op_cb() - IPA uC operation callback
1430 * @op_msg: operation message received from firmware
1431 * @usr_ctxt: user context registered with TL (we register the IPA Global
1432 * context)
1433 *
1434 * Return: None
1435 */
1436static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
1437 struct wlan_ipa_priv *ipa_ctx)
1438{
1439 struct op_msg_type *msg = op_msg;
1440 struct ipa_uc_fw_stats *uc_fw_stat;
1441
1442 if (!op_msg) {
1443 ipa_err("INVALID ARG");
1444 return;
1445 }
1446
1447 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
1448 ipa_err("INVALID OPCODE %d", msg->op_code);
1449 qdf_mem_free(op_msg);
1450 return;
1451 }
1452
1453 ipa_debug("OPCODE=%d", msg->op_code);
1454
1455 if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_RESUME) ||
1456 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_RESUME)) {
1457 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1458 ipa_ctx->activated_fw_pipe++;
1459 if (ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) {
1460 ipa_ctx->resource_loading = false;
1461 qdf_event_set(&ipa_ctx->ipa_resource_comp);
1462 if (ipa_ctx->wdi_enabled == false) {
1463 ipa_ctx->wdi_enabled = true;
1464 if (wlan_ipa_uc_send_wdi_control_msg(true) == 0)
1465 wlan_ipa_send_mcc_scc_msg(ipa_ctx,
1466 ipa_ctx->mcc_mode);
1467 }
1468 if (ipa_ctx->pending_cons_req)
1469 qdf_ipa_rm_notify_completion(
1470 QDF_IPA_RM_RESOURCE_GRANTED,
1471 QDF_IPA_RM_RESOURCE_WLAN_CONS);
1472 ipa_ctx->pending_cons_req = false;
1473 }
1474 qdf_mutex_release(&ipa_ctx->ipa_lock);
1475 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_SUSPEND) ||
1476 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND)) {
1477 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1478 ipa_ctx->activated_fw_pipe--;
1479 if (!ipa_ctx->activated_fw_pipe) {
1480 /*
1481 * Async return success from FW
1482 * Disable/suspend all the PIPEs
1483 */
1484 ipa_ctx->resource_unloading = false;
1485 qdf_event_set(&ipa_ctx->ipa_resource_comp);
1486 wlan_ipa_uc_disable_pipes(ipa_ctx);
1487 if (wlan_ipa_is_rm_enabled(ipa_ctx->config))
1488 qdf_ipa_rm_release_resource(
1489 QDF_IPA_RM_RESOURCE_WLAN_PROD);
1490 ipa_ctx->pending_cons_req = false;
1491 }
1492 qdf_mutex_release(&ipa_ctx->ipa_lock);
1493 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
1494 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_DEBUG)) {
1495 uc_fw_stat = (struct ipa_uc_fw_stats *)
1496 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
1497
1498 /* WLAN FW WDI stats */
1499 wlan_ipa_print_fw_wdi_stats(ipa_ctx, uc_fw_stat);
1500 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
1501 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_BW_CAL)) {
1502 /* STATs from FW */
1503 uc_fw_stat = (struct ipa_uc_fw_stats *)
1504 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
1505 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1506 ipa_ctx->ipa_tx_packets_diff = BW_GET_DIFF(
1507 uc_fw_stat->tx_pkts_completed,
1508 ipa_ctx->ipa_p_tx_packets);
1509 ipa_ctx->ipa_rx_packets_diff = BW_GET_DIFF(
1510 (uc_fw_stat->rx_num_ind_drop_no_space +
1511 uc_fw_stat->rx_num_ind_drop_no_buf +
1512 uc_fw_stat->rx_num_pkts_indicated),
1513 ipa_ctx->ipa_p_rx_packets);
1514
1515 ipa_ctx->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
1516 ipa_ctx->ipa_p_rx_packets =
1517 (uc_fw_stat->rx_num_ind_drop_no_space +
1518 uc_fw_stat->rx_num_ind_drop_no_buf +
1519 uc_fw_stat->rx_num_pkts_indicated);
1520 qdf_mutex_release(&ipa_ctx->ipa_lock);
1521 } else if (msg->op_code == WLAN_IPA_UC_OPCODE_UC_READY) {
1522 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1523 wlan_ipa_uc_loaded_handler(ipa_ctx);
1524 qdf_mutex_release(&ipa_ctx->ipa_lock);
1525 } else if (wlan_ipa_uc_op_metering(ipa_ctx, op_msg)) {
1526 ipa_err("Invalid message: op_code=%d, reason=%d",
1527 msg->op_code, ipa_ctx->stat_req_reason);
1528 }
1529
1530 qdf_mem_free(op_msg);
1531}
1532
1533/**
1534 * wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
1535 * @work: uC OP work
1536 *
1537 * Return: None
1538 */
1539static void wlan_ipa_uc_fw_op_event_handler(void *data)
1540{
1541 struct op_msg_type *msg;
1542 struct uc_op_work_struct *uc_op_work =
1543 (struct uc_op_work_struct *)data;
1544 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
1545
1546 msg = uc_op_work->msg;
1547 uc_op_work->msg = NULL;
1548 ipa_debug("posted msg %d", msg->op_code);
1549
1550 wlan_ipa_uc_op_cb(msg, ipa_ctx);
1551}
1552
1553/**
1554 * wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
1555 * @op_msg: operation message received from firmware
1556 * @ipa_ctx: Global IPA context
1557 *
1558 * Return: None
1559 */
1560static void wlan_ipa_uc_op_event_handler(uint8_t *op_msg, void *ctx)
1561{
1562 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)ctx;
1563 struct op_msg_type *msg;
1564 struct uc_op_work_struct *uc_op_work;
1565
1566 if (!ipa_ctx)
1567 goto end;
1568
1569 msg = (struct op_msg_type *)op_msg;
1570
1571 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
1572 ipa_err("Invalid OP Code (%d)", msg->op_code);
1573 goto end;
1574 }
1575
1576 uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
1577 if (uc_op_work->msg) {
1578 /* When the same uC OPCODE is already pended, just return */
1579 goto end;
1580 }
1581
1582 uc_op_work->msg = msg;
1583 qdf_sched_work(0, &uc_op_work->work);
1584 return;
1585
1586end:
1587 qdf_mem_free(op_msg);
1588}
1589
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301590QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx,
1591 qdf_device_t osdev)
1592{
1593 uint8_t i;
1594 QDF_STATUS status = QDF_STATUS_SUCCESS;
1595
1596 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
1597 return QDF_STATUS_SUCCESS;
1598
1599 ipa_debug("enter");
1600
1601 for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) {
1602 ipa_ctx->vdev_to_iface[i] = WLAN_IPA_MAX_SESSION;
1603 ipa_ctx->vdev_offload_enabled[i] = false;
1604 }
1605
1606 /* Set the lowest bandwidth to start with */
1607 status = wlan_ipa_set_perf_level(ipa_ctx, 0, 0);
1608 if (status != QDF_STATUS_SUCCESS) {
1609 ipa_err("Set perf level failed: %d", status);
1610 qdf_ipa_rm_inactivity_timer_destroy(
1611 QDF_IPA_RM_RESOURCE_WLAN_PROD);
1612 goto fail_return;
1613 }
1614
1615 if (cdp_ipa_get_resource(ipa_ctx->dp_soc, ipa_ctx->dp_pdev)) {
1616 ipa_err("IPA UC resource alloc fail");
1617 status = QDF_STATUS_E_FAILURE;
1618 goto fail_return;
1619 }
1620
1621 if (true == ipa_ctx->uc_loaded) {
1622 status = wlan_ipa_wdi_setup(ipa_ctx, osdev);
1623 if (status) {
1624 ipa_err("Failure to setup IPA pipes (status=%d)",
1625 status);
1626 status = QDF_STATUS_E_FAILURE;
1627 goto fail_return;
1628 }
1629
1630 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
1631 wlan_ipa_init_metering(ipa_ctx);
1632 }
1633
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05301634 cdp_ipa_register_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
1635 wlan_ipa_uc_op_event_handler, (void *)ipa_ctx);
1636
1637 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
1638 qdf_create_work(0, &ipa_ctx->uc_op_work[i].work,
1639 wlan_ipa_uc_fw_op_event_handler,
1640 &ipa_ctx->uc_op_work[i]);
1641 ipa_ctx->uc_op_work[i].msg = NULL;
1642 }
1643
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301644fail_return:
1645 ipa_debug("exit: status=%d", status);
1646 return status;
1647}
1648
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05301649/**
1650 * wlan_ipa_cleanup_pending_event() - Cleanup IPA pending event list
1651 * @ipa_ctx: pointer to IPA IPA struct
1652 *
1653 * Return: none
1654 */
1655static void wlan_ipa_cleanup_pending_event(struct wlan_ipa_priv *ipa_ctx)
1656{
1657 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1658
1659 while (qdf_list_remove_front(&ipa_ctx->pending_event,
1660 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
1661 qdf_mem_free(pending_event);
1662}
1663
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301664QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx)
1665{
1666 QDF_STATUS status = QDF_STATUS_SUCCESS;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05301667 int i;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301668
1669 ipa_debug("enter");
1670
1671 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
1672 return status;
1673
1674 if (!ipa_ctx->ipa_pipes_down)
1675 wlan_ipa_uc_disable_pipes(ipa_ctx);
1676
1677 if (true == ipa_ctx->uc_loaded) {
1678 status = cdp_ipa_cleanup(ipa_ctx->dp_soc,
1679 ipa_ctx->tx_pipe_handle,
1680 ipa_ctx->rx_pipe_handle);
1681 if (status)
1682 ipa_err("Failure to cleanup IPA pipes (status=%d)",
1683 status);
1684 }
1685
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05301686 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1687 wlan_ipa_cleanup_pending_event(ipa_ctx);
1688 qdf_mutex_release(&ipa_ctx->ipa_lock);
1689
1690 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
1691 qdf_cancel_work(&ipa_ctx->uc_op_work[i].work);
1692 qdf_mem_free(ipa_ctx->uc_op_work[i].msg);
1693 ipa_ctx->uc_op_work[i].msg = NULL;
1694 }
1695
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301696 ipa_debug("exit: ret=%d", status);
1697 return status;
1698}