blob: 481aeb0b72a0c30c7f3a7373fea5a9fc9d1c9da3 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002 * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ipa.c
30 *
31 * WLAN HDD and ipa interface implementation
32 * Originally written by Qualcomm Atheros, Inc
33 */
34
35#ifdef IPA_OFFLOAD
36
37/* Include Files */
Mohit Khannafa99aea2016-05-12 21:43:13 -070038#include <linux/ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include <wlan_hdd_includes.h>
40#include <wlan_hdd_ipa.h>
41
42#include <linux/etherdevice.h>
43#include <linux/atomic.h>
44#include <linux/netdevice.h>
45#include <linux/skbuff.h>
46#include <linux/list.h>
47#include <linux/debugfs.h>
48#include <linux/inetdevice.h>
49#include <linux/ip.h>
50#include <wlan_hdd_softap_tx_rx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070051#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080052
53#include "cds_sched.h"
54
55#include "wma.h"
56#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080057#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080058
Dhanashri Atreb08959a2016-03-01 17:28:03 -080059#include "cdp_txrx_ipa.h"
60
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080061#define HDD_IPA_DESC_BUFFER_RATIO 4
62#define HDD_IPA_IPV4_NAME_EXT "_ipv4"
63#define HDD_IPA_IPV6_NAME_EXT "_ipv6"
64
65#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
67/* WDI TX and RX PIPE */
68#define HDD_IPA_UC_NUM_WDI_PIPE 2
69#define HDD_IPA_UC_MAX_PENDING_EVENT 33
70
71#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
72#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
73#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
74#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
75
76#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
77#define HDD_IPA_MAX_IFACE 3
78#define HDD_IPA_MAX_SYSBAM_PIPE 4
79#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
80#define HDD_IPA_ENABLE_MASK BIT(0)
81#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
82#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
83#define HDD_IPA_RM_ENABLE_MASK BIT(3)
84#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
85#define HDD_IPA_UC_ENABLE_MASK BIT(5)
86#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
87#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
88
Yun Parkf19e07d2015-11-20 11:34:27 -080089#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
90
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080091typedef enum {
92 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
93 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
94 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
95 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
96 HDD_IPA_UC_OPCODE_STATS = 4,
97 /* keep this last */
98 HDD_IPA_UC_OPCODE_MAX
99} hdd_ipa_uc_op_code;
100
101/**
102 * enum - Reason codes for stat query
103 *
104 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
105 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
106 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
107 */
108enum {
109 HDD_IPA_UC_STAT_REASON_NONE,
110 HDD_IPA_UC_STAT_REASON_DEBUG,
111 HDD_IPA_UC_STAT_REASON_BW_CAL
112};
113
114/**
115 * enum hdd_ipa_rm_state - IPA resource manager state
116 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
117 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
118 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
119 */
120enum hdd_ipa_rm_state {
121 HDD_IPA_RM_RELEASED,
122 HDD_IPA_RM_GRANT_PENDING,
123 HDD_IPA_RM_GRANTED,
124};
125
126struct llc_snap_hdr {
127 uint8_t dsap;
128 uint8_t ssap;
129 uint8_t resv[4];
130 __be16 eth_type;
131} __packed;
132
Leo Chang3bc8fed2015-11-13 10:59:47 -0800133/**
134 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
135 * @eth: ether II header
136 * @llc_snap: LLC snap header
137 *
138 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800139struct hdd_ipa_tx_hdr {
140 struct ethhdr eth;
141 struct llc_snap_hdr llc_snap;
142} __packed;
143
Leo Chang3bc8fed2015-11-13 10:59:47 -0800144/**
145 * struct frag_header - fragment header type registered to IPA hardware
146 * @length: fragment length
147 * @reserved1: Reserved not used
148 * @reserved2: Reserved not used
149 *
150 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800151struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800152 uint16_t length;
153 uint32_t reserved1;
154 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155} __packed;
156
Leo Chang3bc8fed2015-11-13 10:59:47 -0800157/**
158 * struct ipa_header - ipa header type registered to IPA hardware
159 * @vdev_id: vdev id
160 * @reserved: Reserved not used
161 *
162 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800163struct ipa_header {
164 uint32_t
165 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
166 reserved:24;
167} __packed;
168
Leo Chang3bc8fed2015-11-13 10:59:47 -0800169/**
170 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
171 * @frag_hd: fragment header
172 * @ipa_hd: ipa header
173 * @eth: ether II header
174 *
175 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176struct hdd_ipa_uc_tx_hdr {
177 struct frag_header frag_hd;
178 struct ipa_header ipa_hd;
179 struct ethhdr eth;
180} __packed;
181
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800182/**
183 * struct hdd_ipa_cld_hdr - IPA CLD Header
184 * @reserved: reserved fields
185 * @iface_id: interface ID
186 * @sta_id: Station ID
187 *
188 * Packed 32-bit structure
189 * +----------+----------+--------------+--------+
190 * | Reserved | QCMAP ID | interface id | STA ID |
191 * +----------+----------+--------------+--------+
192 */
193struct hdd_ipa_cld_hdr {
194 uint8_t reserved[2];
195 uint8_t iface_id;
196 uint8_t sta_id;
197} __packed;
198
199struct hdd_ipa_rx_hdr {
200 struct hdd_ipa_cld_hdr cld_hdr;
201 struct ethhdr eth;
202} __packed;
203
204struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700205 bool exception;
206 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 struct hdd_ipa_iface_context *iface_context;
208 struct ipa_rx_data *ipa_tx_desc;
209};
210
211struct hdd_ipa_uc_rx_hdr {
212 struct ethhdr eth;
213} __packed;
214
215struct hdd_ipa_sys_pipe {
216 uint32_t conn_hdl;
217 uint8_t conn_hdl_valid;
218 struct ipa_sys_connect_params ipa_sys_params;
219};
220
221struct hdd_ipa_iface_stats {
222 uint64_t num_tx;
223 uint64_t num_tx_drop;
224 uint64_t num_tx_err;
225 uint64_t num_tx_cac_drop;
226 uint64_t num_rx_prefilter;
227 uint64_t num_rx_ipa_excep;
228 uint64_t num_rx_recv;
229 uint64_t num_rx_recv_mul;
230 uint64_t num_rx_send_desc_err;
231 uint64_t max_rx_mul;
232};
233
234struct hdd_ipa_priv;
235
236struct hdd_ipa_iface_context {
237 struct hdd_ipa_priv *hdd_ipa;
238 hdd_adapter_t *adapter;
239 void *tl_context;
240
241 enum ipa_client_type cons_client;
242 enum ipa_client_type prod_client;
243
244 uint8_t iface_id; /* This iface ID */
245 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530246 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800247 uint32_t ifa_address;
248 struct hdd_ipa_iface_stats stats;
249};
250
251struct hdd_ipa_stats {
252 uint32_t event[IPA_WLAN_EVENT_MAX];
253 uint64_t num_send_msg;
254 uint64_t num_free_msg;
255
256 uint64_t num_rm_grant;
257 uint64_t num_rm_release;
258 uint64_t num_rm_grant_imm;
259 uint64_t num_cons_perf_req;
260 uint64_t num_prod_perf_req;
261
262 uint64_t num_rx_drop;
263 uint64_t num_rx_ipa_tx_dp;
264 uint64_t num_rx_ipa_splice;
265 uint64_t num_rx_ipa_loop;
266 uint64_t num_rx_ipa_tx_dp_err;
267 uint64_t num_rx_ipa_write_done;
268 uint64_t num_max_ipa_tx_mul;
269 uint64_t num_rx_ipa_hw_maxed_out;
270 uint64_t max_pend_q_cnt;
271
272 uint64_t num_tx_comp_cnt;
273 uint64_t num_tx_queued;
274 uint64_t num_tx_dequeued;
275 uint64_t num_max_pm_queue;
276
277 uint64_t num_freeq_empty;
278 uint64_t num_pri_freeq_empty;
279 uint64_t num_rx_excep;
280 uint64_t num_tx_bcmc;
281 uint64_t num_tx_bcmc_err;
282};
283
284struct ipa_uc_stas_map {
285 bool is_reserved;
286 uint8_t sta_id;
287};
288struct op_msg_type {
289 uint8_t msg_t;
290 uint8_t rsvd;
291 uint16_t op_code;
292 uint16_t len;
293 uint16_t rsvd_snd;
294};
295
296struct ipa_uc_fw_stats {
297 uint32_t tx_comp_ring_base;
298 uint32_t tx_comp_ring_size;
299 uint32_t tx_comp_ring_dbell_addr;
300 uint32_t tx_comp_ring_dbell_ind_val;
301 uint32_t tx_comp_ring_dbell_cached_val;
302 uint32_t tx_pkts_enqueued;
303 uint32_t tx_pkts_completed;
304 uint32_t tx_is_suspend;
305 uint32_t tx_reserved;
306 uint32_t rx_ind_ring_base;
307 uint32_t rx_ind_ring_size;
308 uint32_t rx_ind_ring_dbell_addr;
309 uint32_t rx_ind_ring_dbell_ind_val;
310 uint32_t rx_ind_ring_dbell_ind_cached_val;
311 uint32_t rx_ind_ring_rdidx_addr;
312 uint32_t rx_ind_ring_rd_idx_cached_val;
313 uint32_t rx_refill_idx;
314 uint32_t rx_num_pkts_indicated;
315 uint32_t rx_buf_refilled;
316 uint32_t rx_num_ind_drop_no_space;
317 uint32_t rx_num_ind_drop_no_buf;
318 uint32_t rx_is_suspend;
319 uint32_t rx_reserved;
320};
321
322struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530323 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800324 hdd_adapter_t *adapter;
325 enum ipa_wlan_event type;
326 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530327 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800328};
329
330/**
331 * struct uc_rm_work_struct
332 * @work: uC RM work
333 * @event: IPA RM event
334 */
335struct uc_rm_work_struct {
336 struct work_struct work;
337 enum ipa_rm_event event;
338};
339
340/**
341 * struct uc_op_work_struct
342 * @work: uC OP work
343 * @msg: OP message
344 */
345struct uc_op_work_struct {
346 struct work_struct work;
347 struct op_msg_type *msg;
348};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800349
350/**
351 * struct uc_rt_debug_info
352 * @time: system time
353 * @ipa_excep_count: IPA exception packet count
354 * @rx_drop_count: IPA Rx drop packet count
355 * @net_sent_count: IPA Rx packet sent to network stack count
356 * @rx_discard_count: IPA Rx discard packet count
357 * @rx_mcbc_count: IPA Rx BCMC packet count
358 * @tx_mcbc_count: IPA Tx BCMC packet countt
359 * @tx_fwd_count: IPA Tx forward packet count
360 * @rx_destructor_call: IPA Rx packet destructor count
361 */
362struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530363 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364 uint64_t ipa_excep_count;
365 uint64_t rx_drop_count;
366 uint64_t net_sent_count;
367 uint64_t rx_discard_count;
368 uint64_t rx_mcbc_count;
369 uint64_t tx_mcbc_count;
370 uint64_t tx_fwd_count;
371 uint64_t rx_destructor_call;
372};
373
374struct hdd_ipa_priv {
375 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
376 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
377 uint8_t num_iface;
378 enum hdd_ipa_rm_state rm_state;
379 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530380 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800381 * APIs as it is taken care gracefully. Without this, kernel would throw
382 * an warning if spin_lock_bh is used while IRQ is disabled
383 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530384 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800385 struct uc_rm_work_struct uc_rm_work;
386 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530387 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388 struct delayed_work wake_lock_work;
389 bool wake_lock_released;
390
391 enum ipa_client_type prod_client;
392
393 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530394 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800395 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530396 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800397 bool suspended;
398
399 uint32_t pending_hw_desc_cnt;
400 uint32_t hw_desc_cnt;
401 spinlock_t q_lock;
402 uint32_t freeq_cnt;
403 struct list_head free_desc_head;
404
405 uint32_t pend_q_cnt;
406 struct list_head pend_desc_head;
407
408 hdd_context_t *hdd_ctx;
409
410 struct dentry *debugfs_dir;
411 struct hdd_ipa_stats stats;
412
413 struct notifier_block ipv4_notifier;
414 uint32_t curr_prod_bw;
415 uint32_t curr_cons_bw;
416
417 uint8_t activated_fw_pipe;
418 uint8_t sap_num_connected_sta;
419 uint8_t sta_connected;
420 uint32_t tx_pipe_handle;
421 uint32_t rx_pipe_handle;
422 bool resource_loading;
423 bool resource_unloading;
424 bool pending_cons_req;
425 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530426 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530427 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700428 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800429 uint32_t ipa_tx_packets_diff;
430 uint32_t ipa_rx_packets_diff;
431 uint32_t ipa_p_tx_packets;
432 uint32_t ipa_p_rx_packets;
433 uint32_t stat_req_reason;
434 uint64_t ipa_tx_forward;
435 uint64_t ipa_rx_discard;
436 uint64_t ipa_rx_net_send_count;
437 uint64_t ipa_rx_internel_drop_count;
438 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530439 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800440 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
441 unsigned int rt_buf_fill_index;
Anurag Chouhan210db072016-02-22 18:42:15 +0530442 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530443 qdf_mutex_t rt_debug_lock;
444 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800445 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800446 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530447 qdf_dma_addr_t tx_comp_doorbell_paddr;
448 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800449
450 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
451 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800452};
453
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800454/**
Houston Hoffman23e76f92016-02-26 12:19:11 -0800455 * FIXME: The following conversion routines are just stubs.
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800456 * They will be implemented fully by another update.
457 * The stubs will let the compile go ahead, and functionality
458 * is broken.
459 * This should be OK and IPA is not enabled yet
460 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700461static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800462{
463 void *vaddr;
464 uint32_t ipa_priv = priv;
465
466 vaddr = &ipa_priv; /* just to use the var */
467 vaddr = NULL;
468 return vaddr;
469}
470
Jeff Johnsond7720632016-10-05 16:04:32 -0700471static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800472{
473 uint32_t ipa_priv = 0;
474
475 BUG_ON(ptr == NULL);
476 return ipa_priv;
477}
Leo Changcc923e22016-06-16 15:29:03 -0700478
479#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
480#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800481#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
482#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
483#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
484#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
485#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
486#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700487#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
488 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489
490#define HDD_IPA_GET_IFACE_ID(_data) \
491 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
492
493#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530494 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800495 "%s:%d: "fmt, __func__, __LINE__, ## args)
496
Govind Singhb6a89772016-08-12 11:23:35 +0530497#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
498 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
499 "%s:%d: "fmt, __func__, __LINE__, ## args)
500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
502 do { \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530503 QDF_TRACE(QDF_MODULE_ID_HDD, _lvl, "%s:", _prefix); \
504 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505 } while (0)
506
507#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
508 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
509
510#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
511 do { \
512 hdd_ipa->ipa_rx_internel_drop_count++; \
513 } while (0)
514#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
515 do { \
516 hdd_ipa->ipa_rx_net_send_count++; \
517 } while (0)
518#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
519
Leo Chang07b28f62016-05-11 12:29:22 -0700520#if defined (QCA_WIFI_3_0) && defined (CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800521#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
522do { \
523 pipe_in.u.ul.rdy_ring_rp_va = \
524 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
525 pipe_in.u.ul.rdy_comp_ring_base_pa = \
526 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
527 pipe_in.u.ul.rdy_comp_ring_size = \
528 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
529 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
530 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
531 pipe_in.u.ul.rdy_comp_ring_wp_va = \
532 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800533} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700534
535#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800536#else
537/* Do nothing */
538#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700539#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700540#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800541
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542static struct hdd_ipa_adapter_2_client {
543 enum ipa_client_type cons_client;
544 enum ipa_client_type prod_client;
545} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
546 {
547 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
548 }, {
549 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
550 }, {
551 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
552 },
553};
554
555/* For Tx pipes, use Ethernet-II Header format */
556struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
557 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800558 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800559 0x00000000,
560 0x00000000
561 },
562 {
563 0x00000000
564 },
565 {
566 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
567 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
568 0x0008
569 }
570};
571
572/* For Tx pipes, use 802.3 Header format */
573static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
574 {
575 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
576 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
577 0x00 /* length can be zero */
578 },
579 {
580 /* LLC SNAP header 8 bytes */
581 0xaa, 0xaa,
582 {0x03, 0x00, 0x00, 0x00},
583 0x0008 /* type value(2 bytes) ,filled by wlan */
584 /* 0x0800 - IPV4, 0x86dd - IPV6 */
585 }
586};
587
588static const char *op_string[] = {
589 "TX_SUSPEND",
590 "TX_RESUME",
591 "RX_SUSPEND",
592 "RX_RESUME",
593 "STATS",
594};
595
596static struct hdd_ipa_priv *ghdd_ipa;
597
598/* Local Function Prototypes */
599static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
600 unsigned long data);
601static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
602 unsigned long data);
603
604static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Mohit Khannafa99aea2016-05-12 21:43:13 -0700605static void hdd_ipa_uc_proc_pending_event (struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800606
607/**
608 * hdd_ipa_is_enabled() - Is IPA enabled?
609 * @hdd_ctx: Global HDD context
610 *
611 * Return: true if IPA is enabled, false otherwise
612 */
613bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
614{
615 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
616}
617
618/**
619 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
620 * @hdd_ctx: Global HDD context
621 *
622 * Return: true if IPA uC offload is enabled, false otherwise
623 */
624bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
625{
626 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
627}
628
629/**
630 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
631 * @hdd_ctx: Global HDD context
632 *
633 * Return: true if STA mode IPA uC offload is enabled, false otherwise
634 */
635static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
636{
637 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
638}
639
640/**
Guolei Bianca144d82016-11-10 11:07:42 +0800641 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
642 * @hdd_ipa: Global HDD IPA context
643 *
644 * Return: None
645 */
646#ifdef IPA_UC_STA_OFFLOAD
647static inline void hdd_ipa_uc_sta_reset_sta_connected(
648 struct hdd_ipa_priv *hdd_ipa)
649{
650 vos_lock_acquire(&hdd_ipa->event_lock);
651 hdd_ipa->sta_connected = 0;
652 vos_lock_release(&hdd_ipa->event_lock);
653}
654#else
655static inline void hdd_ipa_uc_sta_reset_sta_connected(
656 struct hdd_ipa_priv *hdd_ipa)
657{
658}
659#endif
660
661/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800662 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
663 * @hdd_ipa: Global HDD IPA context
664 *
665 * Return: true if pre-filter is enabled, otherwise false
666 */
667static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
668{
669 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
670 HDD_IPA_PRE_FILTER_ENABLE_MASK);
671}
672
673/**
674 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
675 * @hdd_ipa: Global HDD IPA context
676 *
677 * Return: true if IPv6 is enabled, otherwise false
678 */
679static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
680{
681 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
682}
683
684/**
685 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
686 * @hdd_ipa: Global HDD IPA context
687 *
688 * Return: true if resource manager is enabled, otherwise false
689 */
690static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
691{
692 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
693}
694
695/**
696 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
697 * @hdd_ipa: Global HDD IPA context
698 *
699 * Return: true if resource manager is enabled, otherwise false
700 */
701static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
702{
703 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
704}
705
706/**
707 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
708 * @hdd_ipa: Global HDD IPA context
709 *
710 * Return: true if clock scaling is enabled, otherwise false
711 */
712static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
713{
714 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
715 HDD_IPA_CLK_SCALING_ENABLE_MASK |
716 HDD_IPA_RM_ENABLE_MASK);
717}
718
719/**
720 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
721 * @ctext: pointer to hdd context.
722 *
723 * If rt debug enabled, periodically called, and fill debug buffer
724 *
725 * Return: none
726 */
727static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
728{
729 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
730 struct hdd_ipa_priv *hdd_ipa;
731 struct uc_rt_debug_info *dump_info = NULL;
732
733 if (wlan_hdd_validate_context(hdd_ctx))
734 return;
735
736 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530737 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800738 "%s: IPA UC is not enabled", __func__);
739 return;
740 }
741
742 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
743
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530744 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745 dump_info = &hdd_ipa->rt_bug_buffer[
746 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
747
Deepthi Gowri6acee342016-10-28 15:00:38 +0530748 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800749 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
750 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
751 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
752 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
753 dump_info->tx_mcbc_count = hdd_ipa->stats.num_tx_bcmc;
754 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
755 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
756 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530757 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800758
Anurag Chouhan210db072016-02-22 18:42:15 +0530759 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800760 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
761}
762
763/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700764 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800765 * @hdd_ctx: pointer to hdd context.
766 *
767 * If rt debug enabled, dump debug buffer contents based on requirement
768 *
769 * Return: none
770 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700771static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800772{
773 struct hdd_ipa_priv *hdd_ipa;
774 unsigned int dump_count;
775 unsigned int dump_index;
776 struct uc_rt_debug_info *dump_info = NULL;
777
778 if (wlan_hdd_validate_context(hdd_ctx))
779 return;
780
781 hdd_ipa = hdd_ctx->hdd_ipa;
782 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530783 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800784 "%s: IPA UC is not enabled", __func__);
785 return;
786 }
787
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530788 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800789 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530790 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800791 " TM : EXEP : DROP : NETS : MCBC : TXFD : DSTR : DSCD\n");
792
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530793 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800794 for (dump_count = 0;
795 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
796 dump_count++) {
797 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
798 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
799 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530800 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530801 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800802 dump_info->time, dump_info->ipa_excep_count,
803 dump_info->rx_drop_count, dump_info->net_sent_count,
804 dump_info->tx_mcbc_count, dump_info->tx_fwd_count,
805 dump_info->rx_destructor_call,
806 dump_info->rx_discard_count);
807 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530808 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530809 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800810 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
811}
812
813/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700814 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
815 * __hdd_ipa_uc_rt_debug_host_dump
816 * @hdd_ctx: pointer to hdd context.
817 *
818 * If rt debug enabled, dump debug buffer contents based on requirement
819 *
820 * Return: none
821 */
822void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
823{
824 cds_ssr_protect(__func__);
825 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
826 cds_ssr_unprotect(__func__);
827}
828
829/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800830 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
831 * @ctext: pointer to hdd context.
832 *
833 * periodically called by timer expire
834 * will try to alloc dummy memory and detect out of memory condition
835 * if out of memory detected, dump wlan-ipa stats
836 *
837 * Return: none
838 */
839static void hdd_ipa_uc_rt_debug_handler(void *ctext)
840{
841 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700842 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800843 void *dummy_ptr = NULL;
844
845 if (wlan_hdd_validate_context(hdd_ctx))
846 return;
847
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700848 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
849
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530851 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800852 "%s: IPA RT debug is not enabled", __func__);
853 return;
854 }
855
856 /* Allocate dummy buffer periodically and free immediately. this will
857 * proactively detect OOM and if allocation fails dump ipa stats
858 */
859 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
860 GFP_KERNEL | GFP_ATOMIC);
861 if (!dummy_ptr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530862 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800863 "%s: Dummy alloc fail", __func__);
864 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
865 hdd_ipa_uc_stat_request(
Krunal Sonibe766b02016-03-10 13:00:44 -0800866 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800867 } else {
868 kfree(dummy_ptr);
869 }
870
Anurag Chouhan210db072016-02-22 18:42:15 +0530871 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872 HDD_IPA_UC_RT_DEBUG_PERIOD);
873}
874
875/**
876 * hdd_ipa_uc_rt_debug_destructor - called by data packet free
877 * @skb: packet pinter
878 *
879 * when free data packet, will be invoked by wlan client and will increase
880 * free counter
881 *
882 * Return: none
883 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700884static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800885{
886 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530887 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 "%s: invalid hdd context", __func__);
889 return;
890 }
891
892 ghdd_ipa->ipa_rx_destructor_count++;
893}
894
895/**
896 * hdd_ipa_uc_rt_debug_deinit - remove resources to handle rt debugging
897 * @hdd_ctx: hdd main context
898 *
899 * free all rt debugging resources
900 *
901 * Return: none
902 */
903static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
904{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700905 struct hdd_ipa_priv *hdd_ipa;
906
907 if (wlan_hdd_validate_context(hdd_ctx))
908 return;
909
910 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800911
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530912 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800913
914 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530915 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916 "%s: IPA RT debug is not enabled", __func__);
917 return;
918 }
919
Anurag Chouhan210db072016-02-22 18:42:15 +0530920 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -0800921 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
922 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
923 }
924 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
925
926 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +0530927 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
928 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 }
Anurag Chouhan210db072016-02-22 18:42:15 +0530930 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931}
932
933/**
934 * hdd_ipa_uc_rt_debug_init - intialize resources to handle rt debugging
935 * @hdd_ctx: hdd main context
936 *
937 * alloc and initialize all rt debugging resources
938 *
939 * Return: none
940 */
941static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
942{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700943 struct hdd_ipa_priv *hdd_ipa;
944
945 if (wlan_hdd_validate_context(hdd_ctx))
946 return;
947
948 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530950 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530952 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953 sizeof(struct uc_rt_debug_info) *
954 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
955 hdd_ipa->ipa_tx_forward = 0;
956 hdd_ipa->ipa_rx_discard = 0;
957 hdd_ipa->ipa_rx_net_send_count = 0;
958 hdd_ipa->ipa_rx_internel_drop_count = 0;
959 hdd_ipa->ipa_rx_destructor_count = 0;
960
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800961 /* Reatime debug enable on feature enable */
962 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530963 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964 "%s: IPA RT debug is not enabled", __func__);
965 return;
966 }
Yun Parkdfc1da52016-11-15 14:50:11 -0800967
968 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
969 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
970 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
971 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
972
Anurag Chouhan210db072016-02-22 18:42:15 +0530973 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +0530975 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800976 HDD_IPA_UC_RT_DEBUG_PERIOD);
977
978}
979
980/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700981 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800982 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700983 * @ipa_tx_diff: tx packet count diff from previous tx packet count
984 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800985 *
986 * Return: true if IPA is enabled, false otherwise
987 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700988static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
990{
991 struct hdd_ipa_priv *hdd_ipa;
992
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800993 *ipa_tx_diff = 0;
994 *ipa_rx_diff = 0;
995
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700996 if (wlan_hdd_validate_context(hdd_ctx))
997 return;
998
999 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1000
1001 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1002 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001003 return;
1004 }
1005
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301006 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001007 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1008 (false == hdd_ipa->resource_loading)) {
1009 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1010 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkf8d6a122016-10-11 15:49:43 -07001011 HDD_IPA_LOG(LOGOFF, "STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001012 *ipa_tx_diff, *ipa_rx_diff);
1013 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301014 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001015 return;
1016}
1017
1018/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001019 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1020 * @hdd_ctx: Global HDD context
1021 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1022 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1023 *
1024 * Return: true if IPA is enabled, false otherwise
1025 */
1026void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1027 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1028{
1029 cds_ssr_protect(__func__);
1030 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1031 cds_ssr_unprotect(__func__);
1032}
1033
1034/**
1035 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001036 * @adapter: network adapter
1037 * @reason: STAT REQ Reason
1038 *
1039 * Return: None
1040 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001041static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001043 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044 struct hdd_ipa_priv *hdd_ipa;
1045
1046 if (!adapter) {
1047 return;
1048 }
1049
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001050 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1051
1052 if (wlan_hdd_validate_context(hdd_ctx))
1053 return;
1054
1055 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1056 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1057 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001058 return;
1059 }
1060
Yun Park8f289c82016-10-18 16:38:21 -07001061 HDD_IPA_LOG(LOGOFF, "STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301062 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1064 (false == hdd_ipa->resource_loading)) {
1065 hdd_ipa->stat_req_reason = reason;
1066 wma_cli_set_command(
1067 (int)adapter->sessionId,
1068 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1069 0, VDEV_CMD);
1070 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301071 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072}
1073
1074/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001075 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1076 * @adapter: network adapter
1077 * @reason: STAT REQ Reason
1078 *
1079 * Return: None
1080 */
1081void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1082{
1083 cds_ssr_protect(__func__);
1084 __hdd_ipa_uc_stat_request(adapter, reason);
1085 cds_ssr_unprotect(__func__);
1086}
1087
1088/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001089 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1090 * @hdd_ipa: Global HDD IPA context
1091 * @sta_add: Should station be added
1092 * @sta_id: ID of the station being queried
1093 *
1094 * Return: true if the station was found
1095 */
1096static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1097 bool sta_add, uint8_t sta_id)
1098{
1099 bool sta_found = false;
1100 uint8_t idx;
1101 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1102 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1103 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1104 sta_found = true;
1105 break;
1106 }
1107 }
1108 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301109 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001110 "%s: STA ID %d already exist, cannot add",
1111 __func__, sta_id);
1112 return sta_found;
1113 }
1114 if (sta_add) {
1115 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1116 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1117 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1118 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1119 return sta_found;
1120 }
1121 }
1122 }
1123 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301124 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125 "%s: STA ID %d does not exist, cannot delete",
1126 __func__, sta_id);
1127 return sta_found;
1128 }
1129 if (!sta_add) {
1130 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1131 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1132 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1133 hdd_ipa->assoc_stas_map[idx].is_reserved =
1134 false;
1135 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1136 return sta_found;
1137 }
1138 }
1139 }
1140 return sta_found;
1141}
1142
1143/**
1144 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1145 * @hdd_ipa: Global HDD IPA context
1146 *
1147 * Return: 0 on success, negative errno if error
1148 */
1149static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1150{
1151 int result;
1152 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001153 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001154
1155 /* ACTIVATE TX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301156 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001157 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1158 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001159 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1160 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301161 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162 "%s: Enable TX PIPE fail, code %d",
1163 __func__, result);
1164 return result;
1165 }
1166 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1167 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301168 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001169 "%s: Resume TX PIPE fail, code %d",
1170 __func__, result);
1171 return result;
1172 }
Leo Changfdb45c32016-10-28 11:09:23 -07001173 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001174
1175 /* ACTIVATE RX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301176 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001177 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1178 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001179 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1180 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301181 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001182 "%s: Enable RX PIPE fail, code %d",
1183 __func__, result);
1184 return result;
1185 }
1186 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1187 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301188 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001189 "%s: Resume RX PIPE fail, code %d",
1190 __func__, result);
1191 return result;
1192 }
Leo Changfdb45c32016-10-28 11:09:23 -07001193 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, true, false);
Leo Change3e49442015-10-26 20:07:13 -07001194 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001195 return 0;
1196}
1197
1198/**
1199 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1200 * @hdd_ipa: Global HDD IPA context
1201 *
1202 * Return: 0 on success, negative errno if error
1203 */
1204static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1205{
1206 int result;
1207
Leo Change3e49442015-10-26 20:07:13 -07001208 hdd_ipa->ipa_pipes_down = true;
1209
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301210 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001211 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1212 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301213 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001214 "%s: Suspend RX PIPE fail, code %d",
1215 __func__, result);
1216 return result;
1217 }
1218 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1219 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301220 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221 "%s: Disable RX PIPE fail, code %d",
1222 __func__, result);
1223 return result;
1224 }
1225
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301226 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001227 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
1228 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301229 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230 "%s: Suspend TX PIPE fail, code %d",
1231 __func__, result);
1232 return result;
1233 }
1234 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1235 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301236 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001237 "%s: Disable TX PIPE fail, code %d",
1238 __func__, result);
1239 return result;
1240 }
1241
1242 return 0;
1243}
1244
1245/**
1246 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1247 * @hdd_ipa: Global HDD IPA context
1248 *
1249 * Return: 0 on success, negative errno if error
1250 */
1251static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1252{
1253 hdd_ipa->activated_fw_pipe = 0;
1254 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001255
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001256 /* If RM feature enabled
1257 * Request PROD Resource first
1258 * PROD resource may return sync or async manners */
Yun Park4cab6ee2015-10-27 11:43:40 -07001259 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
1260 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1261 /* RM PROD request sync return
1262 * enable pipe immediately
1263 */
1264 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301265 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001266 "%s: IPA WDI Pipe activation failed",
1267 __func__);
1268 hdd_ipa->resource_loading = false;
1269 return -EBUSY;
1270 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001271 }
1272 } else {
1273 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001274 * Just enabled all the PIPEs
1275 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001276 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301277 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001278 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 __func__);
1280 hdd_ipa->resource_loading = false;
1281 return -EBUSY;
1282 }
1283 hdd_ipa->resource_loading = false;
1284 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001285
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301286 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001287 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001288 return 0;
1289}
1290
1291/**
1292 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1293 * @hdd_ipa: Global HDD IPA context
1294 *
1295 * Return: None
1296 */
1297static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1298{
1299 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001300 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001301
Yun Park7c4f31b2016-11-30 10:09:21 -08001302 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
1303 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1304 QDF_ASSERT(0);
1305 return;
1306 }
1307
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001308 hdd_ipa->resource_unloading = true;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301309 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW RX PIPE", __func__);
Leo Changfdb45c32016-10-28 11:09:23 -07001310 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, false, false);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301311 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW TX PIPE", __func__);
Leo Changfdb45c32016-10-28 11:09:23 -07001312 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001313}
1314
1315/**
1316 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
1317 * @context: User context registered with TL (the IPA Global context is
1318 * registered
1319 * @rxpkt: Packet containing the notification
1320 * @staid: ID of the station associated with the packet
1321 *
1322 * Return: None
1323 */
1324static void
1325hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
1326{
1327 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301328 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001329
1330 /*
1331 * When SSR is going on or driver is unloading, just return.
1332 */
1333 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301334 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001335 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001336
1337 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1338 return;
1339
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301340 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001341 __func__, event);
1342
1343 switch (event) {
1344 case IPA_RM_RESOURCE_GRANTED:
1345 /* Differed RM Granted */
1346 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301347 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348 if ((false == hdd_ipa->resource_unloading) &&
1349 (!hdd_ipa->activated_fw_pipe)) {
1350 hdd_ipa_uc_enable_pipes(hdd_ipa);
1351 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301352 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001353 break;
1354
1355 case IPA_RM_RESOURCE_RELEASED:
1356 /* Differed RM Released */
1357 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001358 break;
1359
1360 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301361 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001362 "%s, invalid event code %d", __func__, event);
1363 break;
1364 }
1365}
1366
1367/**
1368 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
1369 * @hdd_ipa: Global HDD IPA context
1370 * @event: IPA resource manager event to be deferred
1371 *
1372 * This function is called when a resource manager event is received
1373 * from firmware in interrupt context. This function will defer the
1374 * handling to the OL RX thread
1375 *
1376 * Return: None
1377 */
1378static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
1379{
1380 enum ipa_rm_event event;
1381 struct uc_rm_work_struct *uc_rm_work = container_of(work,
1382 struct uc_rm_work_struct, work);
1383 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
1384 struct hdd_ipa_priv, uc_rm_work);
1385
1386 cds_ssr_protect(__func__);
1387 event = uc_rm_work->event;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301388 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001389 "%s, posted event %d", __func__, event);
1390
1391 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
1392 cds_ssr_unprotect(__func__);
1393
1394 return;
1395}
1396
1397/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001398 * hdd_ipa_uc_op_cb() - IPA uC operation callback
1399 * @op_msg: operation message received from firmware
1400 * @usr_ctxt: user context registered with TL (we register the HDD Global
1401 * context)
1402 *
1403 * Return: None
1404 */
1405static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
1406{
1407 struct op_msg_type *msg = op_msg;
1408 struct ipa_uc_fw_stats *uc_fw_stat;
1409 struct IpaHwStatsWDIInfoData_t ipa_stat;
1410 struct hdd_ipa_priv *hdd_ipa;
1411 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301412 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001413
1414 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301415 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001416 return;
1417 }
1418
1419 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301420 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001421 "%s, INVALID OPCODE %d", __func__, msg->op_code);
1422 return;
1423 }
1424
1425 hdd_ctx = (hdd_context_t *) usr_ctxt;
1426
1427 /*
1428 * When SSR is going on or driver is unloading, just return.
1429 */
1430 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301431 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301432 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001433 return;
1434 }
1435
1436 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1437
Govind Singhb6a89772016-08-12 11:23:35 +05301438 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001439 "%s, OPCODE %s", __func__, op_string[msg->op_code]);
1440
1441 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
1442 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301443 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444 hdd_ipa->activated_fw_pipe++;
1445 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
1446 hdd_ipa->resource_loading = false;
1447 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08001448 if (hdd_ipa->pending_cons_req)
1449 ipa_rm_notify_completion(
1450 IPA_RM_RESOURCE_GRANTED,
1451 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08001452 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301454 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001455 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301457 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001458 hdd_ipa->activated_fw_pipe--;
1459 if (!hdd_ipa->activated_fw_pipe) {
1460 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08001461 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1462 ipa_rm_release_resource(
1463 IPA_RM_RESOURCE_WLAN_PROD);
1464 /* Sync return success from IPA
1465 * Enable/resume all the PIPEs */
1466 hdd_ipa->resource_unloading = false;
1467 hdd_ipa_uc_proc_pending_event(hdd_ipa);
1468 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001469 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301470 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001471 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001472 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001473 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301475 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001476 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001477 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478 "CE RING SIZE: %d\n"
1479 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001480 (unsigned long long)res->ce_sr_base_paddr,
1481 res->ce_sr_ring_size,
1482 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301483 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001485 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001486 "COMP RING SIZE: %d\n"
1487 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001488 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001489 (unsigned long long)res->tx_comp_ring_base_paddr,
1490 res->tx_comp_ring_size,
1491 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001492 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301493 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001494 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001495 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001497 "IND RING DBELL : 0x%llx\n"
1498 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001499 "NUM EXCP PKT : %llu\n"
1500 "NUM TX BCMC : %llu\n"
1501 "NUM TX BCMC ERR : %llu",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001502 (unsigned long long)res->rx_rdy_ring_base_paddr,
1503 res->rx_rdy_ring_size,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001504 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001505 (unsigned long long)hdd_ipa->ipa_resource.
1506 rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001507 hdd_ipa->stats.num_rx_excep,
1508 hdd_ipa->stats.num_tx_bcmc,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001509 (unsigned long long)hdd_ipa->stats.num_tx_bcmc_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301510 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001511 "==== IPA_UC WLAN_HOST CONTROL ====\n"
1512 "SAP NUM STAs: %d\n"
1513 "STA CONNECTED: %d\n"
1514 "TX PIPE HDL: %d\n"
1515 "RX PIPE HDL : %d\n"
1516 "RSC LOADING : %d\n"
1517 "RSC UNLOADING : %d\n"
1518 "PNDNG CNS RQT : %d",
1519 hdd_ipa->sap_num_connected_sta,
1520 hdd_ipa->sta_connected,
1521 hdd_ipa->tx_pipe_handle,
1522 hdd_ipa->rx_pipe_handle,
1523 (unsigned int)hdd_ipa->resource_loading,
1524 (unsigned int)hdd_ipa->resource_unloading,
1525 (unsigned int)hdd_ipa->pending_cons_req);
1526
1527 /* STATs from FW */
1528 uc_fw_stat = (struct ipa_uc_fw_stats *)
1529 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301530 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001531 "==== IPA_UC WLAN_FW TX ====\n"
1532 "COMP RING BASE: 0x%x\n"
1533 "COMP RING SIZE: %d\n"
1534 "COMP RING DBELL : 0x%x\n"
1535 "COMP RING DBELL IND VAL : %d\n"
1536 "COMP RING DBELL CACHED VAL : %d\n"
1537 "COMP RING DBELL CACHED VAL : %d\n"
1538 "PKTS ENQ : %d\n"
1539 "PKTS COMP : %d\n"
1540 "IS SUSPEND : %d\n"
1541 "RSVD : 0x%x",
1542 uc_fw_stat->tx_comp_ring_base,
1543 uc_fw_stat->tx_comp_ring_size,
1544 uc_fw_stat->tx_comp_ring_dbell_addr,
1545 uc_fw_stat->tx_comp_ring_dbell_ind_val,
1546 uc_fw_stat->tx_comp_ring_dbell_cached_val,
1547 uc_fw_stat->tx_comp_ring_dbell_cached_val,
1548 uc_fw_stat->tx_pkts_enqueued,
1549 uc_fw_stat->tx_pkts_completed,
1550 uc_fw_stat->tx_is_suspend, uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301551 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001552 "==== IPA_UC WLAN_FW RX ====\n"
1553 "IND RING BASE: 0x%x\n"
1554 "IND RING SIZE: %d\n"
1555 "IND RING DBELL : 0x%x\n"
1556 "IND RING DBELL IND VAL : %d\n"
1557 "IND RING DBELL CACHED VAL : %d\n"
1558 "RDY IND ADDR : 0x%x\n"
1559 "RDY IND CACHE VAL : %d\n"
1560 "RFIL IND : %d\n"
1561 "NUM PKT INDICAT : %d\n"
1562 "BUF REFIL : %d\n"
1563 "NUM DROP NO SPC : %d\n"
1564 "NUM DROP NO BUF : %d\n"
1565 "IS SUSPND : %d\n"
1566 "RSVD : 0x%x\n",
1567 uc_fw_stat->rx_ind_ring_base,
1568 uc_fw_stat->rx_ind_ring_size,
1569 uc_fw_stat->rx_ind_ring_dbell_addr,
1570 uc_fw_stat->rx_ind_ring_dbell_ind_val,
1571 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
1572 uc_fw_stat->rx_ind_ring_rdidx_addr,
1573 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
1574 uc_fw_stat->rx_refill_idx,
1575 uc_fw_stat->rx_num_pkts_indicated,
1576 uc_fw_stat->rx_buf_refilled,
1577 uc_fw_stat->rx_num_ind_drop_no_space,
1578 uc_fw_stat->rx_num_ind_drop_no_buf,
1579 uc_fw_stat->rx_is_suspend, uc_fw_stat->rx_reserved);
1580 /* STATs from IPA */
1581 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301582 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001583 "==== IPA_UC IPA TX ====\n"
1584 "NUM PROCD : %d\n"
1585 "CE DBELL : 0x%x\n"
1586 "NUM DBELL FIRED : %d\n"
1587 "COMP RNG FULL : %d\n"
1588 "COMP RNG EMPT : %d\n"
1589 "COMP RNG USE HGH : %d\n"
1590 "COMP RNG USE LOW : %d\n"
1591 "BAM FIFO FULL : %d\n"
1592 "BAM FIFO EMPT : %d\n"
1593 "BAM FIFO USE HGH : %d\n"
1594 "BAM FIFO USE LOW : %d\n"
1595 "NUM DBELL : %d\n"
1596 "NUM UNEXP DBELL : %d\n"
1597 "NUM BAM INT HDL : 0x%x\n"
1598 "NUM BAM INT NON-RUN : 0x%x\n"
1599 "NUM QMB INT HDL : 0x%x",
1600 ipa_stat.tx_ch_stats.num_pkts_processed,
1601 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
1602 ipa_stat.tx_ch_stats.num_db_fired,
1603 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
1604 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
1605 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
1606 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
1607 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
1608 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
1609 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
1610 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
1611 ipa_stat.tx_ch_stats.num_db,
1612 ipa_stat.tx_ch_stats.num_unexpected_db,
1613 ipa_stat.tx_ch_stats.num_bam_int_handled,
1614 ipa_stat.tx_ch_stats.
1615 num_bam_int_in_non_runnning_state,
1616 ipa_stat.tx_ch_stats.num_qmb_int_handled);
1617
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301618 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619 "==== IPA_UC IPA RX ====\n"
1620 "MAX OST PKT : %d\n"
1621 "NUM PKT PRCSD : %d\n"
1622 "RNG RP : 0x%x\n"
1623 "COMP RNG FULL : %d\n"
1624 "COMP RNG EMPT : %d\n"
1625 "COMP RNG USE HGH : %d\n"
1626 "COMP RNG USE LOW : %d\n"
1627 "BAM FIFO FULL : %d\n"
1628 "BAM FIFO EMPT : %d\n"
1629 "BAM FIFO USE HGH : %d\n"
1630 "BAM FIFO USE LOW : %d\n"
1631 "NUM DB : %d\n"
1632 "NUM UNEXP DB : %d\n"
1633 "NUM BAM INT HNDL : 0x%x\n",
1634 ipa_stat.rx_ch_stats.max_outstanding_pkts,
1635 ipa_stat.rx_ch_stats.num_pkts_processed,
1636 ipa_stat.rx_ch_stats.rx_ring_rp_value,
1637 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
1638 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
1639 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
1640 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
1641 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
1642 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
1643 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
1644 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
1645 ipa_stat.rx_ch_stats.num_db,
1646 ipa_stat.rx_ch_stats.num_unexpected_db,
1647 ipa_stat.rx_ch_stats.num_bam_int_handled);
1648 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
1649 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
1650 /* STATs from FW */
1651 uc_fw_stat = (struct ipa_uc_fw_stats *)
1652 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301653 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
1655 uc_fw_stat->tx_pkts_completed,
1656 hdd_ipa->ipa_p_tx_packets);
1657 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
1658 (uc_fw_stat->rx_num_ind_drop_no_space +
1659 uc_fw_stat->rx_num_ind_drop_no_buf +
1660 uc_fw_stat->rx_num_pkts_indicated),
1661 hdd_ipa->ipa_p_rx_packets);
1662
1663 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
1664 hdd_ipa->ipa_p_rx_packets =
1665 (uc_fw_stat->rx_num_ind_drop_no_space +
1666 uc_fw_stat->rx_num_ind_drop_no_buf +
1667 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301668 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669 } else {
Yun Park8292dcb2016-10-07 16:46:06 -07001670 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
1671 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301673 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001674}
1675
1676
1677/**
1678 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
1679 * @adapter: device adapter instance
1680 * @offload_type: MCC or SCC
1681 * @enable: TX offload enable or disable
1682 *
1683 * Return: none
1684 */
1685static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001686 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001687{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001688 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07001690 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001691 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001693 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694 return;
1695
Yun Park8292dcb2016-10-07 16:46:06 -07001696 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001697 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07001698
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001699 if (!iface_context) {
1700 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1701 "Interface context is NULL");
1702 return;
1703 }
1704
1705 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07001706 /* IPA offload status is already set as desired */
1707 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001708 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
1709 "IPA offload status is already set",
1710 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07001711 return;
1712 }
1713
Yun Park4540e862016-11-10 16:30:06 -08001714 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1715 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1716 "invalid session id: %d, offload_type=%d, enable=%d",
1717 adapter->sessionId, offload_type, enable);
1718 return;
1719 }
1720
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301721 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 sizeof(ipa_offload_enable_disable));
1723 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001724 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725 ipa_offload_enable_disable.enable = enable;
1726
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301727 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07001728 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729 ipa_offload_enable_disable.offload_type,
1730 ipa_offload_enable_disable.vdev_id,
1731 ipa_offload_enable_disable.enable);
1732
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301733 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
1735 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301736 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08001737 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
1738 __func__,
1739 ipa_offload_enable_disable.offload_type,
1740 ipa_offload_enable_disable.vdev_id,
1741 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07001742 } else {
1743 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001744 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07001745 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001746 }
1747}
1748
1749/**
1750 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
1751 * @work: uC OP work
1752 *
1753 * Return: None
1754 */
1755static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
1756{
1757 struct op_msg_type *msg;
1758 struct uc_op_work_struct *uc_op_work = container_of(work,
1759 struct uc_op_work_struct, work);
1760 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
1761
1762 cds_ssr_protect(__func__);
1763
1764 msg = uc_op_work->msg;
1765 uc_op_work->msg = NULL;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301766 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767 "%s, posted msg %d", __func__, msg->op_code);
1768
1769 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
1770
1771 cds_ssr_unprotect(__func__);
1772
1773 return;
1774}
1775
1776/**
1777 * hdd_ipa_uc_op_event_handler() - Adapter lookup
1778 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
1779 * @op_msg: operation message received from firmware
1780 * @hdd_ctx: Global HDD context
1781 *
1782 * Return: None
1783 */
1784static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
1785{
1786 struct hdd_ipa_priv *hdd_ipa;
1787 struct op_msg_type *msg;
1788 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301789 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790
1791 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301792 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794
1795 msg = (struct op_msg_type *)op_msg;
1796 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
1797
1798 if (unlikely(!hdd_ipa))
1799 goto end;
1800
1801 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301802 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001803 __func__, msg->op_code);
1804 goto end;
1805 }
1806
1807 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
1808 if (uc_op_work->msg)
1809 /* When the same uC OPCODE is already pended, just return */
1810 goto end;
1811
1812 uc_op_work->msg = msg;
1813 schedule_work(&uc_op_work->work);
1814 return;
1815
1816end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301817 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001818}
1819
1820/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08001821 * hdd_ipa_init_uc_op_work - init ipa uc op work
1822 * @work: struct work_struct
1823 * @work_handler: work_handler
1824 *
1825 * Return: none
1826 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08001827static void hdd_ipa_init_uc_op_work(struct work_struct *work,
1828 work_func_t work_handler)
1829{
1830 INIT_WORK(work, work_handler);
1831}
Rajeev Kumar217f2172016-01-06 18:11:55 -08001832
1833
1834/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
1836 * @hdd_ctx: Global HDD context
1837 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301838 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301840static QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841{
1842 struct ipa_wdi_in_params pipe_in;
1843 struct ipa_wdi_out_params pipe_out;
1844 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1845 p_cds_contextType cds_ctx = hdd_ctx->pcds_context;
1846 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07001847 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301849 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
1850 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001851
Anurag Chouhanffb21542016-02-17 14:33:03 +05301852 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301853 qdf_mutex_create(&ipa_ctxt->event_lock);
1854 qdf_mutex_create(&ipa_ctxt->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855
1856 /* TX PIPE */
1857 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
1858 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
1859 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
1860 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
1861 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
1862 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
1863 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
1864 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
1865 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
1866 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
1867 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
1868 pipe_in.sys.notify = hdd_ipa_i2w_cb;
1869 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301870 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
1872 pipe_in.sys.keep_ipa_awake = true;
1873 }
1874
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001875 pipe_in.u.dl.comp_ring_base_pa =
1876 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08001877 pipe_in.u.dl.comp_ring_size =
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001878 ipa_ctxt->ipa_resource.tx_comp_ring_size *
1879 sizeof(qdf_dma_addr_t);
1880 pipe_in.u.dl.ce_ring_base_pa =
1881 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
1882 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
1883 pipe_in.u.dl.ce_ring_size =
1884 ipa_ctxt->ipa_resource.ce_sr_ring_size;
1885 pipe_in.u.dl.num_tx_buffers =
1886 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887
1888 /* Connect WDI IPA PIPE */
1889 ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
1890 /* Micro Controller Doorbell register */
Govind Singh0487bf22016-08-24 23:08:57 +05301891 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
1892 "%s CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
1893 __func__, (unsigned int)pipe_out.uc_door_bell_pa,
1894 ipa_ctxt->tx_pipe_handle);
Leo Chang3bc8fed2015-11-13 10:59:47 -08001895 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001896 /* WLAN TX PIPE Handle */
1897 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301898 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899 "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x,"
1900 " CERZ %d, NB %d, CDBPAD 0x%x",
1901 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
1902 pipe_in.u.dl.comp_ring_size,
1903 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
1904 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
1905 pipe_in.u.dl.ce_ring_size,
1906 pipe_in.u.dl.num_tx_buffers,
Leo Chang3bc8fed2015-11-13 10:59:47 -08001907 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908
1909 /* RX PIPE */
1910 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
1911 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
1912 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
1913 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
1914 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
1915 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
1916 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
1917 sizeof(struct sps_iovec);
1918 pipe_in.sys.notify = hdd_ipa_w2i_cb;
1919 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301920 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001921 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
1922 pipe_in.sys.keep_ipa_awake = true;
1923 }
1924
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001925 pipe_in.u.ul.rdy_ring_base_pa =
1926 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
1927 pipe_in.u.ul.rdy_ring_size =
1928 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
1929 pipe_in.u.ul.rdy_ring_rp_pa =
1930 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08001931 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932 ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
Leo Chang3bc8fed2015-11-13 10:59:47 -08001933 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301935 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
1937 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
1938 pipe_in.u.ul.rdy_ring_size,
1939 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
Leo Chang3bc8fed2015-11-13 10:59:47 -08001940 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941
Leo Changfdb45c32016-10-28 11:09:23 -07001942 cdp_ipa_set_doorbell_paddr(soc, cds_ctx->pdev_txrx_ctx,
1943 ipa_ctxt->tx_comp_doorbell_paddr,
1944 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945
Leo Changfdb45c32016-10-28 11:09:23 -07001946 cdp_ipa_register_op_cb(soc, cds_ctx->pdev_txrx_ctx,
1947 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948
1949 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08001950 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001951 hdd_ipa_uc_fw_op_event_handler);
1952 ipa_ctxt->uc_op_work[i].msg = NULL;
1953 }
1954
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301955 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001956}
1957
Leo Change3e49442015-10-26 20:07:13 -07001958/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001959 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07001960 * @hdd_ctx: hdd main context
1961 *
1962 * Force shutdown IPA pipe
1963 * Independent of FW pipe status, IPA pipe shutdonw progress
1964 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
1965 * independent from FW pipe status
1966 *
1967 * Return: NONE
1968 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001969static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07001970{
1971 struct hdd_ipa_priv *hdd_ipa;
1972
1973 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
1974 return;
1975
1976 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1977 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301978 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07001979 "IPA pipes are not down yet, force shutdown");
1980 hdd_ipa_uc_disable_pipes(hdd_ipa);
1981 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301982 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Leo Change3e49442015-10-26 20:07:13 -07001983 "IPA pipes are down, do nothing");
1984 }
1985
1986 return;
1987}
1988
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001989/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001990 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
1991 * __hdd_ipa_uc_force_pipe_shutdown
1992 * @hdd_ctx: hdd main context
1993 *
1994 * Force shutdown IPA pipe
1995 * Independent of FW pipe status, IPA pipe shutdonw progress
1996 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
1997 * independent from FW pipe status
1998 *
1999 * Return: NONE
2000 */
2001void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2002{
2003 cds_ssr_protect(__func__);
2004 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2005 cds_ssr_unprotect(__func__);
2006}
2007
2008/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302009 * hdd_ipa_msg_free_fn() - Free an IPA message
2010 * @buff: pointer to the IPA message
2011 * @len: length of the IPA message
2012 * @type: type of IPA message
2013 *
2014 * Return: None
2015 */
2016static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2017{
2018 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len);
2019 ghdd_ipa->stats.num_free_msg++;
2020 qdf_mem_free(buff);
2021}
2022
2023
2024/**
2025 * hdd_ipa_send_disconnect() - ipa send disconnect clients
2026 * adapter: pointer to hdd adapter
2027 * Send disconnect evnt to IPA driver during SSR
2028 *
2029 * Return: 0 - Success
2030 */
2031static int hdd_ipa_send_disconnect(hdd_adapter_t *adapter)
2032{
2033 struct ipa_msg_meta meta;
2034 struct ipa_wlan_msg *msg;
2035 int ret = 0;
2036 int i;
2037
2038 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2039 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2040 continue;
2041 if ((adapter->aStaInfo[i].isUsed) &&
2042 (!adapter->aStaInfo[i].isDeauthInProgress)) {
2043 meta.msg_len = sizeof(struct ipa_wlan_msg);
2044 msg = qdf_mem_malloc(meta.msg_len);
2045 if (msg == NULL) {
2046 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2047 "msg allocation failed");
2048 return -ENOMEM;
2049 }
2050 meta.msg_type = WLAN_CLIENT_DISCONNECT;
2051 strlcpy(msg->name, adapter->dev->name,
2052 IPA_RESOURCE_NAME_MAX);
2053 memcpy(msg->mac_addr, adapter->aStaInfo[i].macAddrSTA.bytes,
2054 ETH_ALEN);
2055 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
2056 msg->name, meta.msg_type);
2057 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2058 if (ret) {
2059 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2060 "%s: Evt: %d fail:%d",
2061 msg->name, meta.msg_type, ret);
2062 qdf_mem_free(msg);
2063 return ret;
2064 }
2065 }
2066 }
2067
2068 return ret;
2069}
2070
2071/**
2072 * hdd_ipa_uc_disconnect_client() - disconnect ipa sap clients
2073 * hdd_ctx: pointer to hdd context
2074 * Send disconnect evnt to IPA driver during SSR
2075 *
2076 * Return: 0 - Success
2077 */
2078static int hdd_ipa_uc_disconnect_client(hdd_context_t *hdd_ctx)
2079{
2080 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2081 QDF_STATUS status;
2082 hdd_adapter_t *adapter;
2083 int ret = 0;
2084
2085
2086 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2087 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2088 adapter = adapter_node->pAdapter;
2089 if (adapter->device_mode == QDF_SAP_MODE)
2090 hdd_ipa_send_disconnect(adapter);
2091 status = hdd_get_next_adapter(
2092 hdd_ctx, adapter_node, &next);
2093 adapter_node = next;
2094 }
2095
2096 return ret;
2097}
2098
2099/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002100 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002101 *
2102 * Deinit basic IPA UC host side to be in sync reloaded FW during
2103 * SSR
2104 *
2105 * Return: 0 - Success
2106 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002107static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002108{
2109 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2110 int idx;
2111 struct hdd_ipa_iface_context *iface_context;
2112
Leo Chang3bc8fed2015-11-13 10:59:47 -08002113 if ((!hdd_ipa) || (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114 return 0;
2115
Govind Singh9c58eba2016-09-02 16:23:06 +05302116 /* send disconnect to ipa driver for connected clients */
2117 hdd_ipa_uc_disconnect_client(hdd_ipa->hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002118 /* Clean up HDD IPA interfaces */
2119 for (idx = 0; (hdd_ipa->num_iface > 0) &&
2120 (idx < HDD_IPA_MAX_IFACE); idx++) {
2121 iface_context = &hdd_ipa->iface_context[idx];
2122 if (iface_context && iface_context->adapter)
2123 hdd_ipa_cleanup_iface(iface_context);
2124 }
2125
2126 /* After SSR, wlan driver reloads FW again. But we need to protect
2127 * IPA submodule during SSR transient state. So deinit basic IPA
2128 * UC host side to be in sync with reloaded FW during SSR
2129 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08002130 if (!hdd_ipa->ipa_pipes_down)
2131 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002132
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302133 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002134 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2135 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
2136 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2137 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302138 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002139
Guolei Bianca144d82016-11-10 11:07:42 +08002140 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
2141 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
2142
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143 /* Full IPA driver cleanup not required since wlan driver is now
2144 * unloaded and reloaded after SSR.
2145 */
2146 return 0;
2147}
2148
2149/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002150 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
2151 *
2152 * Deinit basic IPA UC host side to be in sync reloaded FW during
2153 * SSR
2154 *
2155 * Return: 0 - Success
2156 */
2157int hdd_ipa_uc_ssr_deinit(void)
2158{
2159 int ret;
2160
2161 cds_ssr_protect(__func__);
2162 ret = __hdd_ipa_uc_ssr_deinit();
2163 cds_ssr_unprotect(__func__);
2164
2165 return ret;
2166}
2167
2168/**
2169 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002170 *
2171 * Init basic IPA UC host side to be in sync with reloaded FW after
2172 * SSR to resume IPA UC operations
2173 *
2174 * Return: 0 - Success
2175 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002176static int __hdd_ipa_uc_ssr_reinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002178
2179 /* After SSR is complete, IPA UC can resume operation. But now wlan
2180 * driver will be unloaded and reloaded, which takes care of IPA cleanup
2181 * and initialization. This is a placeholder func if IPA has to resume
2182 * operations without driver reload.
2183 */
2184 return 0;
2185}
Leo Chang3bc8fed2015-11-13 10:59:47 -08002186
2187/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002188 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
2189 *
2190 * Init basic IPA UC host side to be in sync with reloaded FW after
2191 * SSR to resume IPA UC operations
2192 *
2193 * Return: 0 - Success
2194 */
2195int hdd_ipa_uc_ssr_reinit(void)
2196{
2197 int ret;
2198
2199 cds_ssr_protect(__func__);
2200 ret = __hdd_ipa_uc_ssr_reinit();
2201 cds_ssr_unprotect(__func__);
2202
2203 return ret;
2204}
2205
2206/**
2207 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08002208 * @hdd_ctx: Global HDD context
2209 * @skb: skb sent to IPA
2210 * @session_id: send packet instance session id
2211 *
2212 * Send TX packet which generated by system to IPA.
2213 * This routine only will be used for function verification
2214 *
2215 * Return: NULL packet sent to IPA properly
2216 * NULL invalid packet drop
2217 * skb packet not sent to IPA. legacy data path should handle
2218 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002219static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002220 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07002221{
Leo Chang3bc8fed2015-11-13 10:59:47 -08002222 struct ipa_header *ipa_header;
2223 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002224 struct hdd_ipa_priv *hdd_ipa;
2225
2226 if (wlan_hdd_validate_context(hdd_ctx))
2227 return skb;
2228
2229 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002230
2231 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2232 return skb;
2233
Leo Chang07b28f62016-05-11 12:29:22 -07002234 if (!hdd_ipa)
2235 return skb;
2236
2237 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
2238 return skb;
2239
Leo Changcc923e22016-06-16 15:29:03 -07002240 if (skb_headroom(skb) <
2241 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07002242 return skb;
2243
Leo Chang3bc8fed2015-11-13 10:59:47 -08002244 ipa_header = (struct ipa_header *) skb_push(skb,
2245 sizeof(struct ipa_header));
2246 if (!ipa_header) {
2247 /* No headroom, legacy */
2248 return skb;
2249 }
2250 memset(ipa_header, 0, sizeof(*ipa_header));
2251 ipa_header->vdev_id = 0;
2252
2253 frag_header = (struct frag_header *) skb_push(skb,
2254 sizeof(struct frag_header));
2255 if (!frag_header) {
2256 /* No headroom, drop */
2257 kfree_skb(skb);
2258 return NULL;
2259 }
2260 memset(frag_header, 0, sizeof(*frag_header));
2261 frag_header->length = skb->len - sizeof(struct frag_header)
2262 - sizeof(struct ipa_header);
2263
2264 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
2265 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07002266}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002267
2268/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002269 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
2270 * @hdd_ctx: Global HDD context
2271 * @skb: skb sent to IPA
2272 * @session_id: send packet instance session id
2273 *
2274 * Send TX packet which generated by system to IPA.
2275 * This routine only will be used for function verification
2276 *
2277 * Return: NULL packet sent to IPA properly
2278 * NULL invalid packet drop
2279 * skb packet not sent to IPA. legacy data path should handle
2280 */
2281struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
2282 struct sk_buff *skb, uint8_t session_id)
2283{
2284 struct sk_buff *ret;
2285
2286 cds_ssr_protect(__func__);
2287 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
2288 cds_ssr_unprotect(__func__);
2289
2290 return ret;
2291}
2292
2293/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002294 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
2295 * @work: scheduled work
2296 *
2297 * When IPA resources are released in hdd_ipa_rm_try_release() we do
2298 * not want to immediately release the wake lock since the system
2299 * would then potentially try to suspend when there is a healthy data
2300 * rate. Deferred work is scheduled and this function handles the
2301 * work. When this function is called, if the IPA resource is still
2302 * released then we release the wake lock.
2303 *
2304 * Return: None
2305 */
2306static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
2307{
2308 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
2309 struct hdd_ipa_priv,
2310 wake_lock_work);
2311
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302312 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002313
2314 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
2315 goto end;
2316
2317 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302318 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002319 WIFI_POWER_EVENT_WAKELOCK_IPA);
2320
2321end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302322 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002323}
2324
2325/**
2326 * hdd_ipa_rm_request() - Request resource from IPA
2327 * @hdd_ipa: Global HDD IPA context
2328 *
2329 * Return: 0 on success, negative errno on error
2330 */
2331static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
2332{
2333 int ret = 0;
2334
2335 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2336 return 0;
2337
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302338 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339
2340 switch (hdd_ipa->rm_state) {
2341 case HDD_IPA_RM_GRANTED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302342 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002343 return 0;
2344 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302345 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002346 return -EINPROGRESS;
2347 case HDD_IPA_RM_RELEASED:
2348 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
2349 break;
2350 }
2351
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302352 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002353
2354 ret = ipa_rm_inactivity_timer_request_resource(
2355 IPA_RM_RESOURCE_WLAN_PROD);
2356
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302357 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002358 if (ret == 0) {
2359 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
2360 hdd_ipa->stats.num_rm_grant_imm++;
2361 }
2362
2363 cancel_delayed_work(&hdd_ipa->wake_lock_work);
2364 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302365 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002366 WIFI_POWER_EVENT_WAKELOCK_IPA);
2367 hdd_ipa->wake_lock_released = false;
2368 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302369 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002370
2371 return ret;
2372}
2373
2374/**
2375 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
2376 * @hdd_ipa: Global HDD IPA context
2377 *
2378 * Return: 0 if resources released, negative errno otherwise
2379 */
2380static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
2381{
2382 int ret = 0;
2383
2384 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2385 return 0;
2386
2387 if (atomic_read(&hdd_ipa->tx_ref_cnt))
2388 return -EAGAIN;
2389
2390 spin_lock_bh(&hdd_ipa->q_lock);
2391 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
2392 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
2393 spin_unlock_bh(&hdd_ipa->q_lock);
2394 return -EAGAIN;
2395 }
2396 spin_unlock_bh(&hdd_ipa->q_lock);
2397
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302398 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002399
Nirav Shahcbc6d722016-03-01 16:24:53 +05302400 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302401 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002402 return -EAGAIN;
2403 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302404 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002405
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302406 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002407 switch (hdd_ipa->rm_state) {
2408 case HDD_IPA_RM_GRANTED:
2409 break;
2410 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302411 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002412 return -EINPROGRESS;
2413 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302414 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002415 return 0;
2416 }
2417
2418 /* IPA driver returns immediately so set the state here to avoid any
2419 * race condition.
2420 */
2421 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
2422 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302423 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002424
2425 ret =
2426 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
2427
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302428 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002429 if (unlikely(ret != 0)) {
2430 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
2431 WARN_ON(1);
2432 }
2433
2434 /*
2435 * If wake_lock is released immediately, kernel would try to suspend
2436 * immediately as well, Just avoid ping-pong between suspend-resume
2437 * while there is healthy amount of data transfer going on by
2438 * releasing the wake_lock after some delay.
2439 */
2440 schedule_delayed_work(&hdd_ipa->wake_lock_work,
2441 msecs_to_jiffies
2442 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
2443
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302444 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002445
2446 return ret;
2447}
2448
2449/**
2450 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
2451 * @user_data: user data registered with IPA
2452 * @event: the IPA resource manager event that occurred
2453 * @data: the data associated with the event
2454 *
2455 * Return: None
2456 */
2457static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
2458 unsigned long data)
2459{
2460 struct hdd_ipa_priv *hdd_ipa = user_data;
2461
2462 if (unlikely(!hdd_ipa))
2463 return;
2464
2465 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2466 return;
2467
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302468 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002469
2470 switch (event) {
2471 case IPA_RM_RESOURCE_GRANTED:
2472 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2473 /* RM Notification comes with ISR context
2474 * it should be serialized into work queue to avoid
2475 * ISR sleep problem
2476 */
2477 hdd_ipa->uc_rm_work.event = event;
2478 schedule_work(&hdd_ipa->uc_rm_work.work);
2479 break;
2480 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302481 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002482 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302483 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002484 hdd_ipa->stats.num_rm_grant++;
2485 break;
2486
2487 case IPA_RM_RESOURCE_RELEASED:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302488 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002489 hdd_ipa->resource_unloading = false;
2490 break;
2491
2492 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302493 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002494 break;
2495 }
2496}
2497
2498/**
2499 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
2500 *
2501 * Callback function registered with IPA that is called when IPA wants
2502 * to release the WLAN consumer resource
2503 *
2504 * Return: 0 if the request is granted, negative errno otherwise
2505 */
2506static int hdd_ipa_rm_cons_release(void)
2507{
2508 return 0;
2509}
2510
2511/**
2512 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
2513 *
2514 * Callback function registered with IPA that is called when IPA wants
2515 * to access the WLAN consumer resource
2516 *
2517 * Return: 0 if the request is granted, negative errno otherwise
2518 */
2519static int hdd_ipa_rm_cons_request(void)
2520{
Yun Park4d8b60a2015-10-22 13:59:32 -07002521 int ret = 0;
2522
2523 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302524 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07002525 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002526 __func__);
2527 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07002528 ret = -EINPROGRESS;
2529 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302530 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07002531 "%s: IPA resource unloading in progress",
2532 __func__);
2533 ghdd_ipa->pending_cons_req = true;
2534 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002535 }
Yun Park4d8b60a2015-10-22 13:59:32 -07002536
2537 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002538}
2539
2540/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002541 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002542 * @hdd_ctx: Global HDD context
2543 * @tx_packets: Number of packets transmitted in the last sample period
2544 * @rx_packets: Number of packets received in the last sample period
2545 *
2546 * Return: 0 on success, negative errno on error
2547 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002548static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002549 uint64_t rx_packets)
2550{
2551 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002552 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002553 struct ipa_rm_perf_profile profile;
2554 int ret;
2555
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002556 if (wlan_hdd_validate_context(hdd_ctx))
2557 return 0;
2558
2559 hdd_ipa = hdd_ctx->hdd_ipa;
2560
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002561 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
2562 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
2563 return 0;
2564
2565 memset(&profile, 0, sizeof(profile));
2566
2567 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
2568 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
2569 else if (tx_packets >
2570 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
2571 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
2572 else
2573 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
2574
2575 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
2576 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
2577 else if (rx_packets >
2578 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
2579 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
2580 else
2581 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
2582
Yun Park8f289c82016-10-18 16:38:21 -07002583 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002584 "CONS perf curr: %d, next: %d",
2585 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Park8f289c82016-10-18 16:38:21 -07002586 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002587 "PROD perf curr: %d, next: %d",
2588 hdd_ipa->curr_prod_bw, next_prod_bw);
2589
2590 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302591 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002592 "Requesting CONS perf curr: %d, next: %d",
2593 hdd_ipa->curr_cons_bw, next_cons_bw);
2594 profile.max_supported_bandwidth_mbps = next_cons_bw;
2595 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
2596 &profile);
2597 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302598 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002599 "RM CONS set perf profile failed: %d", ret);
2600
2601 return ret;
2602 }
2603 hdd_ipa->curr_cons_bw = next_cons_bw;
2604 hdd_ipa->stats.num_cons_perf_req++;
2605 }
2606
2607 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302608 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002609 "Requesting PROD perf curr: %d, next: %d",
2610 hdd_ipa->curr_prod_bw, next_prod_bw);
2611 profile.max_supported_bandwidth_mbps = next_prod_bw;
2612 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
2613 &profile);
2614 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302615 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002616 "RM PROD set perf profile failed: %d", ret);
2617 return ret;
2618 }
2619 hdd_ipa->curr_prod_bw = next_prod_bw;
2620 hdd_ipa->stats.num_prod_perf_req++;
2621 }
2622
2623 return 0;
2624}
2625
2626/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002627 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
2628 * @hdd_ctx: Global HDD context
2629 * @tx_packets: Number of packets transmitted in the last sample period
2630 * @rx_packets: Number of packets received in the last sample period
2631 *
2632 * Return: 0 on success, negative errno on error
2633 */
2634int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
2635 uint64_t rx_packets)
2636{
2637 int ret;
2638
2639 cds_ssr_protect(__func__);
2640 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
2641 cds_ssr_unprotect(__func__);
2642
2643 return ret;
2644}
2645
2646/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002647 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
2648 * @work: struct work_struct
2649 * @work_handler: work_handler
2650 *
2651 * Return: none
2652 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002653static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
2654 work_func_t work_handler)
2655{
2656 INIT_WORK(work, work_handler);
2657}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002658
2659/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002660 * hdd_ipa_setup_rm() - Setup IPA resource management
2661 * @hdd_ipa: Global HDD IPA context
2662 *
2663 * Return: 0 on success, negative errno on error
2664 */
2665static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
2666{
2667 struct ipa_rm_create_params create_params = { 0 };
2668 int ret;
2669
2670 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2671 return 0;
2672
Rajeev Kumar217f2172016-01-06 18:11:55 -08002673 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
2674 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002675 memset(&create_params, 0, sizeof(create_params));
2676 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
2677 create_params.reg_params.user_data = hdd_ipa;
2678 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
2679 create_params.floor_voltage = IPA_VOLTAGE_SVS;
2680
2681 ret = ipa_rm_create_resource(&create_params);
2682 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302683 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002684 "Create RM resource failed: %d", ret);
2685 goto setup_rm_fail;
2686 }
2687
2688 memset(&create_params, 0, sizeof(create_params));
2689 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
2690 create_params.request_resource = hdd_ipa_rm_cons_request;
2691 create_params.release_resource = hdd_ipa_rm_cons_release;
2692 create_params.floor_voltage = IPA_VOLTAGE_SVS;
2693
2694 ret = ipa_rm_create_resource(&create_params);
2695 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302696 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002697 "Create RM CONS resource failed: %d", ret);
2698 goto delete_prod;
2699 }
2700
2701 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
2702 IPA_RM_RESOURCE_APPS_CONS);
2703
2704 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
2705 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
2706 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302707 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002708 ret);
2709 goto timer_init_failed;
2710 }
2711
2712 /* Set the lowest bandwidth to start with */
2713 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
2714
2715 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302716 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002717 "Set perf level failed: %d", ret);
2718 goto set_perf_failed;
2719 }
2720
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302721 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002722 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
2723 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302724 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002725 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
2726 hdd_ipa->wake_lock_released = true;
2727 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
2728
2729 return ret;
2730
2731set_perf_failed:
2732 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
2733
2734timer_init_failed:
2735 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
2736
2737delete_prod:
2738 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
2739
2740setup_rm_fail:
2741 return ret;
2742}
2743
2744/**
2745 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
2746 * @hdd_ipa: Global HDD IPA context
2747 *
2748 * Destroys all resources associated with the IPA resource manager
2749 *
2750 * Return: None
2751 */
2752static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
2753{
2754 int ret;
2755
2756 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2757 return;
2758
2759 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302760 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002761
2762#ifdef WLAN_OPEN_SOURCE
2763 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
2764#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302765 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002766
2767 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
2768
2769 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
2770 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302771 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002772 "RM PROD resource delete failed %d", ret);
2773
2774 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
2775 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302776 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002777 "RM CONS resource delete failed %d", ret);
2778}
2779
2780/**
2781 * hdd_ipa_send_skb_to_network() - Send skb to kernel
2782 * @skb: network buffer
2783 * @adapter: network adapter
2784 *
2785 * Called when a network buffer is received which should not be routed
2786 * to the IPA module.
2787 *
2788 * Return: None
2789 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05302790static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002791 hdd_adapter_t *adapter)
2792{
2793 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2794 unsigned int cpu_index;
2795
2796 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302797 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798 adapter);
2799 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07002800 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002801 return;
2802 }
2803
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002804 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002805 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07002806 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002807 return;
2808 }
2809
2810 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
2811 skb->dev = adapter->dev;
2812 skb->protocol = eth_type_trans(skb, skb->dev);
2813 skb->ip_summed = CHECKSUM_NONE;
2814
2815 cpu_index = wlan_hdd_get_cpu();
2816
2817 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
2818 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
2819 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
2820 else
2821 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
2822
2823 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
2824 adapter->dev->last_rx = jiffies;
2825}
2826
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002827/**
Leo Chang69c39692016-10-12 20:11:12 -07002828 * hdd_ipa_forward() - handle packet forwarding to wlan tx
2829 * @hdd_ipa: pointer to hdd ipa context
2830 * @adapter: network adapter
2831 * @skb: data pointer
2832 *
2833 * if exception packet has set forward bit, copied new packet should be
2834 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
2835 * put into pm queue and tx procedure will be differed
2836 *
2837 * Return: None
2838 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07002839static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
2840 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07002841{
Leo Chang69c39692016-10-12 20:11:12 -07002842 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
2843
Leo Chang69c39692016-10-12 20:11:12 -07002844 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
2845 /* WLAN subsystem is in suspend, put int queue */
2846 if (hdd_ipa->suspended) {
2847 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
2848 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2849 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002850 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
2851 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07002852 pm_tx_cb->exception = true;
2853 pm_tx_cb->adapter = adapter;
2854 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002855 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07002856 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
2857 hdd_ipa->stats.num_tx_queued++;
2858 } else {
2859 /* Resume, put packet into WLAN TX */
2860 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002861 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07002862 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2863 "packet tx fail");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002864 hdd_ipa->stats.num_tx_bcmc_err++;
Leo Chang69c39692016-10-12 20:11:12 -07002865 } else {
2866 hdd_ipa->stats.num_tx_bcmc++;
2867 hdd_ipa->ipa_tx_forward++;
2868 }
2869 }
2870}
2871
2872/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002873 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
2874 * @hdd_ipa: pointer to HDD IPA struct
2875 * @adapter: hdd adapter pointer
2876 * @desc: Firmware descriptor
2877 * @skb: Data buffer
2878 *
2879 * Return:
2880 * HDD_IPA_FORWARD_PKT_NONE
2881 * HDD_IPA_FORWARD_PKT_DISCARD
2882 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
2883 *
2884 */
2885
2886static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
2887 struct hdd_ipa_priv *hdd_ipa,
2888 hdd_adapter_t *adapter,
2889 uint8_t desc,
2890 qdf_nbuf_t skb)
2891{
2892 int ret = HDD_IPA_FORWARD_PKT_NONE;
2893
2894 if ((desc & FW_RX_DESC_FORWARD_M)) {
2895 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2896 "Forward packet to Tx (fw_desc=%d)", desc);
2897 hdd_ipa->ipa_tx_forward++;
2898
2899 if ((desc & FW_RX_DESC_DISCARD_M)) {
2900 hdd_ipa_forward(hdd_ipa, adapter, skb);
2901 hdd_ipa->ipa_rx_internel_drop_count++;
2902 hdd_ipa->ipa_rx_discard++;
2903 ret = HDD_IPA_FORWARD_PKT_DISCARD;
2904 } else {
2905 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
2906 if (cloned_skb)
2907 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
2908 else
2909 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2910 "%s: tx skb alloc failed",
2911 __func__);
2912 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
2913 }
2914 }
2915
2916 return ret;
2917}
2918
2919/**
Leo Chang69c39692016-10-12 20:11:12 -07002920 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002921 * @priv: pointer to private data registered with IPA (we register a
2922 * pointer to the global IPA context)
2923 * @evt: the IPA event which triggered the callback
2924 * @data: data associated with the event
2925 *
2926 * Return: None
2927 */
Yun Parkf8d6a122016-10-11 15:49:43 -07002928static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002929 unsigned long data)
2930{
2931 struct hdd_ipa_priv *hdd_ipa = NULL;
2932 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05302933 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002934 uint8_t iface_id;
2935 uint8_t session_id;
2936 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002937 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07002938 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002939
2940 hdd_ipa = (struct hdd_ipa_priv *)priv;
2941
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08002942 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2943 return;
2944
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002945 switch (evt) {
2946 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05302947 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07002948
2949 /*
2950 * When SSR is going on or driver is unloading,
2951 * just drop the packets.
2952 */
2953 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
2954 if (0 != status) {
2955 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2956 "Invalid context: drop packet");
2957 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
2958 kfree_skb(skb);
2959 return;
2960 }
2961
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002962 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2963 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002964 iface_id = hdd_ipa->vdev_to_iface[session_id];
Govind Singhb6a89772016-08-12 11:23:35 +05302965 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002966 "IPA_RECEIVE: session_id=%u, iface_id=%u",
2967 session_id, iface_id);
2968 } else {
2969 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
2970 }
2971
2972 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302973 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002974 "IPA_RECEIVE: Invalid iface_id: %u",
2975 iface_id);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302976 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002977 "w2i -- skb", skb->data, 8);
2978 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07002979 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002980 return;
2981 }
2982
2983 iface_context = &hdd_ipa->iface_context[iface_id];
2984 adapter = iface_context->adapter;
2985
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302986 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002987 "w2i -- skb", skb->data, 8);
2988 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2989 hdd_ipa->stats.num_rx_excep++;
2990 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
2991 } else {
2992 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
2993 }
2994
2995 iface_context->stats.num_rx_ipa_excep++;
2996
2997 /* Disable to forward Intra-BSS Rx packets when
2998 * ap_isolate=1 in hostapd.conf
2999 */
Yun Park046101c2016-09-02 15:32:14 -07003000 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003001 /*
3002 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3003 * all Rx packets to IPA uC, which need to be forwarded
3004 * to other interface.
3005 * And, IPA driver will send back to WLAN host driver
3006 * through exception pipe with fw_desc field set by FW.
3007 * Here we are checking fw_desc field for FORWARD bit
3008 * set, and forward to Tx. Then copy to kernel stack
3009 * only when DISCARD bit is not set.
3010 */
3011 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003012 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3013 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3014 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003015 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003016 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303017 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 "Intra-BSS FWD is disabled-skip forward to Tx");
3019 }
3020
3021 hdd_ipa_send_skb_to_network(skb, adapter);
3022 break;
3023
3024 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303025 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003026 "w2i cb wrong event: 0x%x", evt);
3027 return;
3028 }
3029}
3030
3031/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003032 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3033 * @priv: pointer to private data registered with IPA (we register a
3034 * pointer to the global IPA context)
3035 * @evt: the IPA event which triggered the callback
3036 * @data: data associated with the event
3037 *
3038 * Return: None
3039 */
3040static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3041 unsigned long data)
3042{
3043 cds_ssr_protect(__func__);
3044 __hdd_ipa_w2i_cb(priv, evt, data);
3045 cds_ssr_unprotect(__func__);
3046}
3047
3048/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003049 * hdd_ipa_nbuf_cb() - IPA TX complete callback
3050 * @skb: packet buffer which was transmitted
3051 *
3052 * Return: None
3053 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303054void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003055{
3056 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3057
Govind Singhb6a89772016-08-12 11:23:35 +05303058 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05303059 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003060 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303061 ipa_free_skb((struct ipa_rx_data *)
3062 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003063
3064 hdd_ipa->stats.num_tx_comp_cnt++;
3065
3066 atomic_dec(&hdd_ipa->tx_ref_cnt);
3067
3068 hdd_ipa_rm_try_release(hdd_ipa);
3069}
3070
3071/**
3072 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
3073 * @iface_context: interface-specific IPA context
3074 * @ipa_tx_desc: packet data descriptor
3075 *
3076 * Return: None
3077 */
3078static void hdd_ipa_send_pkt_to_tl(
3079 struct hdd_ipa_iface_context *iface_context,
3080 struct ipa_rx_data *ipa_tx_desc)
3081{
3082 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003083 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303084 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003085
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303086 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003087 adapter = iface_context->adapter;
3088 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303089 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090 ipa_free_skb(ipa_tx_desc);
3091 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303092 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003093 hdd_ipa_rm_try_release(hdd_ipa);
3094 return;
3095 }
3096
3097 /*
3098 * During CAC period, data packets shouldn't be sent over the air so
3099 * drop all the packets here
3100 */
3101 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
3102 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303103 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003104 iface_context->stats.num_tx_cac_drop++;
3105 hdd_ipa_rm_try_release(hdd_ipa);
3106 return;
3107 }
3108
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003109 ++adapter->stats.tx_packets;
3110
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303111 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003112
3113 skb = ipa_tx_desc->skb;
3114
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303115 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303116 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003117 /* FIXME: This is broken. No such field in cb any more:
3118 NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb; */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003119 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05303120 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003121 ipa_tx_desc->dma_addr
3122 + HDD_IPA_WLAN_FRAG_HEADER
3123 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124 ipa_tx_desc->skb->len -=
3125 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
3126 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05303127 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003129 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303130 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131
3132 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
3133
Leo Changfdb45c32016-10-28 11:09:23 -07003134 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
3135 iface_context->tl_context, ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003136 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303137 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003138 ipa_free_skb(ipa_tx_desc);
3139 iface_context->stats.num_tx_err++;
3140 hdd_ipa_rm_try_release(hdd_ipa);
3141 return;
3142 }
3143
3144 atomic_inc(&hdd_ipa->tx_ref_cnt);
3145
3146 iface_context->stats.num_tx++;
3147
3148}
3149
3150/**
Leo Chang11545d62016-10-17 14:53:50 -07003151 * hdd_ipa_is_present() - get IPA hw status
3152 * @hdd_ctx: pointer to hdd context
3153 *
3154 * ipa_uc_reg_rdyCB is not directly designed to check
3155 * ipa hw status. This is an undocumented function which
3156 * has confirmed with IPA team.
3157 *
3158 * Return: true - ipa hw present
3159 * false - ipa hw not present
3160 */
3161bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
3162{
3163 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07003164 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07003165 return true;
3166 else
3167 return false;
3168}
3169
3170/**
Leo Chang69c39692016-10-12 20:11:12 -07003171 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003172 * @work: pointer to the scheduled work
3173 *
3174 * Called during PM resume to send packets to TL which were queued
3175 * while host was in the process of suspending.
3176 *
3177 * Return: None
3178 */
Leo Chang69c39692016-10-12 20:11:12 -07003179static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003180{
3181 struct hdd_ipa_priv *hdd_ipa = container_of(work,
3182 struct hdd_ipa_priv,
3183 pm_work);
3184 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303185 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003186 uint32_t dequeued = 0;
3187
Leo Chang69c39692016-10-12 20:11:12 -07003188 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
3189 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303190 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303191 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
3192 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303193 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194
3195 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003196 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07003197 if (pm_tx_cb->exception) {
3198 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3199 "FLUSH EXCEPTION");
3200 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
3201 } else {
3202 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003203 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07003204 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303205 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003206 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303207 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07003208 qdf_wake_lock_release(&hdd_ipa->wake_lock,
3209 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003210
3211 hdd_ipa->stats.num_tx_dequeued += dequeued;
3212 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
3213 hdd_ipa->stats.num_max_pm_queue = dequeued;
3214}
3215
3216/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003217 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003218 * @priv: pointer to private data registered with IPA (we register a
3219 * pointer to the interface-specific IPA context)
3220 * @evt: the IPA event which triggered the callback
3221 * @data: data associated with the event
3222 *
3223 * Return: None
3224 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003225static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003226 unsigned long data)
3227{
3228 struct hdd_ipa_priv *hdd_ipa = NULL;
3229 struct ipa_rx_data *ipa_tx_desc;
3230 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303231 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003232 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303233 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003234
Mukul Sharma81661ae2015-10-30 20:26:02 +05303235 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003236 ipa_tx_desc = (struct ipa_rx_data *)data;
3237 hdd_ipa = iface_context->hdd_ipa;
3238
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003239 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003240 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
3241 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003242 iface_context->stats.num_tx_drop++;
3243 return;
3244 }
3245
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003246 /*
3247 * When SSR is going on or driver is unloading, just drop the packets.
3248 * During SSR, there is no use in queueing the packets as STA has to
3249 * connect back any way
3250 */
3251 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303252 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003253 ipa_free_skb(ipa_tx_desc);
3254 iface_context->stats.num_tx_drop++;
3255 return;
3256 }
3257
3258 skb = ipa_tx_desc->skb;
3259
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303260 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, "i2w", skb->data, 8);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003261
3262 /*
3263 * If PROD resource is not requested here then there may be cases where
3264 * IPA hardware may be clocked down because of not having proper
3265 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
3266 * workaround to request PROD resource while data is going over CONS
3267 * pipe to prevent the IPA hardware clockdown.
3268 */
3269 hdd_ipa_rm_request(hdd_ipa);
3270
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303271 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272 /*
3273 * If host is still suspended then queue the packets and these will be
3274 * drained later when resume completes. When packet is arrived here and
3275 * host is suspended, this means that there is already resume is in
3276 * progress.
3277 */
3278 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303279 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003280 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
3281 pm_tx_cb->iface_context = iface_context;
3282 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303283 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003284 hdd_ipa->stats.num_tx_queued++;
3285
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303286 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003287 return;
3288 }
3289
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303290 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003291
3292 /*
3293 * If we are here means, host is not suspended, wait for the work queue
3294 * to finish.
3295 */
3296#ifdef WLAN_OPEN_SOURCE
3297 flush_work(&hdd_ipa->pm_work);
3298#endif
3299
3300 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
3301}
3302
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003303/*
3304 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
3305 * @priv: pointer to private data registered with IPA (we register a
3306 * pointer to the interface-specific IPA context)
3307 * @evt: the IPA event which triggered the callback
3308 * @data: data associated with the event
3309 *
3310 * Return: None
3311 */
3312static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
3313 unsigned long data)
3314{
3315 cds_ssr_protect(__func__);
3316 __hdd_ipa_i2w_cb(priv, evt, data);
3317 cds_ssr_unprotect(__func__);
3318}
3319
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003320/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003321 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003322 * @hdd_ctx: Global HDD context
3323 *
3324 * Return: 0 on success, negativer errno on error
3325 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003326static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003327{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003328 struct hdd_ipa_priv *hdd_ipa;
3329
3330 if (wlan_hdd_validate_context(hdd_ctx))
3331 return 0;
3332
3333 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003334
3335 if (!hdd_ipa_is_enabled(hdd_ctx))
3336 return 0;
3337
3338 /*
3339 * Check if IPA is ready for suspend, If we are here means, there is
3340 * high chance that suspend would go through but just to avoid any race
3341 * condition after suspend started, these checks are conducted before
3342 * allowing to suspend.
3343 */
3344 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3345 return -EAGAIN;
3346
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303347 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003348
3349 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303350 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003351 return -EAGAIN;
3352 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303353 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003354
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303355 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303357 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003358
3359 return 0;
3360}
3361
3362/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003363 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
3364 * @hdd_ctx: Global HDD context
3365 *
3366 * Return: 0 on success, negativer errno on error
3367 */
3368int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
3369{
3370 int ret;
3371
3372 cds_ssr_protect(__func__);
3373 ret = __hdd_ipa_suspend(hdd_ctx);
3374 cds_ssr_unprotect(__func__);
3375
3376 return ret;
3377}
3378
3379/**
3380 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003381 * hdd_ctx: Global HDD context
3382 *
3383 * Return: 0 on success, negative errno on error
3384 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003385static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003386{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003387 struct hdd_ipa_priv *hdd_ipa;
3388
3389 if (wlan_hdd_validate_context(hdd_ctx))
3390 return 0;
3391
3392 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003393
3394 if (!hdd_ipa_is_enabled(hdd_ctx))
3395 return 0;
3396
3397 schedule_work(&hdd_ipa->pm_work);
3398
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303399 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003400 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303401 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003402
3403 return 0;
3404}
3405
3406/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003407 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
3408 * hdd_ctx: Global HDD context
3409 *
3410 * Return: 0 on success, negative errno on error
3411 */
3412int hdd_ipa_resume(hdd_context_t *hdd_ctx)
3413{
3414 int ret;
3415
3416 cds_ssr_protect(__func__);
3417 ret = __hdd_ipa_resume(hdd_ctx);
3418 cds_ssr_unprotect(__func__);
3419
3420 return ret;
3421}
3422
3423/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
3425 * @hdd_ipa: Global HDD IPA context
3426 *
3427 * Return: 0 on success, negative errno on error
3428 */
3429static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
3430{
3431 int i, ret = 0;
3432 struct ipa_sys_connect_params *ipa;
3433 uint32_t desc_fifo_sz;
3434
3435 /* The maximum number of descriptors that can be provided to a BAM at
3436 * once is one less than the total number of descriptors that the buffer
3437 * can contain.
3438 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
3439 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
3440 * be provided at once.
3441 * Because of above requirement, one extra descriptor will be added to
3442 * make sure hardware always has one descriptor.
3443 */
3444 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
3445 + sizeof(struct sps_iovec);
3446
3447 /*setup TX pipes */
3448 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3449 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
3450
3451 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
3452 ipa->desc_fifo_sz = desc_fifo_sz;
3453 ipa->priv = &hdd_ipa->iface_context[i];
3454 ipa->notify = hdd_ipa_i2w_cb;
3455
3456 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
3457 ipa->ipa_ep_cfg.hdr.hdr_len =
3458 HDD_IPA_UC_WLAN_TX_HDR_LEN;
3459 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3460 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
3461 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
3462 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
3463 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
3464 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
3465 } else {
3466 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
3467 }
3468 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
3469
3470 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3471 ipa->keep_ipa_awake = 1;
3472
3473 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
3474 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303475 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003476 " ret: %d", i, ret);
3477 goto setup_sys_pipe_fail;
3478 }
3479 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
3480 }
3481
3482 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
3483 /*
3484 * Hard code it here, this can be extended if in case
3485 * PROD pipe is also per interface.
3486 * Right now there is no advantage of doing this.
3487 */
3488 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
3489
3490 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
3491
3492 ipa->client = hdd_ipa->prod_client;
3493
3494 ipa->desc_fifo_sz = desc_fifo_sz;
3495 ipa->priv = hdd_ipa;
3496 ipa->notify = hdd_ipa_w2i_cb;
3497
3498 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3499 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
3500 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
3501 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
3502
3503 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3504 ipa->keep_ipa_awake = 1;
3505
3506 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
3507 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303508 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003509 "Failed for RX pipe: %d", ret);
3510 goto setup_sys_pipe_fail;
3511 }
3512 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
3513 }
3514
3515 return ret;
3516
3517setup_sys_pipe_fail:
3518
3519 while (--i >= 0) {
3520 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303521 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003522 sizeof(struct hdd_ipa_sys_pipe));
3523 }
3524
3525 return ret;
3526}
3527
3528/**
3529 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
3530 * @hdd_ipa: Global HDD IPA context
3531 *
3532 * Return: None
3533 */
3534static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
3535{
3536 int ret = 0, i;
3537 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
3538 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
3539 ret =
3540 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
3541 conn_hdl);
3542 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303543 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003544 ret);
3545
3546 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
3547 }
3548 }
3549}
3550
3551/**
3552 * hdd_ipa_register_interface() - register IPA interface
3553 * @hdd_ipa: Global IPA context
3554 * @iface_context: Per-interface IPA context
3555 *
3556 * Return: 0 on success, negative errno on error
3557 */
3558static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
3559 struct hdd_ipa_iface_context
3560 *iface_context)
3561{
3562 struct ipa_tx_intf tx_intf;
3563 struct ipa_rx_intf rx_intf;
3564 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
3565 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
3566 char *ifname = iface_context->adapter->dev->name;
3567
3568 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
3569 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
3570
3571 int num_prop = 1;
3572 int ret = 0;
3573
3574 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
3575 num_prop++;
3576
3577 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
3578 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303579 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003580 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303581 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003582 goto register_interface_fail;
3583 }
3584
3585 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
3586 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303587 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003588 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303589 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590 goto register_interface_fail;
3591 }
3592
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303593 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
3594 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003595
3596 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
3597 ifname, HDD_IPA_IPV4_NAME_EXT);
3598 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
3599 ifname, HDD_IPA_IPV6_NAME_EXT);
3600
3601 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
3602 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
3603 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3604 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
3605
3606 /*
3607 * Interface ID is 3rd byte in the CLD header. Add the meta data and
3608 * mask to identify the interface in IPA hardware
3609 */
3610 rx_prop[IPA_IP_v4].attrib.meta_data =
3611 htonl(iface_context->adapter->sessionId << 16);
3612 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
3613
3614 rx_intf.num_props++;
3615 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3616 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
3617 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
3618 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3619 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
3620 rx_prop[IPA_IP_v4].attrib.meta_data =
3621 htonl(iface_context->adapter->sessionId << 16);
3622 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
3623
3624 rx_intf.num_props++;
3625 }
3626
3627 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
3628 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3629 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
3630 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
3631 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
3632 IPA_RESOURCE_NAME_MAX);
3633 tx_intf.num_props++;
3634
3635 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3636 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
3637 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3638 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
3639 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
3640 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
3641 IPA_RESOURCE_NAME_MAX);
3642 tx_intf.num_props++;
3643 }
3644
3645 tx_intf.prop = tx_prop;
3646 rx_intf.prop = rx_prop;
3647
3648 /* Call the ipa api to register interface */
3649 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
3650
3651register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303652 qdf_mem_free(tx_prop);
3653 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003654 return ret;
3655}
3656
3657/**
3658 * hdd_remove_ipa_header() - Remove a specific header from IPA
3659 * @name: Name of the header to be removed
3660 *
3661 * Return: None
3662 */
3663static void hdd_ipa_remove_header(char *name)
3664{
3665 struct ipa_ioc_get_hdr hdrlookup;
3666 int ret = 0, len;
3667 struct ipa_ioc_del_hdr *ipa_hdr;
3668
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303669 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003670 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
3671 ret = ipa_get_hdr(&hdrlookup);
3672 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303673 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003674 name, ret);
3675 return;
3676 }
3677
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303678 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003679 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303680 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003681 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303682 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003683 return;
3684 }
3685 ipa_hdr->num_hdls = 1;
3686 ipa_hdr->commit = 0;
3687 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
3688 ipa_hdr->hdl[0].status = -1;
3689 ret = ipa_del_hdr(ipa_hdr);
3690 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303691 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003692 ret);
3693
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303694 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003695}
3696
3697/**
3698 * hdd_ipa_add_header_info() - Add IPA header for a given interface
3699 * @hdd_ipa: Global HDD IPA context
3700 * @iface_context: Interface-specific HDD IPA context
3701 * @mac_addr: Interface MAC address
3702 *
3703 * Return: 0 on success, negativer errno value on error
3704 */
3705static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
3706 struct hdd_ipa_iface_context *iface_context,
3707 uint8_t *mac_addr)
3708{
3709 hdd_adapter_t *adapter = iface_context->adapter;
3710 char *ifname;
3711 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
3712 int ret = -EINVAL;
3713 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
3714 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
3715
3716 ifname = adapter->dev->name;
3717
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303718 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003719 ifname, mac_addr);
3720
3721 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303722 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003723 + sizeof(struct ipa_hdr_add));
3724 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303725 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003726 "%s: ipa_hdr allocation failed", ifname);
3727 ret = -ENOMEM;
3728 goto end;
3729 }
3730
3731 ipa_hdr->commit = 0;
3732 ipa_hdr->num_hdrs = 1;
3733
3734 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3735 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
3736 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
3737 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
3738 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303739 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003740 "ifname=%s, vdev_id=%d",
3741 ifname, uc_tx_hdr->ipa_hd.vdev_id);
3742 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
3743 ifname, HDD_IPA_IPV4_NAME_EXT);
3744 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
3745 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
3746 ipa_hdr->hdr[0].is_partial = 1;
3747 ipa_hdr->hdr[0].hdr_hdl = 0;
3748 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
3749 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
3750
3751 ret = ipa_add_hdr(ipa_hdr);
3752 } else {
3753 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
3754
3755 /* Set the Source MAC */
3756 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
3757 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
3758
3759 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
3760 ifname, HDD_IPA_IPV4_NAME_EXT);
3761 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
3762 ipa_hdr->hdr[0].is_partial = 1;
3763 ipa_hdr->hdr[0].hdr_hdl = 0;
3764 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
3765 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
3766
3767 /* Set the type to IPV4 in the header */
3768 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
3769
3770 ret = ipa_add_hdr(ipa_hdr);
3771 }
3772 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303773 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003774 ifname, ret);
3775 goto end;
3776 }
3777
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303778 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003779 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
3780
3781 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3782 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
3783 ifname, HDD_IPA_IPV6_NAME_EXT);
3784
3785 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3786 uc_tx_hdr =
3787 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
3788 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
3789 } else {
3790 /* Set the type to IPV6 in the header */
3791 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
3792 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
3793 }
3794
3795 ret = ipa_add_hdr(ipa_hdr);
3796 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303797 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003798 "%s: IPv6 add hdr failed: %d", ifname, ret);
3799 goto clean_ipv4_hdr;
3800 }
3801
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303802 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003803 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
3804 }
3805
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303806 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003807
3808 return ret;
3809
3810clean_ipv4_hdr:
3811 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
3812 ifname, HDD_IPA_IPV4_NAME_EXT);
3813 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
3814end:
3815 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303816 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003817
3818 return ret;
3819}
3820
3821/**
3822 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
3823 * @adapter: Adapter upon which IPA was previously configured
3824 *
3825 * Return: None
3826 */
3827static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
3828{
3829 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3830 int ret;
3831 char name_ipa[IPA_RESOURCE_NAME_MAX];
3832
3833 /* Remove the headers */
3834 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
3835 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
3836 hdd_ipa_remove_header(name_ipa);
3837
3838 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3839 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
3840 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
3841 hdd_ipa_remove_header(name_ipa);
3842 }
3843 /* unregister the interface with IPA */
3844 ret = ipa_deregister_intf(adapter->dev->name);
3845 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303846 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003847 "%s: ipa_deregister_intf fail: %d",
3848 adapter->dev->name, ret);
3849}
3850
3851/**
3852 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
3853 * @iface_context: interface-specific IPA context
3854 *
3855 * Return: None
3856 */
3857static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
3858{
3859 if (iface_context == NULL)
3860 return;
3861
3862 hdd_ipa_clean_hdr(iface_context->adapter);
3863
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303864 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003865 iface_context->adapter->ipa_context = NULL;
3866 iface_context->adapter = NULL;
3867 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303868 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003869 iface_context->ifa_address = 0;
3870 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303871 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003872 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05303873 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003874 }
3875 iface_context->hdd_ipa->num_iface--;
3876}
3877
3878/**
3879 * hdd_ipa_setup_iface() - Setup IPA on a given interface
3880 * @hdd_ipa: HDD IPA global context
3881 * @adapter: Interface upon which IPA is being setup
3882 * @sta_id: Station ID of the API instance
3883 *
3884 * Return: 0 on success, negative errno value on error
3885 */
3886static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
3887 hdd_adapter_t *adapter, uint8_t sta_id)
3888{
3889 struct hdd_ipa_iface_context *iface_context = NULL;
3890 void *tl_context = NULL;
3891 int i, ret = 0;
3892
3893 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
3894 * channel change indication. Since these indications are sent by lower
3895 * layer as SAP updates and IPA doesn't have to do anything for these
3896 * updates so ignoring!
3897 */
Krunal Sonibe766b02016-03-10 13:00:44 -08003898 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003899 return 0;
3900
3901 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3902 if (hdd_ipa->iface_context[i].adapter == NULL) {
3903 iface_context = &(hdd_ipa->iface_context[i]);
3904 break;
3905 }
3906 }
3907
3908 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303909 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910 "All the IPA interfaces are in use");
3911 ret = -ENOMEM;
3912 goto end;
3913 }
3914
3915 adapter->ipa_context = iface_context;
3916 iface_context->adapter = adapter;
3917 iface_context->sta_id = sta_id;
Leo Changfdb45c32016-10-28 11:09:23 -07003918 tl_context = cdp_peer_get_vdev_by_sta_id(
3919 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003920 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303921 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003922 "Not able to get TL context sta_id: %d", sta_id);
3923 ret = -EINVAL;
3924 goto end;
3925 }
3926
3927 iface_context->tl_context = tl_context;
3928
3929 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
3930 adapter->dev->dev_addr);
3931
3932 if (ret)
3933 goto end;
3934
3935 /* Configure the TX and RX pipes filter rules */
3936 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
3937 if (ret)
3938 goto cleanup_header;
3939
3940 hdd_ipa->num_iface++;
3941 return ret;
3942
3943cleanup_header:
3944
3945 hdd_ipa_clean_hdr(adapter);
3946end:
3947 if (iface_context)
3948 hdd_ipa_cleanup_iface(iface_context);
3949 return ret;
3950}
3951
Yun Parka27049a2016-10-11 12:30:49 -07003952#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003953/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003954 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003955 * @mcc_mode: 0=MCC/1=SCC
3956 *
3957 * Return: 0 on success, negative errno value on error
3958 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003959static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003960{
3961 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303962 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003963 hdd_adapter_t *pAdapter;
3964 struct ipa_msg_meta meta;
3965 struct ipa_wlan_msg *msg;
3966 int ret;
3967
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003968 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003969 return -EINVAL;
3970
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003971 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
3972 return -EINVAL;
3973
3974 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003975 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003976 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303977 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003978 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08003979 if (pAdapter->device_mode == QDF_STA_MODE ||
3980 pAdapter->device_mode == QDF_SAP_MODE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303981 hddLog(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982 "MCC->SCC: Flush TxRx queue(d_mode=%d)",
3983 pAdapter->device_mode);
3984 hdd_deinit_tx_rx(pAdapter);
3985 }
3986 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003987 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003988 adapter_node = next;
3989 }
3990 }
3991
3992 /* Send SCC/MCC Switching event to IPA */
3993 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303994 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003995 if (msg == NULL) {
3996 hddLog(LOGE, "msg allocation failed");
3997 return -ENOMEM;
3998 }
3999
4000 meta.msg_type = mcc_mode ?
4001 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
4002 hddLog(LOG1, "ipa_send_msg(Evt:%d)", meta.msg_type);
4003
4004 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4005
4006 if (ret) {
4007 hddLog(LOGE, "ipa_send_msg(Evt:%d) - fail=%d",
4008 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304009 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004010 }
4011
4012 return ret;
4013}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004014
4015/**
4016 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4017 * @mcc_mode: 0=MCC/1=SCC
4018 *
4019 * Return: 0 on success, negative errno value on error
4020 */
4021int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
4022{
4023 int ret;
4024
4025 cds_ssr_protect(__func__);
4026 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4027 cds_ssr_unprotect(__func__);
4028
4029 return ret;
4030}
Yun Parka27049a2016-10-11 12:30:49 -07004031#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004032
4033/**
4034 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4035 * @event: IPA WLAN event to be converted to a string
4036 *
4037 * Return: ASCII string representing the IPA WLAN event
4038 */
4039static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4040{
4041 switch (event) {
4042 case WLAN_CLIENT_CONNECT:
4043 return "WLAN_CLIENT_CONNECT";
4044 case WLAN_CLIENT_DISCONNECT:
4045 return "WLAN_CLIENT_DISCONNECT";
4046 case WLAN_CLIENT_POWER_SAVE_MODE:
4047 return "WLAN_CLIENT_POWER_SAVE_MODE";
4048 case WLAN_CLIENT_NORMAL_MODE:
4049 return "WLAN_CLIENT_NORMAL_MODE";
4050 case SW_ROUTING_ENABLE:
4051 return "SW_ROUTING_ENABLE";
4052 case SW_ROUTING_DISABLE:
4053 return "SW_ROUTING_DISABLE";
4054 case WLAN_AP_CONNECT:
4055 return "WLAN_AP_CONNECT";
4056 case WLAN_AP_DISCONNECT:
4057 return "WLAN_AP_DISCONNECT";
4058 case WLAN_STA_CONNECT:
4059 return "WLAN_STA_CONNECT";
4060 case WLAN_STA_DISCONNECT:
4061 return "WLAN_STA_DISCONNECT";
4062 case WLAN_CLIENT_CONNECT_EX:
4063 return "WLAN_CLIENT_CONNECT_EX";
4064
4065 case IPA_WLAN_EVENT_MAX:
4066 default:
4067 return "UNKNOWN";
4068 }
4069}
4070
4071/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004072 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4073 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4074 *
4075 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4076 */
4077static enum ipa_wlan_event
4078hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4079{
4080 enum ipa_wlan_event ipa_event;
4081
4082 switch (hdd_ipa_event_type) {
4083 case HDD_IPA_CLIENT_CONNECT:
4084 ipa_event = WLAN_CLIENT_CONNECT;
4085 break;
4086 case HDD_IPA_CLIENT_DISCONNECT:
4087 ipa_event = WLAN_CLIENT_DISCONNECT;
4088 break;
4089 case HDD_IPA_AP_CONNECT:
4090 ipa_event = WLAN_AP_CONNECT;
4091 break;
4092 case HDD_IPA_AP_DISCONNECT:
4093 ipa_event = WLAN_AP_DISCONNECT;
4094 break;
4095 case HDD_IPA_STA_CONNECT:
4096 ipa_event = WLAN_STA_CONNECT;
4097 break;
4098 case HDD_IPA_STA_DISCONNECT:
4099 ipa_event = WLAN_STA_DISCONNECT;
4100 break;
4101 case HDD_IPA_CLIENT_CONNECT_EX:
4102 ipa_event = WLAN_CLIENT_CONNECT_EX;
4103 break;
4104 case HDD_IPA_WLAN_EVENT_MAX:
4105 default:
4106 ipa_event = IPA_WLAN_EVENT_MAX;
4107 break;
4108 }
4109 return ipa_event;
4110
4111}
4112
4113/**
4114 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115 * @adapter: adapter upon which the event was received
4116 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004117 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004118 * @mac_address: MAC address associated with the event
4119 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004120 * This function is meant to be called from within wlan_hdd_ipa.c
4121 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004122 * Return: 0 on success, negative errno value on error
4123 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004124static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004125 enum ipa_wlan_event type, uint8_t *mac_addr)
4126{
4127 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4128 struct ipa_msg_meta meta;
4129 struct ipa_wlan_msg *msg;
4130 struct ipa_wlan_msg_ex *msg_ex = NULL;
4131 int ret;
4132
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304133 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004134 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4135 mac_addr, sta_id);
4136
4137 if (type >= IPA_WLAN_EVENT_MAX)
4138 return -EINVAL;
4139
4140 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4141 return -EINVAL;
4142
4143 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304144 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004145 return -EINVAL;
4146 }
4147
4148 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4149 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004150 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004151 return 0;
4152 }
4153
4154 /*
4155 * During IPA UC resource loading/unloading new events can be issued.
4156 * Store the events separately and handle them later.
4157 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004158 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4159 if (hdd_ipa->resource_loading) {
4160 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004161 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004162
Yun Park7c4f31b2016-11-30 10:09:21 -08004163 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA resource %s inprogress",
4164 hdd_ipa->resource_loading ? "load":"unload");
4165
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004166 hdd_err("IPA resource %s inprogress",
4167 hdd_ipa->resource_loading ? "load":"unload");
Yun Parkf19e07d2015-11-20 11:34:27 -08004168
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004169 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004170
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004171 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4172 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
4173 hdd_notice("Reached max pending event count");
4174 qdf_list_remove_front(&hdd_ipa->pending_event,
4175 (qdf_list_node_t **)&pending_event);
4176 } else {
4177 pending_event =
4178 (struct ipa_uc_pending_event *)qdf_mem_malloc(
4179 sizeof(struct ipa_uc_pending_event));
4180 }
4181
4182 if (!pending_event) {
Yun Park7c4f31b2016-11-30 10:09:21 -08004183 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4184 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004185 qdf_mutex_release(&hdd_ipa->event_lock);
4186 return -ENOMEM;
4187 }
4188
4189 pending_event->adapter = adapter;
4190 pending_event->sta_id = sta_id;
4191 pending_event->type = type;
4192 qdf_mem_copy(pending_event->mac_addr,
4193 mac_addr,
4194 QDF_MAC_ADDR_SIZE);
4195 qdf_list_insert_back(&hdd_ipa->pending_event,
4196 &pending_event->node);
4197
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304198 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004199 return 0;
4200 } else if (hdd_ipa->resource_unloading) {
4201 hdd_err("%s: IPA resource unload inprogress", __func__);
4202 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004203 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004204 }
4205
4206 hdd_ipa->stats.event[type]++;
4207
Leo Chang3bc8fed2015-11-13 10:59:47 -08004208 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004209 switch (type) {
4210 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004211 qdf_mutex_acquire(&hdd_ipa->event_lock);
4212
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004213 /* STA already connected and without disconnect, connect again
4214 * This is Roaming scenario
4215 */
4216 if (hdd_ipa->sta_connected)
4217 hdd_ipa_cleanup_iface(adapter->ipa_context);
4218
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004219 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4220 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304221 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004222 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004223 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004224
Yun Park8f289c82016-10-18 16:38:21 -07004225 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4226 (hdd_ipa->sap_num_connected_sta > 0) &&
4227 !hdd_ipa->sta_connected) {
4228 qdf_mutex_release(&hdd_ipa->event_lock);
4229 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004230 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004231 qdf_mutex_acquire(&hdd_ipa->event_lock);
4232 }
4233
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004234 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004235 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004236 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004237
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004238 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07004239
4240 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004241 break;
4242
4243 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004244 qdf_mutex_acquire(&hdd_ipa->event_lock);
4245
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004246 /* For DFS channel we get two start_bss event (before and after
4247 * CAC). Also when ACS range includes both DFS and non DFS
4248 * channels, we could possibly change channel many times due to
4249 * RADAR detection and chosen channel may not be a DFS channels.
4250 * So dont return error here. Just discard the event.
4251 */
Yun Park8f289c82016-10-18 16:38:21 -07004252 if (adapter->ipa_context) {
4253 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07004255 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004256
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4258 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304259 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004260 "%s: Evt: %d, Interface setup failed",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304261 adapter->dev->name, type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304262 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004263 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004264 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265
Yun Park8f289c82016-10-18 16:38:21 -07004266 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4267 qdf_mutex_release(&hdd_ipa->event_lock);
4268 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004269 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004270 qdf_mutex_acquire(&hdd_ipa->event_lock);
4271 }
4272
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004273 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004274 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004275 (adapter->ipa_context))->iface_id;
4276
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304277 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004278 break;
4279
4280 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304281 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004282
4283 if (!hdd_ipa->sta_connected) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304284 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004285 "%s: Evt: %d, STA already disconnected",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304286 adapter->dev->name, type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304287 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004288 return -EINVAL;
4289 }
Yun Parka37592b2016-06-11 17:10:28 -07004290
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004291 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07004292
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304294 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004295 "%s: IPA UC OFFLOAD NOT ENABLED",
4296 msg_ex->name);
4297 } else {
4298 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07004299 if (!hdd_ipa->num_iface &&
4300 (HDD_IPA_UC_NUM_WDI_PIPE ==
4301 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004302 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004303 }
4304
Yun Park74127cf2016-09-18 11:22:41 -07004305 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4306 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07004307 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004308 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004309 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004310 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004311 hdd_ipa->vdev_to_iface[adapter->sessionId] =
4312 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004313 }
4314
Yun Park8f289c82016-10-18 16:38:21 -07004315 hdd_ipa_cleanup_iface(adapter->ipa_context);
4316
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304317 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004318 break;
4319
4320 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004321 qdf_mutex_acquire(&hdd_ipa->event_lock);
4322
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004323 if (!adapter->ipa_context) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304324 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004325 "%s: Evt: %d, SAP already disconnected",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304326 adapter->dev->name, type);
Yun Park8f289c82016-10-18 16:38:21 -07004327 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004328 return -EINVAL;
4329 }
4330
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004331 if ((!hdd_ipa->num_iface) &&
4332 (HDD_IPA_UC_NUM_WDI_PIPE ==
4333 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004334 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004335 /*
4336 * We disable WDI pipes directly here since
4337 * IPA_OPCODE_TX/RX_SUSPEND message will not be
4338 * processed when unloading WLAN driver is in
4339 * progress
4340 */
4341 hdd_ipa_uc_disable_pipes(hdd_ipa);
4342 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304343 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344 "NO INTF left but still pipe clean up");
4345 hdd_ipa_uc_handle_last_discon(hdd_ipa);
4346 }
4347 }
4348
4349 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07004350 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004351 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004352 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004353 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004354 hdd_ipa->vdev_to_iface[adapter->sessionId] =
4355 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004356 }
Yun Parka37592b2016-06-11 17:10:28 -07004357
Yun Park8f289c82016-10-18 16:38:21 -07004358 hdd_ipa_cleanup_iface(adapter->ipa_context);
4359
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304360 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004361 break;
4362
4363 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004364 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304365 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304367 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004368 return 0;
4369 }
4370
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304371 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004372 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
4373 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07004374 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304375 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004376 "%s: STA ID %d found, not valid",
4377 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004378 return 0;
4379 }
Yun Park312f71a2015-12-08 10:22:42 -08004380
4381 /* Enable IPA UC Data PIPEs when first STA connected */
Yun Parka37592b2016-06-11 17:10:28 -07004382 if (0 == hdd_ipa->sap_num_connected_sta) {
4383 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07004384 hdd_ipa->sta_connected) {
4385 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07004386 hdd_ipa_uc_offload_enable_disable(
4387 hdd_get_adapter(hdd_ipa->hdd_ctx,
4388 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004389 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004390 qdf_mutex_acquire(&hdd_ipa->event_lock);
4391 }
Yun Parka37592b2016-06-11 17:10:28 -07004392
Yun Park312f71a2015-12-08 10:22:42 -08004393 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
4394 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304395 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08004396 "%s: handle 1st con ret %d",
4397 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07004398
4399 if (hdd_ipa_uc_sta_is_enabled(
4400 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07004401 hdd_ipa->sta_connected) {
4402 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07004403 hdd_ipa_uc_offload_enable_disable(
4404 hdd_get_adapter(
4405 hdd_ipa->hdd_ctx,
4406 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004407 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004408 } else {
4409 qdf_mutex_release(&hdd_ipa->event_lock);
4410 }
Yun Parka37592b2016-06-11 17:10:28 -07004411
Yun Park312f71a2015-12-08 10:22:42 -08004412 return ret;
4413 }
4414 }
4415
4416 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08004417
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304418 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004419
4420 meta.msg_type = type;
4421 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
4422 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304423 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004424
4425 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304426 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 "msg_ex allocation failed");
4428 return -ENOMEM;
4429 }
4430 strlcpy(msg_ex->name, adapter->dev->name,
4431 IPA_RESOURCE_NAME_MAX);
4432 msg_ex->num_of_attribs = 1;
4433 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
4434 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4435 msg_ex->attribs[0].offset =
4436 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4437 } else {
4438 msg_ex->attribs[0].offset =
4439 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4440 }
4441 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
4442 IPA_MAC_ADDR_SIZE);
4443
4444 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
4445
4446 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304447 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304448 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304449 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004450 return ret;
4451 }
4452 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004453 return ret;
4454
4455 case WLAN_CLIENT_DISCONNECT:
4456 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304457 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004458 "%s: IPA UC OFFLOAD NOT ENABLED",
4459 msg_ex->name);
4460 return 0;
4461 }
4462
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304463 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004464 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304465 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004466 "%s: STA ID %d NOT found, not valid",
4467 msg_ex->name, sta_id);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304468 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004469 return 0;
4470 }
4471 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07004472
Yun Park9b5030f2016-11-08 12:02:37 -08004473 /* Disable IPA UC TX PIPE when last STA disconnected */
4474 if (!hdd_ipa->sap_num_connected_sta) {
4475 if ((false == hdd_ipa->resource_unloading)
4476 && (HDD_IPA_UC_NUM_WDI_PIPE ==
4477 hdd_ipa->activated_fw_pipe)) {
4478 hdd_ipa_uc_handle_last_discon(hdd_ipa);
4479 }
4480
Yun Park8f289c82016-10-18 16:38:21 -07004481 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08004482
4483 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4484 hdd_ipa->sta_connected)
4485 hdd_ipa_uc_offload_enable_disable(
4486 hdd_get_adapter(hdd_ipa->hdd_ctx,
4487 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004488 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004489 } else {
4490 qdf_mutex_release(&hdd_ipa->event_lock);
4491 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492 break;
4493
4494 default:
4495 return 0;
4496 }
4497
4498 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304499 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004500 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304501 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502 return -ENOMEM;
4503 }
4504
4505 meta.msg_type = type;
4506 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
4507 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
4508
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304509 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004510 msg->name, meta.msg_type);
4511
4512 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4513
4514 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304515 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d fail:%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004516 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304517 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004518 return ret;
4519 }
4520
4521 hdd_ipa->stats.num_send_msg++;
4522
4523end:
4524 return ret;
4525}
4526
4527/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004528 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07004529 * @adapter: adapter upon which the event was received
4530 * @sta_id: station id for the event
4531 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
4532 * @mac_address: MAC address associated with the event
4533 *
4534 * This function is meant to be called from outside of wlan_hdd_ipa.c.
4535 *
4536 * Return: 0 on success, negative errno value on error
4537 */
4538int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
4539 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
4540{
4541 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004542 int ret = 0;
4543
4544 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07004545
Leo Changa202b522016-10-14 16:13:50 -07004546 /* Data path offload only support for STA and SAP mode */
4547 if ((QDF_STA_MODE == adapter->device_mode) ||
4548 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004549 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07004550
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004551 cds_ssr_unprotect(__func__);
4552
4553 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07004554}
4555
4556/**
4557 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
4558 * @hdd_ipa: Global HDD IPA context
4559 *
4560 * Return: None
4561 */
4562static void
4563hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
4564{
4565 unsigned int pending_event_count;
4566 struct ipa_uc_pending_event *pending_event = NULL;
4567
4568 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4569 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4570 "%s, Pending Event Count %d", __func__, pending_event_count);
4571 if (!pending_event_count) {
4572 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4573 "%s, No Pending Event", __func__);
4574 return;
4575 }
4576
4577 qdf_list_remove_front(&hdd_ipa->pending_event,
4578 (qdf_list_node_t **)&pending_event);
4579 while (pending_event != NULL) {
4580 __hdd_ipa_wlan_evt(pending_event->adapter,
4581 pending_event->type,
4582 pending_event->sta_id,
4583 pending_event->mac_addr);
4584 qdf_mem_free(pending_event);
4585 pending_event = NULL;
4586 qdf_list_remove_front(&hdd_ipa->pending_event,
4587 (qdf_list_node_t **)&pending_event);
4588 }
4589}
4590
4591/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004592 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
4593 * @state: IPA RM state value
4594 *
4595 * Return: ASCII string representing the IPA RM state
4596 */
4597static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
4598{
4599 switch (state) {
4600 case HDD_IPA_RM_RELEASED:
4601 return "RELEASED";
4602 case HDD_IPA_RM_GRANT_PENDING:
4603 return "GRANT_PENDING";
4604 case HDD_IPA_RM_GRANTED:
4605 return "GRANTED";
4606 }
4607
4608 return "UNKNOWN";
4609}
4610
4611/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004612 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 * @hdd_ctx: HDD global context
4614 *
4615 * Allocate hdd_ipa resources, ipa pipe resource and register
4616 * wlan interface with IPA module.
4617 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304618 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004619 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004620static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004621{
4622 struct hdd_ipa_priv *hdd_ipa = NULL;
4623 int ret, i;
4624 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park7f171ab2016-07-29 15:44:22 -07004625 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004626
4627 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304628 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004629
Yun Park7f171ab2016-07-29 15:44:22 -07004630 if (!pdev) {
4631 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
4632 goto fail_return;
4633 }
4634
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304635 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004636 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304637 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08004638 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004639 }
4640
4641 hdd_ctx->hdd_ipa = hdd_ipa;
4642 ghdd_ipa = hdd_ipa;
4643 hdd_ipa->hdd_ctx = hdd_ctx;
4644 hdd_ipa->num_iface = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07004645 cdp_ipa_get_resource(cds_get_context(QDF_MODULE_ID_SOC),
4646 cds_get_context(QDF_MODULE_ID_TXRX),
4647 &hdd_ipa->ipa_resource);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08004648 if ((0 == hdd_ipa->ipa_resource.ce_sr_base_paddr) ||
4649 (0 == hdd_ipa->ipa_resource.tx_comp_ring_base_paddr) ||
4650 (0 == hdd_ipa->ipa_resource.rx_rdy_ring_base_paddr) ||
4651 (0 == hdd_ipa->ipa_resource.rx2_rdy_ring_base_paddr)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304652 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Leo Chang3bc8fed2015-11-13 10:59:47 -08004653 "IPA UC resource alloc fail");
4654 goto fail_get_resource;
4655 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004656
4657 /* Create the interface context */
4658 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4659 iface_context = &hdd_ipa->iface_context[i];
4660 iface_context->hdd_ipa = hdd_ipa;
4661 iface_context->cons_client =
4662 hdd_ipa_adapter_2_client[i].cons_client;
4663 iface_context->prod_client =
4664 hdd_ipa_adapter_2_client[i].prod_client;
4665 iface_context->iface_id = i;
4666 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304667 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08004668 }
4669 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004670 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
4671 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004672 }
4673
Leo Chang69c39692016-10-12 20:11:12 -07004674 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304675 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304676 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004677
4678 ret = hdd_ipa_setup_rm(hdd_ipa);
4679 if (ret)
4680 goto fail_setup_rm;
4681
4682 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4683 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304684 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004685 hdd_ipa->sap_num_connected_sta = 0;
4686 hdd_ipa->ipa_tx_packets_diff = 0;
4687 hdd_ipa->ipa_rx_packets_diff = 0;
4688 hdd_ipa->ipa_p_tx_packets = 0;
4689 hdd_ipa->ipa_p_rx_packets = 0;
4690 hdd_ipa->resource_loading = false;
4691 hdd_ipa->resource_unloading = false;
4692 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07004693 hdd_ipa->ipa_pipes_down = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004694 /* Setup IPA sys_pipe for MCC */
4695 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4696 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
4697 if (ret)
4698 goto fail_create_sys_pipe;
4699 }
4700 hdd_ipa_uc_ol_init(hdd_ctx);
4701 } else {
4702 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
4703 if (ret)
4704 goto fail_create_sys_pipe;
4705 }
4706
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304707 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004708
4709fail_create_sys_pipe:
4710 hdd_ipa_destroy_rm_resource(hdd_ipa);
4711fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304712 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Leo Chang3bc8fed2015-11-13 10:59:47 -08004713fail_get_resource:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304714 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08004715 hdd_ctx->hdd_ipa = NULL;
4716 ghdd_ipa = NULL;
4717fail_return:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304718 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004719}
4720
4721/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004722 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
4723 * @hdd_ctx: HDD global context
4724 *
4725 * Allocate hdd_ipa resources, ipa pipe resource and register
4726 * wlan interface with IPA module.
4727 *
4728 * Return: QDF_STATUS enumeration
4729 */
4730QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
4731{
4732 QDF_STATUS ret;
4733
4734 cds_ssr_protect(__func__);
4735 ret = __hdd_ipa_init(hdd_ctx);
4736 cds_ssr_unprotect(__func__);
4737
4738 return ret;
4739}
4740
4741/**
Yun Parkf19e07d2015-11-20 11:34:27 -08004742 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
4743 * @hdd_ipa: pointer to HDD IPA struct
4744 *
4745 * Return: none
4746 */
Jeff Johnsond7720632016-10-05 16:04:32 -07004747static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08004748{
4749 struct ipa_uc_pending_event *pending_event = NULL;
4750
Anurag Chouhanffb21542016-02-17 14:33:03 +05304751 while (qdf_list_remove_front(&hdd_ipa->pending_event,
4752 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304753 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08004754 }
4755
Anurag Chouhanffb21542016-02-17 14:33:03 +05304756 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08004757}
4758
4759/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004760 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004761 * @hdd_ctx: HDD global context
4762 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304763 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004764 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004765static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004766{
4767 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
4768 int i;
4769 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304770 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004771 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
4772
4773 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304774 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004775
4776 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
4777 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
4778 hdd_ipa_teardown_sys_pipe(hdd_ipa);
4779 }
4780
4781 /* Teardown IPA sys_pipe for MCC */
4782 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
4783 hdd_ipa_teardown_sys_pipe(hdd_ipa);
4784
4785 hdd_ipa_destroy_rm_resource(hdd_ipa);
4786
4787#ifdef WLAN_OPEN_SOURCE
4788 cancel_work_sync(&hdd_ipa->pm_work);
4789#endif
4790
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304791 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004792
Nirav Shahcbc6d722016-03-01 16:24:53 +05304793 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4794 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304795 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004796
4797 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4798 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
4799
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304800 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004801 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304802 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004803
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304804 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004805
4806 /* destory the interface lock */
4807 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4808 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304809 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004810 }
4811
4812 /* This should never hit but still make sure that there are no pending
4813 * descriptor in IPA hardware
4814 */
4815 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304816 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004817 "IPA Pending write done: %d Waiting!",
4818 hdd_ipa->pending_hw_desc_cnt);
4819
4820 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
4821 usleep_range(100, 100);
4822 }
4823
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304824 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004825 "IPA Pending write done: desc: %d %s(%d)!",
4826 hdd_ipa->pending_hw_desc_cnt,
4827 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
4828 : "leak", i);
4829 }
4830 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
4831 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304832 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05304833 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
4834 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004835 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304836 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05304837 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
4838 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004839 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304840 qdf_mutex_destroy(&hdd_ipa->event_lock);
4841 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004842 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004843
4844#ifdef WLAN_OPEN_SOURCE
4845 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
4846 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
4847 hdd_ipa->uc_op_work[i].msg = NULL;
4848 }
4849#endif
4850 }
4851
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304852 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004853 hdd_ctx->hdd_ipa = NULL;
4854
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304855 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004856}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004857
4858/**
4859 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
4860 * @hdd_ctx: HDD global context
4861 *
4862 * Return: QDF_STATUS enumeration
4863 */
4864QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
4865{
4866 QDF_STATUS ret;
4867
4868 cds_ssr_protect(__func__);
4869 ret = __hdd_ipa_cleanup(hdd_ctx);
4870 cds_ssr_unprotect(__func__);
4871
4872 return ret;
4873}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004874#endif /* IPA_OFFLOAD */