blob: 40aa042d1303265fb6f29f620480841b62f2563e [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"
Sravan Kumar Kairamce792eb2018-06-15 15:07:11 +053025#include "qdf_str.h"
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +053026
27static struct wlan_ipa_priv *gp_ipa;
28
29static struct wlan_ipa_iface_2_client {
30 qdf_ipa_client_type_t cons_client;
31 qdf_ipa_client_type_t prod_client;
32} wlan_ipa_iface_2_client[WLAN_IPA_MAX_IFACE] = {
33 {
34 QDF_IPA_CLIENT_WLAN2_CONS, QDF_IPA_CLIENT_WLAN1_PROD
35 }, {
36 QDF_IPA_CLIENT_WLAN3_CONS, QDF_IPA_CLIENT_WLAN1_PROD
37 }, {
38 QDF_IPA_CLIENT_WLAN4_CONS, QDF_IPA_CLIENT_WLAN1_PROD
39 }
40};
41
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +053042/* Local Function Prototypes */
43static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
44 unsigned long data);
45static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
46 unsigned long data);
47
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +053048/**
49 * wlan_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
50 * @ipa_cfg: IPA config
51 *
52 * Return: true if STA mode IPA uC offload is enabled, false otherwise
53 */
54static inline bool wlan_ipa_uc_sta_is_enabled(struct wlan_ipa_config *ipa_cfg)
55{
56 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_STA_ENABLE_MASK);
57}
58
59/**
60 * wlan_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
61 * @ipa_cfg: IPA config
62 *
63 * Return: true if pre-filter is enabled, otherwise false
64 */
65static inline
66bool wlan_ipa_is_pre_filter_enabled(struct wlan_ipa_config *ipa_cfg)
67{
68 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg,
69 WLAN_IPA_PRE_FILTER_ENABLE_MASK);
70}
71
72/**
73 * wlan_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
74 * @ipa_cfg: IPA config
75 *
76 * Return: true if IPv6 is enabled, otherwise false
77 */
78static inline bool wlan_ipa_is_ipv6_enabled(struct wlan_ipa_config *ipa_cfg)
79{
80 return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_IPV6_ENABLE_MASK);
81}
82
83/**
84 * wlan_ipa_msg_free_fn() - Free an IPA message
85 * @buff: pointer to the IPA message
86 * @len: length of the IPA message
87 * @type: type of IPA message
88 *
89 * Return: None
90 */
91static void wlan_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
92{
93 ipa_debug("msg type:%d, len:%d", type, len);
94 qdf_mem_free(buff);
95}
96
97/**
98 * wlan_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
99 * @priv_ctxt: IPA context
100 *
101 * Will be called by IPA context.
102 * It's atomic context, then should be scheduled to kworker thread
103 *
104 * Return: None
105 */
106static void wlan_ipa_uc_loaded_uc_cb(void *priv_ctxt)
107{
108 struct wlan_ipa_priv *ipa_ctx;
109 struct op_msg_type *msg;
110 struct uc_op_work_struct *uc_op_work;
111
112 if (!priv_ctxt) {
113 ipa_err("Invalid IPA context");
114 return;
115 }
116
117 ipa_ctx = priv_ctxt;
Sravan Kumar Kairam7eb6e4c2018-04-26 15:35:47 +0530118 ipa_ctx->uc_loaded = true;
119
120 uc_op_work = &ipa_ctx->uc_op_work[WLAN_IPA_UC_OPCODE_UC_READY];
121 if (!list_empty(&uc_op_work->work.work.entry)) {
122 /* uc_op_work is not initialized yet */
123 return;
124 }
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530125
126 msg = qdf_mem_malloc(sizeof(*msg));
127 if (!msg) {
128 ipa_err("op_msg allocation fails");
129 return;
130 }
131
132 msg->op_code = WLAN_IPA_UC_OPCODE_UC_READY;
133
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530134 /* When the same uC OPCODE is already pended, just return */
135 if (uc_op_work->msg)
136 goto done;
137
138 uc_op_work->msg = msg;
139 qdf_sched_work(0, &uc_op_work->work);
Sravan Kumar Kairam7eb6e4c2018-04-26 15:35:47 +0530140
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530141 /* work handler will free the msg buffer */
142 return;
143
144done:
145 qdf_mem_free(msg);
146}
147
148/**
149 * wlan_ipa_uc_send_wdi_control_msg() - Set WDI control message
150 * @ctrl: WDI control value
151 *
152 * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
153 *
154 * Return: QDF_STATUS
155 */
156static QDF_STATUS wlan_ipa_uc_send_wdi_control_msg(bool ctrl)
157{
jiad629b2172018-05-11 15:34:22 +0800158 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530159 qdf_ipa_msg_meta_t meta;
160 qdf_ipa_wlan_msg_t *ipa_msg;
161 int ret = 0;
162
163 /* WDI enable message to IPA */
164 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
165 ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
166 if (!ipa_msg) {
167 ipa_err("msg allocation failed");
168 return QDF_STATUS_E_NOMEM;
169 }
170
jiad629b2172018-05-11 15:34:22 +0800171 if (ctrl) {
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530172 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_ENABLE);
jiad629b2172018-05-11 15:34:22 +0800173 ipa_ctx->stats.event[QDF_WDI_ENABLE]++;
174 } else {
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530175 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_DISABLE);
jiad629b2172018-05-11 15:34:22 +0800176 ipa_ctx->stats.event[QDF_WDI_DISABLE]++;
177 }
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530178
179 ipa_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
180 ret = qdf_ipa_send_msg(&meta, ipa_msg, wlan_ipa_msg_free_fn);
181 if (ret) {
182 ipa_err("ipa_send_msg(Evt:%d)-fail=%d",
183 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
184 qdf_mem_free(ipa_msg);
185 return QDF_STATUS_E_FAILURE;
186 }
187
188 return QDF_STATUS_SUCCESS;
189}
190
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530191struct wlan_ipa_priv *wlan_ipa_get_obj_context(void)
192{
193 return gp_ipa;
194}
195
Yun Parke74e6092018-04-27 11:36:34 -0700196/**
197 * wlan_ipa_send_pkt_to_tl() - Send an IPA packet to TL
198 * @iface_context: interface-specific IPA context
199 * @ipa_tx_desc: packet data descriptor
200 *
201 * Return: None
202 */
203static void wlan_ipa_send_pkt_to_tl(
204 struct wlan_ipa_iface_context *iface_context,
205 qdf_ipa_rx_data_t *ipa_tx_desc)
206{
207 struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
208 qdf_nbuf_t skb;
209 struct wlan_ipa_tx_desc *tx_desc;
210
211 qdf_spin_lock_bh(&iface_context->interface_lock);
212 /*
213 * During CAC period, data packets shouldn't be sent over the air so
214 * drop all the packets here
215 */
216 if (iface_context->device_mode == QDF_SAP_MODE ||
217 iface_context->device_mode == QDF_P2P_GO_MODE) {
218 if (ipa_ctx->dfs_cac_block_tx) {
219 ipa_free_skb(ipa_tx_desc);
220 qdf_spin_unlock_bh(&iface_context->interface_lock);
221 iface_context->stats.num_tx_cac_drop++;
222 wlan_ipa_wdi_rm_try_release(ipa_ctx);
223 return;
224 }
225 }
226 qdf_spin_unlock_bh(&iface_context->interface_lock);
227
228 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
229
230 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
231
232 /* Store IPA Tx buffer ownership into SKB CB */
233 qdf_nbuf_ipa_owned_set(skb);
234 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
235 qdf_nbuf_mapped_paddr_set(skb,
236 QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc)
237 + WLAN_IPA_WLAN_FRAG_HEADER
238 + WLAN_IPA_WLAN_IPA_HEADER);
239 QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -=
240 WLAN_IPA_WLAN_FRAG_HEADER + WLAN_IPA_WLAN_IPA_HEADER;
241 } else
242 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
243
244 qdf_spin_lock_bh(&ipa_ctx->q_lock);
245 /* get free Tx desc and assign ipa_tx_desc pointer */
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +0530246 if (qdf_list_remove_front(&ipa_ctx->tx_desc_free_list,
247 (qdf_list_node_t **)&tx_desc) ==
Yun Parke74e6092018-04-27 11:36:34 -0700248 QDF_STATUS_SUCCESS) {
249 tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
250 ipa_ctx->stats.num_tx_desc_q_cnt++;
251 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
252 /* Store Tx Desc index into SKB CB */
253 QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
254 } else {
255 ipa_ctx->stats.num_tx_desc_error++;
256 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
257 qdf_ipa_free_skb(ipa_tx_desc);
258 wlan_ipa_wdi_rm_try_release(ipa_ctx);
259 return;
260 }
261
262 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
263 (struct cdp_vdev *)iface_context->tl_context,
264 QDF_IPA_RX_DATA_SKB(ipa_tx_desc));
265 if (skb) {
266 qdf_nbuf_free(skb);
267 iface_context->stats.num_tx_err++;
268 return;
269 }
270
271 atomic_inc(&ipa_ctx->tx_ref_cnt);
272
273 iface_context->stats.num_tx++;
274}
275
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530276#ifdef CONFIG_IPA_WDI_UNIFIED_API
277
278/*
279 * TODO: Get WDI version through FW capabilities
280 */
281#ifdef CONFIG_LITHIUM
282static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
283{
284 ipa_ctx->wdi_version = IPA_WDI_3;
285}
286#elif defined(QCA_WIFI_3_0)
287static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
288{
289 ipa_ctx->wdi_version = IPA_WDI_2;
290}
291#else
292static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
293{
294 ipa_ctx->wdi_version = IPA_WDI_1;
295}
296#endif
297
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530298static inline bool wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx,
299 qdf_device_t osdev)
300{
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +0530301 return ipa_ctx->is_smmu_enabled && qdf_mem_smmu_s1_enabled(osdev);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530302}
303
304static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx,
305 qdf_device_t osdev)
306{
307 qdf_ipa_sys_connect_params_t sys_in[WLAN_IPA_MAX_IFACE];
308 int i;
309
310 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++)
311 qdf_mem_copy(&sys_in[i],
312 &ipa_ctx->sys_pipe[i].ipa_sys_params,
313 sizeof(qdf_ipa_sys_connect_params_t));
314
315 return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
316 wlan_ipa_i2w_cb, wlan_ipa_w2i_cb,
317 wlan_ipa_wdi_meter_notifier_cb,
318 ipa_ctx->config->desc_size,
319 ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config),
320 &ipa_ctx->tx_pipe_handle,
321 &ipa_ctx->rx_pipe_handle,
322 wlan_ipa_wdi_is_smmu_enabled(ipa_ctx, osdev),
323 sys_in);
324}
325
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530326#ifdef FEATURE_METERING
327/**
328 * wlan_ipa_wdi_init_metering() - IPA WDI metering init
329 * @ipa_ctx: IPA context
330 * @in: IPA WDI in param
331 *
332 * Return: QDF_STATUS
333 */
334static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
335 qdf_ipa_wdi_init_in_params_t *in)
336{
337 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(in) =
338 wlan_ipa_wdi_meter_notifier_cb;
339}
340#else
341static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
342 qdf_ipa_wdi_init_in_params_t *in)
343{
344}
345#endif
346
347/**
348 * wlan_ipa_wdi_init() - IPA WDI init
349 * @ipa_ctx: IPA context
350 *
351 * Return: QDF_STATUS
352 */
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530353static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
354{
355 qdf_ipa_wdi_init_in_params_t in;
356 qdf_ipa_wdi_init_out_params_t out;
357 int ret;
358
359 ipa_ctx->uc_loaded = false;
360
361 QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version;
362 QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb;
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +0530363 QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = ipa_ctx;
364 wlan_ipa_wdi_init_metering(ipa_ctx, &in);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530365
366 ret = qdf_ipa_wdi_init(&in, &out);
367 if (ret) {
368 ipa_err("ipa_wdi_init failed with ret=%d", ret);
369 return QDF_STATUS_E_FAILURE;
370 }
371
372 if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
373 ipa_info("IPA uC READY");
374 ipa_ctx->uc_loaded = true;
375 ipa_ctx->is_smmu_enabled =
376 QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
377 ipa_info("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled);
378 } else {
379 return QDF_STATUS_E_BUSY;
380 }
381
382 return QDF_STATUS_SUCCESS;
383}
384
385static inline int wlan_ipa_wdi_cleanup(void)
386{
387 int ret;
388
389 ret = qdf_ipa_wdi_cleanup();
390 if (ret)
391 ipa_info("ipa_wdi_cleanup failed ret=%d", ret);
392 return ret;
393}
394
395static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
396 struct ipa_sys_connect_params *sys,
397 uint32_t *handle)
398{
399 return 0;
400}
401
402static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
403 uint32_t handle)
404{
405 return 0;
406}
407
Yun Parke74e6092018-04-27 11:36:34 -0700408/**
409 * wlan_ipa_pm_flush() - flush queued packets
410 * @work: pointer to the scheduled work
411 *
412 * Called during PM resume to send packets to TL which were queued
413 * while host was in the process of suspending.
414 *
415 * Return: None
416 */
417static void wlan_ipa_pm_flush(void *data)
418{
419 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
420 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
421 qdf_nbuf_t skb;
422 uint32_t dequeued = 0;
423
424 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
425 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) !=
426 NULL)) {
427 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
428
429 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
430 dequeued++;
431
jiadab8cea02018-05-24 09:16:14 +0800432 if (pm_tx_cb->exception) {
433 if (ipa_ctx->softap_xmit &&
434 pm_tx_cb->iface_context->dev) {
435 ipa_ctx->softap_xmit(skb,
436 pm_tx_cb->iface_context->dev);
437 ipa_ctx->stats.num_tx_fwd_ok++;
438 } else {
439 dev_kfree_skb_any(skb);
440 }
441 } else {
442 wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
443 pm_tx_cb->ipa_tx_desc);
444 }
Yun Parke74e6092018-04-27 11:36:34 -0700445
446 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
447 }
448 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
449
450 ipa_ctx->stats.num_tx_dequeued += dequeued;
451 if (dequeued > ipa_ctx->stats.num_max_pm_queue)
452 ipa_ctx->stats.num_max_pm_queue = dequeued;
453}
454
jiadae9959f2018-05-08 11:19:07 +0800455int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
456{
457 if (!num_buf) {
458 ipa_info("No buffers to map/unmap");
459 return 0;
460 }
461
462 if (map)
463 return qdf_ipa_wdi_create_smmu_mapping(num_buf, buf_arr);
464 else
465 return qdf_ipa_wdi_release_smmu_mapping(num_buf, buf_arr);
466}
467
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530468#else /* CONFIG_IPA_WDI_UNIFIED_API */
469
470static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
471{
472}
473
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +0530474static inline int wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx,
475 qdf_device_t osdev)
476{
477 return qdf_mem_smmu_s1_enabled(osdev);
478}
479
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530480static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx,
481 qdf_device_t osdev)
482{
483 return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
484 wlan_ipa_i2w_cb, wlan_ipa_w2i_cb,
485 wlan_ipa_wdi_meter_notifier_cb,
486 ipa_ctx->config->desc_size,
487 ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config),
488 &ipa_ctx->tx_pipe_handle,
489 &ipa_ctx->rx_pipe_handle);
490}
491
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530492static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
493{
494 struct ipa_wdi_uc_ready_params uc_ready_param;
495
496 ipa_ctx->uc_loaded = false;
497 uc_ready_param.priv = (void *)ipa_ctx;
498 uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb;
499 if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) {
500 ipa_info("UC Ready CB register fail");
501 return QDF_STATUS_E_FAILURE;
502 }
503
504 if (true == uc_ready_param.is_uC_ready) {
505 ipa_info("UC Ready");
506 ipa_ctx->uc_loaded = true;
507 } else {
508 return QDF_STATUS_E_BUSY;
509 }
510
511 return QDF_STATUS_SUCCESS;
512}
513
514static inline int wlan_ipa_wdi_cleanup(void)
515{
516 int ret;
517
518 ret = qdf_ipa_uc_dereg_rdyCB();
519 if (ret)
520 ipa_info("UC Ready CB deregister fail");
521 return ret;
522}
523
524static inline int wlan_ipa_wdi_setup_sys_pipe(
525 struct wlan_ipa_priv *ipa_ctx,
526 struct ipa_sys_connect_params *sys, uint32_t *handle)
527{
528 return qdf_ipa_setup_sys_pipe(sys, handle);
529}
530
531static inline int wlan_ipa_wdi_teardown_sys_pipe(
532 struct wlan_ipa_priv *ipa_ctx,
533 uint32_t handle)
534{
535 return qdf_ipa_teardown_sys_pipe(handle);
536}
537
Yun Parke74e6092018-04-27 11:36:34 -0700538/**
539 * wlan_ipa_pm_flush() - flush queued packets
540 * @work: pointer to the scheduled work
541 *
542 * Called during PM resume to send packets to TL which were queued
543 * while host was in the process of suspending.
544 *
545 * Return: None
546 */
547static void wlan_ipa_pm_flush(void *data)
548{
549 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
550 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
551 qdf_nbuf_t skb;
552 uint32_t dequeued = 0;
553
554 qdf_wake_lock_acquire(&ipa_ctx->wake_lock,
555 WIFI_POWER_EVENT_WAKELOCK_IPA);
556 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
557 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) !=
558 NULL)) {
559 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
560
561 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
562 dequeued++;
563
jiadab8cea02018-05-24 09:16:14 +0800564 if (pm_tx_cb->exception) {
565 if (ipa_ctx->softap_xmit &&
566 pm_tx_cb->iface_context->dev) {
567 ipa_ctx->softap_xmit(skb,
568 pm_tx_cb->iface_context->dev);
569 ipa_ctx->stats.num_tx_fwd_ok++;
570 } else {
571 dev_kfree_skb_any(skb);
572 }
573 } else {
574 wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
575 pm_tx_cb->ipa_tx_desc);
576 }
Yun Parke74e6092018-04-27 11:36:34 -0700577
578 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
579 }
580 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
581 qdf_wake_lock_release(&ipa_ctx->wake_lock,
582 WIFI_POWER_EVENT_WAKELOCK_IPA);
583
584 ipa_ctx->stats.num_tx_dequeued += dequeued;
585 if (dequeued > ipa_ctx->stats.num_max_pm_queue)
586 ipa_ctx->stats.num_max_pm_queue = dequeued;
587}
588
jiadae9959f2018-05-08 11:19:07 +0800589int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
590{
591 if (!num_buf) {
592 ipa_info("No buffers to map/unmap");
593 return 0;
594 }
595
596 if (map)
597 return qdf_ipa_create_wdi_mapping(num_buf, buf_arr);
598 else
599 return qdf_ipa_release_wdi_mapping(num_buf, buf_arr);
600}
601
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530602#endif /* CONFIG_IPA_WDI_UNIFIED_API */
603
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530604/**
605 * wlan_ipa_send_skb_to_network() - Send skb to kernel
606 * @skb: network buffer
607 * @iface_ctx: IPA interface context
608 *
609 * Called when a network buffer is received which should not be routed
610 * to the IPA module.
611 *
612 * Return: None
613 */
614static void
615wlan_ipa_send_skb_to_network(qdf_nbuf_t skb,
616 struct wlan_ipa_iface_context *iface_ctx)
617{
618 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
619
620 if (!iface_ctx->dev) {
jiadf3ecc752018-07-05 14:36:03 +0800621 ipa_debug_rl("Invalid interface");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530622 ipa_ctx->ipa_rx_internal_drop_count++;
jiadf3ecc752018-07-05 14:36:03 +0800623 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530624 return;
625 }
626
627 skb->destructor = wlan_ipa_uc_rt_debug_destructor;
628
629 if (ipa_ctx->send_to_nw)
630 ipa_ctx->send_to_nw(skb, iface_ctx->dev);
631
632 ipa_ctx->ipa_rx_net_send_count++;
633}
634
635/**
636 * wlan_ipa_forward() - handle packet forwarding to wlan tx
637 * @ipa_ctx: pointer to ipa ipa context
638 * @iface_ctx: interface context
639 * @skb: data pointer
640 *
641 * if exception packet has set forward bit, copied new packet should be
642 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
643 * put into pm queue and tx procedure will be differed
644 *
645 * Return: None
646 */
647static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx,
648 struct wlan_ipa_iface_context *iface_ctx,
649 qdf_nbuf_t skb)
650{
651 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
652
653 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
654
655 /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
656 qdf_nbuf_ipa_owned_set(skb);
657
658 /* WLAN subsystem is in suspend, put in queue */
659 if (ipa_ctx->suspended) {
660 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
jiadf3ecc752018-07-05 14:36:03 +0800661 ipa_info_rl("Tx in suspend, put in queue");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530662 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)) {
jiadf3ecc752018-07-05 14:36:03 +0800676 ipa_err_rl("packet Tx fail");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530677 ipa_ctx->stats.num_tx_fwd_err++;
678 } else {
679 ipa_ctx->stats.num_tx_fwd_ok++;
680 }
681 } else {
jiadab8cea02018-05-24 09:16:14 +0800682 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530683 }
684 }
685}
686
687/**
688 * wlan_ipa_intrabss_forward() - Forward intra bss packets.
689 * @ipa_ctx: pointer to IPA IPA struct
690 * @iface_ctx: ipa interface context
691 * @desc: Firmware descriptor
692 * @skb: Data buffer
693 *
694 * Return:
695 * WLAN_IPA_FORWARD_PKT_NONE
696 * WLAN_IPA_FORWARD_PKT_DISCARD
697 * WLAN_IPA_FORWARD_PKT_LOCAL_STACK
698 *
699 */
700
701static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward(
702 struct wlan_ipa_priv *ipa_ctx,
703 struct wlan_ipa_iface_context *iface_ctx,
704 uint8_t desc,
705 qdf_nbuf_t skb)
706{
707 int ret = WLAN_IPA_FORWARD_PKT_NONE;
708 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
709 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
710
711 if ((desc & FW_RX_DESC_FORWARD_M)) {
712 if (!ol_txrx_fwd_desc_thresh_check(
713 (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc,
714 (struct cdp_pdev *)pdev,
715 iface_ctx->session_id))) {
716 /* Drop the packet*/
717 ipa_ctx->stats.num_tx_fwd_err++;
jiadab8cea02018-05-24 09:16:14 +0800718 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530719 ret = WLAN_IPA_FORWARD_PKT_DISCARD;
720 return ret;
721 }
jiadf3ecc752018-07-05 14:36:03 +0800722 ipa_debug_rl("Forward packet to Tx (fw_desc=%d)", desc);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530723 ipa_ctx->ipa_tx_forward++;
724
725 if ((desc & FW_RX_DESC_DISCARD_M)) {
726 wlan_ipa_forward(ipa_ctx, iface_ctx, skb);
727 ipa_ctx->ipa_rx_internal_drop_count++;
728 ipa_ctx->ipa_rx_discard++;
729 ret = WLAN_IPA_FORWARD_PKT_DISCARD;
730 } else {
731 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
732
733 if (cloned_skb)
734 wlan_ipa_forward(ipa_ctx, iface_ctx,
735 cloned_skb);
736 else
jiadf3ecc752018-07-05 14:36:03 +0800737 ipa_err_rl("tx skb alloc failed");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530738 ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK;
739 }
740 }
741
742 return ret;
743}
744
745/**
746 * wlan_ipa_w2i_cb() - WLAN to IPA callback handler
747 * @priv: pointer to private data registered with IPA (we register a
748 * pointer to the global IPA context)
749 * @evt: the IPA event which triggered the callback
750 * @data: data associated with the event
751 *
752 * Return: None
753 */
754static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
755 unsigned long data)
756{
757 struct wlan_ipa_priv *ipa_ctx = NULL;
758 qdf_nbuf_t skb;
759 uint8_t iface_id;
760 uint8_t session_id;
761 struct wlan_ipa_iface_context *iface_context;
762 uint8_t fw_desc;
763
764 ipa_ctx = (struct wlan_ipa_priv *)priv;
765
766 if (!ipa_ctx)
767 return;
768
769 switch (evt) {
770 case IPA_RECEIVE:
771 skb = (qdf_nbuf_t) data;
772
773 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
774 session_id = (uint8_t)skb->cb[0];
775 iface_id = ipa_ctx->vdev_to_iface[session_id];
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530776 } else {
777 iface_id = WLAN_IPA_GET_IFACE_ID(skb->data);
778 }
779 if (iface_id >= WLAN_IPA_MAX_IFACE) {
jiadf3ecc752018-07-05 14:36:03 +0800780 ipa_err_rl("Invalid iface_id: %u", iface_id);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530781 ipa_ctx->ipa_rx_internal_drop_count++;
jiadab8cea02018-05-24 09:16:14 +0800782 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530783 return;
784 }
785
786 iface_context = &ipa_ctx->iface_context[iface_id];
787 if (!iface_context->tl_context) {
jiadf3ecc752018-07-05 14:36:03 +0800788 ipa_err_rl("TL context of iface_id %u is NULL",
789 iface_id);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530790 ipa_ctx->ipa_rx_internal_drop_count++;
jiadab8cea02018-05-24 09:16:14 +0800791 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530792 return;
793 }
794
795 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
796 ipa_ctx->stats.num_rx_excep++;
797 qdf_nbuf_pull_head(skb, WLAN_IPA_UC_WLAN_CLD_HDR_LEN);
798 } else {
799 qdf_nbuf_pull_head(skb, WLAN_IPA_WLAN_CLD_HDR_LEN);
800 }
801
802 iface_context->stats.num_rx_ipa_excep++;
803
804 /* Disable to forward Intra-BSS Rx packets when
805 * ap_isolate=1 in hostapd.conf
806 */
807 if (!ipa_ctx->ap_intrabss_fwd) {
808 /*
809 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
810 * all Rx packets to IPA uC, which need to be forwarded
811 * to other interface.
812 * And, IPA driver will send back to WLAN host driver
813 * through exception pipe with fw_desc field set by FW.
814 * Here we are checking fw_desc field for FORWARD bit
815 * set, and forward to Tx. Then copy to kernel stack
816 * only when DISCARD bit is not set.
817 */
818 fw_desc = (uint8_t)skb->cb[1];
819 if (WLAN_IPA_FORWARD_PKT_DISCARD ==
820 wlan_ipa_intrabss_forward(ipa_ctx, iface_context,
821 fw_desc, skb))
822 break;
823 } else {
jiadf3ecc752018-07-05 14:36:03 +0800824 ipa_debug_rl("Intra-BSS forwarding is disabled");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530825 }
826
827 wlan_ipa_send_skb_to_network(skb, iface_context);
828 break;
829
830 default:
jiadf3ecc752018-07-05 14:36:03 +0800831 ipa_err_rl("w2i cb wrong event: 0x%x", evt);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530832 return;
833 }
834}
835
836/**
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530837 * wlan_ipa_i2w_cb() - IPA to WLAN callback
838 * @priv: pointer to private data registered with IPA (we register a
839 * pointer to the interface-specific IPA context)
840 * @evt: the IPA event which triggered the callback
841 * @data: data associated with the event
842 *
843 * Return: None
844 */
845static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
846 unsigned long data)
847{
848 struct wlan_ipa_priv *ipa_ctx = NULL;
849 qdf_ipa_rx_data_t *ipa_tx_desc;
850 struct wlan_ipa_iface_context *iface_context;
851 qdf_nbuf_t skb;
852 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
853
854 iface_context = (struct wlan_ipa_iface_context *)priv;
855 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
856 ipa_ctx = iface_context->ipa_ctx;
857
858 if (evt != IPA_RECEIVE) {
jiadf3ecc752018-07-05 14:36:03 +0800859 ipa_err_rl("Event is not IPA_RECEIVE");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530860 ipa_free_skb(ipa_tx_desc);
861 iface_context->stats.num_tx_drop++;
862 return;
863 }
864
865 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
866
867 /*
868 * If PROD resource is not requested here then there may be cases where
869 * IPA hardware may be clocked down because of not having proper
870 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
871 * workaround to request PROD resource while data is going over CONS
872 * pipe to prevent the IPA hardware clockdown.
873 */
874 wlan_ipa_wdi_rm_request(ipa_ctx);
875
876 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
877 /*
878 * If host is still suspended then queue the packets and these will be
879 * drained later when resume completes. When packet is arrived here and
880 * host is suspended, this means that there is already resume is in
881 * progress.
882 */
883 if (ipa_ctx->suspended) {
884 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
885 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
886 pm_tx_cb->iface_context = iface_context;
887 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
888 qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
889 ipa_ctx->stats.num_tx_queued++;
890
891 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
892 return;
893 }
894
895 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
896
897 /*
898 * If we are here means, host is not suspended, wait for the work queue
899 * to finish.
900 */
901 qdf_flush_work(&ipa_ctx->pm_work);
902
903 return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
904}
905
906QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx)
907{
908 /*
909 * Check if IPA is ready for suspend, If we are here means, there is
910 * high chance that suspend would go through but just to avoid any race
911 * condition after suspend started, these checks are conducted before
912 * allowing to suspend.
913 */
914 if (atomic_read(&ipa_ctx->tx_ref_cnt))
915 return QDF_STATUS_E_AGAIN;
916
Yun Parke74e6092018-04-27 11:36:34 -0700917 if (!wlan_ipa_is_rm_released(ipa_ctx))
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530918 return QDF_STATUS_E_AGAIN;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530919
920 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
921 ipa_ctx->suspended = true;
922 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
923
924 return QDF_STATUS_SUCCESS;
925}
926
927QDF_STATUS wlan_ipa_resume(struct wlan_ipa_priv *ipa_ctx)
928{
929 qdf_sched_work(0, &ipa_ctx->pm_work);
930
931 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
932 ipa_ctx->suspended = false;
933 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
934
935 return QDF_STATUS_SUCCESS;
936}
937
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530938QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx)
939{
940 int result;
941
942 ipa_debug("enter");
943
944 if (!ipa_ctx->ipa_pipes_down) {
945 /*
946 * IPA WDI Pipes are already activated due to
947 * rm deferred resources grant
948 */
949 ipa_warn("IPA WDI Pipes are already activated");
950 goto end;
951 }
952
953 result = cdp_ipa_enable_pipes(ipa_ctx->dp_soc,
954 ipa_ctx->dp_pdev);
955 if (result) {
956 ipa_err("Enable IPA WDI PIPE failed: ret=%d", result);
957 return QDF_STATUS_E_FAILURE;
958 }
959
960 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
961 ipa_ctx->ipa_pipes_down = false;
962
963 cdp_ipa_enable_autonomy(ipa_ctx->dp_soc,
964 ipa_ctx->dp_pdev);
965
966end:
967 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
968
969 return QDF_STATUS_SUCCESS;
970}
971
972QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx)
973{
974 int result;
975
976 ipa_debug("enter");
977
978 if (ipa_ctx->ipa_pipes_down) {
979 /*
980 * This shouldn't happen :
981 * IPA WDI Pipes are already deactivated
982 */
983 QDF_ASSERT(0);
984 ipa_warn("IPA WDI Pipes are already deactivated");
985 goto end;
986 }
987
988 cdp_ipa_disable_autonomy(ipa_ctx->dp_soc,
989 ipa_ctx->dp_pdev);
990
991 result = cdp_ipa_disable_pipes(ipa_ctx->dp_soc,
992 ipa_ctx->dp_pdev);
993 if (result) {
994 ipa_err("Disable IPA WDI PIPE failed: ret=%d", result);
995 return QDF_STATUS_E_FAILURE;
996 }
997
998 ipa_ctx->ipa_pipes_down = true;
999
1000end:
1001 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
1002
1003 return QDF_STATUS_SUCCESS;
1004}
1005
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301006/**
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301007 * wlan_ipa_uc_find_add_assoc_sta() - Find associated station
1008 * @ipa_ctx: Global IPA IPA context
1009 * @sta_add: Should station be added
1010 * @sta_id: ID of the station being queried
1011 *
1012 * Return: true if the station was found
1013 */
1014static bool wlan_ipa_uc_find_add_assoc_sta(struct wlan_ipa_priv *ipa_ctx,
1015 bool sta_add, uint8_t sta_id,
1016 uint8_t *mac_addr)
1017{
1018 bool sta_found = false;
1019 uint8_t idx;
1020
1021 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1022 if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
1023 (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
1024 sta_found = true;
1025 break;
1026 }
1027 }
1028 if (sta_add && sta_found) {
1029 ipa_err("STA ID %d already exist, cannot add", sta_id);
1030 return sta_found;
1031 }
1032 if (sta_add) {
1033 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1034 if (!ipa_ctx->assoc_stas_map[idx].is_reserved) {
1035 ipa_ctx->assoc_stas_map[idx].is_reserved = true;
1036 ipa_ctx->assoc_stas_map[idx].sta_id = sta_id;
1037 qdf_mem_copy(&ipa_ctx->assoc_stas_map[idx].
1038 mac_addr, mac_addr,
1039 QDF_NET_ETH_LEN);
1040 return sta_found;
1041 }
1042 }
1043 }
1044 if (!sta_add && !sta_found) {
1045 ipa_err("STA ID %d does not exist, cannot delete", sta_id);
1046 return sta_found;
1047 }
1048 if (!sta_add) {
1049 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1050 if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
1051 (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
1052 ipa_ctx->assoc_stas_map[idx].is_reserved =
1053 false;
1054 ipa_ctx->assoc_stas_map[idx].sta_id = 0xFF;
1055 qdf_mem_set(&ipa_ctx->assoc_stas_map[idx].
1056 mac_addr, 0, QDF_NET_ETH_LEN);
1057 return sta_found;
1058 }
1059 }
1060 }
1061
1062 return sta_found;
1063}
1064
1065/**
1066 * wlan_ipa_get_ifaceid() - Get IPA context interface ID
1067 * @ipa_ctx: IPA context
1068 * @session_id: Session ID
1069 *
1070 * Return: None
1071 */
1072static int wlan_ipa_get_ifaceid(struct wlan_ipa_priv *ipa_ctx,
1073 uint8_t session_id)
1074{
1075 struct wlan_ipa_iface_context *iface_ctx;
1076 int i;
1077
1078 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1079 iface_ctx = &ipa_ctx->iface_context[i];
1080 if (iface_ctx->session_id == session_id)
1081 break;
1082 }
1083
1084 return i;
1085}
1086
1087/**
1088 * wlan_ipa_cleanup_iface() - Cleanup IPA on a given interface
1089 * @iface_context: interface-specific IPA context
1090 *
1091 * Return: None
1092 */
1093static void wlan_ipa_cleanup_iface(struct wlan_ipa_iface_context *iface_context)
1094{
1095 struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
1096
1097 ipa_debug("enter");
1098
1099 if (!iface_context->tl_context)
1100 return;
1101
1102 cdp_ipa_cleanup_iface(ipa_ctx->dp_soc,
1103 iface_context->dev->name,
1104 wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
1105
1106 qdf_spin_lock_bh(&iface_context->interface_lock);
1107 iface_context->tl_context = NULL;
1108 iface_context->dev = NULL;
1109 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
1110 iface_context->session_id = WLAN_IPA_MAX_SESSION;
1111 iface_context->sta_id = WLAN_IPA_MAX_STA_COUNT;
1112 qdf_spin_unlock_bh(&iface_context->interface_lock);
1113 iface_context->ifa_address = 0;
1114 if (!iface_context->ipa_ctx->num_iface) {
1115 ipa_err("NUM INTF 0, Invalid");
1116 QDF_ASSERT(0);
1117 }
1118 iface_context->ipa_ctx->num_iface--;
1119 ipa_debug("exit: num_iface=%d", iface_context->ipa_ctx->num_iface);
1120}
1121
1122/**
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05301123 * wlan_ipa_nbuf_cb() - IPA TX complete callback
1124 * @skb: packet buffer which was transmitted
1125 *
1126 * Return: None
1127 */
1128static void wlan_ipa_nbuf_cb(qdf_nbuf_t skb)
1129{
1130 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
1131 qdf_ipa_rx_data_t *ipa_tx_desc;
1132 struct wlan_ipa_tx_desc *tx_desc;
1133 uint16_t id;
1134
1135 if (!qdf_nbuf_ipa_owned_get(skb)) {
1136 dev_kfree_skb_any(skb);
1137 return;
1138 }
1139
1140 /* Get Tx desc pointer from SKB CB */
1141 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
1142 tx_desc = &ipa_ctx->tx_desc_pool[id];
1143 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
1144
1145 /* Return Tx Desc to IPA */
1146 qdf_ipa_free_skb(ipa_tx_desc);
1147
1148 /* Return to free tx desc list */
1149 qdf_spin_lock_bh(&ipa_ctx->q_lock);
1150 tx_desc->ipa_tx_desc_ptr = NULL;
1151 qdf_list_insert_back(&ipa_ctx->tx_desc_free_list, &tx_desc->node);
1152 ipa_ctx->stats.num_tx_desc_q_cnt--;
1153 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
1154
1155 ipa_ctx->stats.num_tx_comp_cnt++;
1156
1157 qdf_atomic_dec(&ipa_ctx->tx_ref_cnt);
1158
1159 wlan_ipa_wdi_rm_try_release(ipa_ctx);
1160}
1161
1162/**
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301163 * wlan_ipa_setup_iface() - Setup IPA on a given interface
1164 * @ipa_ctx: IPA IPA global context
1165 * @net_dev: Interface net device
1166 * @device_mode: Net interface device mode
1167 * @adapter: Interface upon which IPA is being setup
1168 * @sta_id: Station ID of the API instance
1169 * @session_id: Station ID of the API instance
1170 *
1171 * Return: QDF STATUS
1172 */
1173static QDF_STATUS wlan_ipa_setup_iface(struct wlan_ipa_priv *ipa_ctx,
1174 qdf_netdev_t net_dev,
1175 uint8_t device_mode, uint8_t sta_id,
1176 uint8_t session_id)
1177{
1178 struct wlan_ipa_iface_context *iface_context = NULL;
1179 void *tl_context = NULL;
1180 int i;
1181 QDF_STATUS status;
1182
1183 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
1184 * channel change indication. Since these indications are sent by lower
1185 * layer as SAP updates and IPA doesn't have to do anything for these
1186 * updates so ignoring!
1187 */
1188 if (device_mode == QDF_SAP_MODE) {
1189 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1190 iface_context = &(ipa_ctx->iface_context[i]);
1191 if (iface_context->dev == net_dev)
1192 return QDF_STATUS_SUCCESS;
1193 }
1194 }
1195
Yun Park21ec4902018-04-24 12:11:01 -07001196 if (WLAN_IPA_MAX_IFACE == ipa_ctx->num_iface) {
1197 ipa_err("Max interface reached %d", WLAN_IPA_MAX_IFACE);
1198 status = QDF_STATUS_E_NOMEM;
1199 QDF_ASSERT(0);
1200 goto end;
1201 }
1202
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301203 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1204 if (ipa_ctx->iface_context[i].tl_context == NULL) {
1205 iface_context = &(ipa_ctx->iface_context[i]);
1206 break;
1207 }
1208 }
1209
1210 if (iface_context == NULL) {
1211 ipa_err("All the IPA interfaces are in use");
1212 status = QDF_STATUS_E_NOMEM;
Yun Park21ec4902018-04-24 12:11:01 -07001213 QDF_ASSERT(0);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301214 goto end;
1215 }
1216
1217 iface_context->sta_id = sta_id;
1218 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(ipa_ctx->dp_soc,
1219 ipa_ctx->dp_pdev,
1220 sta_id);
1221 if (tl_context == NULL) {
1222 ipa_err("Not able to get TL context sta_id: %d", sta_id);
1223 status = QDF_STATUS_E_INVAL;
1224 goto end;
1225 }
1226
1227 iface_context->tl_context = tl_context;
1228 iface_context->dev = net_dev;
1229 iface_context->device_mode = device_mode;
1230 iface_context->session_id = session_id;
1231
1232 status = cdp_ipa_setup_iface(ipa_ctx->dp_soc, net_dev->name,
1233 net_dev->dev_addr,
1234 iface_context->prod_client,
1235 iface_context->cons_client,
1236 session_id,
1237 wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
1238 if (status != QDF_STATUS_SUCCESS)
1239 goto end;
1240
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05301241 /* Register IPA Tx desc free callback */
1242 qdf_nbuf_reg_free_cb(wlan_ipa_nbuf_cb);
1243
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301244 ipa_ctx->num_iface++;
1245
1246 ipa_debug("exit: num_iface=%d", ipa_ctx->num_iface);
1247
1248 return status;
1249
1250end:
1251 if (iface_context)
1252 wlan_ipa_cleanup_iface(iface_context);
1253
1254 return status;
1255}
1256
1257/**
1258 * wlan_ipa_uc_handle_first_con() - Handle first uC IPA connection
1259 * @ipa_ctx: IPA context
1260 *
1261 * Return: QDF STATUS
1262 */
1263static QDF_STATUS wlan_ipa_uc_handle_first_con(struct wlan_ipa_priv *ipa_ctx)
1264{
1265 ipa_debug("enter");
1266
1267 ipa_ctx->activated_fw_pipe = 0;
1268 ipa_ctx->resource_loading = true;
1269
1270 /* If RM feature enabled
1271 * Request PROD Resource first
1272 * PROD resource may return sync or async manners
1273 */
1274 if (wlan_ipa_is_rm_enabled(ipa_ctx->config)) {
Yun Parke114fbf2018-04-05 20:02:12 -07001275 if (!wlan_ipa_wdi_rm_request_resource(ipa_ctx,
1276 IPA_RM_RESOURCE_WLAN_PROD)) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301277 /* RM PROD request sync return
1278 * enable pipe immediately
1279 */
1280 if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
1281 ipa_err("IPA WDI Pipe activation failed");
1282 ipa_ctx->resource_loading = false;
1283 return QDF_STATUS_E_BUSY;
1284 }
1285 } else {
1286 ipa_err("IPA WDI Pipe activation deferred");
1287 }
1288 } else {
1289 /* RM Disabled
1290 * Just enabled all the PIPEs
1291 */
1292 if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
1293 ipa_err("IPA WDI Pipe activation failed");
1294 ipa_ctx->resource_loading = false;
1295 return QDF_STATUS_E_BUSY;
1296 }
1297 ipa_ctx->resource_loading = false;
1298 }
1299
1300 ipa_debug("exit");
1301
1302 return QDF_STATUS_SUCCESS;
1303}
1304
1305/**
1306 * wlan_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1307 * @ipa_ctx: IPA context
1308 *
1309 * Return: None
1310 */
1311static void wlan_ipa_uc_handle_last_discon(struct wlan_ipa_priv *ipa_ctx)
1312{
1313 ipa_debug("enter");
1314
1315 ipa_ctx->resource_unloading = true;
1316 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
1317 ipa_info("Disable FW RX PIPE");
1318 cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301319
1320 ipa_debug("exit: IPA WDI Pipes deactivated");
1321}
1322
1323/**
1324 * wlan_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
1325 * @ipa_ctx: global IPA context
1326 * @offload_type: MCC or SCC
1327 * @session_id: Session Id
1328 * @enable: TX offload enable or disable
1329 *
1330 * Return: none
1331 */
1332static void wlan_ipa_uc_offload_enable_disable(struct wlan_ipa_priv *ipa_ctx,
1333 uint32_t offload_type,
1334 uint8_t session_id,
1335 bool enable)
1336{
1337
1338 struct ipa_uc_offload_control_params req = {0};
1339
1340 if (session_id >= WLAN_IPA_MAX_SESSION) {
1341 ipa_err("invalid session id: %d", session_id);
1342 return;
1343 }
1344
1345 if (enable == ipa_ctx->vdev_offload_enabled[session_id]) {
1346 /*
1347 * This shouldn't happen :
1348 * IPA offload status is already set as desired
1349 */
1350 QDF_ASSERT(0);
1351 ipa_warn("IPA offload status is already set");
1352 ipa_warn("offload_type=%d, vdev_id=%d, enable=%d",
1353 offload_type, session_id, enable);
1354 return;
1355 }
1356
1357 ipa_info("offload_type=%d, session_id=%d, enable=%d",
1358 offload_type, session_id, enable);
1359
1360 req.offload_type = offload_type;
1361 req.vdev_id = session_id;
1362 req.enable = enable;
1363
1364 if (QDF_STATUS_SUCCESS !=
1365 ipa_send_uc_offload_enable_disable(ipa_ctx->pdev, &req)) {
1366 ipa_err("Fail to enable IPA offload");
1367 ipa_err("offload type=%d, vdev_id=%d, enable=%d",
1368 offload_type, session_id, enable);
1369 } else {
1370 ipa_ctx->vdev_offload_enabled[session_id] = enable;
1371 }
1372}
1373
1374/**
1375 * __wlan_ipa_wlan_evt() - IPA event handler
1376 * @net_dev: Interface net device
1377 * @device_mode: Net interface device mode
1378 * @sta_id: station id for the event
1379 * @session_id: session id for the event
1380 * @type: event enum of type ipa_wlan_event
1381 * @mac_address: MAC address associated with the event
1382 *
1383 * This function is meant to be called from within wlan_ipa_ctx.c
1384 *
1385 * Return: QDF STATUS
1386 */
1387static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
1388 uint8_t sta_id, uint8_t session_id,
1389 qdf_ipa_wlan_event type,
1390 uint8_t *mac_addr)
1391{
1392 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
1393 struct wlan_ipa_iface_context *iface_ctx = NULL;
1394 qdf_ipa_msg_meta_t meta;
1395 qdf_ipa_wlan_msg_t *msg;
1396 qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
1397 int i;
1398 QDF_STATUS status;
Ryan Hsub5783cf2018-05-14 12:13:15 -07001399 uint8_t sta_session_id = WLAN_IPA_MAX_SESSION;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301400
1401 ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d",
1402 net_dev->name, type, mac_addr, sta_id);
1403
1404 if (type >= QDF_IPA_WLAN_EVENT_MAX)
1405 return QDF_STATUS_E_INVAL;
1406
1407 if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
1408 !wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1409 (device_mode != QDF_SAP_MODE)) {
1410 return QDF_STATUS_SUCCESS;
1411 }
1412
Ryan Hsub5783cf2018-05-14 12:13:15 -07001413 if (ipa_ctx->sta_connected) {
1414 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
1415 if (iface_ctx)
1416 sta_session_id = iface_ctx->session_id;
1417 else
1418 ipa_err("sta iface_ctx is NULL");
1419 }
1420
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301421 /*
1422 * During IPA UC resource loading/unloading new events can be issued.
1423 */
1424 if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
1425 (ipa_ctx->resource_loading || ipa_ctx->resource_unloading)) {
1426 unsigned int pending_event_count;
1427 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1428
1429 ipa_info("Event:%d IPA resource %s inprogress", type,
1430 ipa_ctx->resource_loading ?
1431 "load" : "unload");
1432
1433 /* Wait until completion of the long/unloading */
1434 status = qdf_wait_for_event_completion(
1435 &ipa_ctx->ipa_resource_comp,
jiada8c542c2018-05-29 16:24:13 +08001436 IPA_RESOURCE_COMP_WAIT_TIME);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301437 if (status != QDF_STATUS_SUCCESS) {
1438 /*
1439 * If timed out, store the events separately and
1440 * handle them later.
1441 */
1442 ipa_info("IPA resource %s timed out",
1443 ipa_ctx->resource_loading ?
1444 "load" : "unload");
1445
1446 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1447
1448 pending_event_count =
1449 qdf_list_size(&ipa_ctx->pending_event);
1450 if (pending_event_count >=
1451 WLAN_IPA_MAX_PENDING_EVENT_COUNT) {
1452 ipa_info("Reached max pending evt count");
1453 qdf_list_remove_front(
1454 &ipa_ctx->pending_event,
1455 (qdf_list_node_t **)&pending_event);
1456 } else {
1457 pending_event =
1458 (struct wlan_ipa_uc_pending_event *)
1459 qdf_mem_malloc(sizeof(
1460 struct wlan_ipa_uc_pending_event));
1461 }
1462
1463 if (!pending_event) {
1464 ipa_err("Pending event memory alloc fail");
1465 qdf_mutex_release(&ipa_ctx->ipa_lock);
1466 return QDF_STATUS_E_NOMEM;
1467 }
1468
1469 pending_event->net_dev = net_dev;
1470 pending_event->device_mode = device_mode;
1471 pending_event->sta_id = sta_id;
1472 pending_event->session_id = session_id;
1473 pending_event->type = type;
1474 pending_event->is_loading = ipa_ctx->resource_loading;
1475 qdf_mem_copy(pending_event->mac_addr,
1476 mac_addr, QDF_MAC_ADDR_SIZE);
1477 qdf_list_insert_back(&ipa_ctx->pending_event,
1478 &pending_event->node);
1479
1480 qdf_mutex_release(&ipa_ctx->ipa_lock);
1481
Yun Park21ec4902018-04-24 12:11:01 -07001482 /* Cleanup interface */
1483 if (type == QDF_IPA_STA_DISCONNECT ||
1484 type == QDF_IPA_AP_DISCONNECT) {
1485 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1486 iface_ctx = &ipa_ctx->iface_context[i];
1487
1488 if (iface_ctx->dev == net_dev)
1489 break;
1490 }
1491 if (iface_ctx)
1492 wlan_ipa_cleanup_iface(iface_ctx);
1493 }
1494
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301495 return QDF_STATUS_SUCCESS;
1496 }
1497 ipa_info("IPA resource %s completed",
1498 ipa_ctx->resource_loading ?
1499 "load" : "unload");
1500 }
1501
1502 ipa_ctx->stats.event[type]++;
1503
1504 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1505 switch (type) {
1506 case QDF_IPA_STA_CONNECT:
1507 qdf_mutex_acquire(&ipa_ctx->event_lock);
1508
1509 /* STA already connected and without disconnect, connect again
1510 * This is Roaming scenario
1511 */
1512 if (ipa_ctx->sta_connected) {
1513 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
1514 if (iface_ctx)
1515 wlan_ipa_cleanup_iface(iface_ctx);
1516 }
1517
1518 status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
1519 sta_id, session_id);
1520 if (status != QDF_STATUS_SUCCESS) {
1521 qdf_mutex_release(&ipa_ctx->event_lock);
1522 goto end;
1523 }
1524
1525 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1526 (ipa_ctx->sap_num_connected_sta > 0) &&
1527 !ipa_ctx->sta_connected) {
1528 qdf_mutex_release(&ipa_ctx->event_lock);
1529 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1530 SIR_STA_RX_DATA_OFFLOAD, session_id,
1531 true);
1532 qdf_mutex_acquire(&ipa_ctx->event_lock);
1533 }
1534
1535 ipa_ctx->vdev_to_iface[session_id] =
1536 wlan_ipa_get_ifaceid(ipa_ctx, session_id);
1537
1538 ipa_ctx->sta_connected = 1;
1539
1540 qdf_mutex_release(&ipa_ctx->event_lock);
1541
1542 ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
1543 break;
1544
1545 case QDF_IPA_AP_CONNECT:
1546 qdf_mutex_acquire(&ipa_ctx->event_lock);
1547
1548 /* For DFS channel we get two start_bss event (before and after
1549 * CAC). Also when ACS range includes both DFS and non DFS
1550 * channels, we could possibly change channel many times due to
1551 * RADAR detection and chosen channel may not be a DFS channels.
1552 * So dont return error here. Just discard the event.
1553 */
jiadc908ada2018-05-11 14:40:54 +08001554 if (ipa_ctx->vdev_to_iface[session_id] !=
1555 WLAN_IPA_MAX_SESSION) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301556 qdf_mutex_release(&ipa_ctx->event_lock);
1557 return 0;
1558 }
1559
1560 status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
1561 sta_id, session_id);
1562 if (status != QDF_STATUS_SUCCESS) {
1563 qdf_mutex_release(&ipa_ctx->event_lock);
1564 ipa_err("%s: Evt: %d, Interface setup failed",
1565 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
1566 goto end;
1567 }
1568
1569 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1570 qdf_mutex_release(&ipa_ctx->event_lock);
1571 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1572 SIR_AP_RX_DATA_OFFLOAD, session_id, true);
1573 qdf_mutex_acquire(&ipa_ctx->event_lock);
1574 }
1575
1576 ipa_ctx->vdev_to_iface[session_id] =
1577 wlan_ipa_get_ifaceid(ipa_ctx, session_id);
1578 qdf_mutex_release(&ipa_ctx->event_lock);
1579 break;
1580
1581 case QDF_IPA_STA_DISCONNECT:
1582 qdf_mutex_acquire(&ipa_ctx->event_lock);
1583
1584 if (!ipa_ctx->sta_connected) {
1585 qdf_mutex_release(&ipa_ctx->event_lock);
1586 ipa_err("%s: Evt: %d, STA already disconnected",
1587 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
1588 return QDF_STATUS_E_INVAL;
1589 }
1590
1591 ipa_ctx->sta_connected = 0;
1592
1593 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1594 ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
1595 msg_ex->name);
1596 } else {
1597 /* Disable IPA UC TX PIPE when STA disconnected */
1598 if ((ipa_ctx->num_iface == 1) &&
Yun Parka29974a2018-04-09 12:05:49 -07001599 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
jiad3a321f32018-07-16 18:16:39 +08001600 !ipa_ctx->ipa_pipes_down) {
1601 if (cds_is_driver_unloading()) {
1602 /*
1603 * We disable WDI pipes directly here
1604 * since IPA_OPCODE_TX/RX_SUSPEND
1605 * message will not be processed when
1606 * unloading WLAN driver is in progress
1607 */
1608 wlan_ipa_uc_disable_pipes(ipa_ctx);
1609 } else {
1610 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1611 }
1612 }
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301613 }
1614
1615 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1616 (ipa_ctx->sap_num_connected_sta > 0)) {
1617 qdf_mutex_release(&ipa_ctx->event_lock);
1618 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1619 SIR_STA_RX_DATA_OFFLOAD, session_id, false);
1620 qdf_mutex_acquire(&ipa_ctx->event_lock);
1621 ipa_ctx->vdev_to_iface[session_id] =
1622 WLAN_IPA_MAX_SESSION;
1623 }
1624
1625 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1626 iface_ctx = &ipa_ctx->iface_context[i];
1627
1628 if (iface_ctx->dev == net_dev)
1629 break;
1630 }
1631 if (i < WLAN_IPA_MAX_IFACE)
1632 wlan_ipa_cleanup_iface(iface_ctx);
1633
1634 qdf_mutex_release(&ipa_ctx->event_lock);
1635
1636 ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
1637 break;
1638
1639 case QDF_IPA_AP_DISCONNECT:
1640 qdf_mutex_acquire(&ipa_ctx->event_lock);
1641
1642 if ((ipa_ctx->num_iface == 1) &&
Yun Parka29974a2018-04-09 12:05:49 -07001643 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301644 !ipa_ctx->ipa_pipes_down) {
1645 if (cds_is_driver_unloading()) {
1646 /*
1647 * We disable WDI pipes directly here since
1648 * IPA_OPCODE_TX/RX_SUSPEND message will not be
1649 * processed when unloading WLAN driver is in
1650 * progress
1651 */
1652 wlan_ipa_uc_disable_pipes(ipa_ctx);
1653 } else {
1654 /*
1655 * This shouldn't happen :
1656 * No interface left but WDI pipes are still
1657 * active - force close WDI pipes
1658 */
1659 ipa_err("No interface left but WDI pipes are still active");
1660 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1661 }
1662 }
1663
1664 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1665 qdf_mutex_release(&ipa_ctx->event_lock);
1666 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1667 SIR_AP_RX_DATA_OFFLOAD, session_id, false);
1668 qdf_mutex_acquire(&ipa_ctx->event_lock);
1669 ipa_ctx->vdev_to_iface[session_id] =
1670 WLAN_IPA_MAX_SESSION;
1671 }
1672
1673 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1674 iface_ctx = &ipa_ctx->iface_context[i];
1675
1676 if (iface_ctx->dev == net_dev)
1677 break;
1678 }
1679 if (i < WLAN_IPA_MAX_IFACE)
1680 wlan_ipa_cleanup_iface(iface_ctx);
1681
1682 qdf_mutex_release(&ipa_ctx->event_lock);
1683 break;
1684
1685 case QDF_IPA_CLIENT_CONNECT_EX:
1686 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1687 ipa_debug("%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
1688 net_dev->name, type);
1689 return QDF_STATUS_SUCCESS;
1690 }
1691
1692 qdf_mutex_acquire(&ipa_ctx->event_lock);
1693 if (wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, true, sta_id,
1694 mac_addr)) {
1695 qdf_mutex_release(&ipa_ctx->event_lock);
1696 ipa_err("%s: STA ID %d found", net_dev->name, sta_id);
1697 return QDF_STATUS_SUCCESS;
1698 }
1699
1700 /* Enable IPA UC Data PIPEs when first STA connected */
1701 if (ipa_ctx->sap_num_connected_sta == 0 &&
1702 ipa_ctx->uc_loaded == true) {
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301703
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301704 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1705 ipa_ctx->sta_connected) {
1706 qdf_mutex_release(&ipa_ctx->event_lock);
1707 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1708 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301709 sta_session_id, true);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301710 qdf_mutex_acquire(&ipa_ctx->event_lock);
1711 }
1712
1713 status = wlan_ipa_uc_handle_first_con(ipa_ctx);
1714 if (status != QDF_STATUS_SUCCESS) {
1715 ipa_info("%s: handle 1st con fail",
1716 net_dev->name);
1717
1718 if (wlan_ipa_uc_sta_is_enabled(
1719 ipa_ctx->config) &&
1720 ipa_ctx->sta_connected) {
1721 qdf_mutex_release(&ipa_ctx->event_lock);
1722 wlan_ipa_uc_offload_enable_disable(
1723 ipa_ctx,
1724 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301725 sta_session_id, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301726 } else {
1727 qdf_mutex_release(&ipa_ctx->event_lock);
1728 }
1729
1730 return status;
1731 }
1732 }
1733
1734 ipa_ctx->sap_num_connected_sta++;
1735
1736 qdf_mutex_release(&ipa_ctx->event_lock);
1737
1738 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1739 QDF_IPA_MSG_META_MSG_LEN(&meta) =
1740 (sizeof(qdf_ipa_wlan_msg_ex_t) +
1741 sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
1742 msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1743
1744 if (msg_ex == NULL) {
1745 ipa_err("msg_ex allocation failed");
1746 return QDF_STATUS_E_NOMEM;
1747 }
1748 strlcpy(msg_ex->name, net_dev->name,
1749 IPA_RESOURCE_NAME_MAX);
1750 msg_ex->num_of_attribs = 1;
1751 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
1752 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1753 msg_ex->attribs[0].offset =
1754 WLAN_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
1755 } else {
1756 msg_ex->attribs[0].offset =
1757 WLAN_IPA_WLAN_HDR_DES_MAC_OFFSET;
1758 }
1759 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
1760 IPA_MAC_ADDR_SIZE);
1761
1762 if (qdf_ipa_send_msg(&meta, msg_ex, wlan_ipa_msg_free_fn)) {
1763 ipa_info("%s: Evt: %d send ipa msg fail",
1764 net_dev->name, type);
1765 qdf_mem_free(msg_ex);
1766 return QDF_STATUS_E_FAILURE;
1767 }
1768 ipa_ctx->stats.num_send_msg++;
1769
1770 ipa_info("sap_num_connected_sta=%d",
1771 ipa_ctx->sap_num_connected_sta);
1772
1773 return QDF_STATUS_SUCCESS;
1774
1775 case WLAN_CLIENT_DISCONNECT:
1776 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1777 ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
1778 msg_ex->name);
1779 return QDF_STATUS_SUCCESS;
1780 }
1781
1782 qdf_mutex_acquire(&ipa_ctx->event_lock);
1783 if (!ipa_ctx->sap_num_connected_sta) {
1784 qdf_mutex_release(&ipa_ctx->event_lock);
1785 ipa_err("%s: Evt: %d, Client already disconnected",
1786 msg_ex->name,
1787 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1788
1789 return QDF_STATUS_SUCCESS;
1790 }
1791 if (!wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, false,
1792 sta_id, mac_addr)) {
1793 qdf_mutex_release(&ipa_ctx->event_lock);
1794 ipa_err("%s: STA ID %d NOT found, not valid",
1795 msg_ex->name, sta_id);
1796
1797 return QDF_STATUS_SUCCESS;
1798 }
1799 ipa_ctx->sap_num_connected_sta--;
1800
1801 /* Disable IPA UC TX PIPE when last STA disconnected */
1802 if (!ipa_ctx->sap_num_connected_sta &&
1803 ipa_ctx->uc_loaded == true) {
Yun Parka29974a2018-04-09 12:05:49 -07001804 if ((false == ipa_ctx->resource_unloading) &&
1805 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
1806 !ipa_ctx->ipa_pipes_down) {
jiad3a321f32018-07-16 18:16:39 +08001807 if (cds_is_driver_unloading()) {
1808 /*
1809 * We disable WDI pipes directly here
1810 * since IPA_OPCODE_TX/RX_SUSPEND
1811 * message will not be processed when
1812 * unloading WLAN driver is in progress
1813 */
1814 wlan_ipa_uc_disable_pipes(ipa_ctx);
1815 } else {
1816 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1817 }
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301818 }
1819
1820 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1821 ipa_ctx->sta_connected) {
1822 qdf_mutex_release(&ipa_ctx->event_lock);
1823 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1824 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301825 sta_session_id, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301826 } else {
1827 qdf_mutex_release(&ipa_ctx->event_lock);
1828 }
1829 } else {
1830 qdf_mutex_release(&ipa_ctx->event_lock);
1831 }
1832
1833 ipa_info("sap_num_connected_sta=%d",
1834 ipa_ctx->sap_num_connected_sta);
1835 break;
1836
1837 default:
1838 return QDF_STATUS_SUCCESS;
1839 }
1840
1841 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
1842 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1843 if (!msg) {
1844 ipa_err("msg allocation failed");
1845 return QDF_STATUS_E_NOMEM;
1846 }
1847
1848 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1849 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name,
1850 IPA_RESOURCE_NAME_MAX);
1851 qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN);
1852
1853 ipa_debug("%s: Evt: %d", QDF_IPA_WLAN_MSG_NAME(msg),
1854 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1855
1856 if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) {
1857
1858 ipa_err("%s: Evt: %d fail",
1859 QDF_IPA_WLAN_MSG_NAME(msg),
1860 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1861 qdf_mem_free(msg);
1862
1863 return QDF_STATUS_E_FAILURE;
1864 }
1865
1866 ipa_ctx->stats.num_send_msg++;
1867
1868end:
1869 return QDF_STATUS_SUCCESS;
1870}
1871
1872/**
1873 * wlan_host_to_ipa_wlan_event() - convert wlan_ipa_wlan_event to ipa_wlan_event
Yun Park84fbb272018-04-02 15:31:01 -07001874 * @wlan_ipa_event_type: event to be converted to an ipa_wlan_event
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301875 *
1876 * Return: qdf_ipa_wlan_event representing the wlan_ipa_wlan_event
1877 */
1878static qdf_ipa_wlan_event
1879wlan_host_to_ipa_wlan_event(enum wlan_ipa_wlan_event wlan_ipa_event_type)
1880{
Yun Park84fbb272018-04-02 15:31:01 -07001881 qdf_ipa_wlan_event ipa_event;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301882
1883 switch (wlan_ipa_event_type) {
1884 case WLAN_IPA_CLIENT_CONNECT:
1885 ipa_event = QDF_IPA_CLIENT_CONNECT;
1886 break;
1887 case WLAN_IPA_CLIENT_DISCONNECT:
1888 ipa_event = QDF_IPA_CLIENT_DISCONNECT;
1889 break;
1890 case WLAN_IPA_AP_CONNECT:
1891 ipa_event = QDF_IPA_AP_CONNECT;
1892 break;
1893 case WLAN_IPA_AP_DISCONNECT:
1894 ipa_event = QDF_IPA_AP_DISCONNECT;
1895 break;
1896 case WLAN_IPA_STA_CONNECT:
1897 ipa_event = QDF_IPA_STA_CONNECT;
1898 break;
1899 case WLAN_IPA_STA_DISCONNECT:
1900 ipa_event = QDF_IPA_STA_DISCONNECT;
1901 break;
1902 case WLAN_IPA_CLIENT_CONNECT_EX:
1903 ipa_event = QDF_IPA_CLIENT_CONNECT_EX;
1904 break;
1905 case WLAN_IPA_WLAN_EVENT_MAX:
1906 default:
1907 ipa_event = QDF_IPA_WLAN_EVENT_MAX;
1908 break;
1909 }
1910
1911 return ipa_event;
1912}
1913
1914/**
1915 * wlan_ipa_wlan_evt() - SSR wrapper for __wlan_ipa_wlan_evt
1916 * @net_dev: Interface net device
1917 * @device_mode: Net interface device mode
1918 * @sta_id: station id for the event
1919 * @session_id: session id for the event
1920 * @ipa_event_type: event enum of type wlan_ipa_wlan_event
1921 * @mac_address: MAC address associated with the event
1922 *
1923 * Return: QDF_STATUS
1924 */
1925QDF_STATUS wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
1926 uint8_t sta_id, uint8_t session_id,
1927 enum wlan_ipa_wlan_event ipa_event_type,
1928 uint8_t *mac_addr)
1929{
1930 qdf_ipa_wlan_event type = wlan_host_to_ipa_wlan_event(ipa_event_type);
1931 QDF_STATUS status = QDF_STATUS_SUCCESS;
1932
1933 /* Data path offload only support for STA and SAP mode */
1934 if ((device_mode == QDF_STA_MODE) ||
1935 (device_mode == QDF_SAP_MODE))
1936 status = __wlan_ipa_wlan_evt(net_dev, device_mode, sta_id,
1937 session_id, type, mac_addr);
1938
1939 return status;
1940}
1941
1942/**
1943 * wlan_ipa_uc_proc_pending_event() - Process IPA uC pending events
1944 * @ipa_ctx: Global IPA IPA context
1945 * @is_loading: Indicate if invoked during loading
1946 *
1947 * Return: None
1948 */
1949static void
1950wlan_ipa_uc_proc_pending_event(struct wlan_ipa_priv *ipa_ctx, bool is_loading)
1951{
1952 unsigned int pending_event_count;
1953 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1954
1955 pending_event_count = qdf_list_size(&ipa_ctx->pending_event);
1956 ipa_debug("Pending Event Count %d", pending_event_count);
1957 if (!pending_event_count) {
1958 ipa_debug("No Pending Event");
1959 return;
1960 }
1961
1962 qdf_list_remove_front(&ipa_ctx->pending_event,
1963 (qdf_list_node_t **)&pending_event);
1964 while (pending_event != NULL) {
Sravan Kumar Kairam8c151e22018-06-15 16:35:39 +05301965 struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
1966 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
1967 struct wlan_objmgr_vdev *vdev =
1968 wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
1969 pending_event->session_id,
1970 WLAN_IPA_ID);
1971 if (pending_event->is_loading == is_loading && vdev) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301972 __wlan_ipa_wlan_evt(pending_event->net_dev,
1973 pending_event->device_mode,
1974 pending_event->sta_id,
1975 pending_event->session_id,
1976 pending_event->type,
1977 pending_event->mac_addr);
1978 }
Sravan Kumar Kairam8c151e22018-06-15 16:35:39 +05301979
1980 if (vdev)
1981 wlan_objmgr_vdev_release_ref(vdev, WLAN_IPA_ID);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301982 qdf_mem_free(pending_event);
1983 pending_event = NULL;
1984 qdf_list_remove_front(&ipa_ctx->pending_event,
1985 (qdf_list_node_t **)&pending_event);
1986 }
1987}
1988
1989/**
Ryan Hsub5783cf2018-05-14 12:13:15 -07001990 * wlan_ipa_free_tx_desc_list() - Free IPA Tx desc list
1991 * @ipa_ctx: IPA context
1992 *
1993 * Return: None
1994 */
1995static inline void wlan_ipa_free_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
1996{
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05301997 int i;
Ryan Hsub5783cf2018-05-14 12:13:15 -07001998 qdf_ipa_rx_data_t *ipa_tx_desc;
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05301999 uint32_t pool_size;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002000
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302001 if (!ipa_ctx->tx_desc_pool)
2002 return;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002003
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302004 qdf_spin_lock_bh(&ipa_ctx->q_lock);
2005 pool_size = ipa_ctx->tx_desc_free_list.max_size;
2006 for (i = 0; i < pool_size; i++) {
2007 ipa_tx_desc = ipa_ctx->tx_desc_pool[i].ipa_tx_desc_ptr;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002008 if (ipa_tx_desc)
2009 qdf_ipa_free_skb(ipa_tx_desc);
2010
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302011 if (qdf_list_remove_node(&ipa_ctx->tx_desc_free_list,
2012 &ipa_ctx->tx_desc_pool[i].node) !=
2013 QDF_STATUS_SUCCESS)
2014 ipa_err("Failed to remove node from tx desc freelist");
Ryan Hsub5783cf2018-05-14 12:13:15 -07002015 }
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302016 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
2017
2018 qdf_list_destroy(&ipa_ctx->tx_desc_free_list);
2019 qdf_mem_free(ipa_ctx->tx_desc_pool);
2020 ipa_ctx->tx_desc_pool = NULL;
2021
2022 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
2023 ipa_ctx->stats.num_tx_desc_error = 0;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002024}
2025
2026/**
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302027 * wlan_ipa_alloc_tx_desc_free_list() - Allocate IPA Tx desc list
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302028 * @ipa_ctx: IPA context
2029 *
2030 * Return: QDF_STATUS
2031 */
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302032static QDF_STATUS
2033wlan_ipa_alloc_tx_desc_free_list(struct wlan_ipa_priv *ipa_ctx)
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302034{
2035 int i;
2036 uint32_t max_desc_cnt;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302037
2038 max_desc_cnt = ipa_ctx->config->txbuf_count;
2039
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302040 ipa_ctx->tx_desc_pool = qdf_mem_malloc(sizeof(struct wlan_ipa_tx_desc) *
2041 max_desc_cnt);
2042
2043 if (!ipa_ctx->tx_desc_pool) {
2044 ipa_err("Free Tx descriptor allocation failed");
2045 return QDF_STATUS_E_NOMEM;
2046 }
2047
2048 qdf_list_create(&ipa_ctx->tx_desc_free_list, max_desc_cnt);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302049
2050 qdf_spin_lock_bh(&ipa_ctx->q_lock);
2051 for (i = 0; i < max_desc_cnt; i++) {
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302052 ipa_ctx->tx_desc_pool[i].id = i;
2053 ipa_ctx->tx_desc_pool[i].ipa_tx_desc_ptr = NULL;
2054 qdf_list_insert_back(&ipa_ctx->tx_desc_free_list,
2055 &ipa_ctx->tx_desc_pool[i].node);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302056 }
2057
2058 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
2059 ipa_ctx->stats.num_tx_desc_error = 0;
2060
2061 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
2062
2063 return QDF_STATUS_SUCCESS;
2064}
2065
2066#ifndef QCA_LL_TX_FLOW_CONTROL_V2
2067/**
2068 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
2069 * @ipa_ctx: Global IPA IPA context
2070 * @desc_fifo_sz: Number of descriptors
2071 *
2072 * Return: 0 on success, negative errno on error
2073 */
2074static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2075 int32_t desc_fifo_sz)
2076{
2077 int i, ret = 0;
2078 qdf_ipa_sys_connect_params_t *ipa;
2079
2080 /*setup TX pipes */
2081 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2082 ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params;
2083
2084 ipa->client = wlan_ipa_iface_2_client[i].cons_client;
2085 ipa->desc_fifo_sz = desc_fifo_sz;
2086 ipa->priv = &ipa_ctx->iface_context[i];
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302087 ipa->notify = wlan_ipa_i2w_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302088
2089 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2090 ipa->ipa_ep_cfg.hdr.hdr_len =
2091 WLAN_IPA_UC_WLAN_TX_HDR_LEN;
2092 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2093 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2094 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2095 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
2096 WLAN_IPA_UC_WLAN_8023_HDR_SIZE;
2097 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2098 } else {
2099 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN;
2100 }
2101 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
2102
2103 ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa,
2104 &ipa_ctx->sys_pipe[i].conn_hdl);
2105 if (ret) {
2106 ipa_err("Failed for pipe %d ret: %d", i, ret);
2107 return ret;
2108 }
2109 ipa_ctx->sys_pipe[i].conn_hdl_valid = 1;
2110 }
2111
2112 return ret;
2113}
2114#else
2115/**
2116 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
2117 * @ipa_ctx: Global IPA IPA context
2118 * @desc_fifo_sz: Number of descriptors
2119 *
2120 * Return: 0 on success, negative errno on error
2121 */
2122static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2123 int32_t desc_fifo_sz)
2124{
2125 /*
2126 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
2127 * is enabled, where per vdev descriptors are supported in firmware.
2128 */
2129 return 0;
2130}
2131#endif
2132
2133/**
2134 * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
2135 * @ipa_ctx: Global IPA IPA context
2136 * @desc_fifo_sz: Number of descriptors
2137 *
2138 * Return: 0 on success, negative errno on error
2139 */
2140static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2141 int32_t desc_fifo_sz)
2142{
2143 int ret = 0;
2144 qdf_ipa_sys_connect_params_t *ipa;
2145
2146 /*
2147 * Hard code it here, this can be extended if in case
2148 * PROD pipe is also per interface.
2149 * Right now there is no advantage of doing this.
2150 */
2151 ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params;
2152
2153 ipa->client = IPA_CLIENT_WLAN1_PROD;
2154
2155 ipa->desc_fifo_sz = desc_fifo_sz;
2156 ipa->priv = ipa_ctx;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302157 ipa->notify = wlan_ipa_w2i_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302158
2159 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2160 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN;
2161 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
2162 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
2163
2164 ret = qdf_ipa_setup_sys_pipe(ipa,
2165 &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl);
2166 if (ret) {
2167 ipa_err("Failed for RX pipe: %d", ret);
2168 return ret;
2169 }
2170 ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1;
2171
2172 return ret;
2173}
2174
2175/**
Ryan Hsub5783cf2018-05-14 12:13:15 -07002176 * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
2177 * @ipa_ctx: Global IPA IPA context
2178 *
2179 * Return: None
2180 */
2181static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
2182{
2183 int ret, i;
2184
2185 if (!ipa_ctx)
2186 return;
2187
2188 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
2189 if (ipa_ctx->sys_pipe[i].conn_hdl_valid) {
2190 ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx,
2191 ipa_ctx->sys_pipe[i].conn_hdl);
2192 if (ret)
2193 ipa_err("Failed:%d", ret);
2194
2195 ipa_ctx->sys_pipe[i].conn_hdl_valid = 0;
2196 }
2197 }
2198
2199 wlan_ipa_free_tx_desc_list(ipa_ctx);
2200}
2201
2202/**
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302203 * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
2204 * @ipa_ctx: Global IPA IPA context
2205 *
2206 * Return: 0 on success, negative errno on error
2207 */
2208static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
2209{
Ryan Hsub5783cf2018-05-14 12:13:15 -07002210 int ret = 0;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302211 uint32_t desc_fifo_sz;
2212
2213 /* The maximum number of descriptors that can be provided to a BAM at
2214 * once is one less than the total number of descriptors that the buffer
2215 * can contain.
2216 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
2217 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
2218 * be provided at once.
2219 * Because of above requirement, one extra descriptor will be added to
2220 * make sure hardware always has one descriptor.
2221 */
2222 desc_fifo_sz = ipa_ctx->config->desc_size
2223 + SPS_DESC_SIZE;
2224
2225 ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz);
2226 if (ret) {
2227 ipa_err("Failed for TX pipe: %d", ret);
2228 goto setup_sys_pipe_fail;
2229 }
2230
2231 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2232 ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz);
2233 if (ret) {
2234 ipa_err("Failed for RX pipe: %d", ret);
2235 goto setup_sys_pipe_fail;
2236 }
2237 }
2238
2239 /* Allocate free Tx desc list */
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302240 ret = wlan_ipa_alloc_tx_desc_free_list(ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302241 if (ret)
2242 goto setup_sys_pipe_fail;
2243
2244 return ret;
2245
2246setup_sys_pipe_fail:
Ryan Hsub5783cf2018-05-14 12:13:15 -07002247 wlan_ipa_teardown_sys_pipe(ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302248
2249 return ret;
2250}
2251
jiadbb47e132018-03-30 16:28:30 +08002252#ifndef QCA_LL_TX_FLOW_CONTROL_V2
2253QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
2254 bool mcc_mode)
2255{
2256 qdf_ipa_msg_meta_t meta;
2257 qdf_ipa_wlan_msg_t *msg;
2258 int ret;
2259
2260 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
2261 return QDF_STATUS_SUCCESS;
2262
2263 /* Send SCC/MCC Switching event to IPA */
2264 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
2265 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
2266 if (msg == NULL) {
2267 ipa_err("msg allocation failed");
2268 return QDF_STATUS_E_NOMEM;
2269 }
2270
jiad629b2172018-05-11 15:34:22 +08002271 if (mcc_mode) {
jiadbb47e132018-03-30 16:28:30 +08002272 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_MCC);
jiad629b2172018-05-11 15:34:22 +08002273 ipa_ctx->stats.event[QDF_SWITCH_TO_MCC]++;
2274 } else {
jiadbb47e132018-03-30 16:28:30 +08002275 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_SCC);
jiad629b2172018-05-11 15:34:22 +08002276 ipa_ctx->stats.event[QDF_SWITCH_TO_SCC]++;
2277 }
2278
jiadbb47e132018-03-30 16:28:30 +08002279 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2280 "ipa_send_msg(Evt:%d)",
2281 QDF_IPA_MSG_META_MSG_TYPE(&meta));
2282
2283 ret = qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn);
2284
2285 if (ret) {
2286 ipa_err("ipa_send_msg(Evt:%d) - fail=%d",
2287 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
2288 qdf_mem_free(msg);
2289 return QDF_STATUS_E_FAILURE;
2290 }
2291
2292 return QDF_STATUS_SUCCESS;
2293}
2294
2295static void wlan_ipa_mcc_work_handler(void *data)
2296{
2297 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
2298
2299 wlan_ipa_send_mcc_scc_msg(ipa_ctx, ipa_ctx->mcc_mode);
2300}
2301#endif
2302
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302303/**
2304 * wlan_ipa_setup() - IPA initialization function
2305 * @ipa_ctx: IPA context
2306 * @ipa_cfg: IPA config
2307 *
2308 * Allocate ipa_ctx resources, ipa pipe resource and register
2309 * wlan interface with IPA module.
2310 *
2311 * Return: QDF_STATUS enumeration
2312 */
2313QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
2314 struct wlan_ipa_config *ipa_cfg)
2315{
2316 int ret, i;
2317 struct wlan_ipa_iface_context *iface_context = NULL;
2318 QDF_STATUS status;
2319
2320 ipa_debug("enter");
2321
2322 gp_ipa = ipa_ctx;
2323 ipa_ctx->num_iface = 0;
2324 ipa_ctx->config = ipa_cfg;
2325
2326 wlan_ipa_wdi_get_wdi_version(ipa_ctx);
2327
2328 /* Create the interface context */
2329 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2330 iface_context = &ipa_ctx->iface_context[i];
2331 iface_context->ipa_ctx = ipa_ctx;
2332 iface_context->cons_client =
2333 wlan_ipa_iface_2_client[i].cons_client;
2334 iface_context->prod_client =
2335 wlan_ipa_iface_2_client[i].prod_client;
2336 iface_context->iface_id = i;
2337 iface_context->dev = NULL;
2338 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
2339 iface_context->tl_context = NULL;
2340 qdf_spinlock_create(&iface_context->interface_lock);
2341 }
2342
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302343 qdf_create_work(0, &ipa_ctx->pm_work, wlan_ipa_pm_flush, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302344 qdf_spinlock_create(&ipa_ctx->pm_lock);
2345 qdf_spinlock_create(&ipa_ctx->q_lock);
2346 qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head);
2347 qdf_list_create(&ipa_ctx->pending_event, 1000);
2348 qdf_mutex_create(&ipa_ctx->event_lock);
2349 qdf_mutex_create(&ipa_ctx->ipa_lock);
2350
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302351 status = wlan_ipa_wdi_setup_rm(ipa_ctx);
2352 if (status != QDF_STATUS_SUCCESS)
2353 goto fail_setup_rm;
2354
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302355 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++)
2356 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
2357 sizeof(struct wlan_ipa_sys_pipe));
2358
2359 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
2360 qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats));
2361 ipa_ctx->sap_num_connected_sta = 0;
2362 ipa_ctx->ipa_tx_packets_diff = 0;
2363 ipa_ctx->ipa_rx_packets_diff = 0;
2364 ipa_ctx->ipa_p_tx_packets = 0;
2365 ipa_ctx->ipa_p_rx_packets = 0;
2366 ipa_ctx->resource_loading = false;
2367 ipa_ctx->resource_unloading = false;
2368 ipa_ctx->sta_connected = 0;
2369 ipa_ctx->ipa_pipes_down = true;
2370 ipa_ctx->wdi_enabled = false;
2371 /* Setup IPA system pipes */
2372 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2373 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
2374 if (ret)
2375 goto fail_create_sys_pipe;
jiadbb47e132018-03-30 16:28:30 +08002376
2377 qdf_create_work(0, &ipa_ctx->mcc_work,
2378 wlan_ipa_mcc_work_handler, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302379 }
2380
2381 status = wlan_ipa_wdi_init(ipa_ctx);
2382 if (status == QDF_STATUS_E_BUSY)
2383 status = wlan_ipa_uc_send_wdi_control_msg(false);
2384 if (status != QDF_STATUS_SUCCESS) {
Ryan Hsub5783cf2018-05-14 12:13:15 -07002385 ipa_err("IPA WDI init failed: ret=%d", status);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302386 goto fail_create_sys_pipe;
2387 }
2388 } else {
2389 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
2390 if (ret)
2391 goto fail_create_sys_pipe;
2392 }
2393
2394 qdf_event_create(&ipa_ctx->ipa_resource_comp);
2395
2396 ipa_debug("exit: success");
2397
2398 return QDF_STATUS_SUCCESS;
2399
2400fail_create_sys_pipe:
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302401 wlan_ipa_wdi_destroy_rm(ipa_ctx);
2402
2403fail_setup_rm:
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302404 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302405 qdf_spinlock_destroy(&ipa_ctx->q_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 qdf_mutex_destroy(&ipa_ctx->event_lock);
2411 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
2412 qdf_list_destroy(&ipa_ctx->pending_event);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302413 gp_ipa = NULL;
2414 ipa_debug("exit: fail");
2415
2416 return QDF_STATUS_E_FAILURE;
2417}
2418
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302419void wlan_ipa_flush(struct wlan_ipa_priv *ipa_ctx)
2420{
2421 qdf_nbuf_t skb;
2422 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
2423
2424 if (!wlan_ipa_is_enabled(ipa_ctx->config))
2425 return;
2426
2427 qdf_cancel_work(&ipa_ctx->pm_work);
2428
2429 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
2430
2431 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head))
2432 != NULL)) {
2433 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
2434
2435 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
jiadab8cea02018-05-24 09:16:14 +08002436
2437 if (pm_tx_cb->exception) {
2438 dev_kfree_skb_any(skb);
2439 } else {
2440 if (pm_tx_cb->ipa_tx_desc)
2441 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
2442 }
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302443
2444 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
2445 }
2446 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
2447}
2448
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302449QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx)
2450{
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302451 struct wlan_ipa_iface_context *iface_context;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302452 int i;
2453
2454 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2455 wlan_ipa_teardown_sys_pipe(ipa_ctx);
2456
2457 /* Teardown IPA sys_pipe for MCC */
jiadbb47e132018-03-30 16:28:30 +08002458 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302459 wlan_ipa_teardown_sys_pipe(ipa_ctx);
jiadbb47e132018-03-30 16:28:30 +08002460 qdf_cancel_work(&ipa_ctx->mcc_work);
2461 }
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302462
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302463 wlan_ipa_wdi_destroy_rm(ipa_ctx);
2464
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302465 wlan_ipa_flush(ipa_ctx);
2466
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302467 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
2468 qdf_spinlock_destroy(&ipa_ctx->q_lock);
2469
2470 /* destroy the interface lock */
2471 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2472 iface_context = &ipa_ctx->iface_context[i];
2473 qdf_spinlock_destroy(&iface_context->interface_lock);
2474 }
2475
2476 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
2477 wlan_ipa_wdi_cleanup();
2478 qdf_mutex_destroy(&ipa_ctx->event_lock);
2479 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
2480 qdf_list_destroy(&ipa_ctx->pending_event);
2481
2482 }
2483
2484 gp_ipa = NULL;
2485
2486 return QDF_STATUS_SUCCESS;
2487}
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +05302488
2489struct wlan_ipa_iface_context
2490*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode)
2491{
2492 struct wlan_ipa_iface_context *iface_ctx = NULL;
2493 int i;
2494
2495 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2496 iface_ctx = &ipa_ctx->iface_context[i];
2497
2498 if (iface_ctx->device_mode == mode)
2499 return iface_ctx;
2500 }
2501
2502 return NULL;
2503}
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302504
jiadbb47e132018-03-30 16:28:30 +08002505void wlan_ipa_set_mcc_mode(struct wlan_ipa_priv *ipa_ctx, bool mcc_mode)
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302506{
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302507 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
jiadbb47e132018-03-30 16:28:30 +08002508 return;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302509
jiadbb47e132018-03-30 16:28:30 +08002510 if (ipa_ctx->mcc_mode == mcc_mode)
2511 return;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302512
jiadbb47e132018-03-30 16:28:30 +08002513 ipa_ctx->mcc_mode = mcc_mode;
2514 qdf_sched_work(0, &ipa_ctx->mcc_work);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302515}
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302516
2517/**
2518 * wlan_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2519 * @ipa_ctx: ipa ipa local context
2520 *
2521 * Will handle IPA UC image loaded indication comes from IPA kernel
2522 *
2523 * Return: None
2524 */
2525static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx)
2526{
2527 struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
2528 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
2529 qdf_device_t qdf_dev = wlan_psoc_get_qdf_dev(psoc);
2530 QDF_STATUS status;
2531
2532 ipa_info("UC READY");
Ryan Hsub5783cf2018-05-14 12:13:15 -07002533
2534 if (!qdf_dev) {
2535 ipa_err("qdf device is NULL!");
2536 return;
2537 }
2538
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302539 if (true == ipa_ctx->uc_loaded) {
2540 ipa_info("UC already loaded");
2541 return;
2542 }
2543
Lihua Liu15f6e452018-05-30 17:31:06 +08002544 if (!qdf_dev) {
2545 ipa_err("qdf_dev is null");
2546 return;
2547 }
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302548 /* Connect pipe */
2549 status = wlan_ipa_wdi_setup(ipa_ctx, qdf_dev);
2550 if (status) {
2551 ipa_err("Failure to setup IPA pipes (status=%d)",
2552 status);
2553 return;
2554 }
2555
2556 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302557
2558 /* If already any STA connected, enable IPA/FW PIPEs */
2559 if (ipa_ctx->sap_num_connected_sta) {
2560 ipa_debug("Client already connected, enable IPA/FW PIPEs");
2561 wlan_ipa_uc_handle_first_con(ipa_ctx);
2562 }
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302563}
2564
2565/**
2566 * wlan_ipa_uc_op_cb() - IPA uC operation callback
2567 * @op_msg: operation message received from firmware
2568 * @usr_ctxt: user context registered with TL (we register the IPA Global
2569 * context)
2570 *
2571 * Return: None
2572 */
2573static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
2574 struct wlan_ipa_priv *ipa_ctx)
2575{
2576 struct op_msg_type *msg = op_msg;
2577 struct ipa_uc_fw_stats *uc_fw_stat;
2578
2579 if (!op_msg) {
2580 ipa_err("INVALID ARG");
2581 return;
2582 }
2583
2584 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
2585 ipa_err("INVALID OPCODE %d", msg->op_code);
2586 qdf_mem_free(op_msg);
2587 return;
2588 }
2589
2590 ipa_debug("OPCODE=%d", msg->op_code);
2591
2592 if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_RESUME) ||
2593 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_RESUME)) {
2594 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2595 ipa_ctx->activated_fw_pipe++;
Yun Parka29974a2018-04-09 12:05:49 -07002596 if (wlan_ipa_is_fw_wdi_activated(ipa_ctx)) {
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302597 ipa_ctx->resource_loading = false;
2598 qdf_event_set(&ipa_ctx->ipa_resource_comp);
2599 if (ipa_ctx->wdi_enabled == false) {
2600 ipa_ctx->wdi_enabled = true;
2601 if (wlan_ipa_uc_send_wdi_control_msg(true) == 0)
2602 wlan_ipa_send_mcc_scc_msg(ipa_ctx,
2603 ipa_ctx->mcc_mode);
2604 }
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302605 wlan_ipa_uc_proc_pending_event(ipa_ctx, true);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302606 if (ipa_ctx->pending_cons_req)
Yun Parke114fbf2018-04-05 20:02:12 -07002607 wlan_ipa_wdi_rm_notify_completion(
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302608 QDF_IPA_RM_RESOURCE_GRANTED,
2609 QDF_IPA_RM_RESOURCE_WLAN_CONS);
2610 ipa_ctx->pending_cons_req = false;
2611 }
2612 qdf_mutex_release(&ipa_ctx->ipa_lock);
2613 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_SUSPEND) ||
2614 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND)) {
2615 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
Sravan Kumar Kairama61e5a92018-06-18 13:01:05 +05302616
2617 if (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND) {
2618 wlan_ipa_uc_disable_pipes(ipa_ctx);
2619 ipa_info("Disable FW TX PIPE");
2620 cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
2621 false, true);
2622 }
2623
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302624 ipa_ctx->activated_fw_pipe--;
2625 if (!ipa_ctx->activated_fw_pipe) {
2626 /*
2627 * Async return success from FW
2628 * Disable/suspend all the PIPEs
2629 */
2630 ipa_ctx->resource_unloading = false;
2631 qdf_event_set(&ipa_ctx->ipa_resource_comp);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302632 if (wlan_ipa_is_rm_enabled(ipa_ctx->config))
Yun Parke114fbf2018-04-05 20:02:12 -07002633 wlan_ipa_wdi_rm_release_resource(ipa_ctx,
2634 QDF_IPA_RM_RESOURCE_WLAN_PROD);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302635 wlan_ipa_uc_proc_pending_event(ipa_ctx, false);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302636 ipa_ctx->pending_cons_req = false;
2637 }
2638 qdf_mutex_release(&ipa_ctx->ipa_lock);
2639 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
2640 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_DEBUG)) {
2641 uc_fw_stat = (struct ipa_uc_fw_stats *)
2642 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2643
2644 /* WLAN FW WDI stats */
2645 wlan_ipa_print_fw_wdi_stats(ipa_ctx, uc_fw_stat);
2646 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
2647 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_BW_CAL)) {
2648 /* STATs from FW */
2649 uc_fw_stat = (struct ipa_uc_fw_stats *)
2650 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2651 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2652 ipa_ctx->ipa_tx_packets_diff = BW_GET_DIFF(
2653 uc_fw_stat->tx_pkts_completed,
2654 ipa_ctx->ipa_p_tx_packets);
2655 ipa_ctx->ipa_rx_packets_diff = BW_GET_DIFF(
2656 (uc_fw_stat->rx_num_ind_drop_no_space +
2657 uc_fw_stat->rx_num_ind_drop_no_buf +
2658 uc_fw_stat->rx_num_pkts_indicated),
2659 ipa_ctx->ipa_p_rx_packets);
2660
2661 ipa_ctx->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2662 ipa_ctx->ipa_p_rx_packets =
2663 (uc_fw_stat->rx_num_ind_drop_no_space +
2664 uc_fw_stat->rx_num_ind_drop_no_buf +
2665 uc_fw_stat->rx_num_pkts_indicated);
2666 qdf_mutex_release(&ipa_ctx->ipa_lock);
2667 } else if (msg->op_code == WLAN_IPA_UC_OPCODE_UC_READY) {
2668 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2669 wlan_ipa_uc_loaded_handler(ipa_ctx);
2670 qdf_mutex_release(&ipa_ctx->ipa_lock);
2671 } else if (wlan_ipa_uc_op_metering(ipa_ctx, op_msg)) {
2672 ipa_err("Invalid message: op_code=%d, reason=%d",
2673 msg->op_code, ipa_ctx->stat_req_reason);
2674 }
2675
2676 qdf_mem_free(op_msg);
2677}
2678
2679/**
2680 * wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2681 * @work: uC OP work
2682 *
2683 * Return: None
2684 */
2685static void wlan_ipa_uc_fw_op_event_handler(void *data)
2686{
2687 struct op_msg_type *msg;
2688 struct uc_op_work_struct *uc_op_work =
2689 (struct uc_op_work_struct *)data;
2690 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
2691
2692 msg = uc_op_work->msg;
2693 uc_op_work->msg = NULL;
2694 ipa_debug("posted msg %d", msg->op_code);
2695
2696 wlan_ipa_uc_op_cb(msg, ipa_ctx);
2697}
2698
2699/**
2700 * wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
2701 * @op_msg: operation message received from firmware
2702 * @ipa_ctx: Global IPA context
2703 *
2704 * Return: None
2705 */
2706static void wlan_ipa_uc_op_event_handler(uint8_t *op_msg, void *ctx)
2707{
2708 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)ctx;
2709 struct op_msg_type *msg;
2710 struct uc_op_work_struct *uc_op_work;
2711
2712 if (!ipa_ctx)
2713 goto end;
2714
2715 msg = (struct op_msg_type *)op_msg;
2716
2717 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
2718 ipa_err("Invalid OP Code (%d)", msg->op_code);
2719 goto end;
2720 }
2721
2722 uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
2723 if (uc_op_work->msg) {
2724 /* When the same uC OPCODE is already pended, just return */
2725 goto end;
2726 }
2727
2728 uc_op_work->msg = msg;
2729 qdf_sched_work(0, &uc_op_work->work);
2730 return;
2731
2732end:
2733 qdf_mem_free(op_msg);
2734}
2735
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302736QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx,
2737 qdf_device_t osdev)
2738{
2739 uint8_t i;
2740 QDF_STATUS status = QDF_STATUS_SUCCESS;
2741
2742 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2743 return QDF_STATUS_SUCCESS;
2744
2745 ipa_debug("enter");
2746
2747 for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) {
2748 ipa_ctx->vdev_to_iface[i] = WLAN_IPA_MAX_SESSION;
2749 ipa_ctx->vdev_offload_enabled[i] = false;
2750 }
2751
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302752 if (cdp_ipa_get_resource(ipa_ctx->dp_soc, ipa_ctx->dp_pdev)) {
2753 ipa_err("IPA UC resource alloc fail");
2754 status = QDF_STATUS_E_FAILURE;
2755 goto fail_return;
2756 }
2757
2758 if (true == ipa_ctx->uc_loaded) {
2759 status = wlan_ipa_wdi_setup(ipa_ctx, osdev);
2760 if (status) {
2761 ipa_err("Failure to setup IPA pipes (status=%d)",
2762 status);
2763 status = QDF_STATUS_E_FAILURE;
2764 goto fail_return;
2765 }
2766
2767 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
2768 wlan_ipa_init_metering(ipa_ctx);
jiadf9771182018-06-12 12:43:40 +08002769
2770 if (wlan_ipa_init_perf_level(ipa_ctx) != QDF_STATUS_SUCCESS)
2771 ipa_err("Failed to init perf level");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302772 }
2773
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302774 cdp_ipa_register_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
2775 wlan_ipa_uc_op_event_handler, (void *)ipa_ctx);
2776
2777 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
2778 qdf_create_work(0, &ipa_ctx->uc_op_work[i].work,
2779 wlan_ipa_uc_fw_op_event_handler,
2780 &ipa_ctx->uc_op_work[i]);
2781 ipa_ctx->uc_op_work[i].msg = NULL;
2782 }
2783
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302784fail_return:
2785 ipa_debug("exit: status=%d", status);
2786 return status;
2787}
2788
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302789/**
2790 * wlan_ipa_cleanup_pending_event() - Cleanup IPA pending event list
2791 * @ipa_ctx: pointer to IPA IPA struct
2792 *
2793 * Return: none
2794 */
2795static void wlan_ipa_cleanup_pending_event(struct wlan_ipa_priv *ipa_ctx)
2796{
2797 struct wlan_ipa_uc_pending_event *pending_event = NULL;
2798
2799 while (qdf_list_remove_front(&ipa_ctx->pending_event,
2800 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
2801 qdf_mem_free(pending_event);
2802}
2803
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302804QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx)
2805{
2806 QDF_STATUS status = QDF_STATUS_SUCCESS;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302807 int i;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302808
2809 ipa_debug("enter");
2810
2811 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2812 return status;
2813
2814 if (!ipa_ctx->ipa_pipes_down)
2815 wlan_ipa_uc_disable_pipes(ipa_ctx);
2816
2817 if (true == ipa_ctx->uc_loaded) {
2818 status = cdp_ipa_cleanup(ipa_ctx->dp_soc,
2819 ipa_ctx->tx_pipe_handle,
2820 ipa_ctx->rx_pipe_handle);
2821 if (status)
2822 ipa_err("Failure to cleanup IPA pipes (status=%d)",
2823 status);
2824 }
2825
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302826 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2827 wlan_ipa_cleanup_pending_event(ipa_ctx);
2828 qdf_mutex_release(&ipa_ctx->ipa_lock);
2829
2830 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
2831 qdf_cancel_work(&ipa_ctx->uc_op_work[i].work);
2832 qdf_mem_free(ipa_ctx->uc_op_work[i].msg);
2833 ipa_ctx->uc_op_work[i].msg = NULL;
2834 }
2835
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302836 ipa_debug("exit: ret=%d", status);
2837 return status;
2838}
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +05302839
Yun Parka29974a2018-04-09 12:05:49 -07002840bool wlan_ipa_is_fw_wdi_activated(struct wlan_ipa_priv *ipa_ctx)
2841{
2842 return (WLAN_IPA_UC_NUM_WDI_PIPE == ipa_ctx->activated_fw_pipe);
2843}
2844
Sravan Kumar Kairamce792eb2018-06-15 15:07:11 +05302845/**
2846 * wlan_ipa_uc_send_evt() - send event to ipa
2847 * @net_dev: Interface net device
2848 * @type: event type
2849 * @mac_addr: pointer to mac address
2850 *
2851 * Send event to IPA driver
2852 *
2853 * Return: QDF_STATUS
2854 */
2855static QDF_STATUS wlan_ipa_uc_send_evt(qdf_netdev_t net_dev,
2856 qdf_ipa_wlan_event type,
2857 uint8_t *mac_addr)
2858{
2859 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
2860 qdf_ipa_msg_meta_t meta;
2861 qdf_ipa_wlan_msg_t *msg;
2862
2863 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
2864 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
2865 if (!msg) {
2866 ipa_err("msg allocation failed");
2867 return QDF_STATUS_E_NOMEM;
2868 }
2869
2870 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
2871 qdf_str_lcopy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name,
2872 IPA_RESOURCE_NAME_MAX);
2873 qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN);
2874
2875 if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) {
2876 ipa_err("%s: Evt: %d fail",
2877 QDF_IPA_WLAN_MSG_NAME(msg),
2878 QDF_IPA_MSG_META_MSG_TYPE(&meta));
2879 qdf_mem_free(msg);
2880
2881 return QDF_STATUS_E_FAILURE;
2882 }
2883
2884 ipa_ctx->stats.num_send_msg++;
2885
2886 return QDF_STATUS_SUCCESS;
2887}
2888
2889QDF_STATUS wlan_ipa_uc_disconnect_ap(struct wlan_ipa_priv *ipa_ctx,
2890 qdf_netdev_t net_dev)
2891{
2892 struct wlan_ipa_iface_context *iface_ctx;
2893 QDF_STATUS status;
2894
2895 ipa_debug("enter");
2896
2897 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_SAP_MODE);
2898 if (iface_ctx)
2899 status = wlan_ipa_uc_send_evt(net_dev, QDF_IPA_AP_DISCONNECT,
2900 net_dev->dev_addr);
2901 else
2902 return QDF_STATUS_E_INVAL;
2903
2904 ipa_debug("exit :%d", status);
2905
2906 return status;
2907}
2908
2909void wlan_ipa_cleanup_dev_iface(struct wlan_ipa_priv *ipa_ctx,
2910 qdf_netdev_t net_dev)
2911{
2912 struct wlan_ipa_iface_context *iface_ctx;
2913 int i;
2914
2915 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2916 iface_ctx = &ipa_ctx->iface_context[i];
2917 if (iface_ctx->dev == net_dev)
2918 break;
2919 }
2920
2921 if (iface_ctx)
2922 wlan_ipa_cleanup_iface(iface_ctx);
2923}