blob: 52da0e02eaf3288cd6786261bf193bcf4134e2c7 [file] [log] [blame]
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301/*
2 * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
3 *
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05304 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +053019/* Include Files */
20#include "wlan_ipa_core.h"
21#include "wlan_ipa_main.h"
22#include <ol_txrx.h>
23#include "cdp_txrx_ipa.h"
24#include "wal_rx_desc.h"
25
26static struct wlan_ipa_priv *gp_ipa;
27
28static struct wlan_ipa_iface_2_client {
29 qdf_ipa_client_type_t cons_client;
30 qdf_ipa_client_type_t prod_client;
31} wlan_ipa_iface_2_client[WLAN_IPA_MAX_IFACE] = {
32 {
33 QDF_IPA_CLIENT_WLAN2_CONS, QDF_IPA_CLIENT_WLAN1_PROD
34 }, {
35 QDF_IPA_CLIENT_WLAN3_CONS, QDF_IPA_CLIENT_WLAN1_PROD
36 }, {
37 QDF_IPA_CLIENT_WLAN4_CONS, QDF_IPA_CLIENT_WLAN1_PROD
38 }
39};
40
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +053041/* Local Function Prototypes */
42static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
43 unsigned long data);
44static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
45 unsigned long data);
46
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +053047/**
48 * wlan_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
49 * @ipa_cfg: IPA config
50 *
51 * Return: true if STA mode IPA uC offload is enabled, false otherwise
52 */
53static inline bool wlan_ipa_uc_sta_is_enabled(struct wlan_ipa_config *ipa_cfg)
54{
55 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_STA_ENABLE_MASK);
56}
57
58/**
59 * wlan_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
60 * @ipa_cfg: IPA config
61 *
62 * Return: true if pre-filter is enabled, otherwise false
63 */
64static inline
65bool wlan_ipa_is_pre_filter_enabled(struct wlan_ipa_config *ipa_cfg)
66{
67 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg,
68 WLAN_IPA_PRE_FILTER_ENABLE_MASK);
69}
70
71/**
72 * wlan_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
73 * @ipa_cfg: IPA config
74 *
75 * Return: true if IPv6 is enabled, otherwise false
76 */
77static inline bool wlan_ipa_is_ipv6_enabled(struct wlan_ipa_config *ipa_cfg)
78{
79 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_IPV6_ENABLE_MASK);
80}
81
82/**
83 * wlan_ipa_msg_free_fn() - Free an IPA message
84 * @buff: pointer to the IPA message
85 * @len: length of the IPA message
86 * @type: type of IPA message
87 *
88 * Return: None
89 */
90static void wlan_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
91{
92 ipa_debug("msg type:%d, len:%d", type, len);
93 qdf_mem_free(buff);
94}
95
96/**
97 * wlan_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
98 * @priv_ctxt: IPA context
99 *
100 * Will be called by IPA context.
101 * It's atomic context, then should be scheduled to kworker thread
102 *
103 * Return: None
104 */
105static void wlan_ipa_uc_loaded_uc_cb(void *priv_ctxt)
106{
107 struct wlan_ipa_priv *ipa_ctx;
108 struct op_msg_type *msg;
109 struct uc_op_work_struct *uc_op_work;
110
111 if (!priv_ctxt) {
112 ipa_err("Invalid IPA context");
113 return;
114 }
115
116 ipa_ctx = priv_ctxt;
Sravan Kumar Kairam7eb6e4c2018-04-26 15:35:47 +0530117 ipa_ctx->uc_loaded = true;
118
119 uc_op_work = &ipa_ctx->uc_op_work[WLAN_IPA_UC_OPCODE_UC_READY];
120 if (!list_empty(&uc_op_work->work.work.entry)) {
121 /* uc_op_work is not initialized yet */
122 return;
123 }
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530124
125 msg = qdf_mem_malloc(sizeof(*msg));
126 if (!msg) {
127 ipa_err("op_msg allocation fails");
128 return;
129 }
130
131 msg->op_code = WLAN_IPA_UC_OPCODE_UC_READY;
132
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530133 /* When the same uC OPCODE is already pended, just return */
134 if (uc_op_work->msg)
135 goto done;
136
137 uc_op_work->msg = msg;
138 qdf_sched_work(0, &uc_op_work->work);
Sravan Kumar Kairam7eb6e4c2018-04-26 15:35:47 +0530139
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530140 /* work handler will free the msg buffer */
141 return;
142
143done:
144 qdf_mem_free(msg);
145}
146
147/**
148 * wlan_ipa_uc_send_wdi_control_msg() - Set WDI control message
149 * @ctrl: WDI control value
150 *
151 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
152 *
153 * Return: QDF_STATUS
154 */
155static QDF_STATUS wlan_ipa_uc_send_wdi_control_msg(bool ctrl)
156{
jiad629b2172018-05-11 15:34:22 +0800157 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530158 qdf_ipa_msg_meta_t meta;
159 qdf_ipa_wlan_msg_t *ipa_msg;
160 int ret = 0;
161
162 /* WDI enable message to IPA */
163 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
164 ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
165 if (!ipa_msg) {
166 ipa_err("msg allocation failed");
167 return QDF_STATUS_E_NOMEM;
168 }
169
jiad629b2172018-05-11 15:34:22 +0800170 if (ctrl) {
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530171 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_ENABLE);
jiad629b2172018-05-11 15:34:22 +0800172 ipa_ctx->stats.event[QDF_WDI_ENABLE]++;
173 } else {
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530174 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_DISABLE);
jiad629b2172018-05-11 15:34:22 +0800175 ipa_ctx->stats.event[QDF_WDI_DISABLE]++;
176 }
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530177
178 ipa_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
179 ret = qdf_ipa_send_msg(&meta, ipa_msg, wlan_ipa_msg_free_fn);
180 if (ret) {
181 ipa_err("ipa_send_msg(Evt:%d)-fail=%d",
182 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
183 qdf_mem_free(ipa_msg);
184 return QDF_STATUS_E_FAILURE;
185 }
186
187 return QDF_STATUS_SUCCESS;
188}
189
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530190struct wlan_ipa_priv *wlan_ipa_get_obj_context(void)
191{
192 return gp_ipa;
193}
194
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530195#ifdef CONFIG_IPA_WDI_UNIFIED_API
196
197/*
198 * TODO: Get WDI version through FW capabilities
199 */
200#ifdef CONFIG_LITHIUM
201static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
202{
203 ipa_ctx->wdi_version = IPA_WDI_3;
204}
205#elif defined(QCA_WIFI_3_0)
206static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
207{
208 ipa_ctx->wdi_version = IPA_WDI_2;
209}
210#else
211static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
212{
213 ipa_ctx->wdi_version = IPA_WDI_1;
214}
215#endif
216
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530217static inline bool wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx,
218 qdf_device_t osdev)
219{
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +0530220 return ipa_ctx->is_smmu_enabled && qdf_mem_smmu_s1_enabled(osdev);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530221}
222
223static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx,
224 qdf_device_t osdev)
225{
226 qdf_ipa_sys_connect_params_t sys_in[WLAN_IPA_MAX_IFACE];
227 int i;
228
229 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++)
230 qdf_mem_copy(&sys_in[i],
231 &ipa_ctx->sys_pipe[i].ipa_sys_params,
232 sizeof(qdf_ipa_sys_connect_params_t));
233
234 return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
235 wlan_ipa_i2w_cb, wlan_ipa_w2i_cb,
236 wlan_ipa_wdi_meter_notifier_cb,
237 ipa_ctx->config->desc_size,
238 ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config),
239 &ipa_ctx->tx_pipe_handle,
240 &ipa_ctx->rx_pipe_handle,
241 wlan_ipa_wdi_is_smmu_enabled(ipa_ctx, osdev),
242 sys_in);
243}
244
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530245#ifdef FEATURE_METERING
246/**
247 * wlan_ipa_wdi_init_metering() - IPA WDI metering init
248 * @ipa_ctx: IPA context
249 * @in: IPA WDI in param
250 *
251 * Return: QDF_STATUS
252 */
253static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
254 qdf_ipa_wdi_init_in_params_t *in)
255{
256 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(in) =
257 wlan_ipa_wdi_meter_notifier_cb;
258}
259#else
260static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
261 qdf_ipa_wdi_init_in_params_t *in)
262{
263}
264#endif
265
266/**
267 * wlan_ipa_wdi_init() - IPA WDI init
268 * @ipa_ctx: IPA context
269 *
270 * Return: QDF_STATUS
271 */
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530272static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
273{
274 qdf_ipa_wdi_init_in_params_t in;
275 qdf_ipa_wdi_init_out_params_t out;
276 int ret;
277
278 ipa_ctx->uc_loaded = false;
279
280 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version;
281 QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb;
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530282 QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = ipa_ctx;
283 wlan_ipa_wdi_init_metering(ipa_ctx, &in);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530284
285 ret = qdf_ipa_wdi_init(&in, &out);
286 if (ret) {
287 ipa_err("ipa_wdi_init failed with ret=%d", ret);
288 return QDF_STATUS_E_FAILURE;
289 }
290
291 if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
292 ipa_info("IPA uC READY");
293 ipa_ctx->uc_loaded = true;
294 ipa_ctx->is_smmu_enabled =
295 QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
296 ipa_info("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled);
297 } else {
298 return QDF_STATUS_E_BUSY;
299 }
300
301 return QDF_STATUS_SUCCESS;
302}
303
304static inline int wlan_ipa_wdi_cleanup(void)
305{
306 int ret;
307
308 ret = qdf_ipa_wdi_cleanup();
309 if (ret)
310 ipa_info("ipa_wdi_cleanup failed ret=%d", ret);
311 return ret;
312}
313
314static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
315 struct ipa_sys_connect_params *sys,
316 uint32_t *handle)
317{
318 return 0;
319}
320
321static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
322 uint32_t handle)
323{
324 return 0;
325}
326
327#else /* CONFIG_IPA_WDI_UNIFIED_API */
328
329static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
330{
331}
332
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +0530333static inline int wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx,
334 qdf_device_t osdev)
335{
336 return qdf_mem_smmu_s1_enabled(osdev);
337}
338
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530339static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx,
340 qdf_device_t osdev)
341{
342 return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
343 wlan_ipa_i2w_cb, wlan_ipa_w2i_cb,
344 wlan_ipa_wdi_meter_notifier_cb,
345 ipa_ctx->config->desc_size,
346 ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config),
347 &ipa_ctx->tx_pipe_handle,
348 &ipa_ctx->rx_pipe_handle);
349}
350
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530351static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
352{
353 struct ipa_wdi_uc_ready_params uc_ready_param;
354
355 ipa_ctx->uc_loaded = false;
356 uc_ready_param.priv = (void *)ipa_ctx;
357 uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb;
358 if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) {
359 ipa_info("UC Ready CB register fail");
360 return QDF_STATUS_E_FAILURE;
361 }
362
363 if (true == uc_ready_param.is_uC_ready) {
364 ipa_info("UC Ready");
365 ipa_ctx->uc_loaded = true;
366 } else {
367 return QDF_STATUS_E_BUSY;
368 }
369
370 return QDF_STATUS_SUCCESS;
371}
372
373static inline int wlan_ipa_wdi_cleanup(void)
374{
375 int ret;
376
377 ret = qdf_ipa_uc_dereg_rdyCB();
378 if (ret)
379 ipa_info("UC Ready CB deregister fail");
380 return ret;
381}
382
383static inline int wlan_ipa_wdi_setup_sys_pipe(
384 struct wlan_ipa_priv *ipa_ctx,
385 struct ipa_sys_connect_params *sys, uint32_t *handle)
386{
387 return qdf_ipa_setup_sys_pipe(sys, handle);
388}
389
390static inline int wlan_ipa_wdi_teardown_sys_pipe(
391 struct wlan_ipa_priv *ipa_ctx,
392 uint32_t handle)
393{
394 return qdf_ipa_teardown_sys_pipe(handle);
395}
396
397#endif /* CONFIG_IPA_WDI_UNIFIED_API */
398
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530399/**
400 * wlan_ipa_send_skb_to_network() - Send skb to kernel
401 * @skb: network buffer
402 * @iface_ctx: IPA interface context
403 *
404 * Called when a network buffer is received which should not be routed
405 * to the IPA module.
406 *
407 * Return: None
408 */
409static void
410wlan_ipa_send_skb_to_network(qdf_nbuf_t skb,
411 struct wlan_ipa_iface_context *iface_ctx)
412{
413 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
414
415 if (!iface_ctx->dev) {
416 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid interface");
417 ipa_ctx->ipa_rx_internal_drop_count++;
418 qdf_nbuf_free(skb);
419 return;
420 }
421
422 skb->destructor = wlan_ipa_uc_rt_debug_destructor;
423
424 if (ipa_ctx->send_to_nw)
425 ipa_ctx->send_to_nw(skb, iface_ctx->dev);
426
427 ipa_ctx->ipa_rx_net_send_count++;
428}
429
430/**
431 * wlan_ipa_forward() - handle packet forwarding to wlan tx
432 * @ipa_ctx: pointer to ipa ipa context
433 * @iface_ctx: interface context
434 * @skb: data pointer
435 *
436 * if exception packet has set forward bit, copied new packet should be
437 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
438 * put into pm queue and tx procedure will be differed
439 *
440 * Return: None
441 */
442static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx,
443 struct wlan_ipa_iface_context *iface_ctx,
444 qdf_nbuf_t skb)
445{
446 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
447
448 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
449
450 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
451 qdf_nbuf_ipa_owned_set(skb);
452
453 /* WLAN subsystem is in suspend, put in queue */
454 if (ipa_ctx->suspended) {
455 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
456 WLAN_IPA_LOG(QDF_TRACE_LEVEL_INFO,
457 "Tx in suspend, put in queue");
458 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
459 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
460 pm_tx_cb->exception = true;
461 pm_tx_cb->iface_context = iface_ctx;
462 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
463 qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
464 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
465 ipa_ctx->stats.num_tx_queued++;
466 } else {
467 /* Resume, put packet into WLAN TX */
468 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
469
470 if (ipa_ctx->softap_xmit) {
471 if (ipa_ctx->softap_xmit(skb, iface_ctx->dev)) {
472 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
473 "packet Tx fail");
474 ipa_ctx->stats.num_tx_fwd_err++;
475 } else {
476 ipa_ctx->stats.num_tx_fwd_ok++;
477 }
478 } else {
479 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
480 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
481 }
482 }
483}
484
485/**
486 * wlan_ipa_intrabss_forward() - Forward intra bss packets.
487 * @ipa_ctx: pointer to IPA IPA struct
488 * @iface_ctx: ipa interface context
489 * @desc: Firmware descriptor
490 * @skb: Data buffer
491 *
492 * Return:
493 * WLAN_IPA_FORWARD_PKT_NONE
494 * WLAN_IPA_FORWARD_PKT_DISCARD
495 * WLAN_IPA_FORWARD_PKT_LOCAL_STACK
496 *
497 */
498
499static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward(
500 struct wlan_ipa_priv *ipa_ctx,
501 struct wlan_ipa_iface_context *iface_ctx,
502 uint8_t desc,
503 qdf_nbuf_t skb)
504{
505 int ret = WLAN_IPA_FORWARD_PKT_NONE;
506 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
507 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
508
509 if ((desc & FW_RX_DESC_FORWARD_M)) {
510 if (!ol_txrx_fwd_desc_thresh_check(
511 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
512 (struct cdp_pdev *)pdev,
513 iface_ctx->session_id))) {
514 /* Drop the packet*/
515 ipa_ctx->stats.num_tx_fwd_err++;
516 kfree_skb(skb);
517 ret = WLAN_IPA_FORWARD_PKT_DISCARD;
518 return ret;
519 }
520 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
521 "Forward packet to Tx (fw_desc=%d)", desc);
522 ipa_ctx->ipa_tx_forward++;
523
524 if ((desc & FW_RX_DESC_DISCARD_M)) {
525 wlan_ipa_forward(ipa_ctx, iface_ctx, skb);
526 ipa_ctx->ipa_rx_internal_drop_count++;
527 ipa_ctx->ipa_rx_discard++;
528 ret = WLAN_IPA_FORWARD_PKT_DISCARD;
529 } else {
530 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
531
532 if (cloned_skb)
533 wlan_ipa_forward(ipa_ctx, iface_ctx,
534 cloned_skb);
535 else
536 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
537 "tx skb alloc failed");
538 ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK;
539 }
540 }
541
542 return ret;
543}
544
545/**
546 * wlan_ipa_w2i_cb() - WLAN to IPA callback handler
547 * @priv: pointer to private data registered with IPA (we register a
548 * pointer to the global IPA context)
549 * @evt: the IPA event which triggered the callback
550 * @data: data associated with the event
551 *
552 * Return: None
553 */
554static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
555 unsigned long data)
556{
557 struct wlan_ipa_priv *ipa_ctx = NULL;
558 qdf_nbuf_t skb;
559 uint8_t iface_id;
560 uint8_t session_id;
561 struct wlan_ipa_iface_context *iface_context;
562 uint8_t fw_desc;
563
564 ipa_ctx = (struct wlan_ipa_priv *)priv;
565
566 if (!ipa_ctx)
567 return;
568
569 switch (evt) {
570 case IPA_RECEIVE:
571 skb = (qdf_nbuf_t) data;
572
573 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
574 session_id = (uint8_t)skb->cb[0];
575 iface_id = ipa_ctx->vdev_to_iface[session_id];
576 ipa_debug("IPA_RECEIVE: session_id=%u, iface_id=%u",
577 session_id, iface_id);
578 } else {
579 iface_id = WLAN_IPA_GET_IFACE_ID(skb->data);
580 }
581 if (iface_id >= WLAN_IPA_MAX_IFACE) {
582 ipa_err("IPA_RECEIVE: Invalid iface_id: %u",
583 iface_id);
584 ipa_ctx->ipa_rx_internal_drop_count++;
585 qdf_nbuf_free(skb);
586 return;
587 }
588
589 iface_context = &ipa_ctx->iface_context[iface_id];
590 if (!iface_context->tl_context) {
591 ipa_err("IPA_RECEIVE: TL context is NULL");
592 ipa_ctx->ipa_rx_internal_drop_count++;
593 qdf_nbuf_free(skb);
594 return;
595 }
596
597 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
598 ipa_ctx->stats.num_rx_excep++;
599 qdf_nbuf_pull_head(skb, WLAN_IPA_UC_WLAN_CLD_HDR_LEN);
600 } else {
601 qdf_nbuf_pull_head(skb, WLAN_IPA_WLAN_CLD_HDR_LEN);
602 }
603
604 iface_context->stats.num_rx_ipa_excep++;
605
606 /* Disable to forward Intra-BSS Rx packets when
607 * ap_isolate=1 in hostapd.conf
608 */
609 if (!ipa_ctx->ap_intrabss_fwd) {
610 /*
611 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
612 * all Rx packets to IPA uC, which need to be forwarded
613 * to other interface.
614 * And, IPA driver will send back to WLAN host driver
615 * through exception pipe with fw_desc field set by FW.
616 * Here we are checking fw_desc field for FORWARD bit
617 * set, and forward to Tx. Then copy to kernel stack
618 * only when DISCARD bit is not set.
619 */
620 fw_desc = (uint8_t)skb->cb[1];
621 if (WLAN_IPA_FORWARD_PKT_DISCARD ==
622 wlan_ipa_intrabss_forward(ipa_ctx, iface_context,
623 fw_desc, skb))
624 break;
625 } else {
626 ipa_debug("Intra-BSS FWD is disabled-skip forward to Tx");
627 }
628
629 wlan_ipa_send_skb_to_network(skb, iface_context);
630 break;
631
632 default:
633 ipa_err("w2i cb wrong event: 0x%x", evt);
634 return;
635 }
636}
637
638/**
639 * wlan_ipa_send_pkt_to_tl() - Send an IPA packet to TL
640 * @iface_context: interface-specific IPA context
641 * @ipa_tx_desc: packet data descriptor
642 *
643 * Return: None
644 */
645static void wlan_ipa_send_pkt_to_tl(
646 struct wlan_ipa_iface_context *iface_context,
647 qdf_ipa_rx_data_t *ipa_tx_desc)
648{
649 struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
650 qdf_nbuf_t skb;
651 struct wlan_ipa_tx_desc *tx_desc;
652
653 qdf_spin_lock_bh(&iface_context->interface_lock);
654 /*
655 * During CAC period, data packets shouldn't be sent over the air so
656 * drop all the packets here
657 */
658 if (iface_context->device_mode == QDF_SAP_MODE ||
659 iface_context->device_mode == QDF_P2P_GO_MODE) {
660 if (ipa_ctx->dfs_cac_block_tx) {
661 ipa_free_skb(ipa_tx_desc);
662 qdf_spin_unlock_bh(&iface_context->interface_lock);
663 iface_context->stats.num_tx_cac_drop++;
664 wlan_ipa_wdi_rm_try_release(ipa_ctx);
665 return;
666 }
667 }
668 qdf_spin_unlock_bh(&iface_context->interface_lock);
669
670 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
671
672 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
673
674 /* Store IPA Tx buffer ownership into SKB CB */
675 qdf_nbuf_ipa_owned_set(skb);
676 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
677 qdf_nbuf_mapped_paddr_set(skb,
678 QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
679 + WLAN_IPA_WLAN_FRAG_HEADER
680 + WLAN_IPA_WLAN_IPA_HEADER);
681 QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
682 WLAN_IPA_WLAN_FRAG_HEADER + WLAN_IPA_WLAN_IPA_HEADER;
683 } else
684 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
685
686 qdf_spin_lock_bh(&ipa_ctx->q_lock);
687 /* get free Tx desc and assign ipa_tx_desc pointer */
688 if (qdf_list_remove_front(&ipa_ctx->tx_desc_list,
689 (qdf_list_node_t **)&tx_desc) ==
690 QDF_STATUS_SUCCESS) {
691 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
692 ipa_ctx->stats.num_tx_desc_q_cnt++;
693 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
694 /* Store Tx Desc index into SKB CB */
695 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
696 } else {
697 ipa_ctx->stats.num_tx_desc_error++;
698 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
699 qdf_ipa_free_skb(ipa_tx_desc);
700 wlan_ipa_wdi_rm_try_release(ipa_ctx);
701 return;
702 }
703
704 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
705 (struct cdp_vdev *)iface_context->tl_context,
706 QDF_IPA_RX_DATA_SKB(ipa_tx_desc));
707 if (skb) {
708 qdf_nbuf_free(skb);
709 iface_context->stats.num_tx_err++;
710 return;
711 }
712
713 atomic_inc(&ipa_ctx->tx_ref_cnt);
714
715 iface_context->stats.num_tx++;
716}
717
718/**
719 * wlan_ipa_i2w_cb() - IPA to WLAN callback
720 * @priv: pointer to private data registered with IPA (we register a
721 * pointer to the interface-specific IPA context)
722 * @evt: the IPA event which triggered the callback
723 * @data: data associated with the event
724 *
725 * Return: None
726 */
727static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
728 unsigned long data)
729{
730 struct wlan_ipa_priv *ipa_ctx = NULL;
731 qdf_ipa_rx_data_t *ipa_tx_desc;
732 struct wlan_ipa_iface_context *iface_context;
733 qdf_nbuf_t skb;
734 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
735
736 iface_context = (struct wlan_ipa_iface_context *)priv;
737 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
738 ipa_ctx = iface_context->ipa_ctx;
739
740 if (evt != IPA_RECEIVE) {
741 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
742 ipa_free_skb(ipa_tx_desc);
743 iface_context->stats.num_tx_drop++;
744 return;
745 }
746
747 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
748
749 /*
750 * If PROD resource is not requested here then there may be cases where
751 * IPA hardware may be clocked down because of not having proper
752 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
753 * workaround to request PROD resource while data is going over CONS
754 * pipe to prevent the IPA hardware clockdown.
755 */
756 wlan_ipa_wdi_rm_request(ipa_ctx);
757
758 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
759 /*
760 * If host is still suspended then queue the packets and these will be
761 * drained later when resume completes. When packet is arrived here and
762 * host is suspended, this means that there is already resume is in
763 * progress.
764 */
765 if (ipa_ctx->suspended) {
766 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
767 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
768 pm_tx_cb->iface_context = iface_context;
769 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
770 qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
771 ipa_ctx->stats.num_tx_queued++;
772
773 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
774 return;
775 }
776
777 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
778
779 /*
780 * If we are here means, host is not suspended, wait for the work queue
781 * to finish.
782 */
783 qdf_flush_work(&ipa_ctx->pm_work);
784
785 return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
786}
787
788QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx)
789{
790 /*
791 * Check if IPA is ready for suspend, If we are here means, there is
792 * high chance that suspend would go through but just to avoid any race
793 * condition after suspend started, these checks are conducted before
794 * allowing to suspend.
795 */
796 if (atomic_read(&ipa_ctx->tx_ref_cnt))
797 return QDF_STATUS_E_AGAIN;
798
799 qdf_spin_lock_bh(&ipa_ctx->rm_lock);
800
801 if (ipa_ctx->rm_state != WLAN_IPA_RM_RELEASED) {
802 qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
803 return QDF_STATUS_E_AGAIN;
804 }
805 qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
806
807 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
808 ipa_ctx->suspended = true;
809 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
810
811 return QDF_STATUS_SUCCESS;
812}
813
814QDF_STATUS wlan_ipa_resume(struct wlan_ipa_priv *ipa_ctx)
815{
816 qdf_sched_work(0, &ipa_ctx->pm_work);
817
818 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
819 ipa_ctx->suspended = false;
820 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
821
822 return QDF_STATUS_SUCCESS;
823}
824
825/**
826 * wlan_ipa_pm_flush() - flush queued packets
827 * @work: pointer to the scheduled work
828 *
829 * Called during PM resume to send packets to TL which were queued
830 * while host was in the process of suspending.
831 *
832 * Return: None
833 */
834static void wlan_ipa_pm_flush(void *data)
835{
836 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
837 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
838 qdf_nbuf_t skb;
839 uint32_t dequeued = 0;
840
841 qdf_wake_lock_acquire(&ipa_ctx->wake_lock,
842 WIFI_POWER_EVENT_WAKELOCK_IPA);
843 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
844 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) !=
845 NULL)) {
846 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
847
848 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
849 dequeued++;
850
851 wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
852 pm_tx_cb->ipa_tx_desc);
853
854 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
855 }
856 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
857 qdf_wake_lock_release(&ipa_ctx->wake_lock,
858 WIFI_POWER_EVENT_WAKELOCK_IPA);
859
860 ipa_ctx->stats.num_tx_dequeued += dequeued;
861 if (dequeued > ipa_ctx->stats.num_max_pm_queue)
862 ipa_ctx->stats.num_max_pm_queue = dequeued;
863}
864
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530865QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx)
866{
867 int result;
868
869 ipa_debug("enter");
870
871 if (!ipa_ctx->ipa_pipes_down) {
872 /*
873 * IPA WDI Pipes are already activated due to
874 * rm deferred resources grant
875 */
876 ipa_warn("IPA WDI Pipes are already activated");
877 goto end;
878 }
879
880 result = cdp_ipa_enable_pipes(ipa_ctx->dp_soc,
881 ipa_ctx->dp_pdev);
882 if (result) {
883 ipa_err("Enable IPA WDI PIPE failed: ret=%d", result);
884 return QDF_STATUS_E_FAILURE;
885 }
886
887 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
888 ipa_ctx->ipa_pipes_down = false;
889
890 cdp_ipa_enable_autonomy(ipa_ctx->dp_soc,
891 ipa_ctx->dp_pdev);
892
893end:
894 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
895
896 return QDF_STATUS_SUCCESS;
897}
898
899QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx)
900{
901 int result;
902
903 ipa_debug("enter");
904
905 if (ipa_ctx->ipa_pipes_down) {
906 /*
907 * This shouldn't happen :
908 * IPA WDI Pipes are already deactivated
909 */
910 QDF_ASSERT(0);
911 ipa_warn("IPA WDI Pipes are already deactivated");
912 goto end;
913 }
914
915 cdp_ipa_disable_autonomy(ipa_ctx->dp_soc,
916 ipa_ctx->dp_pdev);
917
918 result = cdp_ipa_disable_pipes(ipa_ctx->dp_soc,
919 ipa_ctx->dp_pdev);
920 if (result) {
921 ipa_err("Disable IPA WDI PIPE failed: ret=%d", result);
922 return QDF_STATUS_E_FAILURE;
923 }
924
925 ipa_ctx->ipa_pipes_down = true;
926
927end:
928 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
929
930 return QDF_STATUS_SUCCESS;
931}
932
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530933/**
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +0530934 * wlan_ipa_uc_find_add_assoc_sta() - Find associated station
935 * @ipa_ctx: Global IPA IPA context
936 * @sta_add: Should station be added
937 * @sta_id: ID of the station being queried
938 *
939 * Return: true if the station was found
940 */
941static bool wlan_ipa_uc_find_add_assoc_sta(struct wlan_ipa_priv *ipa_ctx,
942 bool sta_add, uint8_t sta_id,
943 uint8_t *mac_addr)
944{
945 bool sta_found = false;
946 uint8_t idx;
947
948 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
949 if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
950 (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
951 sta_found = true;
952 break;
953 }
954 }
955 if (sta_add && sta_found) {
956 ipa_err("STA ID %d already exist, cannot add", sta_id);
957 return sta_found;
958 }
959 if (sta_add) {
960 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
961 if (!ipa_ctx->assoc_stas_map[idx].is_reserved) {
962 ipa_ctx->assoc_stas_map[idx].is_reserved = true;
963 ipa_ctx->assoc_stas_map[idx].sta_id = sta_id;
964 qdf_mem_copy(&ipa_ctx->assoc_stas_map[idx].
965 mac_addr, mac_addr,
966 QDF_NET_ETH_LEN);
967 return sta_found;
968 }
969 }
970 }
971 if (!sta_add && !sta_found) {
972 ipa_err("STA ID %d does not exist, cannot delete", sta_id);
973 return sta_found;
974 }
975 if (!sta_add) {
976 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
977 if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
978 (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
979 ipa_ctx->assoc_stas_map[idx].is_reserved =
980 false;
981 ipa_ctx->assoc_stas_map[idx].sta_id = 0xFF;
982 qdf_mem_set(&ipa_ctx->assoc_stas_map[idx].
983 mac_addr, 0, QDF_NET_ETH_LEN);
984 return sta_found;
985 }
986 }
987 }
988
989 return sta_found;
990}
991
992/**
993 * wlan_ipa_get_ifaceid() - Get IPA context interface ID
994 * @ipa_ctx: IPA context
995 * @session_id: Session ID
996 *
997 * Return: None
998 */
999static int wlan_ipa_get_ifaceid(struct wlan_ipa_priv *ipa_ctx,
1000 uint8_t session_id)
1001{
1002 struct wlan_ipa_iface_context *iface_ctx;
1003 int i;
1004
1005 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1006 iface_ctx = &ipa_ctx->iface_context[i];
1007 if (iface_ctx->session_id == session_id)
1008 break;
1009 }
1010
1011 return i;
1012}
1013
1014/**
1015 * wlan_ipa_cleanup_iface() - Cleanup IPA on a given interface
1016 * @iface_context: interface-specific IPA context
1017 *
1018 * Return: None
1019 */
1020static void wlan_ipa_cleanup_iface(struct wlan_ipa_iface_context *iface_context)
1021{
1022 struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
1023
1024 ipa_debug("enter");
1025
1026 if (!iface_context->tl_context)
1027 return;
1028
1029 cdp_ipa_cleanup_iface(ipa_ctx->dp_soc,
1030 iface_context->dev->name,
1031 wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
1032
1033 qdf_spin_lock_bh(&iface_context->interface_lock);
1034 iface_context->tl_context = NULL;
1035 iface_context->dev = NULL;
1036 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
1037 iface_context->session_id = WLAN_IPA_MAX_SESSION;
1038 iface_context->sta_id = WLAN_IPA_MAX_STA_COUNT;
1039 qdf_spin_unlock_bh(&iface_context->interface_lock);
1040 iface_context->ifa_address = 0;
1041 if (!iface_context->ipa_ctx->num_iface) {
1042 ipa_err("NUM INTF 0, Invalid");
1043 QDF_ASSERT(0);
1044 }
1045 iface_context->ipa_ctx->num_iface--;
1046 ipa_debug("exit: num_iface=%d", iface_context->ipa_ctx->num_iface);
1047}
1048
1049/**
1050 * wlan_ipa_setup_iface() - Setup IPA on a given interface
1051 * @ipa_ctx: IPA IPA global context
1052 * @net_dev: Interface net device
1053 * @device_mode: Net interface device mode
1054 * @adapter: Interface upon which IPA is being setup
1055 * @sta_id: Station ID of the API instance
1056 * @session_id: Station ID of the API instance
1057 *
1058 * Return: QDF STATUS
1059 */
1060static QDF_STATUS wlan_ipa_setup_iface(struct wlan_ipa_priv *ipa_ctx,
1061 qdf_netdev_t net_dev,
1062 uint8_t device_mode, uint8_t sta_id,
1063 uint8_t session_id)
1064{
1065 struct wlan_ipa_iface_context *iface_context = NULL;
1066 void *tl_context = NULL;
1067 int i;
1068 QDF_STATUS status;
1069
1070 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
1071 * channel change indication. Since these indications are sent by lower
1072 * layer as SAP updates and IPA doesn't have to do anything for these
1073 * updates so ignoring!
1074 */
1075 if (device_mode == QDF_SAP_MODE) {
1076 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1077 iface_context = &(ipa_ctx->iface_context[i]);
1078 if (iface_context->dev == net_dev)
1079 return QDF_STATUS_SUCCESS;
1080 }
1081 }
1082
Yun Park21ec4902018-04-24 12:11:01 -07001083 if (WLAN_IPA_MAX_IFACE == ipa_ctx->num_iface) {
1084 ipa_err("Max interface reached %d", WLAN_IPA_MAX_IFACE);
1085 status = QDF_STATUS_E_NOMEM;
1086 QDF_ASSERT(0);
1087 goto end;
1088 }
1089
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301090 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1091 if (ipa_ctx->iface_context[i].tl_context == NULL) {
1092 iface_context = &(ipa_ctx->iface_context[i]);
1093 break;
1094 }
1095 }
1096
1097 if (iface_context == NULL) {
1098 ipa_err("All the IPA interfaces are in use");
1099 status = QDF_STATUS_E_NOMEM;
Yun Park21ec4902018-04-24 12:11:01 -07001100 QDF_ASSERT(0);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301101 goto end;
1102 }
1103
1104 iface_context->sta_id = sta_id;
1105 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(ipa_ctx->dp_soc,
1106 ipa_ctx->dp_pdev,
1107 sta_id);
1108 if (tl_context == NULL) {
1109 ipa_err("Not able to get TL context sta_id: %d", sta_id);
1110 status = QDF_STATUS_E_INVAL;
1111 goto end;
1112 }
1113
1114 iface_context->tl_context = tl_context;
1115 iface_context->dev = net_dev;
1116 iface_context->device_mode = device_mode;
1117 iface_context->session_id = session_id;
1118
1119 status = cdp_ipa_setup_iface(ipa_ctx->dp_soc, net_dev->name,
1120 net_dev->dev_addr,
1121 iface_context->prod_client,
1122 iface_context->cons_client,
1123 session_id,
1124 wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
1125 if (status != QDF_STATUS_SUCCESS)
1126 goto end;
1127
1128 ipa_ctx->num_iface++;
1129
1130 ipa_debug("exit: num_iface=%d", ipa_ctx->num_iface);
1131
1132 return status;
1133
1134end:
1135 if (iface_context)
1136 wlan_ipa_cleanup_iface(iface_context);
1137
1138 return status;
1139}
1140
1141/**
1142 * wlan_ipa_uc_handle_first_con() - Handle first uC IPA connection
1143 * @ipa_ctx: IPA context
1144 *
1145 * Return: QDF STATUS
1146 */
1147static QDF_STATUS wlan_ipa_uc_handle_first_con(struct wlan_ipa_priv *ipa_ctx)
1148{
1149 ipa_debug("enter");
1150
1151 ipa_ctx->activated_fw_pipe = 0;
1152 ipa_ctx->resource_loading = true;
1153
1154 /* If RM feature enabled
1155 * Request PROD Resource first
1156 * PROD resource may return sync or async manners
1157 */
1158 if (wlan_ipa_is_rm_enabled(ipa_ctx->config)) {
Yun Parke114fbf2018-04-05 20:02:12 -07001159 if (!wlan_ipa_wdi_rm_request_resource(ipa_ctx,
1160 IPA_RM_RESOURCE_WLAN_PROD)) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301161 /* RM PROD request sync return
1162 * enable pipe immediately
1163 */
1164 if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
1165 ipa_err("IPA WDI Pipe activation failed");
1166 ipa_ctx->resource_loading = false;
1167 return QDF_STATUS_E_BUSY;
1168 }
1169 } else {
1170 ipa_err("IPA WDI Pipe activation deferred");
1171 }
1172 } else {
1173 /* RM Disabled
1174 * Just enabled all the PIPEs
1175 */
1176 if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
1177 ipa_err("IPA WDI Pipe activation failed");
1178 ipa_ctx->resource_loading = false;
1179 return QDF_STATUS_E_BUSY;
1180 }
1181 ipa_ctx->resource_loading = false;
1182 }
1183
1184 ipa_debug("exit");
1185
1186 return QDF_STATUS_SUCCESS;
1187}
1188
1189/**
1190 * wlan_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1191 * @ipa_ctx: IPA context
1192 *
1193 * Return: None
1194 */
1195static void wlan_ipa_uc_handle_last_discon(struct wlan_ipa_priv *ipa_ctx)
1196{
1197 ipa_debug("enter");
1198
1199 ipa_ctx->resource_unloading = true;
1200 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
1201 ipa_info("Disable FW RX PIPE");
1202 cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, false);
1203 ipa_info("Disable FW TX PIPE");
1204 cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, true);
1205
1206 ipa_debug("exit: IPA WDI Pipes deactivated");
1207}
1208
1209/**
1210 * wlan_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
1211 * @ipa_ctx: global IPA context
1212 * @offload_type: MCC or SCC
1213 * @session_id: Session Id
1214 * @enable: TX offload enable or disable
1215 *
1216 * Return: none
1217 */
1218static void wlan_ipa_uc_offload_enable_disable(struct wlan_ipa_priv *ipa_ctx,
1219 uint32_t offload_type,
1220 uint8_t session_id,
1221 bool enable)
1222{
1223
1224 struct ipa_uc_offload_control_params req = {0};
1225
1226 if (session_id >= WLAN_IPA_MAX_SESSION) {
1227 ipa_err("invalid session id: %d", session_id);
1228 return;
1229 }
1230
1231 if (enable == ipa_ctx->vdev_offload_enabled[session_id]) {
1232 /*
1233 * This shouldn't happen :
1234 * IPA offload status is already set as desired
1235 */
1236 QDF_ASSERT(0);
1237 ipa_warn("IPA offload status is already set");
1238 ipa_warn("offload_type=%d, vdev_id=%d, enable=%d",
1239 offload_type, session_id, enable);
1240 return;
1241 }
1242
1243 ipa_info("offload_type=%d, session_id=%d, enable=%d",
1244 offload_type, session_id, enable);
1245
1246 req.offload_type = offload_type;
1247 req.vdev_id = session_id;
1248 req.enable = enable;
1249
1250 if (QDF_STATUS_SUCCESS !=
1251 ipa_send_uc_offload_enable_disable(ipa_ctx->pdev, &req)) {
1252 ipa_err("Fail to enable IPA offload");
1253 ipa_err("offload type=%d, vdev_id=%d, enable=%d",
1254 offload_type, session_id, enable);
1255 } else {
1256 ipa_ctx->vdev_offload_enabled[session_id] = enable;
1257 }
1258}
1259
1260/**
1261 * __wlan_ipa_wlan_evt() - IPA event handler
1262 * @net_dev: Interface net device
1263 * @device_mode: Net interface device mode
1264 * @sta_id: station id for the event
1265 * @session_id: session id for the event
1266 * @type: event enum of type ipa_wlan_event
1267 * @mac_address: MAC address associated with the event
1268 *
1269 * This function is meant to be called from within wlan_ipa_ctx.c
1270 *
1271 * Return: QDF STATUS
1272 */
1273static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
1274 uint8_t sta_id, uint8_t session_id,
1275 qdf_ipa_wlan_event type,
1276 uint8_t *mac_addr)
1277{
1278 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
1279 struct wlan_ipa_iface_context *iface_ctx = NULL;
1280 qdf_ipa_msg_meta_t meta;
1281 qdf_ipa_wlan_msg_t *msg;
1282 qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
1283 int i;
1284 QDF_STATUS status;
1285
1286 ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d",
1287 net_dev->name, type, mac_addr, sta_id);
1288
1289 if (type >= QDF_IPA_WLAN_EVENT_MAX)
1290 return QDF_STATUS_E_INVAL;
1291
1292 if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
1293 !wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1294 (device_mode != QDF_SAP_MODE)) {
1295 return QDF_STATUS_SUCCESS;
1296 }
1297
1298 /*
1299 * During IPA UC resource loading/unloading new events can be issued.
1300 */
1301 if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
1302 (ipa_ctx->resource_loading || ipa_ctx->resource_unloading)) {
1303 unsigned int pending_event_count;
1304 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1305
1306 ipa_info("Event:%d IPA resource %s inprogress", type,
1307 ipa_ctx->resource_loading ?
1308 "load" : "unload");
1309
1310 /* Wait until completion of the long/unloading */
1311 status = qdf_wait_for_event_completion(
1312 &ipa_ctx->ipa_resource_comp,
1313 msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME));
1314 if (status != QDF_STATUS_SUCCESS) {
1315 /*
1316 * If timed out, store the events separately and
1317 * handle them later.
1318 */
1319 ipa_info("IPA resource %s timed out",
1320 ipa_ctx->resource_loading ?
1321 "load" : "unload");
1322
1323 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1324
1325 pending_event_count =
1326 qdf_list_size(&ipa_ctx->pending_event);
1327 if (pending_event_count >=
1328 WLAN_IPA_MAX_PENDING_EVENT_COUNT) {
1329 ipa_info("Reached max pending evt count");
1330 qdf_list_remove_front(
1331 &ipa_ctx->pending_event,
1332 (qdf_list_node_t **)&pending_event);
1333 } else {
1334 pending_event =
1335 (struct wlan_ipa_uc_pending_event *)
1336 qdf_mem_malloc(sizeof(
1337 struct wlan_ipa_uc_pending_event));
1338 }
1339
1340 if (!pending_event) {
1341 ipa_err("Pending event memory alloc fail");
1342 qdf_mutex_release(&ipa_ctx->ipa_lock);
1343 return QDF_STATUS_E_NOMEM;
1344 }
1345
1346 pending_event->net_dev = net_dev;
1347 pending_event->device_mode = device_mode;
1348 pending_event->sta_id = sta_id;
1349 pending_event->session_id = session_id;
1350 pending_event->type = type;
1351 pending_event->is_loading = ipa_ctx->resource_loading;
1352 qdf_mem_copy(pending_event->mac_addr,
1353 mac_addr, QDF_MAC_ADDR_SIZE);
1354 qdf_list_insert_back(&ipa_ctx->pending_event,
1355 &pending_event->node);
1356
1357 qdf_mutex_release(&ipa_ctx->ipa_lock);
1358
Yun Park21ec4902018-04-24 12:11:01 -07001359 /* Cleanup interface */
1360 if (type == QDF_IPA_STA_DISCONNECT ||
1361 type == QDF_IPA_AP_DISCONNECT) {
1362 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1363 iface_ctx = &ipa_ctx->iface_context[i];
1364
1365 if (iface_ctx->dev == net_dev)
1366 break;
1367 }
1368 if (iface_ctx)
1369 wlan_ipa_cleanup_iface(iface_ctx);
1370 }
1371
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301372 return QDF_STATUS_SUCCESS;
1373 }
1374 ipa_info("IPA resource %s completed",
1375 ipa_ctx->resource_loading ?
1376 "load" : "unload");
1377 }
1378
1379 ipa_ctx->stats.event[type]++;
1380
1381 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1382 switch (type) {
1383 case QDF_IPA_STA_CONNECT:
1384 qdf_mutex_acquire(&ipa_ctx->event_lock);
1385
1386 /* STA already connected and without disconnect, connect again
1387 * This is Roaming scenario
1388 */
1389 if (ipa_ctx->sta_connected) {
1390 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
1391 if (iface_ctx)
1392 wlan_ipa_cleanup_iface(iface_ctx);
1393 }
1394
1395 status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
1396 sta_id, session_id);
1397 if (status != QDF_STATUS_SUCCESS) {
1398 qdf_mutex_release(&ipa_ctx->event_lock);
1399 goto end;
1400 }
1401
1402 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1403 (ipa_ctx->sap_num_connected_sta > 0) &&
1404 !ipa_ctx->sta_connected) {
1405 qdf_mutex_release(&ipa_ctx->event_lock);
1406 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1407 SIR_STA_RX_DATA_OFFLOAD, session_id,
1408 true);
1409 qdf_mutex_acquire(&ipa_ctx->event_lock);
1410 }
1411
1412 ipa_ctx->vdev_to_iface[session_id] =
1413 wlan_ipa_get_ifaceid(ipa_ctx, session_id);
1414
1415 ipa_ctx->sta_connected = 1;
1416
1417 qdf_mutex_release(&ipa_ctx->event_lock);
1418
1419 ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
1420 break;
1421
1422 case QDF_IPA_AP_CONNECT:
1423 qdf_mutex_acquire(&ipa_ctx->event_lock);
1424
1425 /* For DFS channel we get two start_bss event (before and after
1426 * CAC). Also when ACS range includes both DFS and non DFS
1427 * channels, we could possibly change channel many times due to
1428 * RADAR detection and chosen channel may not be a DFS channels.
1429 * So dont return error here. Just discard the event.
1430 */
jiadc908ada2018-05-11 14:40:54 +08001431 if (ipa_ctx->vdev_to_iface[session_id] !=
1432 WLAN_IPA_MAX_SESSION) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301433 qdf_mutex_release(&ipa_ctx->event_lock);
1434 return 0;
1435 }
1436
1437 status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
1438 sta_id, session_id);
1439 if (status != QDF_STATUS_SUCCESS) {
1440 qdf_mutex_release(&ipa_ctx->event_lock);
1441 ipa_err("%s: Evt: %d, Interface setup failed",
1442 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
1443 goto end;
1444 }
1445
1446 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1447 qdf_mutex_release(&ipa_ctx->event_lock);
1448 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1449 SIR_AP_RX_DATA_OFFLOAD, session_id, true);
1450 qdf_mutex_acquire(&ipa_ctx->event_lock);
1451 }
1452
1453 ipa_ctx->vdev_to_iface[session_id] =
1454 wlan_ipa_get_ifaceid(ipa_ctx, session_id);
1455 qdf_mutex_release(&ipa_ctx->event_lock);
1456 break;
1457
1458 case QDF_IPA_STA_DISCONNECT:
1459 qdf_mutex_acquire(&ipa_ctx->event_lock);
1460
1461 if (!ipa_ctx->sta_connected) {
1462 qdf_mutex_release(&ipa_ctx->event_lock);
1463 ipa_err("%s: Evt: %d, STA already disconnected",
1464 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
1465 return QDF_STATUS_E_INVAL;
1466 }
1467
1468 ipa_ctx->sta_connected = 0;
1469
1470 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1471 ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
1472 msg_ex->name);
1473 } else {
1474 /* Disable IPA UC TX PIPE when STA disconnected */
1475 if ((ipa_ctx->num_iface == 1) &&
Yun Parka29974a2018-04-09 12:05:49 -07001476 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301477 !ipa_ctx->ipa_pipes_down)
1478 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1479 }
1480
1481 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1482 (ipa_ctx->sap_num_connected_sta > 0)) {
1483 qdf_mutex_release(&ipa_ctx->event_lock);
1484 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1485 SIR_STA_RX_DATA_OFFLOAD, session_id, false);
1486 qdf_mutex_acquire(&ipa_ctx->event_lock);
1487 ipa_ctx->vdev_to_iface[session_id] =
1488 WLAN_IPA_MAX_SESSION;
1489 }
1490
1491 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1492 iface_ctx = &ipa_ctx->iface_context[i];
1493
1494 if (iface_ctx->dev == net_dev)
1495 break;
1496 }
1497 if (i < WLAN_IPA_MAX_IFACE)
1498 wlan_ipa_cleanup_iface(iface_ctx);
1499
1500 qdf_mutex_release(&ipa_ctx->event_lock);
1501
1502 ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
1503 break;
1504
1505 case QDF_IPA_AP_DISCONNECT:
1506 qdf_mutex_acquire(&ipa_ctx->event_lock);
1507
1508 if ((ipa_ctx->num_iface == 1) &&
Yun Parka29974a2018-04-09 12:05:49 -07001509 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301510 !ipa_ctx->ipa_pipes_down) {
1511 if (cds_is_driver_unloading()) {
1512 /*
1513 * We disable WDI pipes directly here since
1514 * IPA_OPCODE_TX/RX_SUSPEND message will not be
1515 * processed when unloading WLAN driver is in
1516 * progress
1517 */
1518 wlan_ipa_uc_disable_pipes(ipa_ctx);
1519 } else {
1520 /*
1521 * This shouldn't happen :
1522 * No interface left but WDI pipes are still
1523 * active - force close WDI pipes
1524 */
1525 ipa_err("No interface left but WDI pipes are still active");
1526 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1527 }
1528 }
1529
1530 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1531 qdf_mutex_release(&ipa_ctx->event_lock);
1532 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1533 SIR_AP_RX_DATA_OFFLOAD, session_id, false);
1534 qdf_mutex_acquire(&ipa_ctx->event_lock);
1535 ipa_ctx->vdev_to_iface[session_id] =
1536 WLAN_IPA_MAX_SESSION;
1537 }
1538
1539 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1540 iface_ctx = &ipa_ctx->iface_context[i];
1541
1542 if (iface_ctx->dev == net_dev)
1543 break;
1544 }
1545 if (i < WLAN_IPA_MAX_IFACE)
1546 wlan_ipa_cleanup_iface(iface_ctx);
1547
1548 qdf_mutex_release(&ipa_ctx->event_lock);
1549 break;
1550
1551 case QDF_IPA_CLIENT_CONNECT_EX:
1552 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1553 ipa_debug("%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
1554 net_dev->name, type);
1555 return QDF_STATUS_SUCCESS;
1556 }
1557
1558 qdf_mutex_acquire(&ipa_ctx->event_lock);
1559 if (wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, true, sta_id,
1560 mac_addr)) {
1561 qdf_mutex_release(&ipa_ctx->event_lock);
1562 ipa_err("%s: STA ID %d found", net_dev->name, sta_id);
1563 return QDF_STATUS_SUCCESS;
1564 }
1565
1566 /* Enable IPA UC Data PIPEs when first STA connected */
1567 if (ipa_ctx->sap_num_connected_sta == 0 &&
1568 ipa_ctx->uc_loaded == true) {
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301569 struct wlan_ipa_iface_context *iface_ctx;
1570 uint8_t sta_session_id;
1571
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301572 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1573 ipa_ctx->sta_connected) {
1574 qdf_mutex_release(&ipa_ctx->event_lock);
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301575 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
1576 sta_session_id = iface_ctx->session_id;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301577 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1578 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301579 sta_session_id, true);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301580 qdf_mutex_acquire(&ipa_ctx->event_lock);
1581 }
1582
1583 status = wlan_ipa_uc_handle_first_con(ipa_ctx);
1584 if (status != QDF_STATUS_SUCCESS) {
1585 ipa_info("%s: handle 1st con fail",
1586 net_dev->name);
1587
1588 if (wlan_ipa_uc_sta_is_enabled(
1589 ipa_ctx->config) &&
1590 ipa_ctx->sta_connected) {
1591 qdf_mutex_release(&ipa_ctx->event_lock);
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301592 iface_ctx = wlan_ipa_get_iface(ipa_ctx,
1593 QDF_STA_MODE);
1594 sta_session_id = iface_ctx->session_id;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301595 wlan_ipa_uc_offload_enable_disable(
1596 ipa_ctx,
1597 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301598 sta_session_id, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301599 } else {
1600 qdf_mutex_release(&ipa_ctx->event_lock);
1601 }
1602
1603 return status;
1604 }
1605 }
1606
1607 ipa_ctx->sap_num_connected_sta++;
1608
1609 qdf_mutex_release(&ipa_ctx->event_lock);
1610
1611 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1612 QDF_IPA_MSG_META_MSG_LEN(&meta) =
1613 (sizeof(qdf_ipa_wlan_msg_ex_t) +
1614 sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
1615 msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1616
1617 if (msg_ex == NULL) {
1618 ipa_err("msg_ex allocation failed");
1619 return QDF_STATUS_E_NOMEM;
1620 }
1621 strlcpy(msg_ex->name, net_dev->name,
1622 IPA_RESOURCE_NAME_MAX);
1623 msg_ex->num_of_attribs = 1;
1624 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
1625 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1626 msg_ex->attribs[0].offset =
1627 WLAN_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
1628 } else {
1629 msg_ex->attribs[0].offset =
1630 WLAN_IPA_WLAN_HDR_DES_MAC_OFFSET;
1631 }
1632 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
1633 IPA_MAC_ADDR_SIZE);
1634
1635 if (qdf_ipa_send_msg(&meta, msg_ex, wlan_ipa_msg_free_fn)) {
1636 ipa_info("%s: Evt: %d send ipa msg fail",
1637 net_dev->name, type);
1638 qdf_mem_free(msg_ex);
1639 return QDF_STATUS_E_FAILURE;
1640 }
1641 ipa_ctx->stats.num_send_msg++;
1642
1643 ipa_info("sap_num_connected_sta=%d",
1644 ipa_ctx->sap_num_connected_sta);
1645
1646 return QDF_STATUS_SUCCESS;
1647
1648 case WLAN_CLIENT_DISCONNECT:
1649 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1650 ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
1651 msg_ex->name);
1652 return QDF_STATUS_SUCCESS;
1653 }
1654
1655 qdf_mutex_acquire(&ipa_ctx->event_lock);
1656 if (!ipa_ctx->sap_num_connected_sta) {
1657 qdf_mutex_release(&ipa_ctx->event_lock);
1658 ipa_err("%s: Evt: %d, Client already disconnected",
1659 msg_ex->name,
1660 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1661
1662 return QDF_STATUS_SUCCESS;
1663 }
1664 if (!wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, false,
1665 sta_id, mac_addr)) {
1666 qdf_mutex_release(&ipa_ctx->event_lock);
1667 ipa_err("%s: STA ID %d NOT found, not valid",
1668 msg_ex->name, sta_id);
1669
1670 return QDF_STATUS_SUCCESS;
1671 }
1672 ipa_ctx->sap_num_connected_sta--;
1673
1674 /* Disable IPA UC TX PIPE when last STA disconnected */
1675 if (!ipa_ctx->sap_num_connected_sta &&
1676 ipa_ctx->uc_loaded == true) {
Yun Parka29974a2018-04-09 12:05:49 -07001677 if ((false == ipa_ctx->resource_unloading) &&
1678 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
1679 !ipa_ctx->ipa_pipes_down) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301680 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1681 }
1682
1683 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1684 ipa_ctx->sta_connected) {
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301685 struct wlan_ipa_iface_context *iface_ctx;
1686 uint8_t sta_session_id;
1687
1688 iface_ctx = wlan_ipa_get_iface(ipa_ctx,
1689 QDF_STA_MODE);
1690 sta_session_id = iface_ctx->session_id;
1691
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301692 qdf_mutex_release(&ipa_ctx->event_lock);
1693 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1694 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301695 sta_session_id, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301696 } else {
1697 qdf_mutex_release(&ipa_ctx->event_lock);
1698 }
1699 } else {
1700 qdf_mutex_release(&ipa_ctx->event_lock);
1701 }
1702
1703 ipa_info("sap_num_connected_sta=%d",
1704 ipa_ctx->sap_num_connected_sta);
1705 break;
1706
1707 default:
1708 return QDF_STATUS_SUCCESS;
1709 }
1710
1711 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
1712 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1713 if (!msg) {
1714 ipa_err("msg allocation failed");
1715 return QDF_STATUS_E_NOMEM;
1716 }
1717
1718 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1719 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name,
1720 IPA_RESOURCE_NAME_MAX);
1721 qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN);
1722
1723 ipa_debug("%s: Evt: %d", QDF_IPA_WLAN_MSG_NAME(msg),
1724 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1725
1726 if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) {
1727
1728 ipa_err("%s: Evt: %d fail",
1729 QDF_IPA_WLAN_MSG_NAME(msg),
1730 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1731 qdf_mem_free(msg);
1732
1733 return QDF_STATUS_E_FAILURE;
1734 }
1735
1736 ipa_ctx->stats.num_send_msg++;
1737
1738end:
1739 return QDF_STATUS_SUCCESS;
1740}
1741
1742/**
1743 * wlan_host_to_ipa_wlan_event() - convert wlan_ipa_wlan_event to ipa_wlan_event
Yun Park84fbb272018-04-02 15:31:01 -07001744 * @wlan_ipa_event_type: event to be converted to an ipa_wlan_event
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301745 *
1746 * Return: qdf_ipa_wlan_event representing the wlan_ipa_wlan_event
1747 */
1748static qdf_ipa_wlan_event
1749wlan_host_to_ipa_wlan_event(enum wlan_ipa_wlan_event wlan_ipa_event_type)
1750{
Yun Park84fbb272018-04-02 15:31:01 -07001751 qdf_ipa_wlan_event ipa_event;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301752
1753 switch (wlan_ipa_event_type) {
1754 case WLAN_IPA_CLIENT_CONNECT:
1755 ipa_event = QDF_IPA_CLIENT_CONNECT;
1756 break;
1757 case WLAN_IPA_CLIENT_DISCONNECT:
1758 ipa_event = QDF_IPA_CLIENT_DISCONNECT;
1759 break;
1760 case WLAN_IPA_AP_CONNECT:
1761 ipa_event = QDF_IPA_AP_CONNECT;
1762 break;
1763 case WLAN_IPA_AP_DISCONNECT:
1764 ipa_event = QDF_IPA_AP_DISCONNECT;
1765 break;
1766 case WLAN_IPA_STA_CONNECT:
1767 ipa_event = QDF_IPA_STA_CONNECT;
1768 break;
1769 case WLAN_IPA_STA_DISCONNECT:
1770 ipa_event = QDF_IPA_STA_DISCONNECT;
1771 break;
1772 case WLAN_IPA_CLIENT_CONNECT_EX:
1773 ipa_event = QDF_IPA_CLIENT_CONNECT_EX;
1774 break;
1775 case WLAN_IPA_WLAN_EVENT_MAX:
1776 default:
1777 ipa_event = QDF_IPA_WLAN_EVENT_MAX;
1778 break;
1779 }
1780
1781 return ipa_event;
1782}
1783
1784/**
1785 * wlan_ipa_wlan_evt() - SSR wrapper for __wlan_ipa_wlan_evt
1786 * @net_dev: Interface net device
1787 * @device_mode: Net interface device mode
1788 * @sta_id: station id for the event
1789 * @session_id: session id for the event
1790 * @ipa_event_type: event enum of type wlan_ipa_wlan_event
1791 * @mac_address: MAC address associated with the event
1792 *
1793 * Return: QDF_STATUS
1794 */
1795QDF_STATUS wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
1796 uint8_t sta_id, uint8_t session_id,
1797 enum wlan_ipa_wlan_event ipa_event_type,
1798 uint8_t *mac_addr)
1799{
1800 qdf_ipa_wlan_event type = wlan_host_to_ipa_wlan_event(ipa_event_type);
1801 QDF_STATUS status = QDF_STATUS_SUCCESS;
1802
1803 /* Data path offload only support for STA and SAP mode */
1804 if ((device_mode == QDF_STA_MODE) ||
1805 (device_mode == QDF_SAP_MODE))
1806 status = __wlan_ipa_wlan_evt(net_dev, device_mode, sta_id,
1807 session_id, type, mac_addr);
1808
1809 return status;
1810}
1811
1812/**
1813 * wlan_ipa_uc_proc_pending_event() - Process IPA uC pending events
1814 * @ipa_ctx: Global IPA IPA context
1815 * @is_loading: Indicate if invoked during loading
1816 *
1817 * Return: None
1818 */
1819static void
1820wlan_ipa_uc_proc_pending_event(struct wlan_ipa_priv *ipa_ctx, bool is_loading)
1821{
1822 unsigned int pending_event_count;
1823 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1824
1825 pending_event_count = qdf_list_size(&ipa_ctx->pending_event);
1826 ipa_debug("Pending Event Count %d", pending_event_count);
1827 if (!pending_event_count) {
1828 ipa_debug("No Pending Event");
1829 return;
1830 }
1831
1832 qdf_list_remove_front(&ipa_ctx->pending_event,
1833 (qdf_list_node_t **)&pending_event);
1834 while (pending_event != NULL) {
1835 if (pending_event->is_loading == is_loading) {
1836 __wlan_ipa_wlan_evt(pending_event->net_dev,
1837 pending_event->device_mode,
1838 pending_event->sta_id,
1839 pending_event->session_id,
1840 pending_event->type,
1841 pending_event->mac_addr);
1842 }
1843 qdf_mem_free(pending_event);
1844 pending_event = NULL;
1845 qdf_list_remove_front(&ipa_ctx->pending_event,
1846 (qdf_list_node_t **)&pending_event);
1847 }
1848}
1849
1850/**
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301851 * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
1852 * @ipa_ctx: IPA context
1853 *
1854 * Return: QDF_STATUS
1855 */
1856static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
1857{
1858 int i;
1859 uint32_t max_desc_cnt;
1860 struct wlan_ipa_tx_desc *tmp_desc;
1861
1862 max_desc_cnt = ipa_ctx->config->txbuf_count;
1863
1864 qdf_list_create(&ipa_ctx->tx_desc_list, max_desc_cnt);
1865
1866 qdf_spin_lock_bh(&ipa_ctx->q_lock);
1867 for (i = 0; i < max_desc_cnt; i++) {
1868 tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc));
1869 tmp_desc->id = i;
1870 tmp_desc->ipa_tx_desc_ptr = NULL;
1871 qdf_list_insert_back(&ipa_ctx->tx_desc_list,
1872 &tmp_desc->node);
1873 tmp_desc++;
1874 }
1875
1876 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
1877 ipa_ctx->stats.num_tx_desc_error = 0;
1878
1879 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
1880
1881 return QDF_STATUS_SUCCESS;
1882}
1883
1884#ifndef QCA_LL_TX_FLOW_CONTROL_V2
1885/**
1886 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
1887 * @ipa_ctx: Global IPA IPA context
1888 * @desc_fifo_sz: Number of descriptors
1889 *
1890 * Return: 0 on success, negative errno on error
1891 */
1892static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
1893 int32_t desc_fifo_sz)
1894{
1895 int i, ret = 0;
1896 qdf_ipa_sys_connect_params_t *ipa;
1897
1898 /*setup TX pipes */
1899 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1900 ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params;
1901
1902 ipa->client = wlan_ipa_iface_2_client[i].cons_client;
1903 ipa->desc_fifo_sz = desc_fifo_sz;
1904 ipa->priv = &ipa_ctx->iface_context[i];
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301905 ipa->notify = wlan_ipa_i2w_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301906
1907 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
1908 ipa->ipa_ep_cfg.hdr.hdr_len =
1909 WLAN_IPA_UC_WLAN_TX_HDR_LEN;
1910 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
1911 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
1912 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
1913 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
1914 WLAN_IPA_UC_WLAN_8023_HDR_SIZE;
1915 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
1916 } else {
1917 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN;
1918 }
1919 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
1920
1921 ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa,
1922 &ipa_ctx->sys_pipe[i].conn_hdl);
1923 if (ret) {
1924 ipa_err("Failed for pipe %d ret: %d", i, ret);
1925 return ret;
1926 }
1927 ipa_ctx->sys_pipe[i].conn_hdl_valid = 1;
1928 }
1929
1930 return ret;
1931}
1932#else
1933/**
1934 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
1935 * @ipa_ctx: Global IPA IPA context
1936 * @desc_fifo_sz: Number of descriptors
1937 *
1938 * Return: 0 on success, negative errno on error
1939 */
1940static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
1941 int32_t desc_fifo_sz)
1942{
1943 /*
1944 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
1945 * is enabled, where per vdev descriptors are supported in firmware.
1946 */
1947 return 0;
1948}
1949#endif
1950
1951/**
1952 * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
1953 * @ipa_ctx: Global IPA IPA context
1954 * @desc_fifo_sz: Number of descriptors
1955 *
1956 * Return: 0 on success, negative errno on error
1957 */
1958static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
1959 int32_t desc_fifo_sz)
1960{
1961 int ret = 0;
1962 qdf_ipa_sys_connect_params_t *ipa;
1963
1964 /*
1965 * Hard code it here, this can be extended if in case
1966 * PROD pipe is also per interface.
1967 * Right now there is no advantage of doing this.
1968 */
1969 ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params;
1970
1971 ipa->client = IPA_CLIENT_WLAN1_PROD;
1972
1973 ipa->desc_fifo_sz = desc_fifo_sz;
1974 ipa->priv = ipa_ctx;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301975 ipa->notify = wlan_ipa_w2i_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301976
1977 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
1978 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN;
1979 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
1980 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
1981
1982 ret = qdf_ipa_setup_sys_pipe(ipa,
1983 &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl);
1984 if (ret) {
1985 ipa_err("Failed for RX pipe: %d", ret);
1986 return ret;
1987 }
1988 ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1;
1989
1990 return ret;
1991}
1992
1993/**
1994 * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
1995 * @ipa_ctx: Global IPA IPA context
1996 *
1997 * Return: 0 on success, negative errno on error
1998 */
1999static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
2000{
2001 int i = WLAN_IPA_MAX_IFACE, ret = 0;
2002 uint32_t desc_fifo_sz;
2003
2004 /* The maximum number of descriptors that can be provided to a BAM at
2005 * once is one less than the total number of descriptors that the buffer
2006 * can contain.
2007 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
2008 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
2009 * be provided at once.
2010 * Because of above requirement, one extra descriptor will be added to
2011 * make sure hardware always has one descriptor.
2012 */
2013 desc_fifo_sz = ipa_ctx->config->desc_size
2014 + SPS_DESC_SIZE;
2015
2016 ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz);
2017 if (ret) {
2018 ipa_err("Failed for TX pipe: %d", ret);
2019 goto setup_sys_pipe_fail;
2020 }
2021
2022 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2023 ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz);
2024 if (ret) {
2025 ipa_err("Failed for RX pipe: %d", ret);
2026 goto setup_sys_pipe_fail;
2027 }
2028 }
2029
2030 /* Allocate free Tx desc list */
2031 ret = wlan_ipa_alloc_tx_desc_list(ipa_ctx);
2032 if (ret)
2033 goto setup_sys_pipe_fail;
2034
2035 return ret;
2036
2037setup_sys_pipe_fail:
2038
2039 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
2040 if (ipa_ctx->sys_pipe[i].conn_hdl_valid)
2041 qdf_ipa_teardown_sys_pipe(
2042 ipa_ctx->sys_pipe[i].conn_hdl);
2043 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
2044 sizeof(struct wlan_ipa_sys_pipe));
2045 }
2046
2047 return ret;
2048}
2049
2050/**
2051 * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
2052 * @ipa_ctx: Global IPA IPA context
2053 *
2054 * Return: None
2055 */
2056static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
2057{
2058 int ret = 0, i;
2059 struct wlan_ipa_tx_desc *tmp_desc;
2060 qdf_ipa_rx_data_t *ipa_tx_desc;
2061 qdf_list_node_t *node;
2062
2063 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
2064 if (ipa_ctx->sys_pipe[i].conn_hdl_valid) {
2065 ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx,
2066 ipa_ctx->sys_pipe[i].conn_hdl);
2067 if (ret)
2068 ipa_err("Failed:%d", ret);
2069
2070 ipa_ctx->sys_pipe[i].conn_hdl_valid = 0;
2071 }
2072 }
2073
2074 while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) ==
2075 QDF_STATUS_SUCCESS) {
2076 tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc,
2077 node);
2078 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
2079 if (ipa_tx_desc)
2080 qdf_ipa_free_skb(ipa_tx_desc);
2081
2082 qdf_mem_free(tmp_desc);
2083 }
2084}
2085
jiadbb47e132018-03-30 16:28:30 +08002086#ifndef QCA_LL_TX_FLOW_CONTROL_V2
2087QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
2088 bool mcc_mode)
2089{
2090 qdf_ipa_msg_meta_t meta;
2091 qdf_ipa_wlan_msg_t *msg;
2092 int ret;
2093
2094 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
2095 return QDF_STATUS_SUCCESS;
2096
2097 /* Send SCC/MCC Switching event to IPA */
2098 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
2099 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
2100 if (msg == NULL) {
2101 ipa_err("msg allocation failed");
2102 return QDF_STATUS_E_NOMEM;
2103 }
2104
jiad629b2172018-05-11 15:34:22 +08002105 if (mcc_mode) {
jiadbb47e132018-03-30 16:28:30 +08002106 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_MCC);
jiad629b2172018-05-11 15:34:22 +08002107 ipa_ctx->stats.event[QDF_SWITCH_TO_MCC]++;
2108 } else {
jiadbb47e132018-03-30 16:28:30 +08002109 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_SCC);
jiad629b2172018-05-11 15:34:22 +08002110 ipa_ctx->stats.event[QDF_SWITCH_TO_SCC]++;
2111 }
2112
jiadbb47e132018-03-30 16:28:30 +08002113 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2114 "ipa_send_msg(Evt:%d)",
2115 QDF_IPA_MSG_META_MSG_TYPE(&meta));
2116
2117 ret = qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn);
2118
2119 if (ret) {
2120 ipa_err("ipa_send_msg(Evt:%d) - fail=%d",
2121 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
2122 qdf_mem_free(msg);
2123 return QDF_STATUS_E_FAILURE;
2124 }
2125
2126 return QDF_STATUS_SUCCESS;
2127}
2128
2129static void wlan_ipa_mcc_work_handler(void *data)
2130{
2131 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
2132
2133 wlan_ipa_send_mcc_scc_msg(ipa_ctx, ipa_ctx->mcc_mode);
2134}
2135#endif
2136
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302137/**
2138 * wlan_ipa_setup() - IPA initialization function
2139 * @ipa_ctx: IPA context
2140 * @ipa_cfg: IPA config
2141 *
2142 * Allocate ipa_ctx resources, ipa pipe resource and register
2143 * wlan interface with IPA module.
2144 *
2145 * Return: QDF_STATUS enumeration
2146 */
2147QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
2148 struct wlan_ipa_config *ipa_cfg)
2149{
2150 int ret, i;
2151 struct wlan_ipa_iface_context *iface_context = NULL;
2152 QDF_STATUS status;
2153
2154 ipa_debug("enter");
2155
2156 gp_ipa = ipa_ctx;
2157 ipa_ctx->num_iface = 0;
2158 ipa_ctx->config = ipa_cfg;
2159
2160 wlan_ipa_wdi_get_wdi_version(ipa_ctx);
2161
2162 /* Create the interface context */
2163 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2164 iface_context = &ipa_ctx->iface_context[i];
2165 iface_context->ipa_ctx = ipa_ctx;
2166 iface_context->cons_client =
2167 wlan_ipa_iface_2_client[i].cons_client;
2168 iface_context->prod_client =
2169 wlan_ipa_iface_2_client[i].prod_client;
2170 iface_context->iface_id = i;
2171 iface_context->dev = NULL;
2172 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
2173 iface_context->tl_context = NULL;
2174 qdf_spinlock_create(&iface_context->interface_lock);
2175 }
2176
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302177 qdf_create_work(0, &ipa_ctx->pm_work, wlan_ipa_pm_flush, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302178 qdf_spinlock_create(&ipa_ctx->pm_lock);
2179 qdf_spinlock_create(&ipa_ctx->q_lock);
2180 qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head);
2181 qdf_list_create(&ipa_ctx->pending_event, 1000);
2182 qdf_mutex_create(&ipa_ctx->event_lock);
2183 qdf_mutex_create(&ipa_ctx->ipa_lock);
2184
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302185 status = wlan_ipa_wdi_setup_rm(ipa_ctx);
2186 if (status != QDF_STATUS_SUCCESS)
2187 goto fail_setup_rm;
2188
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302189 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++)
2190 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
2191 sizeof(struct wlan_ipa_sys_pipe));
2192
2193 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
2194 qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats));
2195 ipa_ctx->sap_num_connected_sta = 0;
2196 ipa_ctx->ipa_tx_packets_diff = 0;
2197 ipa_ctx->ipa_rx_packets_diff = 0;
2198 ipa_ctx->ipa_p_tx_packets = 0;
2199 ipa_ctx->ipa_p_rx_packets = 0;
2200 ipa_ctx->resource_loading = false;
2201 ipa_ctx->resource_unloading = false;
2202 ipa_ctx->sta_connected = 0;
2203 ipa_ctx->ipa_pipes_down = true;
2204 ipa_ctx->wdi_enabled = false;
2205 /* Setup IPA system pipes */
2206 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2207 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
2208 if (ret)
2209 goto fail_create_sys_pipe;
jiadbb47e132018-03-30 16:28:30 +08002210
2211 qdf_create_work(0, &ipa_ctx->mcc_work,
2212 wlan_ipa_mcc_work_handler, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302213 }
2214
2215 status = wlan_ipa_wdi_init(ipa_ctx);
2216 if (status == QDF_STATUS_E_BUSY)
2217 status = wlan_ipa_uc_send_wdi_control_msg(false);
2218 if (status != QDF_STATUS_SUCCESS) {
2219 ipa_err("IPA WDI init failed: ret=%d", ret);
2220 goto fail_create_sys_pipe;
2221 }
2222 } else {
2223 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
2224 if (ret)
2225 goto fail_create_sys_pipe;
2226 }
2227
2228 qdf_event_create(&ipa_ctx->ipa_resource_comp);
2229
2230 ipa_debug("exit: success");
2231
2232 return QDF_STATUS_SUCCESS;
2233
2234fail_create_sys_pipe:
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302235 wlan_ipa_wdi_destroy_rm(ipa_ctx);
2236
2237fail_setup_rm:
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302238 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302239 qdf_spinlock_destroy(&ipa_ctx->q_lock);
2240 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2241 iface_context = &ipa_ctx->iface_context[i];
2242 qdf_spinlock_destroy(&iface_context->interface_lock);
2243 }
2244 qdf_mutex_destroy(&ipa_ctx->event_lock);
2245 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
2246 qdf_list_destroy(&ipa_ctx->pending_event);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302247 gp_ipa = NULL;
2248 ipa_debug("exit: fail");
2249
2250 return QDF_STATUS_E_FAILURE;
2251}
2252
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302253void wlan_ipa_flush(struct wlan_ipa_priv *ipa_ctx)
2254{
2255 qdf_nbuf_t skb;
2256 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
2257
2258 if (!wlan_ipa_is_enabled(ipa_ctx->config))
2259 return;
2260
2261 qdf_cancel_work(&ipa_ctx->pm_work);
2262
2263 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
2264
2265 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head))
2266 != NULL)) {
2267 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
2268
2269 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
2270 if (pm_tx_cb->ipa_tx_desc)
2271 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
2272
2273 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
2274 }
2275 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
2276}
2277
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302278QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx)
2279{
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302280 struct wlan_ipa_iface_context *iface_context;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302281 int i;
2282
2283 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2284 wlan_ipa_teardown_sys_pipe(ipa_ctx);
2285
2286 /* Teardown IPA sys_pipe for MCC */
jiadbb47e132018-03-30 16:28:30 +08002287 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302288 wlan_ipa_teardown_sys_pipe(ipa_ctx);
jiadbb47e132018-03-30 16:28:30 +08002289 qdf_cancel_work(&ipa_ctx->mcc_work);
2290 }
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302291
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302292 wlan_ipa_wdi_destroy_rm(ipa_ctx);
2293
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302294 wlan_ipa_flush(ipa_ctx);
2295
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302296 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
2297 qdf_spinlock_destroy(&ipa_ctx->q_lock);
2298
2299 /* destroy the interface lock */
2300 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2301 iface_context = &ipa_ctx->iface_context[i];
2302 qdf_spinlock_destroy(&iface_context->interface_lock);
2303 }
2304
2305 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
2306 wlan_ipa_wdi_cleanup();
2307 qdf_mutex_destroy(&ipa_ctx->event_lock);
2308 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
2309 qdf_list_destroy(&ipa_ctx->pending_event);
2310
2311 }
2312
2313 gp_ipa = NULL;
2314
2315 return QDF_STATUS_SUCCESS;
2316}
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +05302317
2318struct wlan_ipa_iface_context
2319*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode)
2320{
2321 struct wlan_ipa_iface_context *iface_ctx = NULL;
2322 int i;
2323
2324 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2325 iface_ctx = &ipa_ctx->iface_context[i];
2326
2327 if (iface_ctx->device_mode == mode)
2328 return iface_ctx;
2329 }
2330
2331 return NULL;
2332}
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302333
jiadbb47e132018-03-30 16:28:30 +08002334void wlan_ipa_set_mcc_mode(struct wlan_ipa_priv *ipa_ctx, bool mcc_mode)
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302335{
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302336 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
jiadbb47e132018-03-30 16:28:30 +08002337 return;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302338
jiadbb47e132018-03-30 16:28:30 +08002339 if (ipa_ctx->mcc_mode == mcc_mode)
2340 return;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302341
jiadbb47e132018-03-30 16:28:30 +08002342 ipa_ctx->mcc_mode = mcc_mode;
2343 qdf_sched_work(0, &ipa_ctx->mcc_work);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302344}
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302345
2346/**
2347 * wlan_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2348 * @ipa_ctx: ipa ipa local context
2349 *
2350 * Will handle IPA UC image loaded indication comes from IPA kernel
2351 *
2352 * Return: None
2353 */
2354static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx)
2355{
2356 struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
2357 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
2358 qdf_device_t qdf_dev = wlan_psoc_get_qdf_dev(psoc);
2359 QDF_STATUS status;
2360
2361 ipa_info("UC READY");
2362 if (true == ipa_ctx->uc_loaded) {
2363 ipa_info("UC already loaded");
2364 return;
2365 }
2366
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302367 /* Connect pipe */
2368 status = wlan_ipa_wdi_setup(ipa_ctx, qdf_dev);
2369 if (status) {
2370 ipa_err("Failure to setup IPA pipes (status=%d)",
2371 status);
2372 return;
2373 }
2374
2375 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302376
2377 /* If already any STA connected, enable IPA/FW PIPEs */
2378 if (ipa_ctx->sap_num_connected_sta) {
2379 ipa_debug("Client already connected, enable IPA/FW PIPEs");
2380 wlan_ipa_uc_handle_first_con(ipa_ctx);
2381 }
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302382}
2383
2384/**
2385 * wlan_ipa_uc_op_cb() - IPA uC operation callback
2386 * @op_msg: operation message received from firmware
2387 * @usr_ctxt: user context registered with TL (we register the IPA Global
2388 * context)
2389 *
2390 * Return: None
2391 */
2392static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
2393 struct wlan_ipa_priv *ipa_ctx)
2394{
2395 struct op_msg_type *msg = op_msg;
2396 struct ipa_uc_fw_stats *uc_fw_stat;
2397
2398 if (!op_msg) {
2399 ipa_err("INVALID ARG");
2400 return;
2401 }
2402
2403 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
2404 ipa_err("INVALID OPCODE %d", msg->op_code);
2405 qdf_mem_free(op_msg);
2406 return;
2407 }
2408
2409 ipa_debug("OPCODE=%d", msg->op_code);
2410
2411 if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_RESUME) ||
2412 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_RESUME)) {
2413 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2414 ipa_ctx->activated_fw_pipe++;
Yun Parka29974a2018-04-09 12:05:49 -07002415 if (wlan_ipa_is_fw_wdi_activated(ipa_ctx)) {
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302416 ipa_ctx->resource_loading = false;
2417 qdf_event_set(&ipa_ctx->ipa_resource_comp);
2418 if (ipa_ctx->wdi_enabled == false) {
2419 ipa_ctx->wdi_enabled = true;
2420 if (wlan_ipa_uc_send_wdi_control_msg(true) == 0)
2421 wlan_ipa_send_mcc_scc_msg(ipa_ctx,
2422 ipa_ctx->mcc_mode);
2423 }
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302424 wlan_ipa_uc_proc_pending_event(ipa_ctx, true);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302425 if (ipa_ctx->pending_cons_req)
Yun Parke114fbf2018-04-05 20:02:12 -07002426 wlan_ipa_wdi_rm_notify_completion(
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302427 QDF_IPA_RM_RESOURCE_GRANTED,
2428 QDF_IPA_RM_RESOURCE_WLAN_CONS);
2429 ipa_ctx->pending_cons_req = false;
2430 }
2431 qdf_mutex_release(&ipa_ctx->ipa_lock);
2432 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_SUSPEND) ||
2433 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND)) {
2434 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2435 ipa_ctx->activated_fw_pipe--;
2436 if (!ipa_ctx->activated_fw_pipe) {
2437 /*
2438 * Async return success from FW
2439 * Disable/suspend all the PIPEs
2440 */
2441 ipa_ctx->resource_unloading = false;
2442 qdf_event_set(&ipa_ctx->ipa_resource_comp);
2443 wlan_ipa_uc_disable_pipes(ipa_ctx);
2444 if (wlan_ipa_is_rm_enabled(ipa_ctx->config))
Yun Parke114fbf2018-04-05 20:02:12 -07002445 wlan_ipa_wdi_rm_release_resource(ipa_ctx,
2446 QDF_IPA_RM_RESOURCE_WLAN_PROD);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302447 wlan_ipa_uc_proc_pending_event(ipa_ctx, false);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302448 ipa_ctx->pending_cons_req = false;
2449 }
2450 qdf_mutex_release(&ipa_ctx->ipa_lock);
2451 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
2452 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_DEBUG)) {
2453 uc_fw_stat = (struct ipa_uc_fw_stats *)
2454 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2455
2456 /* WLAN FW WDI stats */
2457 wlan_ipa_print_fw_wdi_stats(ipa_ctx, uc_fw_stat);
2458 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
2459 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_BW_CAL)) {
2460 /* STATs from FW */
2461 uc_fw_stat = (struct ipa_uc_fw_stats *)
2462 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2463 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2464 ipa_ctx->ipa_tx_packets_diff = BW_GET_DIFF(
2465 uc_fw_stat->tx_pkts_completed,
2466 ipa_ctx->ipa_p_tx_packets);
2467 ipa_ctx->ipa_rx_packets_diff = BW_GET_DIFF(
2468 (uc_fw_stat->rx_num_ind_drop_no_space +
2469 uc_fw_stat->rx_num_ind_drop_no_buf +
2470 uc_fw_stat->rx_num_pkts_indicated),
2471 ipa_ctx->ipa_p_rx_packets);
2472
2473 ipa_ctx->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2474 ipa_ctx->ipa_p_rx_packets =
2475 (uc_fw_stat->rx_num_ind_drop_no_space +
2476 uc_fw_stat->rx_num_ind_drop_no_buf +
2477 uc_fw_stat->rx_num_pkts_indicated);
2478 qdf_mutex_release(&ipa_ctx->ipa_lock);
2479 } else if (msg->op_code == WLAN_IPA_UC_OPCODE_UC_READY) {
2480 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2481 wlan_ipa_uc_loaded_handler(ipa_ctx);
2482 qdf_mutex_release(&ipa_ctx->ipa_lock);
2483 } else if (wlan_ipa_uc_op_metering(ipa_ctx, op_msg)) {
2484 ipa_err("Invalid message: op_code=%d, reason=%d",
2485 msg->op_code, ipa_ctx->stat_req_reason);
2486 }
2487
2488 qdf_mem_free(op_msg);
2489}
2490
2491/**
2492 * wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2493 * @work: uC OP work
2494 *
2495 * Return: None
2496 */
2497static void wlan_ipa_uc_fw_op_event_handler(void *data)
2498{
2499 struct op_msg_type *msg;
2500 struct uc_op_work_struct *uc_op_work =
2501 (struct uc_op_work_struct *)data;
2502 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
2503
2504 msg = uc_op_work->msg;
2505 uc_op_work->msg = NULL;
2506 ipa_debug("posted msg %d", msg->op_code);
2507
2508 wlan_ipa_uc_op_cb(msg, ipa_ctx);
2509}
2510
2511/**
2512 * wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
2513 * @op_msg: operation message received from firmware
2514 * @ipa_ctx: Global IPA context
2515 *
2516 * Return: None
2517 */
2518static void wlan_ipa_uc_op_event_handler(uint8_t *op_msg, void *ctx)
2519{
2520 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)ctx;
2521 struct op_msg_type *msg;
2522 struct uc_op_work_struct *uc_op_work;
2523
2524 if (!ipa_ctx)
2525 goto end;
2526
2527 msg = (struct op_msg_type *)op_msg;
2528
2529 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
2530 ipa_err("Invalid OP Code (%d)", msg->op_code);
2531 goto end;
2532 }
2533
2534 uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
2535 if (uc_op_work->msg) {
2536 /* When the same uC OPCODE is already pended, just return */
2537 goto end;
2538 }
2539
2540 uc_op_work->msg = msg;
2541 qdf_sched_work(0, &uc_op_work->work);
2542 return;
2543
2544end:
2545 qdf_mem_free(op_msg);
2546}
2547
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302548QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx,
2549 qdf_device_t osdev)
2550{
2551 uint8_t i;
2552 QDF_STATUS status = QDF_STATUS_SUCCESS;
2553
2554 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2555 return QDF_STATUS_SUCCESS;
2556
2557 ipa_debug("enter");
2558
2559 for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) {
2560 ipa_ctx->vdev_to_iface[i] = WLAN_IPA_MAX_SESSION;
2561 ipa_ctx->vdev_offload_enabled[i] = false;
2562 }
2563
2564 /* Set the lowest bandwidth to start with */
2565 status = wlan_ipa_set_perf_level(ipa_ctx, 0, 0);
2566 if (status != QDF_STATUS_SUCCESS) {
2567 ipa_err("Set perf level failed: %d", status);
Yun Parke114fbf2018-04-05 20:02:12 -07002568 wlan_ipa_wdi_rm_inactivity_timer_destroy(
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302569 QDF_IPA_RM_RESOURCE_WLAN_PROD);
2570 goto fail_return;
2571 }
2572
2573 if (cdp_ipa_get_resource(ipa_ctx->dp_soc, ipa_ctx->dp_pdev)) {
2574 ipa_err("IPA UC resource alloc fail");
2575 status = QDF_STATUS_E_FAILURE;
2576 goto fail_return;
2577 }
2578
2579 if (true == ipa_ctx->uc_loaded) {
2580 status = wlan_ipa_wdi_setup(ipa_ctx, osdev);
2581 if (status) {
2582 ipa_err("Failure to setup IPA pipes (status=%d)",
2583 status);
2584 status = QDF_STATUS_E_FAILURE;
2585 goto fail_return;
2586 }
2587
2588 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
2589 wlan_ipa_init_metering(ipa_ctx);
2590 }
2591
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302592 cdp_ipa_register_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
2593 wlan_ipa_uc_op_event_handler, (void *)ipa_ctx);
2594
2595 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
2596 qdf_create_work(0, &ipa_ctx->uc_op_work[i].work,
2597 wlan_ipa_uc_fw_op_event_handler,
2598 &ipa_ctx->uc_op_work[i]);
2599 ipa_ctx->uc_op_work[i].msg = NULL;
2600 }
2601
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302602fail_return:
2603 ipa_debug("exit: status=%d", status);
2604 return status;
2605}
2606
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302607/**
2608 * wlan_ipa_cleanup_pending_event() - Cleanup IPA pending event list
2609 * @ipa_ctx: pointer to IPA IPA struct
2610 *
2611 * Return: none
2612 */
2613static void wlan_ipa_cleanup_pending_event(struct wlan_ipa_priv *ipa_ctx)
2614{
2615 struct wlan_ipa_uc_pending_event *pending_event = NULL;
2616
2617 while (qdf_list_remove_front(&ipa_ctx->pending_event,
2618 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
2619 qdf_mem_free(pending_event);
2620}
2621
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302622QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx)
2623{
2624 QDF_STATUS status = QDF_STATUS_SUCCESS;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302625 int i;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302626
2627 ipa_debug("enter");
2628
2629 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2630 return status;
2631
2632 if (!ipa_ctx->ipa_pipes_down)
2633 wlan_ipa_uc_disable_pipes(ipa_ctx);
2634
2635 if (true == ipa_ctx->uc_loaded) {
2636 status = cdp_ipa_cleanup(ipa_ctx->dp_soc,
2637 ipa_ctx->tx_pipe_handle,
2638 ipa_ctx->rx_pipe_handle);
2639 if (status)
2640 ipa_err("Failure to cleanup IPA pipes (status=%d)",
2641 status);
2642 }
2643
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302644 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2645 wlan_ipa_cleanup_pending_event(ipa_ctx);
2646 qdf_mutex_release(&ipa_ctx->ipa_lock);
2647
2648 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
2649 qdf_cancel_work(&ipa_ctx->uc_op_work[i].work);
2650 qdf_mem_free(ipa_ctx->uc_op_work[i].msg);
2651 ipa_ctx->uc_op_work[i].msg = NULL;
2652 }
2653
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302654 ipa_debug("exit: ret=%d", status);
2655 return status;
2656}
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +05302657
2658int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
2659{
2660 ipa_debug("Map: %d Num_buf: %d", map, num_buf);
2661
2662 if (!num_buf) {
2663 ipa_info("No buffers to map/unmap");
2664 return 0;
2665 }
2666
2667 if (map)
2668 return qdf_ipa_create_wdi_mapping(num_buf, buf_arr);
2669 else
2670 return qdf_ipa_release_wdi_mapping(num_buf, buf_arr);
2671}
Yun Parka29974a2018-04-09 12:05:49 -07002672
2673/**
2674 * wlan_ipa_is_fw_wdi_activated() - Is FW WDI actived?
2675 * @ipa_ctx: IPA contex
2676 *
2677 * Return: true if FW WDI actived, false otherwise
2678 */
2679bool wlan_ipa_is_fw_wdi_activated(struct wlan_ipa_priv *ipa_ctx)
2680{
2681 return (WLAN_IPA_UC_NUM_WDI_PIPE == ipa_ctx->activated_fw_pipe);
2682}
2683