blob: 9f9bc1ceed10156802b88c7e22cde94de622351d [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)) {
Dustin Brown7e761c72018-07-31 13:50:17 -0700373 ipa_debug("IPA uC READY");
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530374 ipa_ctx->uc_loaded = true;
375 ipa_ctx->is_smmu_enabled =
376 QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
Dustin Brown7e761c72018-07-31 13:50:17 -0700377 ipa_debug("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +0530378 } 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/**
jitiphilfdcaaba2018-09-03 16:19:52 +0530746 * __wlan_ipa_w2i_cb() - WLAN to IPA callback handler
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530747 * @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 */
jitiphilfdcaaba2018-09-03 16:19:52 +0530754static void __wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
755 unsigned long data)
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530756{
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
jitiphilfdcaaba2018-09-03 16:19:52 +0530764 if (qdf_is_module_state_transitioning()) {
765 ipa_err("Module transition in progress");
766 return;
767 }
768
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530769 ipa_ctx = (struct wlan_ipa_priv *)priv;
770
771 if (!ipa_ctx)
772 return;
773
774 switch (evt) {
775 case IPA_RECEIVE:
776 skb = (qdf_nbuf_t) data;
777
778 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
779 session_id = (uint8_t)skb->cb[0];
780 iface_id = ipa_ctx->vdev_to_iface[session_id];
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530781 } else {
782 iface_id = WLAN_IPA_GET_IFACE_ID(skb->data);
783 }
784 if (iface_id >= WLAN_IPA_MAX_IFACE) {
jiadf3ecc752018-07-05 14:36:03 +0800785 ipa_err_rl("Invalid iface_id: %u", iface_id);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530786 ipa_ctx->ipa_rx_internal_drop_count++;
jiadab8cea02018-05-24 09:16:14 +0800787 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530788 return;
789 }
790
791 iface_context = &ipa_ctx->iface_context[iface_id];
792 if (!iface_context->tl_context) {
jiadf3ecc752018-07-05 14:36:03 +0800793 ipa_err_rl("TL context of iface_id %u is NULL",
794 iface_id);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530795 ipa_ctx->ipa_rx_internal_drop_count++;
jiadab8cea02018-05-24 09:16:14 +0800796 dev_kfree_skb_any(skb);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530797 return;
798 }
799
800 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
801 ipa_ctx->stats.num_rx_excep++;
802 qdf_nbuf_pull_head(skb, WLAN_IPA_UC_WLAN_CLD_HDR_LEN);
803 } else {
804 qdf_nbuf_pull_head(skb, WLAN_IPA_WLAN_CLD_HDR_LEN);
805 }
806
807 iface_context->stats.num_rx_ipa_excep++;
808
809 /* Disable to forward Intra-BSS Rx packets when
810 * ap_isolate=1 in hostapd.conf
811 */
812 if (!ipa_ctx->ap_intrabss_fwd) {
813 /*
814 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
815 * all Rx packets to IPA uC, which need to be forwarded
816 * to other interface.
817 * And, IPA driver will send back to WLAN host driver
818 * through exception pipe with fw_desc field set by FW.
819 * Here we are checking fw_desc field for FORWARD bit
820 * set, and forward to Tx. Then copy to kernel stack
821 * only when DISCARD bit is not set.
822 */
823 fw_desc = (uint8_t)skb->cb[1];
824 if (WLAN_IPA_FORWARD_PKT_DISCARD ==
825 wlan_ipa_intrabss_forward(ipa_ctx, iface_context,
826 fw_desc, skb))
827 break;
828 } else {
jiadf3ecc752018-07-05 14:36:03 +0800829 ipa_debug_rl("Intra-BSS forwarding is disabled");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530830 }
831
832 wlan_ipa_send_skb_to_network(skb, iface_context);
833 break;
834
835 default:
jiadf3ecc752018-07-05 14:36:03 +0800836 ipa_err_rl("w2i cb wrong event: 0x%x", evt);
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530837 return;
838 }
839}
840
841/**
jitiphilfdcaaba2018-09-03 16:19:52 +0530842 * wlan_ipa_w2i_cb() - SSR wrapper for __wlan_ipa_w2i_cb
843 * @priv: pointer to private data registered with IPA (we register a
844 * pointer to the global IPA context)
845 * @evt: the IPA event which triggered the callback
846 * @data: data associated with the event
847 *
848 * Return: None
849 */
850static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
851 unsigned long data)
852{
853 qdf_ssr_protect(__func__);
854 __wlan_ipa_w2i_cb(priv, evt, data);
855 qdf_ssr_unprotect(__func__);
856}
857
858/**
859 * __wlan_ipa_i2w_cb() - IPA to WLAN callback
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530860 * @priv: pointer to private data registered with IPA (we register a
861 * pointer to the interface-specific IPA context)
862 * @evt: the IPA event which triggered the callback
863 * @data: data associated with the event
864 *
865 * Return: None
866 */
jitiphilfdcaaba2018-09-03 16:19:52 +0530867static void __wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
868 unsigned long data)
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530869{
870 struct wlan_ipa_priv *ipa_ctx = NULL;
871 qdf_ipa_rx_data_t *ipa_tx_desc;
872 struct wlan_ipa_iface_context *iface_context;
873 qdf_nbuf_t skb;
874 struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
875
jitiphilfdcaaba2018-09-03 16:19:52 +0530876 if (qdf_is_module_state_transitioning()) {
877 ipa_err("Module transition in progress");
878 return;
879 }
880
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530881 iface_context = (struct wlan_ipa_iface_context *)priv;
882 ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
883 ipa_ctx = iface_context->ipa_ctx;
884
885 if (evt != IPA_RECEIVE) {
jiadf3ecc752018-07-05 14:36:03 +0800886 ipa_err_rl("Event is not IPA_RECEIVE");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530887 ipa_free_skb(ipa_tx_desc);
888 iface_context->stats.num_tx_drop++;
889 return;
890 }
891
892 skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc);
893
894 /*
895 * If PROD resource is not requested here then there may be cases where
896 * IPA hardware may be clocked down because of not having proper
897 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
898 * workaround to request PROD resource while data is going over CONS
899 * pipe to prevent the IPA hardware clockdown.
900 */
901 wlan_ipa_wdi_rm_request(ipa_ctx);
902
903 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
904 /*
905 * If host is still suspended then queue the packets and these will be
906 * drained later when resume completes. When packet is arrived here and
907 * host is suspended, this means that there is already resume is in
908 * progress.
909 */
910 if (ipa_ctx->suspended) {
911 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
912 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
913 pm_tx_cb->iface_context = iface_context;
914 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
915 qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
916 ipa_ctx->stats.num_tx_queued++;
917
918 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
919 return;
920 }
921
922 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
923
924 /*
925 * If we are here means, host is not suspended, wait for the work queue
926 * to finish.
927 */
928 qdf_flush_work(&ipa_ctx->pm_work);
929
930 return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
931}
932
jitiphilfdcaaba2018-09-03 16:19:52 +0530933/**
934 * wlan_ipa_i2w_cb() - IPA to WLAN callback
935 * @priv: pointer to private data registered with IPA (we register a
936 * pointer to the interface-specific IPA context)
937 * @evt: the IPA event which triggered the callback
938 * @data: data associated with the event
939 *
940 * Return: None
941 */
942static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
943 unsigned long data)
944{
945 qdf_ssr_protect(__func__);
946 __wlan_ipa_i2w_cb(priv, evt, data);
947 qdf_ssr_unprotect(__func__);
948}
949
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530950QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx)
951{
952 /*
953 * Check if IPA is ready for suspend, If we are here means, there is
954 * high chance that suspend would go through but just to avoid any race
955 * condition after suspend started, these checks are conducted before
956 * allowing to suspend.
957 */
958 if (atomic_read(&ipa_ctx->tx_ref_cnt))
959 return QDF_STATUS_E_AGAIN;
960
Yun Parke74e6092018-04-27 11:36:34 -0700961 if (!wlan_ipa_is_rm_released(ipa_ctx))
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530962 return QDF_STATUS_E_AGAIN;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +0530963
964 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
965 ipa_ctx->suspended = true;
966 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
967
968 return QDF_STATUS_SUCCESS;
969}
970
971QDF_STATUS wlan_ipa_resume(struct wlan_ipa_priv *ipa_ctx)
972{
973 qdf_sched_work(0, &ipa_ctx->pm_work);
974
975 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
976 ipa_ctx->suspended = false;
977 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
978
979 return QDF_STATUS_SUCCESS;
980}
981
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +0530982QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx)
983{
984 int result;
985
986 ipa_debug("enter");
987
988 if (!ipa_ctx->ipa_pipes_down) {
989 /*
990 * IPA WDI Pipes are already activated due to
991 * rm deferred resources grant
992 */
993 ipa_warn("IPA WDI Pipes are already activated");
994 goto end;
995 }
996
997 result = cdp_ipa_enable_pipes(ipa_ctx->dp_soc,
998 ipa_ctx->dp_pdev);
999 if (result) {
1000 ipa_err("Enable IPA WDI PIPE failed: ret=%d", result);
1001 return QDF_STATUS_E_FAILURE;
1002 }
1003
1004 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
1005 ipa_ctx->ipa_pipes_down = false;
1006
1007 cdp_ipa_enable_autonomy(ipa_ctx->dp_soc,
1008 ipa_ctx->dp_pdev);
1009
1010end:
1011 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
1012
1013 return QDF_STATUS_SUCCESS;
1014}
1015
1016QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx)
1017{
1018 int result;
1019
1020 ipa_debug("enter");
1021
1022 if (ipa_ctx->ipa_pipes_down) {
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05301023 ipa_warn("IPA WDI Pipes are already deactivated");
1024 goto end;
1025 }
1026
1027 cdp_ipa_disable_autonomy(ipa_ctx->dp_soc,
1028 ipa_ctx->dp_pdev);
1029
1030 result = cdp_ipa_disable_pipes(ipa_ctx->dp_soc,
1031 ipa_ctx->dp_pdev);
1032 if (result) {
1033 ipa_err("Disable IPA WDI PIPE failed: ret=%d", result);
1034 return QDF_STATUS_E_FAILURE;
1035 }
1036
1037 ipa_ctx->ipa_pipes_down = true;
1038
1039end:
1040 ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down);
1041
1042 return QDF_STATUS_SUCCESS;
1043}
1044
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05301045/**
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301046 * wlan_ipa_uc_find_add_assoc_sta() - Find associated station
1047 * @ipa_ctx: Global IPA IPA context
1048 * @sta_add: Should station be added
1049 * @sta_id: ID of the station being queried
1050 *
1051 * Return: true if the station was found
1052 */
1053static bool wlan_ipa_uc_find_add_assoc_sta(struct wlan_ipa_priv *ipa_ctx,
1054 bool sta_add, uint8_t sta_id,
1055 uint8_t *mac_addr)
1056{
1057 bool sta_found = false;
1058 uint8_t idx;
1059
1060 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1061 if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
1062 (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
1063 sta_found = true;
1064 break;
1065 }
1066 }
1067 if (sta_add && sta_found) {
1068 ipa_err("STA ID %d already exist, cannot add", sta_id);
1069 return sta_found;
1070 }
1071 if (sta_add) {
1072 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1073 if (!ipa_ctx->assoc_stas_map[idx].is_reserved) {
1074 ipa_ctx->assoc_stas_map[idx].is_reserved = true;
1075 ipa_ctx->assoc_stas_map[idx].sta_id = sta_id;
1076 qdf_mem_copy(&ipa_ctx->assoc_stas_map[idx].
1077 mac_addr, mac_addr,
1078 QDF_NET_ETH_LEN);
1079 return sta_found;
1080 }
1081 }
1082 }
1083 if (!sta_add && !sta_found) {
1084 ipa_err("STA ID %d does not exist, cannot delete", sta_id);
1085 return sta_found;
1086 }
1087 if (!sta_add) {
1088 for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
1089 if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
1090 (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
1091 ipa_ctx->assoc_stas_map[idx].is_reserved =
1092 false;
1093 ipa_ctx->assoc_stas_map[idx].sta_id = 0xFF;
1094 qdf_mem_set(&ipa_ctx->assoc_stas_map[idx].
1095 mac_addr, 0, QDF_NET_ETH_LEN);
1096 return sta_found;
1097 }
1098 }
1099 }
1100
1101 return sta_found;
1102}
1103
1104/**
1105 * wlan_ipa_get_ifaceid() - Get IPA context interface ID
1106 * @ipa_ctx: IPA context
1107 * @session_id: Session ID
1108 *
1109 * Return: None
1110 */
1111static int wlan_ipa_get_ifaceid(struct wlan_ipa_priv *ipa_ctx,
1112 uint8_t session_id)
1113{
1114 struct wlan_ipa_iface_context *iface_ctx;
1115 int i;
1116
1117 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1118 iface_ctx = &ipa_ctx->iface_context[i];
1119 if (iface_ctx->session_id == session_id)
1120 break;
1121 }
1122
1123 return i;
1124}
1125
1126/**
1127 * wlan_ipa_cleanup_iface() - Cleanup IPA on a given interface
1128 * @iface_context: interface-specific IPA context
1129 *
1130 * Return: None
1131 */
1132static void wlan_ipa_cleanup_iface(struct wlan_ipa_iface_context *iface_context)
1133{
1134 struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
1135
1136 ipa_debug("enter");
1137
1138 if (!iface_context->tl_context)
1139 return;
1140
1141 cdp_ipa_cleanup_iface(ipa_ctx->dp_soc,
1142 iface_context->dev->name,
1143 wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
1144
1145 qdf_spin_lock_bh(&iface_context->interface_lock);
1146 iface_context->tl_context = NULL;
1147 iface_context->dev = NULL;
1148 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
1149 iface_context->session_id = WLAN_IPA_MAX_SESSION;
1150 iface_context->sta_id = WLAN_IPA_MAX_STA_COUNT;
1151 qdf_spin_unlock_bh(&iface_context->interface_lock);
1152 iface_context->ifa_address = 0;
1153 if (!iface_context->ipa_ctx->num_iface) {
1154 ipa_err("NUM INTF 0, Invalid");
1155 QDF_ASSERT(0);
1156 }
1157 iface_context->ipa_ctx->num_iface--;
1158 ipa_debug("exit: num_iface=%d", iface_context->ipa_ctx->num_iface);
1159}
1160
1161/**
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05301162 * wlan_ipa_nbuf_cb() - IPA TX complete callback
1163 * @skb: packet buffer which was transmitted
1164 *
1165 * Return: None
1166 */
1167static void wlan_ipa_nbuf_cb(qdf_nbuf_t skb)
1168{
1169 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
1170 qdf_ipa_rx_data_t *ipa_tx_desc;
1171 struct wlan_ipa_tx_desc *tx_desc;
1172 uint16_t id;
1173
1174 if (!qdf_nbuf_ipa_owned_get(skb)) {
1175 dev_kfree_skb_any(skb);
1176 return;
1177 }
1178
1179 /* Get Tx desc pointer from SKB CB */
1180 id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
1181 tx_desc = &ipa_ctx->tx_desc_pool[id];
1182 ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
1183
1184 /* Return Tx Desc to IPA */
1185 qdf_ipa_free_skb(ipa_tx_desc);
1186
1187 /* Return to free tx desc list */
1188 qdf_spin_lock_bh(&ipa_ctx->q_lock);
1189 tx_desc->ipa_tx_desc_ptr = NULL;
1190 qdf_list_insert_back(&ipa_ctx->tx_desc_free_list, &tx_desc->node);
1191 ipa_ctx->stats.num_tx_desc_q_cnt--;
1192 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
1193
1194 ipa_ctx->stats.num_tx_comp_cnt++;
1195
1196 qdf_atomic_dec(&ipa_ctx->tx_ref_cnt);
1197
1198 wlan_ipa_wdi_rm_try_release(ipa_ctx);
1199}
1200
1201/**
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301202 * wlan_ipa_setup_iface() - Setup IPA on a given interface
1203 * @ipa_ctx: IPA IPA global context
1204 * @net_dev: Interface net device
1205 * @device_mode: Net interface device mode
1206 * @adapter: Interface upon which IPA is being setup
1207 * @sta_id: Station ID of the API instance
1208 * @session_id: Station ID of the API instance
1209 *
1210 * Return: QDF STATUS
1211 */
1212static QDF_STATUS wlan_ipa_setup_iface(struct wlan_ipa_priv *ipa_ctx,
1213 qdf_netdev_t net_dev,
1214 uint8_t device_mode, uint8_t sta_id,
1215 uint8_t session_id)
1216{
1217 struct wlan_ipa_iface_context *iface_context = NULL;
1218 void *tl_context = NULL;
1219 int i;
1220 QDF_STATUS status;
1221
1222 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
1223 * channel change indication. Since these indications are sent by lower
1224 * layer as SAP updates and IPA doesn't have to do anything for these
1225 * updates so ignoring!
1226 */
1227 if (device_mode == QDF_SAP_MODE) {
1228 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1229 iface_context = &(ipa_ctx->iface_context[i]);
1230 if (iface_context->dev == net_dev)
1231 return QDF_STATUS_SUCCESS;
1232 }
1233 }
1234
Yun Park21ec4902018-04-24 12:11:01 -07001235 if (WLAN_IPA_MAX_IFACE == ipa_ctx->num_iface) {
1236 ipa_err("Max interface reached %d", WLAN_IPA_MAX_IFACE);
1237 status = QDF_STATUS_E_NOMEM;
1238 QDF_ASSERT(0);
1239 goto end;
1240 }
1241
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301242 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1243 if (ipa_ctx->iface_context[i].tl_context == NULL) {
1244 iface_context = &(ipa_ctx->iface_context[i]);
1245 break;
1246 }
1247 }
1248
1249 if (iface_context == NULL) {
1250 ipa_err("All the IPA interfaces are in use");
1251 status = QDF_STATUS_E_NOMEM;
Yun Park21ec4902018-04-24 12:11:01 -07001252 QDF_ASSERT(0);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301253 goto end;
1254 }
1255
1256 iface_context->sta_id = sta_id;
1257 tl_context = (void *)cdp_peer_get_vdev_by_sta_id(ipa_ctx->dp_soc,
1258 ipa_ctx->dp_pdev,
1259 sta_id);
1260 if (tl_context == NULL) {
1261 ipa_err("Not able to get TL context sta_id: %d", sta_id);
1262 status = QDF_STATUS_E_INVAL;
1263 goto end;
1264 }
1265
1266 iface_context->tl_context = tl_context;
1267 iface_context->dev = net_dev;
1268 iface_context->device_mode = device_mode;
1269 iface_context->session_id = session_id;
1270
1271 status = cdp_ipa_setup_iface(ipa_ctx->dp_soc, net_dev->name,
1272 net_dev->dev_addr,
1273 iface_context->prod_client,
1274 iface_context->cons_client,
1275 session_id,
1276 wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
1277 if (status != QDF_STATUS_SUCCESS)
1278 goto end;
1279
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05301280 /* Register IPA Tx desc free callback */
1281 qdf_nbuf_reg_free_cb(wlan_ipa_nbuf_cb);
1282
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301283 ipa_ctx->num_iface++;
1284
1285 ipa_debug("exit: num_iface=%d", ipa_ctx->num_iface);
1286
1287 return status;
1288
1289end:
1290 if (iface_context)
1291 wlan_ipa_cleanup_iface(iface_context);
1292
1293 return status;
1294}
1295
1296/**
1297 * wlan_ipa_uc_handle_first_con() - Handle first uC IPA connection
1298 * @ipa_ctx: IPA context
1299 *
1300 * Return: QDF STATUS
1301 */
1302static QDF_STATUS wlan_ipa_uc_handle_first_con(struct wlan_ipa_priv *ipa_ctx)
1303{
1304 ipa_debug("enter");
1305
1306 ipa_ctx->activated_fw_pipe = 0;
1307 ipa_ctx->resource_loading = true;
1308
1309 /* If RM feature enabled
1310 * Request PROD Resource first
1311 * PROD resource may return sync or async manners
1312 */
1313 if (wlan_ipa_is_rm_enabled(ipa_ctx->config)) {
Yun Parke114fbf2018-04-05 20:02:12 -07001314 if (!wlan_ipa_wdi_rm_request_resource(ipa_ctx,
1315 IPA_RM_RESOURCE_WLAN_PROD)) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301316 /* RM PROD request sync return
1317 * enable pipe immediately
1318 */
1319 if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
1320 ipa_err("IPA WDI Pipe activation failed");
1321 ipa_ctx->resource_loading = false;
1322 return QDF_STATUS_E_BUSY;
1323 }
1324 } else {
1325 ipa_err("IPA WDI Pipe activation deferred");
1326 }
1327 } else {
1328 /* RM Disabled
1329 * Just enabled all the PIPEs
1330 */
1331 if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
1332 ipa_err("IPA WDI Pipe activation failed");
1333 ipa_ctx->resource_loading = false;
1334 return QDF_STATUS_E_BUSY;
1335 }
1336 ipa_ctx->resource_loading = false;
1337 }
1338
1339 ipa_debug("exit");
1340
1341 return QDF_STATUS_SUCCESS;
1342}
1343
1344/**
1345 * wlan_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1346 * @ipa_ctx: IPA context
1347 *
1348 * Return: None
1349 */
1350static void wlan_ipa_uc_handle_last_discon(struct wlan_ipa_priv *ipa_ctx)
1351{
1352 ipa_debug("enter");
1353
1354 ipa_ctx->resource_unloading = true;
1355 qdf_event_reset(&ipa_ctx->ipa_resource_comp);
1356 ipa_info("Disable FW RX PIPE");
1357 cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301358
1359 ipa_debug("exit: IPA WDI Pipes deactivated");
1360}
1361
1362/**
1363 * wlan_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
1364 * @ipa_ctx: global IPA context
1365 * @offload_type: MCC or SCC
1366 * @session_id: Session Id
1367 * @enable: TX offload enable or disable
1368 *
1369 * Return: none
1370 */
1371static void wlan_ipa_uc_offload_enable_disable(struct wlan_ipa_priv *ipa_ctx,
1372 uint32_t offload_type,
1373 uint8_t session_id,
1374 bool enable)
1375{
1376
1377 struct ipa_uc_offload_control_params req = {0};
1378
1379 if (session_id >= WLAN_IPA_MAX_SESSION) {
1380 ipa_err("invalid session id: %d", session_id);
1381 return;
1382 }
1383
1384 if (enable == ipa_ctx->vdev_offload_enabled[session_id]) {
Sravan Kumar Kairamcd430b62018-08-23 18:35:50 +05301385 ipa_info("IPA offload status is already set");
1386 ipa_info("offload_type=%d, vdev_id=%d, enable=%d",
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301387 offload_type, session_id, enable);
1388 return;
1389 }
1390
1391 ipa_info("offload_type=%d, session_id=%d, enable=%d",
1392 offload_type, session_id, enable);
1393
1394 req.offload_type = offload_type;
1395 req.vdev_id = session_id;
1396 req.enable = enable;
1397
1398 if (QDF_STATUS_SUCCESS !=
1399 ipa_send_uc_offload_enable_disable(ipa_ctx->pdev, &req)) {
1400 ipa_err("Fail to enable IPA offload");
1401 ipa_err("offload type=%d, vdev_id=%d, enable=%d",
1402 offload_type, session_id, enable);
1403 } else {
1404 ipa_ctx->vdev_offload_enabled[session_id] = enable;
1405 }
1406}
1407
1408/**
1409 * __wlan_ipa_wlan_evt() - IPA event handler
1410 * @net_dev: Interface net device
1411 * @device_mode: Net interface device mode
1412 * @sta_id: station id for the event
1413 * @session_id: session id for the event
1414 * @type: event enum of type ipa_wlan_event
1415 * @mac_address: MAC address associated with the event
1416 *
1417 * This function is meant to be called from within wlan_ipa_ctx.c
1418 *
1419 * Return: QDF STATUS
1420 */
1421static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
1422 uint8_t sta_id, uint8_t session_id,
1423 qdf_ipa_wlan_event type,
1424 uint8_t *mac_addr)
1425{
1426 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
1427 struct wlan_ipa_iface_context *iface_ctx = NULL;
1428 qdf_ipa_msg_meta_t meta;
1429 qdf_ipa_wlan_msg_t *msg;
1430 qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
1431 int i;
1432 QDF_STATUS status;
Ryan Hsub5783cf2018-05-14 12:13:15 -07001433 uint8_t sta_session_id = WLAN_IPA_MAX_SESSION;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301434
1435 ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d",
1436 net_dev->name, type, mac_addr, sta_id);
1437
1438 if (type >= QDF_IPA_WLAN_EVENT_MAX)
1439 return QDF_STATUS_E_INVAL;
1440
1441 if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
1442 !wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1443 (device_mode != QDF_SAP_MODE)) {
1444 return QDF_STATUS_SUCCESS;
1445 }
1446
Ryan Hsub5783cf2018-05-14 12:13:15 -07001447 if (ipa_ctx->sta_connected) {
1448 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
1449 if (iface_ctx)
1450 sta_session_id = iface_ctx->session_id;
1451 else
1452 ipa_err("sta iface_ctx is NULL");
1453 }
1454
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301455 /*
1456 * During IPA UC resource loading/unloading new events can be issued.
1457 */
1458 if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
1459 (ipa_ctx->resource_loading || ipa_ctx->resource_unloading)) {
1460 unsigned int pending_event_count;
1461 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1462
1463 ipa_info("Event:%d IPA resource %s inprogress", type,
1464 ipa_ctx->resource_loading ?
1465 "load" : "unload");
1466
1467 /* Wait until completion of the long/unloading */
1468 status = qdf_wait_for_event_completion(
1469 &ipa_ctx->ipa_resource_comp,
jiada8c542c2018-05-29 16:24:13 +08001470 IPA_RESOURCE_COMP_WAIT_TIME);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301471 if (status != QDF_STATUS_SUCCESS) {
1472 /*
1473 * If timed out, store the events separately and
1474 * handle them later.
1475 */
1476 ipa_info("IPA resource %s timed out",
1477 ipa_ctx->resource_loading ?
1478 "load" : "unload");
1479
Sravan Kumar Kairamcd430b62018-08-23 18:35:50 +05301480 if (type == QDF_IPA_AP_DISCONNECT)
1481 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1482 SIR_AP_RX_DATA_OFFLOAD,
1483 session_id, false);
1484
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301485 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
1486
1487 pending_event_count =
1488 qdf_list_size(&ipa_ctx->pending_event);
1489 if (pending_event_count >=
1490 WLAN_IPA_MAX_PENDING_EVENT_COUNT) {
1491 ipa_info("Reached max pending evt count");
1492 qdf_list_remove_front(
1493 &ipa_ctx->pending_event,
1494 (qdf_list_node_t **)&pending_event);
1495 } else {
1496 pending_event =
1497 (struct wlan_ipa_uc_pending_event *)
1498 qdf_mem_malloc(sizeof(
1499 struct wlan_ipa_uc_pending_event));
1500 }
1501
1502 if (!pending_event) {
1503 ipa_err("Pending event memory alloc fail");
1504 qdf_mutex_release(&ipa_ctx->ipa_lock);
1505 return QDF_STATUS_E_NOMEM;
1506 }
1507
1508 pending_event->net_dev = net_dev;
1509 pending_event->device_mode = device_mode;
1510 pending_event->sta_id = sta_id;
1511 pending_event->session_id = session_id;
1512 pending_event->type = type;
1513 pending_event->is_loading = ipa_ctx->resource_loading;
1514 qdf_mem_copy(pending_event->mac_addr,
1515 mac_addr, QDF_MAC_ADDR_SIZE);
1516 qdf_list_insert_back(&ipa_ctx->pending_event,
1517 &pending_event->node);
1518
1519 qdf_mutex_release(&ipa_ctx->ipa_lock);
1520
Yun Park21ec4902018-04-24 12:11:01 -07001521 /* Cleanup interface */
1522 if (type == QDF_IPA_STA_DISCONNECT ||
1523 type == QDF_IPA_AP_DISCONNECT) {
1524 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1525 iface_ctx = &ipa_ctx->iface_context[i];
1526
1527 if (iface_ctx->dev == net_dev)
1528 break;
1529 }
1530 if (iface_ctx)
1531 wlan_ipa_cleanup_iface(iface_ctx);
1532 }
1533
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301534 return QDF_STATUS_SUCCESS;
1535 }
1536 ipa_info("IPA resource %s completed",
1537 ipa_ctx->resource_loading ?
1538 "load" : "unload");
1539 }
1540
1541 ipa_ctx->stats.event[type]++;
1542
1543 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1544 switch (type) {
1545 case QDF_IPA_STA_CONNECT:
1546 qdf_mutex_acquire(&ipa_ctx->event_lock);
1547
1548 /* STA already connected and without disconnect, connect again
1549 * This is Roaming scenario
1550 */
1551 if (ipa_ctx->sta_connected) {
1552 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
1553 if (iface_ctx)
1554 wlan_ipa_cleanup_iface(iface_ctx);
1555 }
1556
1557 status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
1558 sta_id, session_id);
1559 if (status != QDF_STATUS_SUCCESS) {
1560 qdf_mutex_release(&ipa_ctx->event_lock);
1561 goto end;
1562 }
1563
1564 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1565 (ipa_ctx->sap_num_connected_sta > 0) &&
1566 !ipa_ctx->sta_connected) {
1567 qdf_mutex_release(&ipa_ctx->event_lock);
1568 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1569 SIR_STA_RX_DATA_OFFLOAD, session_id,
1570 true);
1571 qdf_mutex_acquire(&ipa_ctx->event_lock);
1572 }
1573
1574 ipa_ctx->vdev_to_iface[session_id] =
1575 wlan_ipa_get_ifaceid(ipa_ctx, session_id);
1576
1577 ipa_ctx->sta_connected = 1;
1578
1579 qdf_mutex_release(&ipa_ctx->event_lock);
1580
1581 ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
1582 break;
1583
1584 case QDF_IPA_AP_CONNECT:
1585 qdf_mutex_acquire(&ipa_ctx->event_lock);
1586
1587 /* For DFS channel we get two start_bss event (before and after
1588 * CAC). Also when ACS range includes both DFS and non DFS
1589 * channels, we could possibly change channel many times due to
1590 * RADAR detection and chosen channel may not be a DFS channels.
1591 * So dont return error here. Just discard the event.
1592 */
jiadc908ada2018-05-11 14:40:54 +08001593 if (ipa_ctx->vdev_to_iface[session_id] !=
1594 WLAN_IPA_MAX_SESSION) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301595 qdf_mutex_release(&ipa_ctx->event_lock);
1596 return 0;
1597 }
1598
1599 status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
1600 sta_id, session_id);
1601 if (status != QDF_STATUS_SUCCESS) {
1602 qdf_mutex_release(&ipa_ctx->event_lock);
1603 ipa_err("%s: Evt: %d, Interface setup failed",
1604 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
1605 goto end;
1606 }
1607
1608 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1609 qdf_mutex_release(&ipa_ctx->event_lock);
1610 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1611 SIR_AP_RX_DATA_OFFLOAD, session_id, true);
1612 qdf_mutex_acquire(&ipa_ctx->event_lock);
1613 }
1614
1615 ipa_ctx->vdev_to_iface[session_id] =
1616 wlan_ipa_get_ifaceid(ipa_ctx, session_id);
1617 qdf_mutex_release(&ipa_ctx->event_lock);
1618 break;
1619
1620 case QDF_IPA_STA_DISCONNECT:
1621 qdf_mutex_acquire(&ipa_ctx->event_lock);
1622
1623 if (!ipa_ctx->sta_connected) {
1624 qdf_mutex_release(&ipa_ctx->event_lock);
1625 ipa_err("%s: Evt: %d, STA already disconnected",
1626 msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
1627 return QDF_STATUS_E_INVAL;
1628 }
1629
1630 ipa_ctx->sta_connected = 0;
1631
1632 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1633 ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
1634 msg_ex->name);
1635 } else {
1636 /* Disable IPA UC TX PIPE when STA disconnected */
1637 if ((ipa_ctx->num_iface == 1) &&
Yun Parka29974a2018-04-09 12:05:49 -07001638 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
jiadfa131fe2018-08-06 13:41:36 +08001639 !ipa_ctx->ipa_pipes_down &&
1640 (ipa_ctx->resource_unloading == false)) {
jiad3a321f32018-07-16 18:16:39 +08001641 if (cds_is_driver_unloading()) {
1642 /*
1643 * We disable WDI pipes directly here
1644 * since IPA_OPCODE_TX/RX_SUSPEND
1645 * message will not be processed when
1646 * unloading WLAN driver is in progress
1647 */
1648 wlan_ipa_uc_disable_pipes(ipa_ctx);
1649 } else {
1650 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1651 }
1652 }
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301653 }
1654
1655 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1656 (ipa_ctx->sap_num_connected_sta > 0)) {
1657 qdf_mutex_release(&ipa_ctx->event_lock);
1658 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1659 SIR_STA_RX_DATA_OFFLOAD, session_id, false);
1660 qdf_mutex_acquire(&ipa_ctx->event_lock);
1661 ipa_ctx->vdev_to_iface[session_id] =
1662 WLAN_IPA_MAX_SESSION;
1663 }
1664
1665 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1666 iface_ctx = &ipa_ctx->iface_context[i];
1667
1668 if (iface_ctx->dev == net_dev)
1669 break;
1670 }
1671 if (i < WLAN_IPA_MAX_IFACE)
1672 wlan_ipa_cleanup_iface(iface_ctx);
1673
1674 qdf_mutex_release(&ipa_ctx->event_lock);
1675
1676 ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
1677 break;
1678
1679 case QDF_IPA_AP_DISCONNECT:
1680 qdf_mutex_acquire(&ipa_ctx->event_lock);
1681
1682 if ((ipa_ctx->num_iface == 1) &&
Yun Parka29974a2018-04-09 12:05:49 -07001683 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
jiadfa131fe2018-08-06 13:41:36 +08001684 !ipa_ctx->ipa_pipes_down &&
1685 (ipa_ctx->resource_unloading == false)) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301686 if (cds_is_driver_unloading()) {
1687 /*
1688 * We disable WDI pipes directly here since
1689 * IPA_OPCODE_TX/RX_SUSPEND message will not be
1690 * processed when unloading WLAN driver is in
1691 * progress
1692 */
1693 wlan_ipa_uc_disable_pipes(ipa_ctx);
1694 } else {
1695 /*
1696 * This shouldn't happen :
1697 * No interface left but WDI pipes are still
1698 * active - force close WDI pipes
1699 */
1700 ipa_err("No interface left but WDI pipes are still active");
1701 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1702 }
1703 }
1704
1705 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1706 qdf_mutex_release(&ipa_ctx->event_lock);
1707 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1708 SIR_AP_RX_DATA_OFFLOAD, session_id, false);
1709 qdf_mutex_acquire(&ipa_ctx->event_lock);
1710 ipa_ctx->vdev_to_iface[session_id] =
1711 WLAN_IPA_MAX_SESSION;
1712 }
1713
1714 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
1715 iface_ctx = &ipa_ctx->iface_context[i];
1716
1717 if (iface_ctx->dev == net_dev)
1718 break;
1719 }
1720 if (i < WLAN_IPA_MAX_IFACE)
1721 wlan_ipa_cleanup_iface(iface_ctx);
1722
1723 qdf_mutex_release(&ipa_ctx->event_lock);
1724 break;
1725
1726 case QDF_IPA_CLIENT_CONNECT_EX:
1727 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1728 ipa_debug("%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
1729 net_dev->name, type);
1730 return QDF_STATUS_SUCCESS;
1731 }
1732
1733 qdf_mutex_acquire(&ipa_ctx->event_lock);
1734 if (wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, true, sta_id,
1735 mac_addr)) {
1736 qdf_mutex_release(&ipa_ctx->event_lock);
1737 ipa_err("%s: STA ID %d found", net_dev->name, sta_id);
1738 return QDF_STATUS_SUCCESS;
1739 }
1740
1741 /* Enable IPA UC Data PIPEs when first STA connected */
1742 if (ipa_ctx->sap_num_connected_sta == 0 &&
1743 ipa_ctx->uc_loaded == true) {
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301744
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301745 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1746 ipa_ctx->sta_connected) {
1747 qdf_mutex_release(&ipa_ctx->event_lock);
1748 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1749 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301750 sta_session_id, true);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301751 qdf_mutex_acquire(&ipa_ctx->event_lock);
1752 }
1753
1754 status = wlan_ipa_uc_handle_first_con(ipa_ctx);
1755 if (status != QDF_STATUS_SUCCESS) {
1756 ipa_info("%s: handle 1st con fail",
1757 net_dev->name);
1758
1759 if (wlan_ipa_uc_sta_is_enabled(
1760 ipa_ctx->config) &&
1761 ipa_ctx->sta_connected) {
1762 qdf_mutex_release(&ipa_ctx->event_lock);
1763 wlan_ipa_uc_offload_enable_disable(
1764 ipa_ctx,
1765 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301766 sta_session_id, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301767 } else {
1768 qdf_mutex_release(&ipa_ctx->event_lock);
1769 }
1770
1771 return status;
1772 }
1773 }
1774
1775 ipa_ctx->sap_num_connected_sta++;
1776
1777 qdf_mutex_release(&ipa_ctx->event_lock);
1778
1779 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1780 QDF_IPA_MSG_META_MSG_LEN(&meta) =
1781 (sizeof(qdf_ipa_wlan_msg_ex_t) +
1782 sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
1783 msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1784
1785 if (msg_ex == NULL) {
1786 ipa_err("msg_ex allocation failed");
1787 return QDF_STATUS_E_NOMEM;
1788 }
1789 strlcpy(msg_ex->name, net_dev->name,
1790 IPA_RESOURCE_NAME_MAX);
1791 msg_ex->num_of_attribs = 1;
1792 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
1793 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1794 msg_ex->attribs[0].offset =
1795 WLAN_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
1796 } else {
1797 msg_ex->attribs[0].offset =
1798 WLAN_IPA_WLAN_HDR_DES_MAC_OFFSET;
1799 }
1800 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
1801 IPA_MAC_ADDR_SIZE);
1802
1803 if (qdf_ipa_send_msg(&meta, msg_ex, wlan_ipa_msg_free_fn)) {
1804 ipa_info("%s: Evt: %d send ipa msg fail",
1805 net_dev->name, type);
1806 qdf_mem_free(msg_ex);
1807 return QDF_STATUS_E_FAILURE;
1808 }
1809 ipa_ctx->stats.num_send_msg++;
1810
1811 ipa_info("sap_num_connected_sta=%d",
1812 ipa_ctx->sap_num_connected_sta);
1813
1814 return QDF_STATUS_SUCCESS;
1815
1816 case WLAN_CLIENT_DISCONNECT:
1817 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
1818 ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
1819 msg_ex->name);
1820 return QDF_STATUS_SUCCESS;
1821 }
1822
1823 qdf_mutex_acquire(&ipa_ctx->event_lock);
1824 if (!ipa_ctx->sap_num_connected_sta) {
1825 qdf_mutex_release(&ipa_ctx->event_lock);
1826 ipa_err("%s: Evt: %d, Client already disconnected",
1827 msg_ex->name,
1828 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1829
1830 return QDF_STATUS_SUCCESS;
1831 }
1832 if (!wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, false,
1833 sta_id, mac_addr)) {
1834 qdf_mutex_release(&ipa_ctx->event_lock);
1835 ipa_err("%s: STA ID %d NOT found, not valid",
1836 msg_ex->name, sta_id);
1837
1838 return QDF_STATUS_SUCCESS;
1839 }
1840 ipa_ctx->sap_num_connected_sta--;
1841
1842 /* Disable IPA UC TX PIPE when last STA disconnected */
1843 if (!ipa_ctx->sap_num_connected_sta &&
1844 ipa_ctx->uc_loaded == true) {
Yun Parka29974a2018-04-09 12:05:49 -07001845 if ((false == ipa_ctx->resource_unloading) &&
1846 wlan_ipa_is_fw_wdi_activated(ipa_ctx) &&
1847 !ipa_ctx->ipa_pipes_down) {
jiad3a321f32018-07-16 18:16:39 +08001848 if (cds_is_driver_unloading()) {
1849 /*
1850 * We disable WDI pipes directly here
1851 * since IPA_OPCODE_TX/RX_SUSPEND
1852 * message will not be processed when
1853 * unloading WLAN driver is in progress
1854 */
1855 wlan_ipa_uc_disable_pipes(ipa_ctx);
1856 } else {
1857 wlan_ipa_uc_handle_last_discon(ipa_ctx);
1858 }
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301859 }
1860
1861 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
1862 ipa_ctx->sta_connected) {
1863 qdf_mutex_release(&ipa_ctx->event_lock);
1864 wlan_ipa_uc_offload_enable_disable(ipa_ctx,
1865 SIR_STA_RX_DATA_OFFLOAD,
Sravan Kumar Kairamf59aec12018-03-23 19:35:01 +05301866 sta_session_id, false);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301867 } else {
1868 qdf_mutex_release(&ipa_ctx->event_lock);
1869 }
1870 } else {
1871 qdf_mutex_release(&ipa_ctx->event_lock);
1872 }
1873
1874 ipa_info("sap_num_connected_sta=%d",
1875 ipa_ctx->sap_num_connected_sta);
1876 break;
1877
1878 default:
1879 return QDF_STATUS_SUCCESS;
1880 }
1881
1882 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
1883 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
1884 if (!msg) {
1885 ipa_err("msg allocation failed");
1886 return QDF_STATUS_E_NOMEM;
1887 }
1888
1889 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
1890 strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name,
1891 IPA_RESOURCE_NAME_MAX);
1892 qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN);
1893
1894 ipa_debug("%s: Evt: %d", QDF_IPA_WLAN_MSG_NAME(msg),
1895 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1896
1897 if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) {
1898
1899 ipa_err("%s: Evt: %d fail",
1900 QDF_IPA_WLAN_MSG_NAME(msg),
1901 QDF_IPA_MSG_META_MSG_TYPE(&meta));
1902 qdf_mem_free(msg);
1903
1904 return QDF_STATUS_E_FAILURE;
1905 }
1906
1907 ipa_ctx->stats.num_send_msg++;
1908
1909end:
1910 return QDF_STATUS_SUCCESS;
1911}
1912
1913/**
1914 * wlan_host_to_ipa_wlan_event() - convert wlan_ipa_wlan_event to ipa_wlan_event
Yun Park84fbb272018-04-02 15:31:01 -07001915 * @wlan_ipa_event_type: event to be converted to an ipa_wlan_event
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301916 *
1917 * Return: qdf_ipa_wlan_event representing the wlan_ipa_wlan_event
1918 */
1919static qdf_ipa_wlan_event
1920wlan_host_to_ipa_wlan_event(enum wlan_ipa_wlan_event wlan_ipa_event_type)
1921{
Yun Park84fbb272018-04-02 15:31:01 -07001922 qdf_ipa_wlan_event ipa_event;
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05301923
1924 switch (wlan_ipa_event_type) {
1925 case WLAN_IPA_CLIENT_CONNECT:
1926 ipa_event = QDF_IPA_CLIENT_CONNECT;
1927 break;
1928 case WLAN_IPA_CLIENT_DISCONNECT:
1929 ipa_event = QDF_IPA_CLIENT_DISCONNECT;
1930 break;
1931 case WLAN_IPA_AP_CONNECT:
1932 ipa_event = QDF_IPA_AP_CONNECT;
1933 break;
1934 case WLAN_IPA_AP_DISCONNECT:
1935 ipa_event = QDF_IPA_AP_DISCONNECT;
1936 break;
1937 case WLAN_IPA_STA_CONNECT:
1938 ipa_event = QDF_IPA_STA_CONNECT;
1939 break;
1940 case WLAN_IPA_STA_DISCONNECT:
1941 ipa_event = QDF_IPA_STA_DISCONNECT;
1942 break;
1943 case WLAN_IPA_CLIENT_CONNECT_EX:
1944 ipa_event = QDF_IPA_CLIENT_CONNECT_EX;
1945 break;
1946 case WLAN_IPA_WLAN_EVENT_MAX:
1947 default:
1948 ipa_event = QDF_IPA_WLAN_EVENT_MAX;
1949 break;
1950 }
1951
1952 return ipa_event;
1953}
1954
1955/**
1956 * wlan_ipa_wlan_evt() - SSR wrapper for __wlan_ipa_wlan_evt
1957 * @net_dev: Interface net device
1958 * @device_mode: Net interface device mode
1959 * @sta_id: station id for the event
1960 * @session_id: session id for the event
1961 * @ipa_event_type: event enum of type wlan_ipa_wlan_event
1962 * @mac_address: MAC address associated with the event
1963 *
1964 * Return: QDF_STATUS
1965 */
1966QDF_STATUS wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
1967 uint8_t sta_id, uint8_t session_id,
1968 enum wlan_ipa_wlan_event ipa_event_type,
1969 uint8_t *mac_addr)
1970{
1971 qdf_ipa_wlan_event type = wlan_host_to_ipa_wlan_event(ipa_event_type);
1972 QDF_STATUS status = QDF_STATUS_SUCCESS;
1973
1974 /* Data path offload only support for STA and SAP mode */
1975 if ((device_mode == QDF_STA_MODE) ||
1976 (device_mode == QDF_SAP_MODE))
1977 status = __wlan_ipa_wlan_evt(net_dev, device_mode, sta_id,
1978 session_id, type, mac_addr);
1979
1980 return status;
1981}
1982
1983/**
1984 * wlan_ipa_uc_proc_pending_event() - Process IPA uC pending events
1985 * @ipa_ctx: Global IPA IPA context
1986 * @is_loading: Indicate if invoked during loading
1987 *
1988 * Return: None
1989 */
1990static void
1991wlan_ipa_uc_proc_pending_event(struct wlan_ipa_priv *ipa_ctx, bool is_loading)
1992{
1993 unsigned int pending_event_count;
1994 struct wlan_ipa_uc_pending_event *pending_event = NULL;
1995
1996 pending_event_count = qdf_list_size(&ipa_ctx->pending_event);
1997 ipa_debug("Pending Event Count %d", pending_event_count);
1998 if (!pending_event_count) {
1999 ipa_debug("No Pending Event");
2000 return;
2001 }
2002
2003 qdf_list_remove_front(&ipa_ctx->pending_event,
2004 (qdf_list_node_t **)&pending_event);
2005 while (pending_event != NULL) {
Sravan Kumar Kairam8c151e22018-06-15 16:35:39 +05302006 struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
2007 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
2008 struct wlan_objmgr_vdev *vdev =
2009 wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
2010 pending_event->session_id,
2011 WLAN_IPA_ID);
2012 if (pending_event->is_loading == is_loading && vdev) {
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302013 __wlan_ipa_wlan_evt(pending_event->net_dev,
2014 pending_event->device_mode,
2015 pending_event->sta_id,
2016 pending_event->session_id,
2017 pending_event->type,
2018 pending_event->mac_addr);
2019 }
Sravan Kumar Kairam8c151e22018-06-15 16:35:39 +05302020
2021 if (vdev)
2022 wlan_objmgr_vdev_release_ref(vdev, WLAN_IPA_ID);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302023 qdf_mem_free(pending_event);
2024 pending_event = NULL;
2025 qdf_list_remove_front(&ipa_ctx->pending_event,
2026 (qdf_list_node_t **)&pending_event);
2027 }
2028}
2029
2030/**
Ryan Hsub5783cf2018-05-14 12:13:15 -07002031 * wlan_ipa_free_tx_desc_list() - Free IPA Tx desc list
2032 * @ipa_ctx: IPA context
2033 *
2034 * Return: None
2035 */
2036static inline void wlan_ipa_free_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
2037{
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302038 int i;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002039 qdf_ipa_rx_data_t *ipa_tx_desc;
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302040 uint32_t pool_size;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002041
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302042 if (!ipa_ctx->tx_desc_pool)
2043 return;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002044
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302045 qdf_spin_lock_bh(&ipa_ctx->q_lock);
2046 pool_size = ipa_ctx->tx_desc_free_list.max_size;
2047 for (i = 0; i < pool_size; i++) {
2048 ipa_tx_desc = ipa_ctx->tx_desc_pool[i].ipa_tx_desc_ptr;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002049 if (ipa_tx_desc)
2050 qdf_ipa_free_skb(ipa_tx_desc);
2051
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302052 if (qdf_list_remove_node(&ipa_ctx->tx_desc_free_list,
2053 &ipa_ctx->tx_desc_pool[i].node) !=
2054 QDF_STATUS_SUCCESS)
2055 ipa_err("Failed to remove node from tx desc freelist");
Ryan Hsub5783cf2018-05-14 12:13:15 -07002056 }
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302057 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
2058
2059 qdf_list_destroy(&ipa_ctx->tx_desc_free_list);
2060 qdf_mem_free(ipa_ctx->tx_desc_pool);
2061 ipa_ctx->tx_desc_pool = NULL;
2062
2063 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
2064 ipa_ctx->stats.num_tx_desc_error = 0;
Ryan Hsub5783cf2018-05-14 12:13:15 -07002065}
2066
2067/**
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302068 * wlan_ipa_alloc_tx_desc_free_list() - Allocate IPA Tx desc list
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302069 * @ipa_ctx: IPA context
2070 *
2071 * Return: QDF_STATUS
2072 */
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302073static QDF_STATUS
2074wlan_ipa_alloc_tx_desc_free_list(struct wlan_ipa_priv *ipa_ctx)
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302075{
2076 int i;
2077 uint32_t max_desc_cnt;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302078
2079 max_desc_cnt = ipa_ctx->config->txbuf_count;
2080
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302081 ipa_ctx->tx_desc_pool = qdf_mem_malloc(sizeof(struct wlan_ipa_tx_desc) *
2082 max_desc_cnt);
2083
2084 if (!ipa_ctx->tx_desc_pool) {
2085 ipa_err("Free Tx descriptor allocation failed");
2086 return QDF_STATUS_E_NOMEM;
2087 }
2088
2089 qdf_list_create(&ipa_ctx->tx_desc_free_list, max_desc_cnt);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302090
2091 qdf_spin_lock_bh(&ipa_ctx->q_lock);
2092 for (i = 0; i < max_desc_cnt; i++) {
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302093 ipa_ctx->tx_desc_pool[i].id = i;
2094 ipa_ctx->tx_desc_pool[i].ipa_tx_desc_ptr = NULL;
2095 qdf_list_insert_back(&ipa_ctx->tx_desc_free_list,
2096 &ipa_ctx->tx_desc_pool[i].node);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302097 }
2098
2099 ipa_ctx->stats.num_tx_desc_q_cnt = 0;
2100 ipa_ctx->stats.num_tx_desc_error = 0;
2101
2102 qdf_spin_unlock_bh(&ipa_ctx->q_lock);
2103
2104 return QDF_STATUS_SUCCESS;
2105}
2106
2107#ifndef QCA_LL_TX_FLOW_CONTROL_V2
2108/**
2109 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
2110 * @ipa_ctx: Global IPA IPA context
2111 * @desc_fifo_sz: Number of descriptors
2112 *
2113 * Return: 0 on success, negative errno on error
2114 */
2115static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2116 int32_t desc_fifo_sz)
2117{
2118 int i, ret = 0;
2119 qdf_ipa_sys_connect_params_t *ipa;
2120
2121 /*setup TX pipes */
2122 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2123 ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params;
2124
2125 ipa->client = wlan_ipa_iface_2_client[i].cons_client;
2126 ipa->desc_fifo_sz = desc_fifo_sz;
2127 ipa->priv = &ipa_ctx->iface_context[i];
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302128 ipa->notify = wlan_ipa_i2w_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302129
2130 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2131 ipa->ipa_ep_cfg.hdr.hdr_len =
2132 WLAN_IPA_UC_WLAN_TX_HDR_LEN;
2133 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2134 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
2135 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
2136 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
2137 WLAN_IPA_UC_WLAN_8023_HDR_SIZE;
2138 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
2139 } else {
2140 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN;
2141 }
2142 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
2143
2144 ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa,
2145 &ipa_ctx->sys_pipe[i].conn_hdl);
2146 if (ret) {
2147 ipa_err("Failed for pipe %d ret: %d", i, ret);
2148 return ret;
2149 }
2150 ipa_ctx->sys_pipe[i].conn_hdl_valid = 1;
2151 }
2152
2153 return ret;
2154}
2155#else
2156/**
2157 * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
2158 * @ipa_ctx: Global IPA IPA context
2159 * @desc_fifo_sz: Number of descriptors
2160 *
2161 * Return: 0 on success, negative errno on error
2162 */
2163static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2164 int32_t desc_fifo_sz)
2165{
2166 /*
2167 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
2168 * is enabled, where per vdev descriptors are supported in firmware.
2169 */
2170 return 0;
2171}
2172#endif
2173
2174/**
2175 * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
2176 * @ipa_ctx: Global IPA IPA context
2177 * @desc_fifo_sz: Number of descriptors
2178 *
2179 * Return: 0 on success, negative errno on error
2180 */
2181static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
2182 int32_t desc_fifo_sz)
2183{
2184 int ret = 0;
2185 qdf_ipa_sys_connect_params_t *ipa;
2186
2187 /*
2188 * Hard code it here, this can be extended if in case
2189 * PROD pipe is also per interface.
2190 * Right now there is no advantage of doing this.
2191 */
2192 ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params;
2193
2194 ipa->client = IPA_CLIENT_WLAN1_PROD;
2195
2196 ipa->desc_fifo_sz = desc_fifo_sz;
2197 ipa->priv = ipa_ctx;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302198 ipa->notify = wlan_ipa_w2i_cb;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302199
2200 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
2201 ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN;
2202 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
2203 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
2204
2205 ret = qdf_ipa_setup_sys_pipe(ipa,
2206 &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl);
2207 if (ret) {
2208 ipa_err("Failed for RX pipe: %d", ret);
2209 return ret;
2210 }
2211 ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1;
2212
2213 return ret;
2214}
2215
2216/**
Ryan Hsub5783cf2018-05-14 12:13:15 -07002217 * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
2218 * @ipa_ctx: Global IPA IPA context
2219 *
2220 * Return: None
2221 */
2222static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
2223{
2224 int ret, i;
2225
2226 if (!ipa_ctx)
2227 return;
2228
2229 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
2230 if (ipa_ctx->sys_pipe[i].conn_hdl_valid) {
2231 ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx,
2232 ipa_ctx->sys_pipe[i].conn_hdl);
2233 if (ret)
2234 ipa_err("Failed:%d", ret);
2235
2236 ipa_ctx->sys_pipe[i].conn_hdl_valid = 0;
2237 }
2238 }
2239
2240 wlan_ipa_free_tx_desc_list(ipa_ctx);
2241}
2242
2243/**
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302244 * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
2245 * @ipa_ctx: Global IPA IPA context
2246 *
2247 * Return: 0 on success, negative errno on error
2248 */
2249static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
2250{
Ryan Hsub5783cf2018-05-14 12:13:15 -07002251 int ret = 0;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302252 uint32_t desc_fifo_sz;
2253
2254 /* The maximum number of descriptors that can be provided to a BAM at
2255 * once is one less than the total number of descriptors that the buffer
2256 * can contain.
2257 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
2258 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
2259 * be provided at once.
2260 * Because of above requirement, one extra descriptor will be added to
2261 * make sure hardware always has one descriptor.
2262 */
2263 desc_fifo_sz = ipa_ctx->config->desc_size
2264 + SPS_DESC_SIZE;
2265
2266 ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz);
2267 if (ret) {
2268 ipa_err("Failed for TX pipe: %d", ret);
2269 goto setup_sys_pipe_fail;
2270 }
2271
2272 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2273 ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz);
2274 if (ret) {
2275 ipa_err("Failed for RX pipe: %d", ret);
2276 goto setup_sys_pipe_fail;
2277 }
2278 }
2279
2280 /* Allocate free Tx desc list */
Sravan Kumar Kairam1f8f8b32018-07-06 16:05:24 +05302281 ret = wlan_ipa_alloc_tx_desc_free_list(ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302282 if (ret)
2283 goto setup_sys_pipe_fail;
2284
2285 return ret;
2286
2287setup_sys_pipe_fail:
Ryan Hsub5783cf2018-05-14 12:13:15 -07002288 wlan_ipa_teardown_sys_pipe(ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302289
2290 return ret;
2291}
2292
jiadbb47e132018-03-30 16:28:30 +08002293#ifndef QCA_LL_TX_FLOW_CONTROL_V2
2294QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
2295 bool mcc_mode)
2296{
2297 qdf_ipa_msg_meta_t meta;
2298 qdf_ipa_wlan_msg_t *msg;
2299 int ret;
2300
2301 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
2302 return QDF_STATUS_SUCCESS;
2303
2304 /* Send SCC/MCC Switching event to IPA */
2305 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
2306 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
2307 if (msg == NULL) {
2308 ipa_err("msg allocation failed");
2309 return QDF_STATUS_E_NOMEM;
2310 }
2311
jiad629b2172018-05-11 15:34:22 +08002312 if (mcc_mode) {
jiadbb47e132018-03-30 16:28:30 +08002313 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_MCC);
jiad629b2172018-05-11 15:34:22 +08002314 ipa_ctx->stats.event[QDF_SWITCH_TO_MCC]++;
2315 } else {
jiadbb47e132018-03-30 16:28:30 +08002316 QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_SCC);
jiad629b2172018-05-11 15:34:22 +08002317 ipa_ctx->stats.event[QDF_SWITCH_TO_SCC]++;
2318 }
2319
jiadbb47e132018-03-30 16:28:30 +08002320 WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2321 "ipa_send_msg(Evt:%d)",
2322 QDF_IPA_MSG_META_MSG_TYPE(&meta));
2323
2324 ret = qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn);
2325
2326 if (ret) {
2327 ipa_err("ipa_send_msg(Evt:%d) - fail=%d",
2328 QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
2329 qdf_mem_free(msg);
2330 return QDF_STATUS_E_FAILURE;
2331 }
2332
2333 return QDF_STATUS_SUCCESS;
2334}
2335
2336static void wlan_ipa_mcc_work_handler(void *data)
2337{
2338 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data;
2339
2340 wlan_ipa_send_mcc_scc_msg(ipa_ctx, ipa_ctx->mcc_mode);
2341}
2342#endif
2343
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302344/**
2345 * wlan_ipa_setup() - IPA initialization function
2346 * @ipa_ctx: IPA context
2347 * @ipa_cfg: IPA config
2348 *
2349 * Allocate ipa_ctx resources, ipa pipe resource and register
2350 * wlan interface with IPA module.
2351 *
2352 * Return: QDF_STATUS enumeration
2353 */
2354QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
2355 struct wlan_ipa_config *ipa_cfg)
2356{
2357 int ret, i;
2358 struct wlan_ipa_iface_context *iface_context = NULL;
2359 QDF_STATUS status;
2360
2361 ipa_debug("enter");
2362
2363 gp_ipa = ipa_ctx;
2364 ipa_ctx->num_iface = 0;
2365 ipa_ctx->config = ipa_cfg;
2366
2367 wlan_ipa_wdi_get_wdi_version(ipa_ctx);
2368
2369 /* Create the interface context */
2370 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2371 iface_context = &ipa_ctx->iface_context[i];
2372 iface_context->ipa_ctx = ipa_ctx;
2373 iface_context->cons_client =
2374 wlan_ipa_iface_2_client[i].cons_client;
2375 iface_context->prod_client =
2376 wlan_ipa_iface_2_client[i].prod_client;
2377 iface_context->iface_id = i;
2378 iface_context->dev = NULL;
2379 iface_context->device_mode = QDF_MAX_NO_OF_MODE;
2380 iface_context->tl_context = NULL;
2381 qdf_spinlock_create(&iface_context->interface_lock);
2382 }
2383
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302384 qdf_create_work(0, &ipa_ctx->pm_work, wlan_ipa_pm_flush, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302385 qdf_spinlock_create(&ipa_ctx->pm_lock);
2386 qdf_spinlock_create(&ipa_ctx->q_lock);
2387 qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head);
2388 qdf_list_create(&ipa_ctx->pending_event, 1000);
2389 qdf_mutex_create(&ipa_ctx->event_lock);
2390 qdf_mutex_create(&ipa_ctx->ipa_lock);
2391
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302392 status = wlan_ipa_wdi_setup_rm(ipa_ctx);
2393 if (status != QDF_STATUS_SUCCESS)
2394 goto fail_setup_rm;
2395
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302396 for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++)
2397 qdf_mem_zero(&ipa_ctx->sys_pipe[i],
2398 sizeof(struct wlan_ipa_sys_pipe));
2399
2400 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
2401 qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats));
2402 ipa_ctx->sap_num_connected_sta = 0;
2403 ipa_ctx->ipa_tx_packets_diff = 0;
2404 ipa_ctx->ipa_rx_packets_diff = 0;
2405 ipa_ctx->ipa_p_tx_packets = 0;
2406 ipa_ctx->ipa_p_rx_packets = 0;
2407 ipa_ctx->resource_loading = false;
2408 ipa_ctx->resource_unloading = false;
2409 ipa_ctx->sta_connected = 0;
2410 ipa_ctx->ipa_pipes_down = true;
2411 ipa_ctx->wdi_enabled = false;
2412 /* Setup IPA system pipes */
2413 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
2414 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
2415 if (ret)
2416 goto fail_create_sys_pipe;
jiadbb47e132018-03-30 16:28:30 +08002417
2418 qdf_create_work(0, &ipa_ctx->mcc_work,
2419 wlan_ipa_mcc_work_handler, ipa_ctx);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302420 }
2421
2422 status = wlan_ipa_wdi_init(ipa_ctx);
2423 if (status == QDF_STATUS_E_BUSY)
2424 status = wlan_ipa_uc_send_wdi_control_msg(false);
2425 if (status != QDF_STATUS_SUCCESS) {
Ryan Hsub5783cf2018-05-14 12:13:15 -07002426 ipa_err("IPA WDI init failed: ret=%d", status);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302427 goto fail_create_sys_pipe;
2428 }
2429 } else {
2430 ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
2431 if (ret)
2432 goto fail_create_sys_pipe;
2433 }
2434
2435 qdf_event_create(&ipa_ctx->ipa_resource_comp);
2436
2437 ipa_debug("exit: success");
2438
2439 return QDF_STATUS_SUCCESS;
2440
2441fail_create_sys_pipe:
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302442 wlan_ipa_wdi_destroy_rm(ipa_ctx);
2443
2444fail_setup_rm:
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302445 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302446 qdf_spinlock_destroy(&ipa_ctx->q_lock);
2447 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2448 iface_context = &ipa_ctx->iface_context[i];
2449 qdf_spinlock_destroy(&iface_context->interface_lock);
2450 }
2451 qdf_mutex_destroy(&ipa_ctx->event_lock);
2452 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
2453 qdf_list_destroy(&ipa_ctx->pending_event);
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302454 gp_ipa = NULL;
2455 ipa_debug("exit: fail");
2456
2457 return QDF_STATUS_E_FAILURE;
2458}
2459
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302460void wlan_ipa_flush(struct wlan_ipa_priv *ipa_ctx)
2461{
2462 qdf_nbuf_t skb;
2463 struct wlan_ipa_pm_tx_cb *pm_tx_cb;
2464
2465 if (!wlan_ipa_is_enabled(ipa_ctx->config))
2466 return;
2467
2468 qdf_cancel_work(&ipa_ctx->pm_work);
2469
2470 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
2471
2472 while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head))
2473 != NULL)) {
2474 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
2475
2476 pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
jiadab8cea02018-05-24 09:16:14 +08002477
2478 if (pm_tx_cb->exception) {
2479 dev_kfree_skb_any(skb);
2480 } else {
2481 if (pm_tx_cb->ipa_tx_desc)
2482 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
2483 }
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302484
2485 qdf_spin_lock_bh(&ipa_ctx->pm_lock);
2486 }
2487 qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
2488}
2489
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302490QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx)
2491{
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302492 struct wlan_ipa_iface_context *iface_context;
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302493 int i;
2494
2495 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2496 wlan_ipa_teardown_sys_pipe(ipa_ctx);
2497
2498 /* Teardown IPA sys_pipe for MCC */
jiadbb47e132018-03-30 16:28:30 +08002499 if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302500 wlan_ipa_teardown_sys_pipe(ipa_ctx);
jiadbb47e132018-03-30 16:28:30 +08002501 qdf_cancel_work(&ipa_ctx->mcc_work);
2502 }
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302503
Sravan Kumar Kairam2e7aae92018-03-06 19:32:49 +05302504 wlan_ipa_wdi_destroy_rm(ipa_ctx);
2505
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302506 wlan_ipa_flush(ipa_ctx);
2507
Sravan Kumar Kairamd01b4452018-03-07 17:37:09 +05302508 qdf_spinlock_destroy(&ipa_ctx->pm_lock);
2509 qdf_spinlock_destroy(&ipa_ctx->q_lock);
2510
2511 /* destroy the interface lock */
2512 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2513 iface_context = &ipa_ctx->iface_context[i];
2514 qdf_spinlock_destroy(&iface_context->interface_lock);
2515 }
2516
2517 if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
2518 wlan_ipa_wdi_cleanup();
2519 qdf_mutex_destroy(&ipa_ctx->event_lock);
2520 qdf_mutex_destroy(&ipa_ctx->ipa_lock);
2521 qdf_list_destroy(&ipa_ctx->pending_event);
2522
2523 }
2524
2525 gp_ipa = NULL;
2526
2527 return QDF_STATUS_SUCCESS;
2528}
Sravan Kumar Kairam271fab22018-03-07 18:57:41 +05302529
2530struct wlan_ipa_iface_context
2531*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode)
2532{
2533 struct wlan_ipa_iface_context *iface_ctx = NULL;
2534 int i;
2535
2536 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2537 iface_ctx = &ipa_ctx->iface_context[i];
2538
2539 if (iface_ctx->device_mode == mode)
2540 return iface_ctx;
2541 }
2542
2543 return NULL;
2544}
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302545
jiadbb47e132018-03-30 16:28:30 +08002546void wlan_ipa_set_mcc_mode(struct wlan_ipa_priv *ipa_ctx, bool mcc_mode)
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302547{
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302548 if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
jiadbb47e132018-03-30 16:28:30 +08002549 return;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302550
jiadbb47e132018-03-30 16:28:30 +08002551 if (ipa_ctx->mcc_mode == mcc_mode)
2552 return;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302553
jiadbb47e132018-03-30 16:28:30 +08002554 ipa_ctx->mcc_mode = mcc_mode;
2555 qdf_sched_work(0, &ipa_ctx->mcc_work);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302556}
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302557
2558/**
2559 * wlan_ipa_uc_loaded_handler() - Process IPA uC loaded indication
2560 * @ipa_ctx: ipa ipa local context
2561 *
2562 * Will handle IPA UC image loaded indication comes from IPA kernel
2563 *
2564 * Return: None
2565 */
2566static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx)
2567{
2568 struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
2569 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
2570 qdf_device_t qdf_dev = wlan_psoc_get_qdf_dev(psoc);
2571 QDF_STATUS status;
2572
2573 ipa_info("UC READY");
Ryan Hsub5783cf2018-05-14 12:13:15 -07002574
2575 if (!qdf_dev) {
2576 ipa_err("qdf device is NULL!");
2577 return;
2578 }
2579
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302580 if (true == ipa_ctx->uc_loaded) {
2581 ipa_info("UC already loaded");
2582 return;
2583 }
2584
Lihua Liu15f6e452018-05-30 17:31:06 +08002585 if (!qdf_dev) {
2586 ipa_err("qdf_dev is null");
2587 return;
2588 }
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302589 /* Connect pipe */
2590 status = wlan_ipa_wdi_setup(ipa_ctx, qdf_dev);
2591 if (status) {
2592 ipa_err("Failure to setup IPA pipes (status=%d)",
2593 status);
2594 return;
2595 }
2596
2597 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302598
2599 /* If already any STA connected, enable IPA/FW PIPEs */
2600 if (ipa_ctx->sap_num_connected_sta) {
2601 ipa_debug("Client already connected, enable IPA/FW PIPEs");
2602 wlan_ipa_uc_handle_first_con(ipa_ctx);
2603 }
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302604}
2605
2606/**
2607 * wlan_ipa_uc_op_cb() - IPA uC operation callback
2608 * @op_msg: operation message received from firmware
2609 * @usr_ctxt: user context registered with TL (we register the IPA Global
2610 * context)
2611 *
2612 * Return: None
2613 */
2614static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
2615 struct wlan_ipa_priv *ipa_ctx)
2616{
2617 struct op_msg_type *msg = op_msg;
2618 struct ipa_uc_fw_stats *uc_fw_stat;
2619
2620 if (!op_msg) {
2621 ipa_err("INVALID ARG");
2622 return;
2623 }
2624
2625 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
2626 ipa_err("INVALID OPCODE %d", msg->op_code);
2627 qdf_mem_free(op_msg);
2628 return;
2629 }
2630
2631 ipa_debug("OPCODE=%d", msg->op_code);
2632
2633 if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_RESUME) ||
2634 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_RESUME)) {
2635 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2636 ipa_ctx->activated_fw_pipe++;
Yun Parka29974a2018-04-09 12:05:49 -07002637 if (wlan_ipa_is_fw_wdi_activated(ipa_ctx)) {
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302638 ipa_ctx->resource_loading = false;
2639 qdf_event_set(&ipa_ctx->ipa_resource_comp);
2640 if (ipa_ctx->wdi_enabled == false) {
2641 ipa_ctx->wdi_enabled = true;
2642 if (wlan_ipa_uc_send_wdi_control_msg(true) == 0)
2643 wlan_ipa_send_mcc_scc_msg(ipa_ctx,
2644 ipa_ctx->mcc_mode);
2645 }
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302646 wlan_ipa_uc_proc_pending_event(ipa_ctx, true);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302647 if (ipa_ctx->pending_cons_req)
Yun Parke114fbf2018-04-05 20:02:12 -07002648 wlan_ipa_wdi_rm_notify_completion(
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302649 QDF_IPA_RM_RESOURCE_GRANTED,
2650 QDF_IPA_RM_RESOURCE_WLAN_CONS);
2651 ipa_ctx->pending_cons_req = false;
2652 }
2653 qdf_mutex_release(&ipa_ctx->ipa_lock);
2654 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_SUSPEND) ||
2655 (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND)) {
2656 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
Sravan Kumar Kairama61e5a92018-06-18 13:01:05 +05302657
2658 if (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND) {
2659 wlan_ipa_uc_disable_pipes(ipa_ctx);
2660 ipa_info("Disable FW TX PIPE");
2661 cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
2662 false, true);
2663 }
2664
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302665 ipa_ctx->activated_fw_pipe--;
2666 if (!ipa_ctx->activated_fw_pipe) {
2667 /*
2668 * Async return success from FW
2669 * Disable/suspend all the PIPEs
2670 */
2671 ipa_ctx->resource_unloading = false;
2672 qdf_event_set(&ipa_ctx->ipa_resource_comp);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302673 if (wlan_ipa_is_rm_enabled(ipa_ctx->config))
Yun Parke114fbf2018-04-05 20:02:12 -07002674 wlan_ipa_wdi_rm_release_resource(ipa_ctx,
2675 QDF_IPA_RM_RESOURCE_WLAN_PROD);
Sravan Kumar Kairam5214f652018-03-13 09:52:31 +05302676 wlan_ipa_uc_proc_pending_event(ipa_ctx, false);
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302677 ipa_ctx->pending_cons_req = false;
2678 }
2679 qdf_mutex_release(&ipa_ctx->ipa_lock);
2680 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
2681 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_DEBUG)) {
2682 uc_fw_stat = (struct ipa_uc_fw_stats *)
2683 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2684
2685 /* WLAN FW WDI stats */
2686 wlan_ipa_print_fw_wdi_stats(ipa_ctx, uc_fw_stat);
2687 } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
2688 (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_BW_CAL)) {
2689 /* STATs from FW */
2690 uc_fw_stat = (struct ipa_uc_fw_stats *)
2691 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
2692 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2693 ipa_ctx->ipa_tx_packets_diff = BW_GET_DIFF(
2694 uc_fw_stat->tx_pkts_completed,
2695 ipa_ctx->ipa_p_tx_packets);
2696 ipa_ctx->ipa_rx_packets_diff = BW_GET_DIFF(
2697 (uc_fw_stat->rx_num_ind_drop_no_space +
2698 uc_fw_stat->rx_num_ind_drop_no_buf +
2699 uc_fw_stat->rx_num_pkts_indicated),
2700 ipa_ctx->ipa_p_rx_packets);
2701
2702 ipa_ctx->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
2703 ipa_ctx->ipa_p_rx_packets =
2704 (uc_fw_stat->rx_num_ind_drop_no_space +
2705 uc_fw_stat->rx_num_ind_drop_no_buf +
2706 uc_fw_stat->rx_num_pkts_indicated);
2707 qdf_mutex_release(&ipa_ctx->ipa_lock);
2708 } else if (msg->op_code == WLAN_IPA_UC_OPCODE_UC_READY) {
2709 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2710 wlan_ipa_uc_loaded_handler(ipa_ctx);
2711 qdf_mutex_release(&ipa_ctx->ipa_lock);
2712 } else if (wlan_ipa_uc_op_metering(ipa_ctx, op_msg)) {
2713 ipa_err("Invalid message: op_code=%d, reason=%d",
2714 msg->op_code, ipa_ctx->stat_req_reason);
2715 }
2716
2717 qdf_mem_free(op_msg);
2718}
2719
2720/**
jitiphilfdcaaba2018-09-03 16:19:52 +05302721 * __wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
2722 * @data: uC OP work
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302723 *
2724 * Return: None
2725 */
jitiphilfdcaaba2018-09-03 16:19:52 +05302726static void __wlan_ipa_uc_fw_op_event_handler(void *data)
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302727{
2728 struct op_msg_type *msg;
2729 struct uc_op_work_struct *uc_op_work =
2730 (struct uc_op_work_struct *)data;
2731 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
2732
jitiphilfdcaaba2018-09-03 16:19:52 +05302733 if (qdf_is_module_state_transitioning()) {
2734 ipa_err("Module transition in progress");
2735 return;
2736 }
2737
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302738 msg = uc_op_work->msg;
2739 uc_op_work->msg = NULL;
2740 ipa_debug("posted msg %d", msg->op_code);
2741
2742 wlan_ipa_uc_op_cb(msg, ipa_ctx);
2743}
2744
2745/**
jitiphilfdcaaba2018-09-03 16:19:52 +05302746 * wlan_ipa_uc_fw_op_event_handler - SSR wrapper for
2747 * __wlan_ipa_uc_fw_op_event_handler
2748 * @data: uC OP work
2749 *
2750 * Return: None
2751 */
2752static void wlan_ipa_uc_fw_op_event_handler(void *data)
2753{
2754 qdf_ssr_protect(__func__);
2755 __wlan_ipa_uc_fw_op_event_handler(data);
2756 qdf_ssr_unprotect(__func__);
2757}
2758
2759/**
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302760 * wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
2761 * @op_msg: operation message received from firmware
2762 * @ipa_ctx: Global IPA context
2763 *
2764 * Return: None
2765 */
2766static void wlan_ipa_uc_op_event_handler(uint8_t *op_msg, void *ctx)
2767{
2768 struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)ctx;
2769 struct op_msg_type *msg;
2770 struct uc_op_work_struct *uc_op_work;
2771
2772 if (!ipa_ctx)
2773 goto end;
2774
2775 msg = (struct op_msg_type *)op_msg;
2776
2777 if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
2778 ipa_err("Invalid OP Code (%d)", msg->op_code);
2779 goto end;
2780 }
2781
2782 uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
2783 if (uc_op_work->msg) {
2784 /* When the same uC OPCODE is already pended, just return */
2785 goto end;
2786 }
2787
2788 uc_op_work->msg = msg;
2789 qdf_sched_work(0, &uc_op_work->work);
2790 return;
2791
2792end:
2793 qdf_mem_free(op_msg);
2794}
2795
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302796QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx,
2797 qdf_device_t osdev)
2798{
2799 uint8_t i;
2800 QDF_STATUS status = QDF_STATUS_SUCCESS;
2801
2802 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2803 return QDF_STATUS_SUCCESS;
2804
2805 ipa_debug("enter");
2806
2807 for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) {
2808 ipa_ctx->vdev_to_iface[i] = WLAN_IPA_MAX_SESSION;
2809 ipa_ctx->vdev_offload_enabled[i] = false;
2810 }
2811
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302812 if (cdp_ipa_get_resource(ipa_ctx->dp_soc, ipa_ctx->dp_pdev)) {
2813 ipa_err("IPA UC resource alloc fail");
2814 status = QDF_STATUS_E_FAILURE;
2815 goto fail_return;
2816 }
2817
2818 if (true == ipa_ctx->uc_loaded) {
2819 status = wlan_ipa_wdi_setup(ipa_ctx, osdev);
2820 if (status) {
2821 ipa_err("Failure to setup IPA pipes (status=%d)",
2822 status);
2823 status = QDF_STATUS_E_FAILURE;
2824 goto fail_return;
2825 }
2826
2827 cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
2828 wlan_ipa_init_metering(ipa_ctx);
jiadf9771182018-06-12 12:43:40 +08002829
2830 if (wlan_ipa_init_perf_level(ipa_ctx) != QDF_STATUS_SUCCESS)
2831 ipa_err("Failed to init perf level");
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302832 }
2833
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302834 cdp_ipa_register_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
2835 wlan_ipa_uc_op_event_handler, (void *)ipa_ctx);
2836
2837 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
2838 qdf_create_work(0, &ipa_ctx->uc_op_work[i].work,
2839 wlan_ipa_uc_fw_op_event_handler,
2840 &ipa_ctx->uc_op_work[i]);
2841 ipa_ctx->uc_op_work[i].msg = NULL;
2842 }
2843
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302844fail_return:
2845 ipa_debug("exit: status=%d", status);
2846 return status;
2847}
2848
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302849/**
2850 * wlan_ipa_cleanup_pending_event() - Cleanup IPA pending event list
2851 * @ipa_ctx: pointer to IPA IPA struct
2852 *
2853 * Return: none
2854 */
2855static void wlan_ipa_cleanup_pending_event(struct wlan_ipa_priv *ipa_ctx)
2856{
2857 struct wlan_ipa_uc_pending_event *pending_event = NULL;
2858
2859 while (qdf_list_remove_front(&ipa_ctx->pending_event,
2860 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
2861 qdf_mem_free(pending_event);
2862}
2863
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302864QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx)
2865{
2866 QDF_STATUS status = QDF_STATUS_SUCCESS;
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302867 int i;
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302868
2869 ipa_debug("enter");
2870
2871 if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
2872 return status;
2873
2874 if (!ipa_ctx->ipa_pipes_down)
2875 wlan_ipa_uc_disable_pipes(ipa_ctx);
2876
2877 if (true == ipa_ctx->uc_loaded) {
2878 status = cdp_ipa_cleanup(ipa_ctx->dp_soc,
2879 ipa_ctx->tx_pipe_handle,
2880 ipa_ctx->rx_pipe_handle);
2881 if (status)
2882 ipa_err("Failure to cleanup IPA pipes (status=%d)",
2883 status);
2884 }
2885
Sravan Kumar Kairam7d931ff2018-03-13 09:42:02 +05302886 qdf_mutex_acquire(&ipa_ctx->ipa_lock);
2887 wlan_ipa_cleanup_pending_event(ipa_ctx);
2888 qdf_mutex_release(&ipa_ctx->ipa_lock);
2889
2890 for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
2891 qdf_cancel_work(&ipa_ctx->uc_op_work[i].work);
2892 qdf_mem_free(ipa_ctx->uc_op_work[i].msg);
2893 ipa_ctx->uc_op_work[i].msg = NULL;
2894 }
2895
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05302896 ipa_debug("exit: ret=%d", status);
2897 return status;
2898}
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +05302899
Yun Parka29974a2018-04-09 12:05:49 -07002900bool wlan_ipa_is_fw_wdi_activated(struct wlan_ipa_priv *ipa_ctx)
2901{
2902 return (WLAN_IPA_UC_NUM_WDI_PIPE == ipa_ctx->activated_fw_pipe);
2903}
2904
Sravan Kumar Kairamce792eb2018-06-15 15:07:11 +05302905/**
2906 * wlan_ipa_uc_send_evt() - send event to ipa
2907 * @net_dev: Interface net device
2908 * @type: event type
2909 * @mac_addr: pointer to mac address
2910 *
2911 * Send event to IPA driver
2912 *
2913 * Return: QDF_STATUS
2914 */
2915static QDF_STATUS wlan_ipa_uc_send_evt(qdf_netdev_t net_dev,
2916 qdf_ipa_wlan_event type,
2917 uint8_t *mac_addr)
2918{
2919 struct wlan_ipa_priv *ipa_ctx = gp_ipa;
2920 qdf_ipa_msg_meta_t meta;
2921 qdf_ipa_wlan_msg_t *msg;
2922
2923 QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
2924 msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
2925 if (!msg) {
2926 ipa_err("msg allocation failed");
2927 return QDF_STATUS_E_NOMEM;
2928 }
2929
2930 QDF_IPA_SET_META_MSG_TYPE(&meta, type);
2931 qdf_str_lcopy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name,
2932 IPA_RESOURCE_NAME_MAX);
2933 qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN);
2934
2935 if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) {
2936 ipa_err("%s: Evt: %d fail",
2937 QDF_IPA_WLAN_MSG_NAME(msg),
2938 QDF_IPA_MSG_META_MSG_TYPE(&meta));
2939 qdf_mem_free(msg);
2940
2941 return QDF_STATUS_E_FAILURE;
2942 }
2943
2944 ipa_ctx->stats.num_send_msg++;
2945
2946 return QDF_STATUS_SUCCESS;
2947}
2948
2949QDF_STATUS wlan_ipa_uc_disconnect_ap(struct wlan_ipa_priv *ipa_ctx,
2950 qdf_netdev_t net_dev)
2951{
2952 struct wlan_ipa_iface_context *iface_ctx;
2953 QDF_STATUS status;
2954
2955 ipa_debug("enter");
2956
2957 iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_SAP_MODE);
2958 if (iface_ctx)
2959 status = wlan_ipa_uc_send_evt(net_dev, QDF_IPA_AP_DISCONNECT,
2960 net_dev->dev_addr);
2961 else
2962 return QDF_STATUS_E_INVAL;
2963
2964 ipa_debug("exit :%d", status);
2965
2966 return status;
2967}
2968
2969void wlan_ipa_cleanup_dev_iface(struct wlan_ipa_priv *ipa_ctx,
2970 qdf_netdev_t net_dev)
2971{
2972 struct wlan_ipa_iface_context *iface_ctx;
2973 int i;
2974
2975 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2976 iface_ctx = &ipa_ctx->iface_context[i];
2977 if (iface_ctx->dev == net_dev)
2978 break;
2979 }
2980
2981 if (iface_ctx)
2982 wlan_ipa_cleanup_iface(iface_ctx);
2983}
Sravan Kumar Kairam657f89e2018-09-18 10:13:37 +05302984
2985void wlan_ipa_uc_ssr_cleanup(struct wlan_ipa_priv *ipa_ctx)
2986{
2987 struct wlan_ipa_iface_context *iface;
2988 int i;
2989
2990 ipa_info("enter");
2991
2992 for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
2993 iface = &ipa_ctx->iface_context[i];
2994 if (iface->dev) {
2995 if (iface->device_mode == QDF_SAP_MODE)
2996 wlan_ipa_uc_send_evt(iface->dev,
2997 QDF_IPA_AP_DISCONNECT,
2998 iface->dev->dev_addr);
2999 else if (iface->device_mode == QDF_STA_MODE)
3000 wlan_ipa_uc_send_evt(iface->dev,
3001 QDF_IPA_STA_DISCONNECT,
3002 iface->dev->dev_addr);
3003 wlan_ipa_cleanup_iface(iface);
3004 }
3005 }
3006}