blob: 33be842cdd30202bcbb5bb51bf3a0ebaf4d061bf [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
Yun Parke74e6092018-04-27 11:36:34 -0700195/**
196 * wlan_ipa_send_pkt_to_tl() - Send an IPA packet to TL
197 * @iface_context: interface-specific IPA context
198 * @ipa_tx_desc: packet data descriptor
199 *
200 * Return: None
201 */
202static void wlan_ipa_send_pkt_to_tl(
203 struct wlan_ipa_iface_context *iface_context,
204 qdf_ipa_rx_data_t *ipa_tx_desc)
205{
206 struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
207 qdf_nbuf_t skb;
208 struct wlan_ipa_tx_desc *tx_desc;
209
210 qdf_spin_lock_bh(&iface_context->interface_lock);
211 /*
212 * During CAC period, data packets shouldn't be sent over the air so
213 * drop all the packets here
214 */
215 if (iface_context->device_mode == QDF_SAP_MODE ||
216 iface_context->device_mode == QDF_P2P_GO_MODE) {
217 if (ipa_ctx->dfs_cac_block_tx) {
218 ipa_free_skb(ipa_tx_desc);
219 qdf_spin_unlock_bh(&iface_context->interface_lock);
220 iface_context->stats.num_tx_cac_drop++;
221 wlan_ipa_wdi_rm_try_release(ipa_ctx);
222 return;
223 }
224 }
225 qdf_spin_unlock_bh(&iface_context->interface_lock);
226
227 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
228
229 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
230
231 /* Store IPA Tx buffer ownership into SKB CB */
232 qdf_nbuf_ipa_owned_set(skb);
233 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
234 qdf_nbuf_mapped_paddr_set(skb,
235 QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
236 + WLAN_IPA_WLAN_FRAG_HEADER
237 + WLAN_IPA_WLAN_IPA_HEADER);
238 QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
239 WLAN_IPA_WLAN_FRAG_HEADER + WLAN_IPA_WLAN_IPA_HEADER;
240 } else
241 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
242
243 qdf_spin_lock_bh(&ipa_ctx->q_lock);
244 /* get free Tx desc and assign ipa_tx_desc pointer */
245 if (qdf_list_remove_front(&ipa_ctx->tx_desc_list,
246 (qdf_list_node_t **)&tx_desc) ==
247 QDF_STATUS_SUCCESS) {
248 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
249 ipa_ctx->stats.num_tx_desc_q_cnt++;
250 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
251 /* Store Tx Desc index into SKB CB */
252 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
253 } else {
254 ipa_ctx->stats.num_tx_desc_error++;
255 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
256 qdf_ipa_free_skb(ipa_tx_desc);
257 wlan_ipa_wdi_rm_try_release(ipa_ctx);
258 return;
259 }
260
261 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
262 (struct cdp_vdev *)iface_context->tl_context,
263 QDF_IPA_RX_DATA_SKB(ipa_tx_desc));
264 if (skb) {
265 qdf_nbuf_free(skb);
266 iface_context->stats.num_tx_err++;
267 return;
268 }
269
270 atomic_inc(&ipa_ctx->tx_ref_cnt);
271
272 iface_context->stats.num_tx++;
273}
274
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530275#ifdef CONFIG_IPA_WDI_UNIFIED_API
276
277/*
278 * TODO: Get WDI version through FW capabilities
279 */
280#ifdef CONFIG_LITHIUM
281static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
282{
283 ipa_ctx->wdi_version = IPA_WDI_3;
284}
285#elif defined(QCA_WIFI_3_0)
286static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
287{
288 ipa_ctx->wdi_version = IPA_WDI_2;
289}
290#else
291static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
292{
293 ipa_ctx->wdi_version = IPA_WDI_1;
294}
295#endif
296
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530297static inline bool wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx,
298 qdf_device_t osdev)
299{
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +0530300 return ipa_ctx->is_smmu_enabled && qdf_mem_smmu_s1_enabled(osdev);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530301}
302
303static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx,
304 qdf_device_t osdev)
305{
306 qdf_ipa_sys_connect_params_t sys_in[WLAN_IPA_MAX_IFACE];
307 int i;
308
309 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++)
310 qdf_mem_copy(&sys_in[i],
311 &ipa_ctx->sys_pipe[i].ipa_sys_params,
312 sizeof(qdf_ipa_sys_connect_params_t));
313
314 return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
315 wlan_ipa_i2w_cb, wlan_ipa_w2i_cb,
316 wlan_ipa_wdi_meter_notifier_cb,
317 ipa_ctx->config->desc_size,
318 ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config),
319 &ipa_ctx->tx_pipe_handle,
320 &ipa_ctx->rx_pipe_handle,
321 wlan_ipa_wdi_is_smmu_enabled(ipa_ctx, osdev),
322 sys_in);
323}
324
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530325#ifdef FEATURE_METERING
326/**
327 * wlan_ipa_wdi_init_metering() - IPA WDI metering init
328 * @ipa_ctx: IPA context
329 * @in: IPA WDI in param
330 *
331 * Return: QDF_STATUS
332 */
333static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
334 qdf_ipa_wdi_init_in_params_t *in)
335{
336 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(in) =
337 wlan_ipa_wdi_meter_notifier_cb;
338}
339#else
340static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
341 qdf_ipa_wdi_init_in_params_t *in)
342{
343}
344#endif
345
346/**
347 * wlan_ipa_wdi_init() - IPA WDI init
348 * @ipa_ctx: IPA context
349 *
350 * Return: QDF_STATUS
351 */
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530352static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
353{
354 qdf_ipa_wdi_init_in_params_t in;
355 qdf_ipa_wdi_init_out_params_t out;
356 int ret;
357
358 ipa_ctx->uc_loaded = false;
359
360 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version;
361 QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb;
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530362 QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = ipa_ctx;
363 wlan_ipa_wdi_init_metering(ipa_ctx, &in);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530364
365 ret = qdf_ipa_wdi_init(&in, &out);
366 if (ret) {
367 ipa_err("ipa_wdi_init failed with ret=%d", ret);
368 return QDF_STATUS_E_FAILURE;
369 }
370
371 if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
372 ipa_info("IPA uC READY");
373 ipa_ctx->uc_loaded = true;
374 ipa_ctx->is_smmu_enabled =
375 QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
376 ipa_info("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled);
377 } else {
378 return QDF_STATUS_E_BUSY;
379 }
380
381 return QDF_STATUS_SUCCESS;
382}
383
384static inline int wlan_ipa_wdi_cleanup(void)
385{
386 int ret;
387
388 ret = qdf_ipa_wdi_cleanup();
389 if (ret)
390 ipa_info("ipa_wdi_cleanup failed ret=%d", ret);
391 return ret;
392}
393
394static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
395 struct ipa_sys_connect_params *sys,
396 uint32_t *handle)
397{
398 return 0;
399}
400
401static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
402 uint32_t handle)
403{
404 return 0;
405}
406
Yun Parke74e6092018-04-27 11:36:34 -0700407/**
408 * wlan_ipa_pm_flush() - flush queued packets
409 * @work: pointer to the scheduled work
410 *
411 * Called during PM resume to send packets to TL which were queued
412 * while host was in the process of suspending.
413 *
414 * Return: None
415 */
416static void wlan_ipa_pm_flush(void *data)
417{
418 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
419 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
420 qdf_nbuf_t skb;
421 uint32_t dequeued = 0;
422
423 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
424 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) !=
425 NULL)) {
426 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
427
428 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
429 dequeued++;
430
jiadab8cea02018-05-24 09:16:14 +0800431 if (pm_tx_cb->exception) {
432 if (ipa_ctx->softap_xmit &&
433 pm_tx_cb->iface_context->dev) {
434 ipa_ctx->softap_xmit(skb,
435 pm_tx_cb->iface_context->dev);
436 ipa_ctx->stats.num_tx_fwd_ok++;
437 } else {
438 dev_kfree_skb_any(skb);
439 }
440 } else {
441 wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
442 pm_tx_cb->ipa_tx_desc);
443 }
Yun Parke74e6092018-04-27 11:36:34 -0700444
445 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
446 }
447 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
448
449 ipa_ctx->stats.num_tx_dequeued += dequeued;
450 if (dequeued > ipa_ctx->stats.num_max_pm_queue)
451 ipa_ctx->stats.num_max_pm_queue = dequeued;
452}
453
jiadae9959f2018-05-08 11:19:07 +0800454int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
455{
456 if (!num_buf) {
457 ipa_info("No buffers to map/unmap");
458 return 0;
459 }
460
461 if (map)
462 return qdf_ipa_wdi_create_smmu_mapping(num_buf, buf_arr);
463 else
464 return qdf_ipa_wdi_release_smmu_mapping(num_buf, buf_arr);
465}
466
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530467#else /* CONFIG_IPA_WDI_UNIFIED_API */
468
469static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
470{
471}
472
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +0530473static inline int wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx,
474 qdf_device_t osdev)
475{
476 return qdf_mem_smmu_s1_enabled(osdev);
477}
478
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530479static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx,
480 qdf_device_t osdev)
481{
482 return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
483 wlan_ipa_i2w_cb, wlan_ipa_w2i_cb,
484 wlan_ipa_wdi_meter_notifier_cb,
485 ipa_ctx->config->desc_size,
486 ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config),
487 &ipa_ctx->tx_pipe_handle,
488 &ipa_ctx->rx_pipe_handle);
489}
490
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530491static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
492{
493 struct ipa_wdi_uc_ready_params uc_ready_param;
494
495 ipa_ctx->uc_loaded = false;
496 uc_ready_param.priv = (void *)ipa_ctx;
497 uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb;
498 if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) {
499 ipa_info("UC Ready CB register fail");
500 return QDF_STATUS_E_FAILURE;
501 }
502
503 if (true == uc_ready_param.is_uC_ready) {
504 ipa_info("UC Ready");
505 ipa_ctx->uc_loaded = true;
506 } else {
507 return QDF_STATUS_E_BUSY;
508 }
509
510 return QDF_STATUS_SUCCESS;
511}
512
513static inline int wlan_ipa_wdi_cleanup(void)
514{
515 int ret;
516
517 ret = qdf_ipa_uc_dereg_rdyCB();
518 if (ret)
519 ipa_info("UC Ready CB deregister fail");
520 return ret;
521}
522
523static inline int wlan_ipa_wdi_setup_sys_pipe(
524 struct wlan_ipa_priv *ipa_ctx,
525 struct ipa_sys_connect_params *sys, uint32_t *handle)
526{
527 return qdf_ipa_setup_sys_pipe(sys, handle);
528}
529
530static inline int wlan_ipa_wdi_teardown_sys_pipe(
531 struct wlan_ipa_priv *ipa_ctx,
532 uint32_t handle)
533{
534 return qdf_ipa_teardown_sys_pipe(handle);
535}
536
Yun Parke74e6092018-04-27 11:36:34 -0700537/**
538 * wlan_ipa_pm_flush() - flush queued packets
539 * @work: pointer to the scheduled work
540 *
541 * Called during PM resume to send packets to TL which were queued
542 * while host was in the process of suspending.
543 *
544 * Return: None
545 */
546static void wlan_ipa_pm_flush(void *data)
547{
548 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
549 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
550 qdf_nbuf_t skb;
551 uint32_t dequeued = 0;
552
553 qdf_wake_lock_acquire(&ipa_ctx->wake_lock,
554 WIFI_POWER_EVENT_WAKELOCK_IPA);
555 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
556 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) !=
557 NULL)) {
558 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
559
560 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
561 dequeued++;
562
jiadab8cea02018-05-24 09:16:14 +0800563 if (pm_tx_cb->exception) {
564 if (ipa_ctx->softap_xmit &&
565 pm_tx_cb->iface_context->dev) {
566 ipa_ctx->softap_xmit(skb,
567 pm_tx_cb->iface_context->dev);
568 ipa_ctx->stats.num_tx_fwd_ok++;
569 } else {
570 dev_kfree_skb_any(skb);
571 }
572 } else {
573 wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
574 pm_tx_cb->ipa_tx_desc);
575 }
Yun Parke74e6092018-04-27 11:36:34 -0700576
577 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
578 }
579 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
580 qdf_wake_lock_release(&ipa_ctx->wake_lock,
581 WIFI_POWER_EVENT_WAKELOCK_IPA);
582
583 ipa_ctx->stats.num_tx_dequeued += dequeued;
584 if (dequeued > ipa_ctx->stats.num_max_pm_queue)
585 ipa_ctx->stats.num_max_pm_queue = dequeued;
586}
587
jiadae9959f2018-05-08 11:19:07 +0800588int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
589{
590 if (!num_buf) {
591 ipa_info("No buffers to map/unmap");
592 return 0;
593 }
594
595 if (map)
596 return qdf_ipa_create_wdi_mapping(num_buf, buf_arr);
597 else
598 return qdf_ipa_release_wdi_mapping(num_buf, buf_arr);
599}
600
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530601#endif /* CONFIG_IPA_WDI_UNIFIED_API */
602
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530603/**
604 * wlan_ipa_send_skb_to_network() - Send skb to kernel
605 * @skb: network buffer
606 * @iface_ctx: IPA interface context
607 *
608 * Called when a network buffer is received which should not be routed
609 * to the IPA module.
610 *
611 * Return: None
612 */
613static void
614wlan_ipa_send_skb_to_network(qdf_nbuf_t skb,
615 struct wlan_ipa_iface_context *iface_ctx)
616{
617 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
618
619 if (!iface_ctx->dev) {
620 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Invalid interface");
621 ipa_ctx->ipa_rx_internal_drop_count++;
622 qdf_nbuf_free(skb);
623 return;
624 }
625
626 skb->destructor = wlan_ipa_uc_rt_debug_destructor;
627
628 if (ipa_ctx->send_to_nw)
629 ipa_ctx->send_to_nw(skb, iface_ctx->dev);
630
631 ipa_ctx->ipa_rx_net_send_count++;
632}
633
634/**
635 * wlan_ipa_forward() - handle packet forwarding to wlan tx
636 * @ipa_ctx: pointer to ipa ipa context
637 * @iface_ctx: interface context
638 * @skb: data pointer
639 *
640 * if exception packet has set forward bit, copied new packet should be
641 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
642 * put into pm queue and tx procedure will be differed
643 *
644 * Return: None
645 */
646static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx,
647 struct wlan_ipa_iface_context *iface_ctx,
648 qdf_nbuf_t skb)
649{
650 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
651
652 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
653
654 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
655 qdf_nbuf_ipa_owned_set(skb);
656
657 /* WLAN subsystem is in suspend, put in queue */
658 if (ipa_ctx->suspended) {
659 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
660 WLAN_IPA_LOG(QDF_TRACE_LEVEL_INFO,
661 "Tx in suspend, put in queue");
662 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
663 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
664 pm_tx_cb->exception = true;
665 pm_tx_cb->iface_context = iface_ctx;
666 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
667 qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
668 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
669 ipa_ctx->stats.num_tx_queued++;
670 } else {
671 /* Resume, put packet into WLAN TX */
672 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
673
674 if (ipa_ctx->softap_xmit) {
675 if (ipa_ctx->softap_xmit(skb, iface_ctx->dev)) {
676 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
677 "packet Tx fail");
678 ipa_ctx->stats.num_tx_fwd_err++;
679 } else {
680 ipa_ctx->stats.num_tx_fwd_ok++;
681 }
682 } else {
jiadab8cea02018-05-24 09:16:14 +0800683 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530684 }
685 }
686}
687
688/**
689 * wlan_ipa_intrabss_forward() - Forward intra bss packets.
690 * @ipa_ctx: pointer to IPA IPA struct
691 * @iface_ctx: ipa interface context
692 * @desc: Firmware descriptor
693 * @skb: Data buffer
694 *
695 * Return:
696 * WLAN_IPA_FORWARD_PKT_NONE
697 * WLAN_IPA_FORWARD_PKT_DISCARD
698 * WLAN_IPA_FORWARD_PKT_LOCAL_STACK
699 *
700 */
701
702static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward(
703 struct wlan_ipa_priv *ipa_ctx,
704 struct wlan_ipa_iface_context *iface_ctx,
705 uint8_t desc,
706 qdf_nbuf_t skb)
707{
708 int ret = WLAN_IPA_FORWARD_PKT_NONE;
709 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
710 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
711
712 if ((desc & FW_RX_DESC_FORWARD_M)) {
713 if (!ol_txrx_fwd_desc_thresh_check(
714 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
715 (struct cdp_pdev *)pdev,
716 iface_ctx->session_id))) {
717 /* Drop the packet*/
718 ipa_ctx->stats.num_tx_fwd_err++;
jiadab8cea02018-05-24 09:16:14 +0800719 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530720 ret = WLAN_IPA_FORWARD_PKT_DISCARD;
721 return ret;
722 }
723 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
724 "Forward packet to Tx (fw_desc=%d)", desc);
725 ipa_ctx->ipa_tx_forward++;
726
727 if ((desc & FW_RX_DESC_DISCARD_M)) {
728 wlan_ipa_forward(ipa_ctx, iface_ctx, skb);
729 ipa_ctx->ipa_rx_internal_drop_count++;
730 ipa_ctx->ipa_rx_discard++;
731 ret = WLAN_IPA_FORWARD_PKT_DISCARD;
732 } else {
733 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
734
735 if (cloned_skb)
736 wlan_ipa_forward(ipa_ctx, iface_ctx,
737 cloned_skb);
738 else
739 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
740 "tx skb alloc failed");
741 ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK;
742 }
743 }
744
745 return ret;
746}
747
748/**
749 * wlan_ipa_w2i_cb() - WLAN to IPA callback handler
750 * @priv: pointer to private data registered with IPA (we register a
751 * pointer to the global IPA context)
752 * @evt: the IPA event which triggered the callback
753 * @data: data associated with the event
754 *
755 * Return: None
756 */
757static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
758 unsigned long data)
759{
760 struct wlan_ipa_priv *ipa_ctx = NULL;
761 qdf_nbuf_t skb;
762 uint8_t iface_id;
763 uint8_t session_id;
764 struct wlan_ipa_iface_context *iface_context;
765 uint8_t fw_desc;
766
767 ipa_ctx = (struct wlan_ipa_priv *)priv;
768
769 if (!ipa_ctx)
770 return;
771
772 switch (evt) {
773 case IPA_RECEIVE:
774 skb = (qdf_nbuf_t) data;
775
776 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
777 session_id = (uint8_t)skb->cb[0];
778 iface_id = ipa_ctx->vdev_to_iface[session_id];
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530779 } else {
780 iface_id = WLAN_IPA_GET_IFACE_ID(skb->data);
781 }
782 if (iface_id >= WLAN_IPA_MAX_IFACE) {
783 ipa_err("IPA_RECEIVE: Invalid iface_id: %u",
784 iface_id);
785 ipa_ctx->ipa_rx_internal_drop_count++;
jiadab8cea02018-05-24 09:16:14 +0800786 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530787 return;
788 }
789
790 iface_context = &ipa_ctx->iface_context[iface_id];
791 if (!iface_context->tl_context) {
792 ipa_err("IPA_RECEIVE: TL context is NULL");
793 ipa_ctx->ipa_rx_internal_drop_count++;
jiadab8cea02018-05-24 09:16:14 +0800794 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530795 return;
796 }
797
798 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
799 ipa_ctx->stats.num_rx_excep++;
800 qdf_nbuf_pull_head(skb, WLAN_IPA_UC_WLAN_CLD_HDR_LEN);
801 } else {
802 qdf_nbuf_pull_head(skb, WLAN_IPA_WLAN_CLD_HDR_LEN);
803 }
804
805 iface_context->stats.num_rx_ipa_excep++;
806
807 /* Disable to forward Intra-BSS Rx packets when
808 * ap_isolate=1 in hostapd.conf
809 */
810 if (!ipa_ctx->ap_intrabss_fwd) {
811 /*
812 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
813 * all Rx packets to IPA uC, which need to be forwarded
814 * to other interface.
815 * And, IPA driver will send back to WLAN host driver
816 * through exception pipe with fw_desc field set by FW.
817 * Here we are checking fw_desc field for FORWARD bit
818 * set, and forward to Tx. Then copy to kernel stack
819 * only when DISCARD bit is not set.
820 */
821 fw_desc = (uint8_t)skb->cb[1];
822 if (WLAN_IPA_FORWARD_PKT_DISCARD ==
823 wlan_ipa_intrabss_forward(ipa_ctx, iface_context,
824 fw_desc, skb))
825 break;
826 } else {
827 ipa_debug("Intra-BSS FWD is disabled-skip forward to Tx");
828 }
829
830 wlan_ipa_send_skb_to_network(skb, iface_context);
831 break;
832
833 default:
834 ipa_err("w2i cb wrong event: 0x%x", evt);
835 return;
836 }
837}
838
839/**
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530840 * wlan_ipa_i2w_cb() - IPA to WLAN callback
841 * @priv: pointer to private data registered with IPA (we register a
842 * pointer to the interface-specific IPA context)
843 * @evt: the IPA event which triggered the callback
844 * @data: data associated with the event
845 *
846 * Return: None
847 */
848static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
849 unsigned long data)
850{
851 struct wlan_ipa_priv *ipa_ctx = NULL;
852 qdf_ipa_rx_data_t *ipa_tx_desc;
853 struct wlan_ipa_iface_context *iface_context;
854 qdf_nbuf_t skb;
855 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
856
857 iface_context = (struct wlan_ipa_iface_context *)priv;
858 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
859 ipa_ctx = iface_context->ipa_ctx;
860
861 if (evt != IPA_RECEIVE) {
862 WLAN_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
863 ipa_free_skb(ipa_tx_desc);
864 iface_context->stats.num_tx_drop++;
865 return;
866 }
867
868 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
869
870 /*
871 * If PROD resource is not requested here then there may be cases where
872 * IPA hardware may be clocked down because of not having proper
873 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
874 * workaround to request PROD resource while data is going over CONS
875 * pipe to prevent the IPA hardware clockdown.
876 */
877 wlan_ipa_wdi_rm_request(ipa_ctx);
878
879 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
880 /*
881 * If host is still suspended then queue the packets and these will be
882 * drained later when resume completes. When packet is arrived here and
883 * host is suspended, this means that there is already resume is in
884 * progress.
885 */
886 if (ipa_ctx->suspended) {
887 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
888 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
889 pm_tx_cb->iface_context = iface_context;
890 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
891 qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
892 ipa_ctx->stats.num_tx_queued++;
893
894 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
895 return;
896 }
897
898 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
899
900 /*
901 * If we are here means, host is not suspended, wait for the work queue
902 * to finish.
903 */
904 qdf_flush_work(&ipa_ctx->pm_work);
905
906 return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
907}
908
909QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx)
910{
911 /*
912 * Check if IPA is ready for suspend, If we are here means, there is
913 * high chance that suspend would go through but just to avoid any race
914 * condition after suspend started, these checks are conducted before
915 * allowing to suspend.
916 */
917 if (atomic_read(&ipa_ctx->tx_ref_cnt))
918 return QDF_STATUS_E_AGAIN;
919
Yun Parke74e6092018-04-27 11:36:34 -0700920 if (!wlan_ipa_is_rm_released(ipa_ctx))
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530921 return QDF_STATUS_E_AGAIN;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530922
923 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
924 ipa_ctx->suspended = true;
925 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
926
927 return QDF_STATUS_SUCCESS;
928}
929
930QDF_STATUS wlan_ipa_resume(struct wlan_ipa_priv *ipa_ctx)
931{
932 qdf_sched_work(0, &ipa_ctx->pm_work);
933
934 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
935 ipa_ctx->suspended = false;
936 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
937
938 return QDF_STATUS_SUCCESS;
939}
940
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530941QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx)
942{
943 int result;
944
945 ipa_debug("enter");
946
947 if (!ipa_ctx->ipa_pipes_down) {
948 /*
949 * IPA WDI Pipes are already activated due to
950 * rm deferred resources grant
951 */
952 ipa_warn("IPA WDI Pipes are already activated");
953 goto end;
954 }
955
956 result = cdp_ipa_enable_pipes(ipa_ctx->dp_soc,
957 ipa_ctx->dp_pdev);
958 if (result) {
959 ipa_err("Enable IPA WDI PIPE failed: ret=%d", result);
960 return QDF_STATUS_E_FAILURE;
961 }
962
963 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
964 ipa_ctx->ipa_pipes_down = false;
965
966 cdp_ipa_enable_autonomy(ipa_ctx->dp_soc,
967 ipa_ctx->dp_pdev);
968
969end:
970 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
971
972 return QDF_STATUS_SUCCESS;
973}
974
975QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx)
976{
977 int result;
978
979 ipa_debug("enter");
980
981 if (ipa_ctx->ipa_pipes_down) {
982 /*
983 * This shouldn't happen :
984 * IPA WDI Pipes are already deactivated
985 */
986 QDF_ASSERT(0);
987 ipa_warn("IPA WDI Pipes are already deactivated");
988 goto end;
989 }
990
991 cdp_ipa_disable_autonomy(ipa_ctx->dp_soc,
992 ipa_ctx->dp_pdev);
993
994 result = cdp_ipa_disable_pipes(ipa_ctx->dp_soc,
995 ipa_ctx->dp_pdev);
996 if (result) {
997 ipa_err("Disable IPA WDI PIPE failed: ret=%d", result);
998 return QDF_STATUS_E_FAILURE;
999 }
1000
1001 ipa_ctx->ipa_pipes_down = true;
1002
1003end:
1004 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
1005
1006 return QDF_STATUS_SUCCESS;
1007}
1008
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301009/**
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301010 * wlan_ipa_uc_find_add_assoc_sta() - Find associated station
1011 * @ipa_ctx: Global IPA IPA context
1012 * @sta_add: Should station be added
1013 * @sta_id: ID of the station being queried
1014 *
1015 * Return: true if the station was found
1016 */
1017static bool wlan_ipa_uc_find_add_assoc_sta(struct wlan_ipa_priv *ipa_ctx,
1018 bool sta_add, uint8_t sta_id,
1019 uint8_t *mac_addr)
1020{
1021 bool sta_found = false;
1022 uint8_t idx;
1023
1024 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1025 if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
1026 (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
1027 sta_found = true;
1028 break;
1029 }
1030 }
1031 if (sta_add && sta_found) {
1032 ipa_err("STA ID %d already exist, cannot add", sta_id);
1033 return sta_found;
1034 }
1035 if (sta_add) {
1036 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1037 if (!ipa_ctx->assoc_stas_map[idx].is_reserved) {
1038 ipa_ctx->assoc_stas_map[idx].is_reserved = true;
1039 ipa_ctx->assoc_stas_map[idx].sta_id = sta_id;
1040 qdf_mem_copy(&ipa_ctx->assoc_stas_map[idx].
1041 mac_addr, mac_addr,
1042 QDF_NET_ETH_LEN);
1043 return sta_found;
1044 }
1045 }
1046 }
1047 if (!sta_add && !sta_found) {
1048 ipa_err("STA ID %d does not exist, cannot delete", sta_id);
1049 return sta_found;
1050 }
1051 if (!sta_add) {
1052 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1053 if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
1054 (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
1055 ipa_ctx->assoc_stas_map[idx].is_reserved =
1056 false;
1057 ipa_ctx->assoc_stas_map[idx].sta_id = 0xFF;
1058 qdf_mem_set(&ipa_ctx->assoc_stas_map[idx].
1059 mac_addr, 0, QDF_NET_ETH_LEN);
1060 return sta_found;
1061 }
1062 }
1063 }
1064
1065 return sta_found;
1066}
1067
1068/**
1069 * wlan_ipa_get_ifaceid() - Get IPA context interface ID
1070 * @ipa_ctx: IPA context
1071 * @session_id: Session ID
1072 *
1073 * Return: None
1074 */
1075static int wlan_ipa_get_ifaceid(struct wlan_ipa_priv *ipa_ctx,
1076 uint8_t session_id)
1077{
1078 struct wlan_ipa_iface_context *iface_ctx;
1079 int i;
1080
1081 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1082 iface_ctx = &ipa_ctx->iface_context[i];
1083 if (iface_ctx->session_id == session_id)
1084 break;
1085 }
1086
1087 return i;
1088}
1089
1090/**
1091 * wlan_ipa_cleanup_iface() - Cleanup IPA on a given interface
1092 * @iface_context: interface-specific IPA context
1093 *
1094 * Return: None
1095 */
1096static void wlan_ipa_cleanup_iface(struct wlan_ipa_iface_context *iface_context)
1097{
1098 struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
1099
1100 ipa_debug("enter");
1101
1102 if (!iface_context->tl_context)
1103 return;
1104
1105 cdp_ipa_cleanup_iface(ipa_ctx->dp_soc,
1106 iface_context->dev->name,
1107 wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
1108
1109 qdf_spin_lock_bh(&iface_context->interface_lock);
1110 iface_context->tl_context = NULL;
1111 iface_context->dev = NULL;
1112 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
1113 iface_context->session_id = WLAN_IPA_MAX_SESSION;
1114 iface_context->sta_id = WLAN_IPA_MAX_STA_COUNT;
1115 qdf_spin_unlock_bh(&iface_context->interface_lock);
1116 iface_context->ifa_address = 0;
1117 if (!iface_context->ipa_ctx->num_iface) {
1118 ipa_err("NUM INTF 0, Invalid");
1119 QDF_ASSERT(0);
1120 }
1121 iface_context->ipa_ctx->num_iface--;
1122 ipa_debug("exit: num_iface=%d", iface_context->ipa_ctx->num_iface);
1123}
1124
1125/**
1126 * wlan_ipa_setup_iface() - Setup IPA on a given interface
1127 * @ipa_ctx: IPA IPA global context
1128 * @net_dev: Interface net device
1129 * @device_mode: Net interface device mode
1130 * @adapter: Interface upon which IPA is being setup
1131 * @sta_id: Station ID of the API instance
1132 * @session_id: Station ID of the API instance
1133 *
1134 * Return: QDF STATUS
1135 */
1136static QDF_STATUS wlan_ipa_setup_iface(struct wlan_ipa_priv *ipa_ctx,
1137 qdf_netdev_t net_dev,
1138 uint8_t device_mode, uint8_t sta_id,
1139 uint8_t session_id)
1140{
1141 struct wlan_ipa_iface_context *iface_context = NULL;
1142 void *tl_context = NULL;
1143 int i;
1144 QDF_STATUS status;
1145
1146 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
1147 * channel change indication. Since these indications are sent by lower
1148 * layer as SAP updates and IPA doesn't have to do anything for these
1149 * updates so ignoring!
1150 */
1151 if (device_mode == QDF_SAP_MODE) {
1152 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1153 iface_context = &(ipa_ctx->iface_context[i]);
1154 if (iface_context->dev == net_dev)
1155 return QDF_STATUS_SUCCESS;
1156 }
1157 }
1158
Yun Park21ec4902018-04-24 12:11:01 -07001159 if (WLAN_IPA_MAX_IFACE == ipa_ctx->num_iface) {
1160 ipa_err("Max interface reached %d", WLAN_IPA_MAX_IFACE);
1161 status = QDF_STATUS_E_NOMEM;
1162 QDF_ASSERT(0);
1163 goto end;
1164 }
1165
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301166 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1167 if (ipa_ctx->iface_context[i].tl_context == NULL) {
1168 iface_context = &(ipa_ctx->iface_context[i]);
1169 break;
1170 }
1171 }
1172
1173 if (iface_context == NULL) {
1174 ipa_err("All the IPA interfaces are in use");
1175 status = QDF_STATUS_E_NOMEM;
Yun Park21ec4902018-04-24 12:11:01 -07001176 QDF_ASSERT(0);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301177 goto end;
1178 }
1179
1180 iface_context->sta_id = sta_id;
1181 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(ipa_ctx->dp_soc,
1182 ipa_ctx->dp_pdev,
1183 sta_id);
1184 if (tl_context == NULL) {
1185 ipa_err("Not able to get TL context sta_id: %d", sta_id);
1186 status = QDF_STATUS_E_INVAL;
1187 goto end;
1188 }
1189
1190 iface_context->tl_context = tl_context;
1191 iface_context->dev = net_dev;
1192 iface_context->device_mode = device_mode;
1193 iface_context->session_id = session_id;
1194
1195 status = cdp_ipa_setup_iface(ipa_ctx->dp_soc, net_dev->name,
1196 net_dev->dev_addr,
1197 iface_context->prod_client,
1198 iface_context->cons_client,
1199 session_id,
1200 wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
1201 if (status != QDF_STATUS_SUCCESS)
1202 goto end;
1203
1204 ipa_ctx->num_iface++;
1205
1206 ipa_debug("exit: num_iface=%d", ipa_ctx->num_iface);
1207
1208 return status;
1209
1210end:
1211 if (iface_context)
1212 wlan_ipa_cleanup_iface(iface_context);
1213
1214 return status;
1215}
1216
1217/**
1218 * wlan_ipa_uc_handle_first_con() - Handle first uC IPA connection
1219 * @ipa_ctx: IPA context
1220 *
1221 * Return: QDF STATUS
1222 */
1223static QDF_STATUS wlan_ipa_uc_handle_first_con(struct wlan_ipa_priv *ipa_ctx)
1224{
1225 ipa_debug("enter");
1226
1227 ipa_ctx->activated_fw_pipe = 0;
1228 ipa_ctx->resource_loading = true;
1229
1230 /* If RM feature enabled
1231 * Request PROD Resource first
1232 * PROD resource may return sync or async manners
1233 */
1234 if (wlan_ipa_is_rm_enabled(ipa_ctx->config)) {
Yun Parke114fbf2018-04-05 20:02:12 -07001235 if (!wlan_ipa_wdi_rm_request_resource(ipa_ctx,
1236 IPA_RM_RESOURCE_WLAN_PROD)) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301237 /* RM PROD request sync return
1238 * enable pipe immediately
1239 */
1240 if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
1241 ipa_err("IPA WDI Pipe activation failed");
1242 ipa_ctx->resource_loading = false;
1243 return QDF_STATUS_E_BUSY;
1244 }
1245 } else {
1246 ipa_err("IPA WDI Pipe activation deferred");
1247 }
1248 } else {
1249 /* RM Disabled
1250 * Just enabled all the PIPEs
1251 */
1252 if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
1253 ipa_err("IPA WDI Pipe activation failed");
1254 ipa_ctx->resource_loading = false;
1255 return QDF_STATUS_E_BUSY;
1256 }
1257 ipa_ctx->resource_loading = false;
1258 }
1259
1260 ipa_debug("exit");
1261
1262 return QDF_STATUS_SUCCESS;
1263}
1264
1265/**
1266 * wlan_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1267 * @ipa_ctx: IPA context
1268 *
1269 * Return: None
1270 */
1271static void wlan_ipa_uc_handle_last_discon(struct wlan_ipa_priv *ipa_ctx)
1272{
1273 ipa_debug("enter");
1274
1275 ipa_ctx->resource_unloading = true;
1276 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
1277 ipa_info("Disable FW RX PIPE");
1278 cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, false);
1279 ipa_info("Disable FW TX PIPE");
1280 cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, true);
1281
1282 ipa_debug("exit: IPA WDI Pipes deactivated");
1283}
1284
1285/**
1286 * wlan_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
1287 * @ipa_ctx: global IPA context
1288 * @offload_type: MCC or SCC
1289 * @session_id: Session Id
1290 * @enable: TX offload enable or disable
1291 *
1292 * Return: none
1293 */
1294static void wlan_ipa_uc_offload_enable_disable(struct wlan_ipa_priv *ipa_ctx,
1295 uint32_t offload_type,
1296 uint8_t session_id,
1297 bool enable)
1298{
1299
1300 struct ipa_uc_offload_control_params req = {0};
1301
1302 if (session_id >= WLAN_IPA_MAX_SESSION) {
1303 ipa_err("invalid session id: %d", session_id);
1304 return;
1305 }
1306
1307 if (enable == ipa_ctx->vdev_offload_enabled[session_id]) {
1308 /*
1309 * This shouldn't happen :
1310 * IPA offload status is already set as desired
1311 */
1312 QDF_ASSERT(0);
1313 ipa_warn("IPA offload status is already set");
1314 ipa_warn("offload_type=%d, vdev_id=%d, enable=%d",
1315 offload_type, session_id, enable);
1316 return;
1317 }
1318
1319 ipa_info("offload_type=%d, session_id=%d, enable=%d",
1320 offload_type, session_id, enable);
1321
1322 req.offload_type = offload_type;
1323 req.vdev_id = session_id;
1324 req.enable = enable;
1325
1326 if (QDF_STATUS_SUCCESS !=
1327 ipa_send_uc_offload_enable_disable(ipa_ctx->pdev, &req)) {
1328 ipa_err("Fail to enable IPA offload");
1329 ipa_err("offload type=%d, vdev_id=%d, enable=%d",
1330 offload_type, session_id, enable);
1331 } else {
1332 ipa_ctx->vdev_offload_enabled[session_id] = enable;
1333 }
1334}
1335
1336/**
1337 * __wlan_ipa_wlan_evt() - IPA event handler
1338 * @net_dev: Interface net device
1339 * @device_mode: Net interface device mode
1340 * @sta_id: station id for the event
1341 * @session_id: session id for the event
1342 * @type: event enum of type ipa_wlan_event
1343 * @mac_address: MAC address associated with the event
1344 *
1345 * This function is meant to be called from within wlan_ipa_ctx.c
1346 *
1347 * Return: QDF STATUS
1348 */
1349static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
1350 uint8_t sta_id, uint8_t session_id,
1351 qdf_ipa_wlan_event type,
1352 uint8_t *mac_addr)
1353{
1354 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
1355 struct wlan_ipa_iface_context *iface_ctx = NULL;
1356 qdf_ipa_msg_meta_t meta;
1357 qdf_ipa_wlan_msg_t *msg;
1358 qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
1359 int i;
1360 QDF_STATUS status;
Ryan Hsub5783cf2018-05-14 12:13:15 -07001361 uint8_t sta_session_id = WLAN_IPA_MAX_SESSION;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301362
1363 ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d",
1364 net_dev->name, type, mac_addr, sta_id);
1365
1366 if (type >= QDF_IPA_WLAN_EVENT_MAX)
1367 return QDF_STATUS_E_INVAL;
1368
1369 if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
1370 !wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1371 (device_mode != QDF_SAP_MODE)) {
1372 return QDF_STATUS_SUCCESS;
1373 }
1374
Ryan Hsub5783cf2018-05-14 12:13:15 -07001375 if (ipa_ctx->sta_connected) {
1376 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
1377 if (iface_ctx)
1378 sta_session_id = iface_ctx->session_id;
1379 else
1380 ipa_err("sta iface_ctx is NULL");
1381 }
1382
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301383 /*
1384 * During IPA UC resource loading/unloading new events can be issued.
1385 */
1386 if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
1387 (ipa_ctx->resource_loading || ipa_ctx->resource_unloading)) {
1388 unsigned int pending_event_count;
1389 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1390
1391 ipa_info("Event:%d IPA resource %s inprogress", type,
1392 ipa_ctx->resource_loading ?
1393 "load" : "unload");
1394
1395 /* Wait until completion of the long/unloading */
1396 status = qdf_wait_for_event_completion(
1397 &ipa_ctx->ipa_resource_comp,
jiada8c542c2018-05-29 16:24:13 +08001398 IPA_RESOURCE_COMP_WAIT_TIME);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301399 if (status != QDF_STATUS_SUCCESS) {
1400 /*
1401 * If timed out, store the events separately and
1402 * handle them later.
1403 */
1404 ipa_info("IPA resource %s timed out",
1405 ipa_ctx->resource_loading ?
1406 "load" : "unload");
1407
1408 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1409
1410 pending_event_count =
1411 qdf_list_size(&ipa_ctx->pending_event);
1412 if (pending_event_count >=
1413 WLAN_IPA_MAX_PENDING_EVENT_COUNT) {
1414 ipa_info("Reached max pending evt count");
1415 qdf_list_remove_front(
1416 &ipa_ctx->pending_event,
1417 (qdf_list_node_t **)&pending_event);
1418 } else {
1419 pending_event =
1420 (struct wlan_ipa_uc_pending_event *)
1421 qdf_mem_malloc(sizeof(
1422 struct wlan_ipa_uc_pending_event));
1423 }
1424
1425 if (!pending_event) {
1426 ipa_err("Pending event memory alloc fail");
1427 qdf_mutex_release(&ipa_ctx->ipa_lock);
1428 return QDF_STATUS_E_NOMEM;
1429 }
1430
1431 pending_event->net_dev = net_dev;
1432 pending_event->device_mode = device_mode;
1433 pending_event->sta_id = sta_id;
1434 pending_event->session_id = session_id;
1435 pending_event->type = type;
1436 pending_event->is_loading = ipa_ctx->resource_loading;
1437 qdf_mem_copy(pending_event->mac_addr,
1438 mac_addr, QDF_MAC_ADDR_SIZE);
1439 qdf_list_insert_back(&ipa_ctx->pending_event,
1440 &pending_event->node);
1441
1442 qdf_mutex_release(&ipa_ctx->ipa_lock);
1443
Yun Park21ec4902018-04-24 12:11:01 -07001444 /* Cleanup interface */
1445 if (type == QDF_IPA_STA_DISCONNECT ||
1446 type == QDF_IPA_AP_DISCONNECT) {
1447 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1448 iface_ctx = &ipa_ctx->iface_context[i];
1449
1450 if (iface_ctx->dev == net_dev)
1451 break;
1452 }
1453 if (iface_ctx)
1454 wlan_ipa_cleanup_iface(iface_ctx);
1455 }
1456
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301457 return QDF_STATUS_SUCCESS;
1458 }
1459 ipa_info("IPA resource %s completed",
1460 ipa_ctx->resource_loading ?
1461 "load" : "unload");
1462 }
1463
1464 ipa_ctx->stats.event[type]++;
1465
1466 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1467 switch (type) {
1468 case QDF_IPA_STA_CONNECT:
1469 qdf_mutex_acquire(&ipa_ctx->event_lock);
1470
1471 /* STA already connected and without disconnect, connect again
1472 * This is Roaming scenario
1473 */
1474 if (ipa_ctx->sta_connected) {
1475 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
1476 if (iface_ctx)
1477 wlan_ipa_cleanup_iface(iface_ctx);
1478 }
1479
1480 status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
1481 sta_id, session_id);
1482 if (status != QDF_STATUS_SUCCESS) {
1483 qdf_mutex_release(&ipa_ctx->event_lock);
1484 goto end;
1485 }
1486
1487 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1488 (ipa_ctx->sap_num_connected_sta > 0) &&
1489 !ipa_ctx->sta_connected) {
1490 qdf_mutex_release(&ipa_ctx->event_lock);
1491 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1492 SIR_STA_RX_DATA_OFFLOAD, session_id,
1493 true);
1494 qdf_mutex_acquire(&ipa_ctx->event_lock);
1495 }
1496
1497 ipa_ctx->vdev_to_iface[session_id] =
1498 wlan_ipa_get_ifaceid(ipa_ctx, session_id);
1499
1500 ipa_ctx->sta_connected = 1;
1501
1502 qdf_mutex_release(&ipa_ctx->event_lock);
1503
1504 ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
1505 break;
1506
1507 case QDF_IPA_AP_CONNECT:
1508 qdf_mutex_acquire(&ipa_ctx->event_lock);
1509
1510 /* For DFS channel we get two start_bss event (before and after
1511 * CAC). Also when ACS range includes both DFS and non DFS
1512 * channels, we could possibly change channel many times due to
1513 * RADAR detection and chosen channel may not be a DFS channels.
1514 * So dont return error here. Just discard the event.
1515 */
jiadc908ada2018-05-11 14:40:54 +08001516 if (ipa_ctx->vdev_to_iface[session_id] !=
1517 WLAN_IPA_MAX_SESSION) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301518 qdf_mutex_release(&ipa_ctx->event_lock);
1519 return 0;
1520 }
1521
1522 status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
1523 sta_id, session_id);
1524 if (status != QDF_STATUS_SUCCESS) {
1525 qdf_mutex_release(&ipa_ctx->event_lock);
1526 ipa_err("%s: Evt: %d, Interface setup failed",
1527 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
1528 goto end;
1529 }
1530
1531 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1532 qdf_mutex_release(&ipa_ctx->event_lock);
1533 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1534 SIR_AP_RX_DATA_OFFLOAD, session_id, true);
1535 qdf_mutex_acquire(&ipa_ctx->event_lock);
1536 }
1537
1538 ipa_ctx->vdev_to_iface[session_id] =
1539 wlan_ipa_get_ifaceid(ipa_ctx, session_id);
1540 qdf_mutex_release(&ipa_ctx->event_lock);
1541 break;
1542
1543 case QDF_IPA_STA_DISCONNECT:
1544 qdf_mutex_acquire(&ipa_ctx->event_lock);
1545
1546 if (!ipa_ctx->sta_connected) {
1547 qdf_mutex_release(&ipa_ctx->event_lock);
1548 ipa_err("%s: Evt: %d, STA already disconnected",
1549 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
1550 return QDF_STATUS_E_INVAL;
1551 }
1552
1553 ipa_ctx->sta_connected = 0;
1554
1555 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1556 ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
1557 msg_ex->name);
1558 } else {
1559 /* Disable IPA UC TX PIPE when STA disconnected */
1560 if ((ipa_ctx->num_iface == 1) &&
Yun Parka29974a2018-04-09 12:05:49 -07001561 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301562 !ipa_ctx->ipa_pipes_down)
1563 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1564 }
1565
1566 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1567 (ipa_ctx->sap_num_connected_sta > 0)) {
1568 qdf_mutex_release(&ipa_ctx->event_lock);
1569 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1570 SIR_STA_RX_DATA_OFFLOAD, session_id, false);
1571 qdf_mutex_acquire(&ipa_ctx->event_lock);
1572 ipa_ctx->vdev_to_iface[session_id] =
1573 WLAN_IPA_MAX_SESSION;
1574 }
1575
1576 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1577 iface_ctx = &ipa_ctx->iface_context[i];
1578
1579 if (iface_ctx->dev == net_dev)
1580 break;
1581 }
1582 if (i < WLAN_IPA_MAX_IFACE)
1583 wlan_ipa_cleanup_iface(iface_ctx);
1584
1585 qdf_mutex_release(&ipa_ctx->event_lock);
1586
1587 ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
1588 break;
1589
1590 case QDF_IPA_AP_DISCONNECT:
1591 qdf_mutex_acquire(&ipa_ctx->event_lock);
1592
1593 if ((ipa_ctx->num_iface == 1) &&
Yun Parka29974a2018-04-09 12:05:49 -07001594 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301595 !ipa_ctx->ipa_pipes_down) {
1596 if (cds_is_driver_unloading()) {
1597 /*
1598 * We disable WDI pipes directly here since
1599 * IPA_OPCODE_TX/RX_SUSPEND message will not be
1600 * processed when unloading WLAN driver is in
1601 * progress
1602 */
1603 wlan_ipa_uc_disable_pipes(ipa_ctx);
1604 } else {
1605 /*
1606 * This shouldn't happen :
1607 * No interface left but WDI pipes are still
1608 * active - force close WDI pipes
1609 */
1610 ipa_err("No interface left but WDI pipes are still active");
1611 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1612 }
1613 }
1614
1615 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1616 qdf_mutex_release(&ipa_ctx->event_lock);
1617 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1618 SIR_AP_RX_DATA_OFFLOAD, session_id, false);
1619 qdf_mutex_acquire(&ipa_ctx->event_lock);
1620 ipa_ctx->vdev_to_iface[session_id] =
1621 WLAN_IPA_MAX_SESSION;
1622 }
1623
1624 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1625 iface_ctx = &ipa_ctx->iface_context[i];
1626
1627 if (iface_ctx->dev == net_dev)
1628 break;
1629 }
1630 if (i < WLAN_IPA_MAX_IFACE)
1631 wlan_ipa_cleanup_iface(iface_ctx);
1632
1633 qdf_mutex_release(&ipa_ctx->event_lock);
1634 break;
1635
1636 case QDF_IPA_CLIENT_CONNECT_EX:
1637 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1638 ipa_debug("%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
1639 net_dev->name, type);
1640 return QDF_STATUS_SUCCESS;
1641 }
1642
1643 qdf_mutex_acquire(&ipa_ctx->event_lock);
1644 if (wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, true, sta_id,
1645 mac_addr)) {
1646 qdf_mutex_release(&ipa_ctx->event_lock);
1647 ipa_err("%s: STA ID %d found", net_dev->name, sta_id);
1648 return QDF_STATUS_SUCCESS;
1649 }
1650
1651 /* Enable IPA UC Data PIPEs when first STA connected */
1652 if (ipa_ctx->sap_num_connected_sta == 0 &&
1653 ipa_ctx->uc_loaded == true) {
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301654
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301655 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1656 ipa_ctx->sta_connected) {
1657 qdf_mutex_release(&ipa_ctx->event_lock);
1658 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1659 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301660 sta_session_id, true);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301661 qdf_mutex_acquire(&ipa_ctx->event_lock);
1662 }
1663
1664 status = wlan_ipa_uc_handle_first_con(ipa_ctx);
1665 if (status != QDF_STATUS_SUCCESS) {
1666 ipa_info("%s: handle 1st con fail",
1667 net_dev->name);
1668
1669 if (wlan_ipa_uc_sta_is_enabled(
1670 ipa_ctx->config) &&
1671 ipa_ctx->sta_connected) {
1672 qdf_mutex_release(&ipa_ctx->event_lock);
1673 wlan_ipa_uc_offload_enable_disable(
1674 ipa_ctx,
1675 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301676 sta_session_id, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301677 } else {
1678 qdf_mutex_release(&ipa_ctx->event_lock);
1679 }
1680
1681 return status;
1682 }
1683 }
1684
1685 ipa_ctx->sap_num_connected_sta++;
1686
1687 qdf_mutex_release(&ipa_ctx->event_lock);
1688
1689 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1690 QDF_IPA_MSG_META_MSG_LEN(&meta) =
1691 (sizeof(qdf_ipa_wlan_msg_ex_t) +
1692 sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
1693 msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1694
1695 if (msg_ex == NULL) {
1696 ipa_err("msg_ex allocation failed");
1697 return QDF_STATUS_E_NOMEM;
1698 }
1699 strlcpy(msg_ex->name, net_dev->name,
1700 IPA_RESOURCE_NAME_MAX);
1701 msg_ex->num_of_attribs = 1;
1702 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
1703 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1704 msg_ex->attribs[0].offset =
1705 WLAN_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
1706 } else {
1707 msg_ex->attribs[0].offset =
1708 WLAN_IPA_WLAN_HDR_DES_MAC_OFFSET;
1709 }
1710 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
1711 IPA_MAC_ADDR_SIZE);
1712
1713 if (qdf_ipa_send_msg(&meta, msg_ex, wlan_ipa_msg_free_fn)) {
1714 ipa_info("%s: Evt: %d send ipa msg fail",
1715 net_dev->name, type);
1716 qdf_mem_free(msg_ex);
1717 return QDF_STATUS_E_FAILURE;
1718 }
1719 ipa_ctx->stats.num_send_msg++;
1720
1721 ipa_info("sap_num_connected_sta=%d",
1722 ipa_ctx->sap_num_connected_sta);
1723
1724 return QDF_STATUS_SUCCESS;
1725
1726 case WLAN_CLIENT_DISCONNECT:
1727 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1728 ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
1729 msg_ex->name);
1730 return QDF_STATUS_SUCCESS;
1731 }
1732
1733 qdf_mutex_acquire(&ipa_ctx->event_lock);
1734 if (!ipa_ctx->sap_num_connected_sta) {
1735 qdf_mutex_release(&ipa_ctx->event_lock);
1736 ipa_err("%s: Evt: %d, Client already disconnected",
1737 msg_ex->name,
1738 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1739
1740 return QDF_STATUS_SUCCESS;
1741 }
1742 if (!wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, false,
1743 sta_id, mac_addr)) {
1744 qdf_mutex_release(&ipa_ctx->event_lock);
1745 ipa_err("%s: STA ID %d NOT found, not valid",
1746 msg_ex->name, sta_id);
1747
1748 return QDF_STATUS_SUCCESS;
1749 }
1750 ipa_ctx->sap_num_connected_sta--;
1751
1752 /* Disable IPA UC TX PIPE when last STA disconnected */
1753 if (!ipa_ctx->sap_num_connected_sta &&
1754 ipa_ctx->uc_loaded == true) {
Yun Parka29974a2018-04-09 12:05:49 -07001755 if ((false == ipa_ctx->resource_unloading) &&
1756 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
1757 !ipa_ctx->ipa_pipes_down) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301758 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1759 }
1760
1761 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1762 ipa_ctx->sta_connected) {
1763 qdf_mutex_release(&ipa_ctx->event_lock);
1764 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1765 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301766 sta_session_id, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301767 } else {
1768 qdf_mutex_release(&ipa_ctx->event_lock);
1769 }
1770 } else {
1771 qdf_mutex_release(&ipa_ctx->event_lock);
1772 }
1773
1774 ipa_info("sap_num_connected_sta=%d",
1775 ipa_ctx->sap_num_connected_sta);
1776 break;
1777
1778 default:
1779 return QDF_STATUS_SUCCESS;
1780 }
1781
1782 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
1783 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1784 if (!msg) {
1785 ipa_err("msg allocation failed");
1786 return QDF_STATUS_E_NOMEM;
1787 }
1788
1789 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1790 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name,
1791 IPA_RESOURCE_NAME_MAX);
1792 qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN);
1793
1794 ipa_debug("%s: Evt: %d", QDF_IPA_WLAN_MSG_NAME(msg),
1795 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1796
1797 if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) {
1798
1799 ipa_err("%s: Evt: %d fail",
1800 QDF_IPA_WLAN_MSG_NAME(msg),
1801 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1802 qdf_mem_free(msg);
1803
1804 return QDF_STATUS_E_FAILURE;
1805 }
1806
1807 ipa_ctx->stats.num_send_msg++;
1808
1809end:
1810 return QDF_STATUS_SUCCESS;
1811}
1812
1813/**
1814 * wlan_host_to_ipa_wlan_event() - convert wlan_ipa_wlan_event to ipa_wlan_event
Yun Park84fbb272018-04-02 15:31:01 -07001815 * @wlan_ipa_event_type: event to be converted to an ipa_wlan_event
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301816 *
1817 * Return: qdf_ipa_wlan_event representing the wlan_ipa_wlan_event
1818 */
1819static qdf_ipa_wlan_event
1820wlan_host_to_ipa_wlan_event(enum wlan_ipa_wlan_event wlan_ipa_event_type)
1821{
Yun Park84fbb272018-04-02 15:31:01 -07001822 qdf_ipa_wlan_event ipa_event;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301823
1824 switch (wlan_ipa_event_type) {
1825 case WLAN_IPA_CLIENT_CONNECT:
1826 ipa_event = QDF_IPA_CLIENT_CONNECT;
1827 break;
1828 case WLAN_IPA_CLIENT_DISCONNECT:
1829 ipa_event = QDF_IPA_CLIENT_DISCONNECT;
1830 break;
1831 case WLAN_IPA_AP_CONNECT:
1832 ipa_event = QDF_IPA_AP_CONNECT;
1833 break;
1834 case WLAN_IPA_AP_DISCONNECT:
1835 ipa_event = QDF_IPA_AP_DISCONNECT;
1836 break;
1837 case WLAN_IPA_STA_CONNECT:
1838 ipa_event = QDF_IPA_STA_CONNECT;
1839 break;
1840 case WLAN_IPA_STA_DISCONNECT:
1841 ipa_event = QDF_IPA_STA_DISCONNECT;
1842 break;
1843 case WLAN_IPA_CLIENT_CONNECT_EX:
1844 ipa_event = QDF_IPA_CLIENT_CONNECT_EX;
1845 break;
1846 case WLAN_IPA_WLAN_EVENT_MAX:
1847 default:
1848 ipa_event = QDF_IPA_WLAN_EVENT_MAX;
1849 break;
1850 }
1851
1852 return ipa_event;
1853}
1854
1855/**
1856 * wlan_ipa_wlan_evt() - SSR wrapper for __wlan_ipa_wlan_evt
1857 * @net_dev: Interface net device
1858 * @device_mode: Net interface device mode
1859 * @sta_id: station id for the event
1860 * @session_id: session id for the event
1861 * @ipa_event_type: event enum of type wlan_ipa_wlan_event
1862 * @mac_address: MAC address associated with the event
1863 *
1864 * Return: QDF_STATUS
1865 */
1866QDF_STATUS wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
1867 uint8_t sta_id, uint8_t session_id,
1868 enum wlan_ipa_wlan_event ipa_event_type,
1869 uint8_t *mac_addr)
1870{
1871 qdf_ipa_wlan_event type = wlan_host_to_ipa_wlan_event(ipa_event_type);
1872 QDF_STATUS status = QDF_STATUS_SUCCESS;
1873
1874 /* Data path offload only support for STA and SAP mode */
1875 if ((device_mode == QDF_STA_MODE) ||
1876 (device_mode == QDF_SAP_MODE))
1877 status = __wlan_ipa_wlan_evt(net_dev, device_mode, sta_id,
1878 session_id, type, mac_addr);
1879
1880 return status;
1881}
1882
1883/**
1884 * wlan_ipa_uc_proc_pending_event() - Process IPA uC pending events
1885 * @ipa_ctx: Global IPA IPA context
1886 * @is_loading: Indicate if invoked during loading
1887 *
1888 * Return: None
1889 */
1890static void
1891wlan_ipa_uc_proc_pending_event(struct wlan_ipa_priv *ipa_ctx, bool is_loading)
1892{
1893 unsigned int pending_event_count;
1894 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1895
1896 pending_event_count = qdf_list_size(&ipa_ctx->pending_event);
1897 ipa_debug("Pending Event Count %d", pending_event_count);
1898 if (!pending_event_count) {
1899 ipa_debug("No Pending Event");
1900 return;
1901 }
1902
1903 qdf_list_remove_front(&ipa_ctx->pending_event,
1904 (qdf_list_node_t **)&pending_event);
1905 while (pending_event != NULL) {
Sravan Kumar Kairam8c151e22018-06-15 16:35:39 +05301906 struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
1907 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
1908 struct wlan_objmgr_vdev *vdev =
1909 wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
1910 pending_event->session_id,
1911 WLAN_IPA_ID);
1912 if (pending_event->is_loading == is_loading && vdev) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301913 __wlan_ipa_wlan_evt(pending_event->net_dev,
1914 pending_event->device_mode,
1915 pending_event->sta_id,
1916 pending_event->session_id,
1917 pending_event->type,
1918 pending_event->mac_addr);
1919 }
Sravan Kumar Kairam8c151e22018-06-15 16:35:39 +05301920
1921 if (vdev)
1922 wlan_objmgr_vdev_release_ref(vdev, WLAN_IPA_ID);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301923 qdf_mem_free(pending_event);
1924 pending_event = NULL;
1925 qdf_list_remove_front(&ipa_ctx->pending_event,
1926 (qdf_list_node_t **)&pending_event);
1927 }
1928}
1929
1930/**
Ryan Hsub5783cf2018-05-14 12:13:15 -07001931 * wlan_ipa_free_tx_desc_list() - Free IPA Tx desc list
1932 * @ipa_ctx: IPA context
1933 *
1934 * Return: None
1935 */
1936static inline void wlan_ipa_free_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
1937{
1938 struct wlan_ipa_tx_desc *tmp_desc;
1939 qdf_ipa_rx_data_t *ipa_tx_desc;
1940 qdf_list_node_t *node;
1941
1942 while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) ==
1943 QDF_STATUS_SUCCESS) {
1944 tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc,
1945 node);
1946
1947 ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
1948 if (ipa_tx_desc)
1949 qdf_ipa_free_skb(ipa_tx_desc);
1950
1951 qdf_mem_free(tmp_desc);
1952 tmp_desc = NULL;
1953 }
1954}
1955
1956/**
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301957 * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
1958 * @ipa_ctx: IPA context
1959 *
1960 * Return: QDF_STATUS
1961 */
Ryan Hsub5783cf2018-05-14 12:13:15 -07001962static QDF_STATUS wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301963{
1964 int i;
1965 uint32_t max_desc_cnt;
1966 struct wlan_ipa_tx_desc *tmp_desc;
1967
1968 max_desc_cnt = ipa_ctx->config->txbuf_count;
1969
1970 qdf_list_create(&ipa_ctx->tx_desc_list, max_desc_cnt);
1971
1972 qdf_spin_lock_bh(&ipa_ctx->q_lock);
1973 for (i = 0; i < max_desc_cnt; i++) {
1974 tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc));
Ryan Hsub5783cf2018-05-14 12:13:15 -07001975
1976 if (!tmp_desc) {
1977 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
1978 goto alloc_fail;
1979 }
1980
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301981 tmp_desc->id = i;
1982 tmp_desc->ipa_tx_desc_ptr = NULL;
1983 qdf_list_insert_back(&ipa_ctx->tx_desc_list,
1984 &tmp_desc->node);
1985 tmp_desc++;
1986 }
1987
1988 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
1989 ipa_ctx->stats.num_tx_desc_error = 0;
1990
1991 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
1992
1993 return QDF_STATUS_SUCCESS;
Ryan Hsub5783cf2018-05-14 12:13:15 -07001994
1995alloc_fail:
1996 wlan_ipa_free_tx_desc_list(ipa_ctx);
1997 return QDF_STATUS_E_NOMEM;
1998
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301999}
2000
2001#ifndef QCA_LL_TX_FLOW_CONTROL_V2
2002/**
2003 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
2004 * @ipa_ctx: Global IPA IPA context
2005 * @desc_fifo_sz: Number of descriptors
2006 *
2007 * Return: 0 on success, negative errno on error
2008 */
2009static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2010 int32_t desc_fifo_sz)
2011{
2012 int i, ret = 0;
2013 qdf_ipa_sys_connect_params_t *ipa;
2014
2015 /*setup TX pipes */
2016 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2017 ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params;
2018
2019 ipa->client = wlan_ipa_iface_2_client[i].cons_client;
2020 ipa->desc_fifo_sz = desc_fifo_sz;
2021 ipa->priv = &ipa_ctx->iface_context[i];
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302022 ipa->notify = wlan_ipa_i2w_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302023
2024 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2025 ipa->ipa_ep_cfg.hdr.hdr_len =
2026 WLAN_IPA_UC_WLAN_TX_HDR_LEN;
2027 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2028 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2029 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2030 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
2031 WLAN_IPA_UC_WLAN_8023_HDR_SIZE;
2032 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2033 } else {
2034 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN;
2035 }
2036 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
2037
2038 ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa,
2039 &ipa_ctx->sys_pipe[i].conn_hdl);
2040 if (ret) {
2041 ipa_err("Failed for pipe %d ret: %d", i, ret);
2042 return ret;
2043 }
2044 ipa_ctx->sys_pipe[i].conn_hdl_valid = 1;
2045 }
2046
2047 return ret;
2048}
2049#else
2050/**
2051 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
2052 * @ipa_ctx: Global IPA IPA context
2053 * @desc_fifo_sz: Number of descriptors
2054 *
2055 * Return: 0 on success, negative errno on error
2056 */
2057static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2058 int32_t desc_fifo_sz)
2059{
2060 /*
2061 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
2062 * is enabled, where per vdev descriptors are supported in firmware.
2063 */
2064 return 0;
2065}
2066#endif
2067
2068/**
2069 * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
2070 * @ipa_ctx: Global IPA IPA context
2071 * @desc_fifo_sz: Number of descriptors
2072 *
2073 * Return: 0 on success, negative errno on error
2074 */
2075static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2076 int32_t desc_fifo_sz)
2077{
2078 int ret = 0;
2079 qdf_ipa_sys_connect_params_t *ipa;
2080
2081 /*
2082 * Hard code it here, this can be extended if in case
2083 * PROD pipe is also per interface.
2084 * Right now there is no advantage of doing this.
2085 */
2086 ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params;
2087
2088 ipa->client = IPA_CLIENT_WLAN1_PROD;
2089
2090 ipa->desc_fifo_sz = desc_fifo_sz;
2091 ipa->priv = ipa_ctx;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302092 ipa->notify = wlan_ipa_w2i_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302093
2094 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2095 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN;
2096 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
2097 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
2098
2099 ret = qdf_ipa_setup_sys_pipe(ipa,
2100 &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl);
2101 if (ret) {
2102 ipa_err("Failed for RX pipe: %d", ret);
2103 return ret;
2104 }
2105 ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1;
2106
2107 return ret;
2108}
2109
2110/**
Ryan Hsub5783cf2018-05-14 12:13:15 -07002111 * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
2112 * @ipa_ctx: Global IPA IPA context
2113 *
2114 * Return: None
2115 */
2116static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
2117{
2118 int ret, i;
2119
2120 if (!ipa_ctx)
2121 return;
2122
2123 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
2124 if (ipa_ctx->sys_pipe[i].conn_hdl_valid) {
2125 ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx,
2126 ipa_ctx->sys_pipe[i].conn_hdl);
2127 if (ret)
2128 ipa_err("Failed:%d", ret);
2129
2130 ipa_ctx->sys_pipe[i].conn_hdl_valid = 0;
2131 }
2132 }
2133
2134 wlan_ipa_free_tx_desc_list(ipa_ctx);
2135}
2136
2137/**
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302138 * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
2139 * @ipa_ctx: Global IPA IPA context
2140 *
2141 * Return: 0 on success, negative errno on error
2142 */
2143static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
2144{
Ryan Hsub5783cf2018-05-14 12:13:15 -07002145 int ret = 0;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302146 uint32_t desc_fifo_sz;
2147
2148 /* The maximum number of descriptors that can be provided to a BAM at
2149 * once is one less than the total number of descriptors that the buffer
2150 * can contain.
2151 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
2152 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
2153 * be provided at once.
2154 * Because of above requirement, one extra descriptor will be added to
2155 * make sure hardware always has one descriptor.
2156 */
2157 desc_fifo_sz = ipa_ctx->config->desc_size
2158 + SPS_DESC_SIZE;
2159
2160 ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz);
2161 if (ret) {
2162 ipa_err("Failed for TX pipe: %d", ret);
2163 goto setup_sys_pipe_fail;
2164 }
2165
2166 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2167 ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz);
2168 if (ret) {
2169 ipa_err("Failed for RX pipe: %d", ret);
2170 goto setup_sys_pipe_fail;
2171 }
2172 }
2173
2174 /* Allocate free Tx desc list */
2175 ret = wlan_ipa_alloc_tx_desc_list(ipa_ctx);
2176 if (ret)
2177 goto setup_sys_pipe_fail;
2178
2179 return ret;
2180
2181setup_sys_pipe_fail:
Ryan Hsub5783cf2018-05-14 12:13:15 -07002182 wlan_ipa_teardown_sys_pipe(ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302183
2184 return ret;
2185}
2186
jiadbb47e132018-03-30 16:28:30 +08002187#ifndef QCA_LL_TX_FLOW_CONTROL_V2
2188QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
2189 bool mcc_mode)
2190{
2191 qdf_ipa_msg_meta_t meta;
2192 qdf_ipa_wlan_msg_t *msg;
2193 int ret;
2194
2195 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
2196 return QDF_STATUS_SUCCESS;
2197
2198 /* Send SCC/MCC Switching event to IPA */
2199 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
2200 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
2201 if (msg == NULL) {
2202 ipa_err("msg allocation failed");
2203 return QDF_STATUS_E_NOMEM;
2204 }
2205
jiad629b2172018-05-11 15:34:22 +08002206 if (mcc_mode) {
jiadbb47e132018-03-30 16:28:30 +08002207 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_MCC);
jiad629b2172018-05-11 15:34:22 +08002208 ipa_ctx->stats.event[QDF_SWITCH_TO_MCC]++;
2209 } else {
jiadbb47e132018-03-30 16:28:30 +08002210 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_SCC);
jiad629b2172018-05-11 15:34:22 +08002211 ipa_ctx->stats.event[QDF_SWITCH_TO_SCC]++;
2212 }
2213
jiadbb47e132018-03-30 16:28:30 +08002214 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2215 "ipa_send_msg(Evt:%d)",
2216 QDF_IPA_MSG_META_MSG_TYPE(&meta));
2217
2218 ret = qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn);
2219
2220 if (ret) {
2221 ipa_err("ipa_send_msg(Evt:%d) - fail=%d",
2222 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
2223 qdf_mem_free(msg);
2224 return QDF_STATUS_E_FAILURE;
2225 }
2226
2227 return QDF_STATUS_SUCCESS;
2228}
2229
2230static void wlan_ipa_mcc_work_handler(void *data)
2231{
2232 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
2233
2234 wlan_ipa_send_mcc_scc_msg(ipa_ctx, ipa_ctx->mcc_mode);
2235}
2236#endif
2237
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302238/**
2239 * wlan_ipa_setup() - IPA initialization function
2240 * @ipa_ctx: IPA context
2241 * @ipa_cfg: IPA config
2242 *
2243 * Allocate ipa_ctx resources, ipa pipe resource and register
2244 * wlan interface with IPA module.
2245 *
2246 * Return: QDF_STATUS enumeration
2247 */
2248QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
2249 struct wlan_ipa_config *ipa_cfg)
2250{
2251 int ret, i;
2252 struct wlan_ipa_iface_context *iface_context = NULL;
2253 QDF_STATUS status;
2254
2255 ipa_debug("enter");
2256
2257 gp_ipa = ipa_ctx;
2258 ipa_ctx->num_iface = 0;
2259 ipa_ctx->config = ipa_cfg;
2260
2261 wlan_ipa_wdi_get_wdi_version(ipa_ctx);
2262
2263 /* Create the interface context */
2264 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2265 iface_context = &ipa_ctx->iface_context[i];
2266 iface_context->ipa_ctx = ipa_ctx;
2267 iface_context->cons_client =
2268 wlan_ipa_iface_2_client[i].cons_client;
2269 iface_context->prod_client =
2270 wlan_ipa_iface_2_client[i].prod_client;
2271 iface_context->iface_id = i;
2272 iface_context->dev = NULL;
2273 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
2274 iface_context->tl_context = NULL;
2275 qdf_spinlock_create(&iface_context->interface_lock);
2276 }
2277
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302278 qdf_create_work(0, &ipa_ctx->pm_work, wlan_ipa_pm_flush, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302279 qdf_spinlock_create(&ipa_ctx->pm_lock);
2280 qdf_spinlock_create(&ipa_ctx->q_lock);
2281 qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head);
2282 qdf_list_create(&ipa_ctx->pending_event, 1000);
2283 qdf_mutex_create(&ipa_ctx->event_lock);
2284 qdf_mutex_create(&ipa_ctx->ipa_lock);
2285
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302286 status = wlan_ipa_wdi_setup_rm(ipa_ctx);
2287 if (status != QDF_STATUS_SUCCESS)
2288 goto fail_setup_rm;
2289
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302290 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++)
2291 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
2292 sizeof(struct wlan_ipa_sys_pipe));
2293
2294 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
2295 qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats));
2296 ipa_ctx->sap_num_connected_sta = 0;
2297 ipa_ctx->ipa_tx_packets_diff = 0;
2298 ipa_ctx->ipa_rx_packets_diff = 0;
2299 ipa_ctx->ipa_p_tx_packets = 0;
2300 ipa_ctx->ipa_p_rx_packets = 0;
2301 ipa_ctx->resource_loading = false;
2302 ipa_ctx->resource_unloading = false;
2303 ipa_ctx->sta_connected = 0;
2304 ipa_ctx->ipa_pipes_down = true;
2305 ipa_ctx->wdi_enabled = false;
2306 /* Setup IPA system pipes */
2307 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2308 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
2309 if (ret)
2310 goto fail_create_sys_pipe;
jiadbb47e132018-03-30 16:28:30 +08002311
2312 qdf_create_work(0, &ipa_ctx->mcc_work,
2313 wlan_ipa_mcc_work_handler, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302314 }
2315
2316 status = wlan_ipa_wdi_init(ipa_ctx);
2317 if (status == QDF_STATUS_E_BUSY)
2318 status = wlan_ipa_uc_send_wdi_control_msg(false);
2319 if (status != QDF_STATUS_SUCCESS) {
Ryan Hsub5783cf2018-05-14 12:13:15 -07002320 ipa_err("IPA WDI init failed: ret=%d", status);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302321 goto fail_create_sys_pipe;
2322 }
2323 } else {
2324 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
2325 if (ret)
2326 goto fail_create_sys_pipe;
2327 }
2328
2329 qdf_event_create(&ipa_ctx->ipa_resource_comp);
2330
2331 ipa_debug("exit: success");
2332
2333 return QDF_STATUS_SUCCESS;
2334
2335fail_create_sys_pipe:
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302336 wlan_ipa_wdi_destroy_rm(ipa_ctx);
2337
2338fail_setup_rm:
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302339 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302340 qdf_spinlock_destroy(&ipa_ctx->q_lock);
2341 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2342 iface_context = &ipa_ctx->iface_context[i];
2343 qdf_spinlock_destroy(&iface_context->interface_lock);
2344 }
2345 qdf_mutex_destroy(&ipa_ctx->event_lock);
2346 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
2347 qdf_list_destroy(&ipa_ctx->pending_event);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302348 gp_ipa = NULL;
2349 ipa_debug("exit: fail");
2350
2351 return QDF_STATUS_E_FAILURE;
2352}
2353
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302354void wlan_ipa_flush(struct wlan_ipa_priv *ipa_ctx)
2355{
2356 qdf_nbuf_t skb;
2357 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
2358
2359 if (!wlan_ipa_is_enabled(ipa_ctx->config))
2360 return;
2361
2362 qdf_cancel_work(&ipa_ctx->pm_work);
2363
2364 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
2365
2366 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head))
2367 != NULL)) {
2368 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
2369
2370 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
jiadab8cea02018-05-24 09:16:14 +08002371
2372 if (pm_tx_cb->exception) {
2373 dev_kfree_skb_any(skb);
2374 } else {
2375 if (pm_tx_cb->ipa_tx_desc)
2376 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
2377 }
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302378
2379 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
2380 }
2381 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
2382}
2383
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302384QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx)
2385{
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302386 struct wlan_ipa_iface_context *iface_context;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302387 int i;
2388
2389 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2390 wlan_ipa_teardown_sys_pipe(ipa_ctx);
2391
2392 /* Teardown IPA sys_pipe for MCC */
jiadbb47e132018-03-30 16:28:30 +08002393 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302394 wlan_ipa_teardown_sys_pipe(ipa_ctx);
jiadbb47e132018-03-30 16:28:30 +08002395 qdf_cancel_work(&ipa_ctx->mcc_work);
2396 }
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302397
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302398 wlan_ipa_wdi_destroy_rm(ipa_ctx);
2399
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302400 wlan_ipa_flush(ipa_ctx);
2401
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302402 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
2403 qdf_spinlock_destroy(&ipa_ctx->q_lock);
2404
2405 /* destroy the interface lock */
2406 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2407 iface_context = &ipa_ctx->iface_context[i];
2408 qdf_spinlock_destroy(&iface_context->interface_lock);
2409 }
2410
2411 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
2412 wlan_ipa_wdi_cleanup();
2413 qdf_mutex_destroy(&ipa_ctx->event_lock);
2414 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
2415 qdf_list_destroy(&ipa_ctx->pending_event);
2416
2417 }
2418
2419 gp_ipa = NULL;
2420
2421 return QDF_STATUS_SUCCESS;
2422}
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +05302423
2424struct wlan_ipa_iface_context
2425*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode)
2426{
2427 struct wlan_ipa_iface_context *iface_ctx = NULL;
2428 int i;
2429
2430 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2431 iface_ctx = &ipa_ctx->iface_context[i];
2432
2433 if (iface_ctx->device_mode == mode)
2434 return iface_ctx;
2435 }
2436
2437 return NULL;
2438}
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302439
jiadbb47e132018-03-30 16:28:30 +08002440void wlan_ipa_set_mcc_mode(struct wlan_ipa_priv *ipa_ctx, bool mcc_mode)
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302441{
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302442 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
jiadbb47e132018-03-30 16:28:30 +08002443 return;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302444
jiadbb47e132018-03-30 16:28:30 +08002445 if (ipa_ctx->mcc_mode == mcc_mode)
2446 return;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302447
jiadbb47e132018-03-30 16:28:30 +08002448 ipa_ctx->mcc_mode = mcc_mode;
2449 qdf_sched_work(0, &ipa_ctx->mcc_work);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302450}
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302451
2452/**
2453 * wlan_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2454 * @ipa_ctx: ipa ipa local context
2455 *
2456 * Will handle IPA UC image loaded indication comes from IPA kernel
2457 *
2458 * Return: None
2459 */
2460static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx)
2461{
2462 struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
2463 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
2464 qdf_device_t qdf_dev = wlan_psoc_get_qdf_dev(psoc);
2465 QDF_STATUS status;
2466
2467 ipa_info("UC READY");
Ryan Hsub5783cf2018-05-14 12:13:15 -07002468
2469 if (!qdf_dev) {
2470 ipa_err("qdf device is NULL!");
2471 return;
2472 }
2473
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302474 if (true == ipa_ctx->uc_loaded) {
2475 ipa_info("UC already loaded");
2476 return;
2477 }
2478
Lihua Liu15f6e452018-05-30 17:31:06 +08002479 if (!qdf_dev) {
2480 ipa_err("qdf_dev is null");
2481 return;
2482 }
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302483 /* Connect pipe */
2484 status = wlan_ipa_wdi_setup(ipa_ctx, qdf_dev);
2485 if (status) {
2486 ipa_err("Failure to setup IPA pipes (status=%d)",
2487 status);
2488 return;
2489 }
2490
2491 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302492
2493 /* If already any STA connected, enable IPA/FW PIPEs */
2494 if (ipa_ctx->sap_num_connected_sta) {
2495 ipa_debug("Client already connected, enable IPA/FW PIPEs");
2496 wlan_ipa_uc_handle_first_con(ipa_ctx);
2497 }
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302498}
2499
2500/**
2501 * wlan_ipa_uc_op_cb() - IPA uC operation callback
2502 * @op_msg: operation message received from firmware
2503 * @usr_ctxt: user context registered with TL (we register the IPA Global
2504 * context)
2505 *
2506 * Return: None
2507 */
2508static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
2509 struct wlan_ipa_priv *ipa_ctx)
2510{
2511 struct op_msg_type *msg = op_msg;
2512 struct ipa_uc_fw_stats *uc_fw_stat;
2513
2514 if (!op_msg) {
2515 ipa_err("INVALID ARG");
2516 return;
2517 }
2518
2519 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
2520 ipa_err("INVALID OPCODE %d", msg->op_code);
2521 qdf_mem_free(op_msg);
2522 return;
2523 }
2524
2525 ipa_debug("OPCODE=%d", msg->op_code);
2526
2527 if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_RESUME) ||
2528 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_RESUME)) {
2529 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2530 ipa_ctx->activated_fw_pipe++;
Yun Parka29974a2018-04-09 12:05:49 -07002531 if (wlan_ipa_is_fw_wdi_activated(ipa_ctx)) {
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302532 ipa_ctx->resource_loading = false;
2533 qdf_event_set(&ipa_ctx->ipa_resource_comp);
2534 if (ipa_ctx->wdi_enabled == false) {
2535 ipa_ctx->wdi_enabled = true;
2536 if (wlan_ipa_uc_send_wdi_control_msg(true) == 0)
2537 wlan_ipa_send_mcc_scc_msg(ipa_ctx,
2538 ipa_ctx->mcc_mode);
2539 }
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302540 wlan_ipa_uc_proc_pending_event(ipa_ctx, true);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302541 if (ipa_ctx->pending_cons_req)
Yun Parke114fbf2018-04-05 20:02:12 -07002542 wlan_ipa_wdi_rm_notify_completion(
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302543 QDF_IPA_RM_RESOURCE_GRANTED,
2544 QDF_IPA_RM_RESOURCE_WLAN_CONS);
2545 ipa_ctx->pending_cons_req = false;
2546 }
2547 qdf_mutex_release(&ipa_ctx->ipa_lock);
2548 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_SUSPEND) ||
2549 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND)) {
2550 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2551 ipa_ctx->activated_fw_pipe--;
2552 if (!ipa_ctx->activated_fw_pipe) {
2553 /*
2554 * Async return success from FW
2555 * Disable/suspend all the PIPEs
2556 */
2557 ipa_ctx->resource_unloading = false;
2558 qdf_event_set(&ipa_ctx->ipa_resource_comp);
2559 wlan_ipa_uc_disable_pipes(ipa_ctx);
2560 if (wlan_ipa_is_rm_enabled(ipa_ctx->config))
Yun Parke114fbf2018-04-05 20:02:12 -07002561 wlan_ipa_wdi_rm_release_resource(ipa_ctx,
2562 QDF_IPA_RM_RESOURCE_WLAN_PROD);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302563 wlan_ipa_uc_proc_pending_event(ipa_ctx, false);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302564 ipa_ctx->pending_cons_req = false;
2565 }
2566 qdf_mutex_release(&ipa_ctx->ipa_lock);
2567 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
2568 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_DEBUG)) {
2569 uc_fw_stat = (struct ipa_uc_fw_stats *)
2570 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2571
2572 /* WLAN FW WDI stats */
2573 wlan_ipa_print_fw_wdi_stats(ipa_ctx, uc_fw_stat);
2574 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
2575 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_BW_CAL)) {
2576 /* STATs from FW */
2577 uc_fw_stat = (struct ipa_uc_fw_stats *)
2578 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2579 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2580 ipa_ctx->ipa_tx_packets_diff = BW_GET_DIFF(
2581 uc_fw_stat->tx_pkts_completed,
2582 ipa_ctx->ipa_p_tx_packets);
2583 ipa_ctx->ipa_rx_packets_diff = BW_GET_DIFF(
2584 (uc_fw_stat->rx_num_ind_drop_no_space +
2585 uc_fw_stat->rx_num_ind_drop_no_buf +
2586 uc_fw_stat->rx_num_pkts_indicated),
2587 ipa_ctx->ipa_p_rx_packets);
2588
2589 ipa_ctx->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2590 ipa_ctx->ipa_p_rx_packets =
2591 (uc_fw_stat->rx_num_ind_drop_no_space +
2592 uc_fw_stat->rx_num_ind_drop_no_buf +
2593 uc_fw_stat->rx_num_pkts_indicated);
2594 qdf_mutex_release(&ipa_ctx->ipa_lock);
2595 } else if (msg->op_code == WLAN_IPA_UC_OPCODE_UC_READY) {
2596 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2597 wlan_ipa_uc_loaded_handler(ipa_ctx);
2598 qdf_mutex_release(&ipa_ctx->ipa_lock);
2599 } else if (wlan_ipa_uc_op_metering(ipa_ctx, op_msg)) {
2600 ipa_err("Invalid message: op_code=%d, reason=%d",
2601 msg->op_code, ipa_ctx->stat_req_reason);
2602 }
2603
2604 qdf_mem_free(op_msg);
2605}
2606
2607/**
2608 * wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2609 * @work: uC OP work
2610 *
2611 * Return: None
2612 */
2613static void wlan_ipa_uc_fw_op_event_handler(void *data)
2614{
2615 struct op_msg_type *msg;
2616 struct uc_op_work_struct *uc_op_work =
2617 (struct uc_op_work_struct *)data;
2618 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
2619
2620 msg = uc_op_work->msg;
2621 uc_op_work->msg = NULL;
2622 ipa_debug("posted msg %d", msg->op_code);
2623
2624 wlan_ipa_uc_op_cb(msg, ipa_ctx);
2625}
2626
2627/**
2628 * wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
2629 * @op_msg: operation message received from firmware
2630 * @ipa_ctx: Global IPA context
2631 *
2632 * Return: None
2633 */
2634static void wlan_ipa_uc_op_event_handler(uint8_t *op_msg, void *ctx)
2635{
2636 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)ctx;
2637 struct op_msg_type *msg;
2638 struct uc_op_work_struct *uc_op_work;
2639
2640 if (!ipa_ctx)
2641 goto end;
2642
2643 msg = (struct op_msg_type *)op_msg;
2644
2645 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
2646 ipa_err("Invalid OP Code (%d)", msg->op_code);
2647 goto end;
2648 }
2649
2650 uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
2651 if (uc_op_work->msg) {
2652 /* When the same uC OPCODE is already pended, just return */
2653 goto end;
2654 }
2655
2656 uc_op_work->msg = msg;
2657 qdf_sched_work(0, &uc_op_work->work);
2658 return;
2659
2660end:
2661 qdf_mem_free(op_msg);
2662}
2663
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302664QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx,
2665 qdf_device_t osdev)
2666{
2667 uint8_t i;
2668 QDF_STATUS status = QDF_STATUS_SUCCESS;
2669
2670 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2671 return QDF_STATUS_SUCCESS;
2672
2673 ipa_debug("enter");
2674
2675 for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) {
2676 ipa_ctx->vdev_to_iface[i] = WLAN_IPA_MAX_SESSION;
2677 ipa_ctx->vdev_offload_enabled[i] = false;
2678 }
2679
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302680 if (cdp_ipa_get_resource(ipa_ctx->dp_soc, ipa_ctx->dp_pdev)) {
2681 ipa_err("IPA UC resource alloc fail");
2682 status = QDF_STATUS_E_FAILURE;
2683 goto fail_return;
2684 }
2685
2686 if (true == ipa_ctx->uc_loaded) {
2687 status = wlan_ipa_wdi_setup(ipa_ctx, osdev);
2688 if (status) {
2689 ipa_err("Failure to setup IPA pipes (status=%d)",
2690 status);
2691 status = QDF_STATUS_E_FAILURE;
2692 goto fail_return;
2693 }
2694
2695 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
2696 wlan_ipa_init_metering(ipa_ctx);
jiadf9771182018-06-12 12:43:40 +08002697
2698 if (wlan_ipa_init_perf_level(ipa_ctx) != QDF_STATUS_SUCCESS)
2699 ipa_err("Failed to init perf level");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302700 }
2701
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302702 cdp_ipa_register_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
2703 wlan_ipa_uc_op_event_handler, (void *)ipa_ctx);
2704
2705 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
2706 qdf_create_work(0, &ipa_ctx->uc_op_work[i].work,
2707 wlan_ipa_uc_fw_op_event_handler,
2708 &ipa_ctx->uc_op_work[i]);
2709 ipa_ctx->uc_op_work[i].msg = NULL;
2710 }
2711
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302712fail_return:
2713 ipa_debug("exit: status=%d", status);
2714 return status;
2715}
2716
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302717/**
2718 * wlan_ipa_cleanup_pending_event() - Cleanup IPA pending event list
2719 * @ipa_ctx: pointer to IPA IPA struct
2720 *
2721 * Return: none
2722 */
2723static void wlan_ipa_cleanup_pending_event(struct wlan_ipa_priv *ipa_ctx)
2724{
2725 struct wlan_ipa_uc_pending_event *pending_event = NULL;
2726
2727 while (qdf_list_remove_front(&ipa_ctx->pending_event,
2728 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
2729 qdf_mem_free(pending_event);
2730}
2731
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302732QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx)
2733{
2734 QDF_STATUS status = QDF_STATUS_SUCCESS;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302735 int i;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302736
2737 ipa_debug("enter");
2738
2739 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2740 return status;
2741
2742 if (!ipa_ctx->ipa_pipes_down)
2743 wlan_ipa_uc_disable_pipes(ipa_ctx);
2744
2745 if (true == ipa_ctx->uc_loaded) {
2746 status = cdp_ipa_cleanup(ipa_ctx->dp_soc,
2747 ipa_ctx->tx_pipe_handle,
2748 ipa_ctx->rx_pipe_handle);
2749 if (status)
2750 ipa_err("Failure to cleanup IPA pipes (status=%d)",
2751 status);
2752 }
2753
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302754 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2755 wlan_ipa_cleanup_pending_event(ipa_ctx);
2756 qdf_mutex_release(&ipa_ctx->ipa_lock);
2757
2758 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
2759 qdf_cancel_work(&ipa_ctx->uc_op_work[i].work);
2760 qdf_mem_free(ipa_ctx->uc_op_work[i].msg);
2761 ipa_ctx->uc_op_work[i].msg = NULL;
2762 }
2763
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302764 ipa_debug("exit: ret=%d", status);
2765 return status;
2766}
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +05302767
Yun Parka29974a2018-04-09 12:05:49 -07002768/**
2769 * wlan_ipa_is_fw_wdi_activated() - Is FW WDI actived?
2770 * @ipa_ctx: IPA contex
2771 *
2772 * Return: true if FW WDI actived, false otherwise
2773 */
2774bool wlan_ipa_is_fw_wdi_activated(struct wlan_ipa_priv *ipa_ctx)
2775{
2776 return (WLAN_IPA_UC_NUM_WDI_PIPE == ipa_ctx->activated_fw_pipe);
2777}
2778