blob: 358cfe0c03887c5b2ece0e8d22bef7f9c77d369c [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
Jeff Johnsonab2cd402016-12-05 13:54:28 -080037/* denote that this file does not allow legacy hddLog */
38#define HDD_DISALLOW_LEGACY_HDDLOG 1
39
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040/* Include Files */
Mohit Khannafa99aea2016-05-12 21:43:13 -070041#include <linux/ipa.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080042#include <wlan_hdd_includes.h>
43#include <wlan_hdd_ipa.h>
44
45#include <linux/etherdevice.h>
46#include <linux/atomic.h>
47#include <linux/netdevice.h>
48#include <linux/skbuff.h>
49#include <linux/list.h>
50#include <linux/debugfs.h>
51#include <linux/inetdevice.h>
52#include <linux/ip.h>
53#include <wlan_hdd_softap_tx_rx.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070054#include <cdp_txrx_peer_ops.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080055
56#include "cds_sched.h"
57
58#include "wma.h"
59#include "wma_api.h"
Prakash Dhavali87b38e32016-11-14 16:22:53 -080060#include "wal_rx_desc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080061
Dhanashri Atreb08959a2016-03-01 17:28:03 -080062#include "cdp_txrx_ipa.h"
63
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064#define HDD_IPA_DESC_BUFFER_RATIO 4
65#define HDD_IPA_IPV4_NAME_EXT "_ipv4"
66#define HDD_IPA_IPV6_NAME_EXT "_ipv6"
67
68#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080069#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14
70/* WDI TX and RX PIPE */
71#define HDD_IPA_UC_NUM_WDI_PIPE 2
72#define HDD_IPA_UC_MAX_PENDING_EVENT 33
73
74#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000
75#define HDD_IPA_UC_RT_DEBUG_PERIOD 300
76#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30
77#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000
78
79#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0
80#define HDD_IPA_MAX_IFACE 3
81#define HDD_IPA_MAX_SYSBAM_PIPE 4
82#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE
83#define HDD_IPA_ENABLE_MASK BIT(0)
84#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1)
85#define HDD_IPA_IPV6_ENABLE_MASK BIT(2)
86#define HDD_IPA_RM_ENABLE_MASK BIT(3)
87#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4)
88#define HDD_IPA_UC_ENABLE_MASK BIT(5)
89#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6)
90#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8)
91
Yun Parkf19e07d2015-11-20 11:34:27 -080092#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20
93
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080094typedef enum {
95 HDD_IPA_UC_OPCODE_TX_SUSPEND = 0,
96 HDD_IPA_UC_OPCODE_TX_RESUME = 1,
97 HDD_IPA_UC_OPCODE_RX_SUSPEND = 2,
98 HDD_IPA_UC_OPCODE_RX_RESUME = 3,
99 HDD_IPA_UC_OPCODE_STATS = 4,
100 /* keep this last */
101 HDD_IPA_UC_OPCODE_MAX
102} hdd_ipa_uc_op_code;
103
104/**
105 * enum - Reason codes for stat query
106 *
107 * @HDD_IPA_UC_STAT_REASON_NONE: Initial value
108 * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info
109 * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration
110 */
111enum {
112 HDD_IPA_UC_STAT_REASON_NONE,
113 HDD_IPA_UC_STAT_REASON_DEBUG,
114 HDD_IPA_UC_STAT_REASON_BW_CAL
115};
116
117/**
118 * enum hdd_ipa_rm_state - IPA resource manager state
119 * @HDD_IPA_RM_RELEASED: PROD pipe resource released
120 * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet
121 * @HDD_IPA_RM_GRANTED: PROD pipe resource granted
122 */
123enum hdd_ipa_rm_state {
124 HDD_IPA_RM_RELEASED,
125 HDD_IPA_RM_GRANT_PENDING,
126 HDD_IPA_RM_GRANTED,
127};
128
129struct llc_snap_hdr {
130 uint8_t dsap;
131 uint8_t ssap;
132 uint8_t resv[4];
133 __be16 eth_type;
134} __packed;
135
Leo Chang3bc8fed2015-11-13 10:59:47 -0800136/**
137 * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet
138 * @eth: ether II header
139 * @llc_snap: LLC snap header
140 *
141 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800142struct hdd_ipa_tx_hdr {
143 struct ethhdr eth;
144 struct llc_snap_hdr llc_snap;
145} __packed;
146
Leo Chang3bc8fed2015-11-13 10:59:47 -0800147/**
148 * struct frag_header - fragment header type registered to IPA hardware
149 * @length: fragment length
150 * @reserved1: Reserved not used
151 * @reserved2: Reserved not used
152 *
153 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800154struct frag_header {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800155 uint16_t length;
156 uint32_t reserved1;
157 uint32_t reserved2;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158} __packed;
159
Leo Chang3bc8fed2015-11-13 10:59:47 -0800160/**
161 * struct ipa_header - ipa header type registered to IPA hardware
162 * @vdev_id: vdev id
163 * @reserved: Reserved not used
164 *
165 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800166struct ipa_header {
167 uint32_t
168 vdev_id:8, /* vdev_id field is LSB of IPA DESC */
169 reserved:24;
170} __packed;
171
Leo Chang3bc8fed2015-11-13 10:59:47 -0800172/**
173 * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware
174 * @frag_hd: fragment header
175 * @ipa_hd: ipa header
176 * @eth: ether II header
177 *
178 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800179struct hdd_ipa_uc_tx_hdr {
180 struct frag_header frag_hd;
181 struct ipa_header ipa_hd;
182 struct ethhdr eth;
183} __packed;
184
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185/**
186 * struct hdd_ipa_cld_hdr - IPA CLD Header
187 * @reserved: reserved fields
188 * @iface_id: interface ID
189 * @sta_id: Station ID
190 *
191 * Packed 32-bit structure
192 * +----------+----------+--------------+--------+
193 * | Reserved | QCMAP ID | interface id | STA ID |
194 * +----------+----------+--------------+--------+
195 */
196struct hdd_ipa_cld_hdr {
197 uint8_t reserved[2];
198 uint8_t iface_id;
199 uint8_t sta_id;
200} __packed;
201
202struct hdd_ipa_rx_hdr {
203 struct hdd_ipa_cld_hdr cld_hdr;
204 struct ethhdr eth;
205} __packed;
206
207struct hdd_ipa_pm_tx_cb {
Leo Chang69c39692016-10-12 20:11:12 -0700208 bool exception;
209 hdd_adapter_t *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800210 struct hdd_ipa_iface_context *iface_context;
211 struct ipa_rx_data *ipa_tx_desc;
212};
213
214struct hdd_ipa_uc_rx_hdr {
215 struct ethhdr eth;
216} __packed;
217
218struct hdd_ipa_sys_pipe {
219 uint32_t conn_hdl;
220 uint8_t conn_hdl_valid;
221 struct ipa_sys_connect_params ipa_sys_params;
222};
223
224struct hdd_ipa_iface_stats {
225 uint64_t num_tx;
226 uint64_t num_tx_drop;
227 uint64_t num_tx_err;
228 uint64_t num_tx_cac_drop;
229 uint64_t num_rx_prefilter;
230 uint64_t num_rx_ipa_excep;
231 uint64_t num_rx_recv;
232 uint64_t num_rx_recv_mul;
233 uint64_t num_rx_send_desc_err;
234 uint64_t max_rx_mul;
235};
236
237struct hdd_ipa_priv;
238
239struct hdd_ipa_iface_context {
240 struct hdd_ipa_priv *hdd_ipa;
241 hdd_adapter_t *adapter;
242 void *tl_context;
243
244 enum ipa_client_type cons_client;
245 enum ipa_client_type prod_client;
246
247 uint8_t iface_id; /* This iface ID */
248 uint8_t sta_id; /* This iface station ID */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530249 qdf_spinlock_t interface_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800250 uint32_t ifa_address;
251 struct hdd_ipa_iface_stats stats;
252};
253
254struct hdd_ipa_stats {
255 uint32_t event[IPA_WLAN_EVENT_MAX];
256 uint64_t num_send_msg;
257 uint64_t num_free_msg;
258
259 uint64_t num_rm_grant;
260 uint64_t num_rm_release;
261 uint64_t num_rm_grant_imm;
262 uint64_t num_cons_perf_req;
263 uint64_t num_prod_perf_req;
264
265 uint64_t num_rx_drop;
266 uint64_t num_rx_ipa_tx_dp;
267 uint64_t num_rx_ipa_splice;
268 uint64_t num_rx_ipa_loop;
269 uint64_t num_rx_ipa_tx_dp_err;
270 uint64_t num_rx_ipa_write_done;
271 uint64_t num_max_ipa_tx_mul;
272 uint64_t num_rx_ipa_hw_maxed_out;
273 uint64_t max_pend_q_cnt;
274
275 uint64_t num_tx_comp_cnt;
276 uint64_t num_tx_queued;
277 uint64_t num_tx_dequeued;
278 uint64_t num_max_pm_queue;
279
280 uint64_t num_freeq_empty;
281 uint64_t num_pri_freeq_empty;
282 uint64_t num_rx_excep;
283 uint64_t num_tx_bcmc;
284 uint64_t num_tx_bcmc_err;
285};
286
287struct ipa_uc_stas_map {
288 bool is_reserved;
289 uint8_t sta_id;
290};
291struct op_msg_type {
292 uint8_t msg_t;
293 uint8_t rsvd;
294 uint16_t op_code;
295 uint16_t len;
296 uint16_t rsvd_snd;
297};
298
299struct ipa_uc_fw_stats {
300 uint32_t tx_comp_ring_base;
301 uint32_t tx_comp_ring_size;
302 uint32_t tx_comp_ring_dbell_addr;
303 uint32_t tx_comp_ring_dbell_ind_val;
304 uint32_t tx_comp_ring_dbell_cached_val;
305 uint32_t tx_pkts_enqueued;
306 uint32_t tx_pkts_completed;
307 uint32_t tx_is_suspend;
308 uint32_t tx_reserved;
309 uint32_t rx_ind_ring_base;
310 uint32_t rx_ind_ring_size;
311 uint32_t rx_ind_ring_dbell_addr;
312 uint32_t rx_ind_ring_dbell_ind_val;
313 uint32_t rx_ind_ring_dbell_ind_cached_val;
314 uint32_t rx_ind_ring_rdidx_addr;
315 uint32_t rx_ind_ring_rd_idx_cached_val;
316 uint32_t rx_refill_idx;
317 uint32_t rx_num_pkts_indicated;
318 uint32_t rx_buf_refilled;
319 uint32_t rx_num_ind_drop_no_space;
320 uint32_t rx_num_ind_drop_no_buf;
321 uint32_t rx_is_suspend;
322 uint32_t rx_reserved;
323};
324
325struct ipa_uc_pending_event {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530326 qdf_list_node_t node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800327 hdd_adapter_t *adapter;
328 enum ipa_wlan_event type;
329 uint8_t sta_id;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530330 uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800331};
332
333/**
334 * struct uc_rm_work_struct
335 * @work: uC RM work
336 * @event: IPA RM event
337 */
338struct uc_rm_work_struct {
339 struct work_struct work;
340 enum ipa_rm_event event;
341};
342
343/**
344 * struct uc_op_work_struct
345 * @work: uC OP work
346 * @msg: OP message
347 */
348struct uc_op_work_struct {
349 struct work_struct work;
350 struct op_msg_type *msg;
351};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800352
353/**
354 * struct uc_rt_debug_info
355 * @time: system time
356 * @ipa_excep_count: IPA exception packet count
357 * @rx_drop_count: IPA Rx drop packet count
358 * @net_sent_count: IPA Rx packet sent to network stack count
359 * @rx_discard_count: IPA Rx discard packet count
360 * @rx_mcbc_count: IPA Rx BCMC packet count
361 * @tx_mcbc_count: IPA Tx BCMC packet countt
362 * @tx_fwd_count: IPA Tx forward packet count
363 * @rx_destructor_call: IPA Rx packet destructor count
364 */
365struct uc_rt_debug_info {
Deepthi Gowri6acee342016-10-28 15:00:38 +0530366 uint64_t time;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800367 uint64_t ipa_excep_count;
368 uint64_t rx_drop_count;
369 uint64_t net_sent_count;
370 uint64_t rx_discard_count;
371 uint64_t rx_mcbc_count;
372 uint64_t tx_mcbc_count;
373 uint64_t tx_fwd_count;
374 uint64_t rx_destructor_call;
375};
376
377struct hdd_ipa_priv {
378 struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
379 struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
380 uint8_t num_iface;
381 enum hdd_ipa_rm_state rm_state;
382 /*
Nirav Shahcbc6d722016-03-01 16:24:53 +0530383 * IPA driver can send RM notifications with IRQ disabled so using qdf
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800384 * APIs as it is taken care gracefully. Without this, kernel would throw
385 * an warning if spin_lock_bh is used while IRQ is disabled
386 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530387 qdf_spinlock_t rm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388 struct uc_rm_work_struct uc_rm_work;
389 struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX];
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530390 qdf_wake_lock_t wake_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800391 struct delayed_work wake_lock_work;
392 bool wake_lock_released;
393
394 enum ipa_client_type prod_client;
395
396 atomic_t tx_ref_cnt;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530397 qdf_nbuf_queue_t pm_queue_head;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800398 struct work_struct pm_work;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530399 qdf_spinlock_t pm_lock;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800400 bool suspended;
401
402 uint32_t pending_hw_desc_cnt;
403 uint32_t hw_desc_cnt;
404 spinlock_t q_lock;
405 uint32_t freeq_cnt;
406 struct list_head free_desc_head;
407
408 uint32_t pend_q_cnt;
409 struct list_head pend_desc_head;
410
411 hdd_context_t *hdd_ctx;
412
413 struct dentry *debugfs_dir;
414 struct hdd_ipa_stats stats;
415
416 struct notifier_block ipv4_notifier;
417 uint32_t curr_prod_bw;
418 uint32_t curr_cons_bw;
419
420 uint8_t activated_fw_pipe;
421 uint8_t sap_num_connected_sta;
422 uint8_t sta_connected;
423 uint32_t tx_pipe_handle;
424 uint32_t rx_pipe_handle;
425 bool resource_loading;
426 bool resource_unloading;
427 bool pending_cons_req;
428 struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
Anurag Chouhanffb21542016-02-17 14:33:03 +0530429 qdf_list_t pending_event;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530430 qdf_mutex_t event_lock;
Leo Change3e49442015-10-26 20:07:13 -0700431 bool ipa_pipes_down;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800432 uint32_t ipa_tx_packets_diff;
433 uint32_t ipa_rx_packets_diff;
434 uint32_t ipa_p_tx_packets;
435 uint32_t ipa_p_rx_packets;
436 uint32_t stat_req_reason;
437 uint64_t ipa_tx_forward;
438 uint64_t ipa_rx_discard;
439 uint64_t ipa_rx_net_send_count;
440 uint64_t ipa_rx_internel_drop_count;
441 uint64_t ipa_rx_destructor_count;
Anurag Chouhan210db072016-02-22 18:42:15 +0530442 qdf_mc_timer_t rt_debug_timer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800443 struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
444 unsigned int rt_buf_fill_index;
Anurag Chouhan210db072016-02-22 18:42:15 +0530445 qdf_mc_timer_t rt_debug_fill_timer;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530446 qdf_mutex_t rt_debug_lock;
447 qdf_mutex_t ipa_lock;
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800448 struct ol_txrx_ipa_resources ipa_resource;
Leo Chang3bc8fed2015-11-13 10:59:47 -0800449 /* IPA UC doorbell registers paddr */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530450 qdf_dma_addr_t tx_comp_doorbell_paddr;
451 qdf_dma_addr_t rx_ready_doorbell_paddr;
Prakash Dhavali89d406d2016-11-23 11:11:00 -0800452
453 uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX];
454 bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800455};
456
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800457/**
Houston Hoffman23e76f92016-02-26 12:19:11 -0800458 * FIXME: The following conversion routines are just stubs.
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800459 * They will be implemented fully by another update.
460 * The stubs will let the compile go ahead, and functionality
461 * is broken.
462 * This should be OK and IPA is not enabled yet
463 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700464static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800465{
466 void *vaddr;
467 uint32_t ipa_priv = priv;
468
469 vaddr = &ipa_priv; /* just to use the var */
470 vaddr = NULL;
471 return vaddr;
472}
473
Jeff Johnsond7720632016-10-05 16:04:32 -0700474static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
Houston Hoffman43d47fa2016-02-24 16:34:30 -0800475{
476 uint32_t ipa_priv = 0;
477
478 BUG_ON(ptr == NULL);
479 return ipa_priv;
480}
Leo Changcc923e22016-06-16 15:29:03 -0700481
482#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header)
483#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800484#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr)
485#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0
486#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr)
487#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr)
488#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr)
489#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr)
Leo Changcc923e22016-06-16 15:29:03 -0700490#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \
491 (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800492
493#define HDD_IPA_GET_IFACE_ID(_data) \
494 (((struct hdd_ipa_cld_hdr *) (_data))->iface_id)
495
496#define HDD_IPA_LOG(LVL, fmt, args ...) \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530497 QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800498 "%s:%d: "fmt, __func__, __LINE__, ## args)
499
Govind Singhb6a89772016-08-12 11:23:35 +0530500#define HDD_IPA_DP_LOG(LVL, fmt, args...) \
501 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \
502 "%s:%d: "fmt, __func__, __LINE__, ## args)
503
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800504#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \
505 do { \
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530506 QDF_TRACE(QDF_MODULE_ID_HDD, _lvl, "%s:", _prefix); \
507 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, _lvl, _buf, _len); \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800508 } while (0)
509
510#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \
511 (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask))
512
513#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \
514 do { \
515 hdd_ipa->ipa_rx_internel_drop_count++; \
516 } while (0)
517#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \
518 do { \
519 hdd_ipa->ipa_rx_net_send_count++; \
520 } while (0)
521#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
522
Leo Chang07b28f62016-05-11 12:29:22 -0700523#if defined (QCA_WIFI_3_0) && defined (CONFIG_IPA3)
Dhanashri Atreb08959a2016-03-01 17:28:03 -0800524#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \
525do { \
526 pipe_in.u.ul.rdy_ring_rp_va = \
527 ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \
528 pipe_in.u.ul.rdy_comp_ring_base_pa = \
529 ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\
530 pipe_in.u.ul.rdy_comp_ring_size = \
531 ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \
532 pipe_in.u.ul.rdy_comp_ring_wp_pa = \
533 ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \
534 pipe_in.u.ul.rdy_comp_ring_wp_va = \
535 ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \
Leo Chang3bc8fed2015-11-13 10:59:47 -0800536} while (0)
Leo Chang63d73612016-10-18 18:09:43 -0700537
538#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL)
Leo Chang3bc8fed2015-11-13 10:59:47 -0800539#else
540/* Do nothing */
541#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt)
Leo Chang63d73612016-10-18 18:09:43 -0700542#define HDD_IPA_CHECK_HW() 0
Leo Chang07b28f62016-05-11 12:29:22 -0700543#endif /* IPA3 */
Leo Chang3bc8fed2015-11-13 10:59:47 -0800544
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545static struct hdd_ipa_adapter_2_client {
546 enum ipa_client_type cons_client;
547 enum ipa_client_type prod_client;
548} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = {
549 {
550 IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD
551 }, {
552 IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD
553 }, {
554 IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD
555 },
556};
557
558/* For Tx pipes, use Ethernet-II Header format */
559struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = {
560 {
Leo Chang3bc8fed2015-11-13 10:59:47 -0800561 0x0000,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800562 0x00000000,
563 0x00000000
564 },
565 {
566 0x00000000
567 },
568 {
569 {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc},
570 {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff},
571 0x0008
572 }
573};
574
575/* For Tx pipes, use 802.3 Header format */
576static struct hdd_ipa_tx_hdr ipa_tx_hdr = {
577 {
578 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
579 {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF},
580 0x00 /* length can be zero */
581 },
582 {
583 /* LLC SNAP header 8 bytes */
584 0xaa, 0xaa,
585 {0x03, 0x00, 0x00, 0x00},
586 0x0008 /* type value(2 bytes) ,filled by wlan */
587 /* 0x0800 - IPV4, 0x86dd - IPV6 */
588 }
589};
590
591static const char *op_string[] = {
592 "TX_SUSPEND",
593 "TX_RESUME",
594 "RX_SUSPEND",
595 "RX_RESUME",
596 "STATS",
597};
598
599static struct hdd_ipa_priv *ghdd_ipa;
600
601/* Local Function Prototypes */
602static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
603 unsigned long data);
604static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
605 unsigned long data);
606
607static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
Mohit Khannafa99aea2016-05-12 21:43:13 -0700608static void hdd_ipa_uc_proc_pending_event (struct hdd_ipa_priv *hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800609
610/**
611 * hdd_ipa_is_enabled() - Is IPA enabled?
612 * @hdd_ctx: Global HDD context
613 *
614 * Return: true if IPA is enabled, false otherwise
615 */
616bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx)
617{
618 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK);
619}
620
621/**
622 * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled?
623 * @hdd_ctx: Global HDD context
624 *
625 * Return: true if IPA uC offload is enabled, false otherwise
626 */
627bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx)
628{
629 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK);
630}
631
632/**
633 * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
634 * @hdd_ctx: Global HDD context
635 *
636 * Return: true if STA mode IPA uC offload is enabled, false otherwise
637 */
638static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx)
639{
640 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK);
641}
642
643/**
Guolei Bianca144d82016-11-10 11:07:42 +0800644 * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag
645 * @hdd_ipa: Global HDD IPA context
646 *
647 * Return: None
648 */
649#ifdef IPA_UC_STA_OFFLOAD
650static inline void hdd_ipa_uc_sta_reset_sta_connected(
651 struct hdd_ipa_priv *hdd_ipa)
652{
653 vos_lock_acquire(&hdd_ipa->event_lock);
654 hdd_ipa->sta_connected = 0;
655 vos_lock_release(&hdd_ipa->event_lock);
656}
657#else
658static inline void hdd_ipa_uc_sta_reset_sta_connected(
659 struct hdd_ipa_priv *hdd_ipa)
660{
661}
662#endif
663
664/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800665 * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
666 * @hdd_ipa: Global HDD IPA context
667 *
668 * Return: true if pre-filter is enabled, otherwise false
669 */
670static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx)
671{
672 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
673 HDD_IPA_PRE_FILTER_ENABLE_MASK);
674}
675
676/**
677 * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
678 * @hdd_ipa: Global HDD IPA context
679 *
680 * Return: true if IPv6 is enabled, otherwise false
681 */
682static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx)
683{
684 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK);
685}
686
687/**
688 * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled?
689 * @hdd_ipa: Global HDD IPA context
690 *
691 * Return: true if resource manager is enabled, otherwise false
692 */
693static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx)
694{
695 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK);
696}
697
698/**
699 * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled?
700 * @hdd_ipa: Global HDD IPA context
701 *
702 * Return: true if resource manager is enabled, otherwise false
703 */
704static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx)
705{
706 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING);
707}
708
709/**
710 * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled?
711 * @hdd_ipa: Global HDD IPA context
712 *
713 * Return: true if clock scaling is enabled, otherwise false
714 */
715static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx)
716{
717 return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx,
718 HDD_IPA_CLK_SCALING_ENABLE_MASK |
719 HDD_IPA_RM_ENABLE_MASK);
720}
721
722/**
723 * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer
724 * @ctext: pointer to hdd context.
725 *
726 * If rt debug enabled, periodically called, and fill debug buffer
727 *
728 * Return: none
729 */
730static void hdd_ipa_uc_rt_debug_host_fill(void *ctext)
731{
732 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
733 struct hdd_ipa_priv *hdd_ipa;
734 struct uc_rt_debug_info *dump_info = NULL;
735
736 if (wlan_hdd_validate_context(hdd_ctx))
737 return;
738
739 if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530740 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800741 "%s: IPA UC is not enabled", __func__);
742 return;
743 }
744
745 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
746
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530747 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748 dump_info = &hdd_ipa->rt_bug_buffer[
749 hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT];
750
Deepthi Gowri6acee342016-10-28 15:00:38 +0530751 dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800752 dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep;
753 dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count;
754 dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count;
755 dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard;
756 dump_info->tx_mcbc_count = hdd_ipa->stats.num_tx_bcmc;
757 dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward;
758 dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count;
759 hdd_ipa->rt_buf_fill_index++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530760 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761
Anurag Chouhan210db072016-02-22 18:42:15 +0530762 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800763 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
764}
765
766/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700767 * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800768 * @hdd_ctx: pointer to hdd context.
769 *
770 * If rt debug enabled, dump debug buffer contents based on requirement
771 *
772 * Return: none
773 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700774static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800775{
776 struct hdd_ipa_priv *hdd_ipa;
777 unsigned int dump_count;
778 unsigned int dump_index;
779 struct uc_rt_debug_info *dump_info = NULL;
780
781 if (wlan_hdd_validate_context(hdd_ctx))
782 return;
783
784 hdd_ipa = hdd_ctx->hdd_ipa;
785 if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530786 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787 "%s: IPA UC is not enabled", __func__);
788 return;
789 }
790
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530791 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800792 "========= WLAN-IPA DEBUG BUF DUMP ==========\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530793 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800794 " TM : EXEP : DROP : NETS : MCBC : TXFD : DSTR : DSCD\n");
795
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530796 qdf_mutex_acquire(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800797 for (dump_count = 0;
798 dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
799 dump_count++) {
800 dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) %
801 HDD_IPA_UC_RT_DEBUG_BUF_COUNT;
802 dump_info = &hdd_ipa->rt_bug_buffer[dump_index];
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530803 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Deepthi Gowri6acee342016-10-28 15:00:38 +0530804 "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800805 dump_info->time, dump_info->ipa_excep_count,
806 dump_info->rx_drop_count, dump_info->net_sent_count,
807 dump_info->tx_mcbc_count, dump_info->tx_fwd_count,
808 dump_info->rx_destructor_call,
809 dump_info->rx_discard_count);
810 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530811 qdf_mutex_release(&hdd_ipa->rt_debug_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530812 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813 "======= WLAN-IPA DEBUG BUF DUMP END ========\n");
814}
815
816/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700817 * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for
818 * __hdd_ipa_uc_rt_debug_host_dump
819 * @hdd_ctx: pointer to hdd context.
820 *
821 * If rt debug enabled, dump debug buffer contents based on requirement
822 *
823 * Return: none
824 */
825void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx)
826{
827 cds_ssr_protect(__func__);
828 __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
829 cds_ssr_unprotect(__func__);
830}
831
832/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833 * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler
834 * @ctext: pointer to hdd context.
835 *
836 * periodically called by timer expire
837 * will try to alloc dummy memory and detect out of memory condition
838 * if out of memory detected, dump wlan-ipa stats
839 *
840 * Return: none
841 */
842static void hdd_ipa_uc_rt_debug_handler(void *ctext)
843{
844 hdd_context_t *hdd_ctx = (hdd_context_t *)ctext;
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700845 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846 void *dummy_ptr = NULL;
847
848 if (wlan_hdd_validate_context(hdd_ctx))
849 return;
850
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700851 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
852
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800853 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530854 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800855 "%s: IPA RT debug is not enabled", __func__);
856 return;
857 }
858
859 /* Allocate dummy buffer periodically and free immediately. this will
860 * proactively detect OOM and if allocation fails dump ipa stats
861 */
862 dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE,
863 GFP_KERNEL | GFP_ATOMIC);
864 if (!dummy_ptr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530865 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 "%s: Dummy alloc fail", __func__);
867 hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
868 hdd_ipa_uc_stat_request(
Krunal Sonibe766b02016-03-10 13:00:44 -0800869 hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800870 } else {
871 kfree(dummy_ptr);
872 }
873
Anurag Chouhan210db072016-02-22 18:42:15 +0530874 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875 HDD_IPA_UC_RT_DEBUG_PERIOD);
876}
877
878/**
879 * hdd_ipa_uc_rt_debug_destructor - called by data packet free
880 * @skb: packet pinter
881 *
882 * when free data packet, will be invoked by wlan client and will increase
883 * free counter
884 *
885 * Return: none
886 */
Jeff Johnsond7720632016-10-05 16:04:32 -0700887static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888{
889 if (!ghdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530890 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800891 "%s: invalid hdd context", __func__);
892 return;
893 }
894
895 ghdd_ipa->ipa_rx_destructor_count++;
896}
897
898/**
899 * hdd_ipa_uc_rt_debug_deinit - remove resources to handle rt debugging
900 * @hdd_ctx: hdd main context
901 *
902 * free all rt debugging resources
903 *
904 * Return: none
905 */
906static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx)
907{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700908 struct hdd_ipa_priv *hdd_ipa;
909
910 if (wlan_hdd_validate_context(hdd_ctx))
911 return;
912
913 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530915 qdf_mutex_destroy(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916
917 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530918 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 "%s: IPA RT debug is not enabled", __func__);
920 return;
921 }
922
Anurag Chouhan210db072016-02-22 18:42:15 +0530923 if (QDF_TIMER_STATE_STOPPED !=
Prakash Dhavali169de302016-11-30 12:52:49 -0800924 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) {
925 qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer);
926 }
927 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer);
928
929 if (QDF_TIMER_STATE_STOPPED !=
Anurag Chouhan210db072016-02-22 18:42:15 +0530930 qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) {
931 qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932 }
Anurag Chouhan210db072016-02-22 18:42:15 +0530933 qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934}
935
936/**
937 * hdd_ipa_uc_rt_debug_init - intialize resources to handle rt debugging
938 * @hdd_ctx: hdd main context
939 *
940 * alloc and initialize all rt debugging resources
941 *
942 * Return: none
943 */
944static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx)
945{
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700946 struct hdd_ipa_priv *hdd_ipa;
947
948 if (wlan_hdd_validate_context(hdd_ctx))
949 return;
950
951 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800952
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530953 qdf_mutex_create(&hdd_ipa->rt_debug_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954 hdd_ipa->rt_buf_fill_index = 0;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530955 qdf_mem_zero(hdd_ipa->rt_bug_buffer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800956 sizeof(struct uc_rt_debug_info) *
957 HDD_IPA_UC_RT_DEBUG_BUF_COUNT);
958 hdd_ipa->ipa_tx_forward = 0;
959 hdd_ipa->ipa_rx_discard = 0;
960 hdd_ipa->ipa_rx_net_send_count = 0;
961 hdd_ipa->ipa_rx_internel_drop_count = 0;
962 hdd_ipa->ipa_rx_destructor_count = 0;
963
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964 /* Reatime debug enable on feature enable */
965 if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530966 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800967 "%s: IPA RT debug is not enabled", __func__);
968 return;
969 }
Yun Parkdfc1da52016-11-15 14:50:11 -0800970
971 qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
972 hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx);
973 qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer,
974 HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL);
975
Anurag Chouhan210db072016-02-22 18:42:15 +0530976 qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977 hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx);
Anurag Chouhan210db072016-02-22 18:42:15 +0530978 qdf_mc_timer_start(&hdd_ipa->rt_debug_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979 HDD_IPA_UC_RT_DEBUG_PERIOD);
980
981}
982
983/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700984 * __hdd_ipa_uc_stat_query() - Query the IPA stats
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800985 * @hdd_ctx: Global HDD context
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700986 * @ipa_tx_diff: tx packet count diff from previous tx packet count
987 * @ipa_rx_diff: rx packet count diff from previous rx packet count
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800988 *
989 * Return: true if IPA is enabled, false otherwise
990 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700991static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800992 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
993{
994 struct hdd_ipa_priv *hdd_ipa;
995
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800996 *ipa_tx_diff = 0;
997 *ipa_rx_diff = 0;
998
Prakash Dhavali412cdb02016-10-20 21:19:31 -0700999 if (wlan_hdd_validate_context(hdd_ctx))
1000 return;
1001
1002 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1003
1004 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1005 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006 return;
1007 }
1008
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301009 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001010 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1011 (false == hdd_ipa->resource_loading)) {
1012 *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff;
1013 *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff;
Yun Parkf8d6a122016-10-11 15:49:43 -07001014 HDD_IPA_LOG(LOGOFF, "STAT Query TX DIFF %d, RX DIFF %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001015 *ipa_tx_diff, *ipa_rx_diff);
1016 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301017 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001018 return;
1019}
1020
1021/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001022 * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query
1023 * @hdd_ctx: Global HDD context
1024 * @ipa_tx_diff: tx packet count diff from previous tx packet count
1025 * @ipa_rx_diff: rx packet count diff from previous rx packet count
1026 *
1027 * Return: true if IPA is enabled, false otherwise
1028 */
1029void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx,
1030 uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
1031{
1032 cds_ssr_protect(__func__);
1033 __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff);
1034 cds_ssr_unprotect(__func__);
1035}
1036
1037/**
1038 * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 * @adapter: network adapter
1040 * @reason: STAT REQ Reason
1041 *
1042 * Return: None
1043 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001044static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001045{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001046 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001047 struct hdd_ipa_priv *hdd_ipa;
1048
1049 if (!adapter) {
1050 return;
1051 }
1052
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001053 hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
1054
1055 if (wlan_hdd_validate_context(hdd_ctx))
1056 return;
1057
1058 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1059 if (!hdd_ipa_is_enabled(hdd_ctx) ||
1060 !(hdd_ipa_uc_is_enabled(hdd_ctx))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001061 return;
1062 }
1063
Yun Park8f289c82016-10-18 16:38:21 -07001064 HDD_IPA_LOG(LOGOFF, "STAT REQ Reason %d", reason);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301065 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066 if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) &&
1067 (false == hdd_ipa->resource_loading)) {
1068 hdd_ipa->stat_req_reason = reason;
1069 wma_cli_set_command(
1070 (int)adapter->sessionId,
1071 (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID,
1072 0, VDEV_CMD);
1073 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301074 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001075}
1076
1077/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001078 * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request
1079 * @adapter: network adapter
1080 * @reason: STAT REQ Reason
1081 *
1082 * Return: None
1083 */
1084void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason)
1085{
1086 cds_ssr_protect(__func__);
1087 __hdd_ipa_uc_stat_request(adapter, reason);
1088 cds_ssr_unprotect(__func__);
1089}
1090
1091/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001092 * hdd_ipa_uc_find_add_assoc_sta() - Find associated station
1093 * @hdd_ipa: Global HDD IPA context
1094 * @sta_add: Should station be added
1095 * @sta_id: ID of the station being queried
1096 *
1097 * Return: true if the station was found
1098 */
1099static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa,
1100 bool sta_add, uint8_t sta_id)
1101{
1102 bool sta_found = false;
1103 uint8_t idx;
1104 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1105 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1106 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1107 sta_found = true;
1108 break;
1109 }
1110 }
1111 if (sta_add && sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301112 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001113 "%s: STA ID %d already exist, cannot add",
1114 __func__, sta_id);
1115 return sta_found;
1116 }
1117 if (sta_add) {
1118 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1119 if (!hdd_ipa->assoc_stas_map[idx].is_reserved) {
1120 hdd_ipa->assoc_stas_map[idx].is_reserved = true;
1121 hdd_ipa->assoc_stas_map[idx].sta_id = sta_id;
1122 return sta_found;
1123 }
1124 }
1125 }
1126 if (!sta_add && !sta_found) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301127 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 "%s: STA ID %d does not exist, cannot delete",
1129 __func__, sta_id);
1130 return sta_found;
1131 }
1132 if (!sta_add) {
1133 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
1134 if ((hdd_ipa->assoc_stas_map[idx].is_reserved) &&
1135 (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) {
1136 hdd_ipa->assoc_stas_map[idx].is_reserved =
1137 false;
1138 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
1139 return sta_found;
1140 }
1141 }
1142 }
1143 return sta_found;
1144}
1145
1146/**
1147 * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes
1148 * @hdd_ipa: Global HDD IPA context
1149 *
1150 * Return: 0 on success, negative errno if error
1151 */
1152static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
1153{
1154 int result;
1155 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001156 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001157
1158 /* ACTIVATE TX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301159 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001160 "%s: Enable TX PIPE(tx_pipe_handle=%d)",
1161 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162 result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1163 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301164 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001165 "%s: Enable TX PIPE fail, code %d",
1166 __func__, result);
1167 return result;
1168 }
1169 result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle);
1170 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301171 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001172 "%s: Resume TX PIPE fail, code %d",
1173 __func__, result);
1174 return result;
1175 }
Leo Changfdb45c32016-10-28 11:09:23 -07001176 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, true, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177
1178 /* ACTIVATE RX PIPE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301179 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001180 "%s: Enable RX PIPE(rx_pipe_handle=%d)",
1181 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001182 result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1183 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301184 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001185 "%s: Enable RX PIPE fail, code %d",
1186 __func__, result);
1187 return result;
1188 }
1189 result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle);
1190 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301191 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001192 "%s: Resume RX PIPE fail, code %d",
1193 __func__, result);
1194 return result;
1195 }
Leo Changfdb45c32016-10-28 11:09:23 -07001196 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, true, false);
Leo Change3e49442015-10-26 20:07:13 -07001197 hdd_ipa->ipa_pipes_down = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001198 return 0;
1199}
1200
1201/**
1202 * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes
1203 * @hdd_ipa: Global HDD IPA context
1204 *
1205 * Return: 0 on success, negative errno if error
1206 */
1207static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
1208{
1209 int result;
1210
Leo Change3e49442015-10-26 20:07:13 -07001211 hdd_ipa->ipa_pipes_down = true;
1212
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301213 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001214 result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
1215 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301216 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217 "%s: Suspend RX PIPE fail, code %d",
1218 __func__, result);
1219 return result;
1220 }
1221 result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle);
1222 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301223 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001224 "%s: Disable RX PIPE fail, code %d",
1225 __func__, result);
1226 return result;
1227 }
1228
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301229 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable TX PIPE", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230 result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle);
1231 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301232 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001233 "%s: Suspend TX PIPE fail, code %d",
1234 __func__, result);
1235 return result;
1236 }
1237 result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle);
1238 if (result) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301239 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240 "%s: Disable TX PIPE fail, code %d",
1241 __func__, result);
1242 return result;
1243 }
1244
1245 return 0;
1246}
1247
1248/**
1249 * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection
1250 * @hdd_ipa: Global HDD IPA context
1251 *
1252 * Return: 0 on success, negative errno if error
1253 */
1254static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa)
1255{
1256 hdd_ipa->activated_fw_pipe = 0;
1257 hdd_ipa->resource_loading = true;
Yun Park4cab6ee2015-10-27 11:43:40 -07001258
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001259 /* If RM feature enabled
1260 * Request PROD Resource first
1261 * PROD resource may return sync or async manners */
Yun Park4cab6ee2015-10-27 11:43:40 -07001262 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) {
1263 if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
1264 /* RM PROD request sync return
1265 * enable pipe immediately
1266 */
1267 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301268 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001269 "%s: IPA WDI Pipe activation failed",
1270 __func__);
1271 hdd_ipa->resource_loading = false;
1272 return -EBUSY;
1273 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001274 }
1275 } else {
1276 /* RM Disabled
Yun Park4cab6ee2015-10-27 11:43:40 -07001277 * Just enabled all the PIPEs
1278 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 if (hdd_ipa_uc_enable_pipes(hdd_ipa)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301280 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park4cab6ee2015-10-27 11:43:40 -07001281 "%s: IPA WDI Pipe activation failed",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001282 __func__);
1283 hdd_ipa->resource_loading = false;
1284 return -EBUSY;
1285 }
1286 hdd_ipa->resource_loading = false;
1287 }
Yun Park4cab6ee2015-10-27 11:43:40 -07001288
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301289 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park4cab6ee2015-10-27 11:43:40 -07001290 "%s: IPA WDI Pipes activated successfully", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001291 return 0;
1292}
1293
1294/**
1295 * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
1296 * @hdd_ipa: Global HDD IPA context
1297 *
1298 * Return: None
1299 */
1300static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa)
1301{
1302 p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context;
Leo Changfdb45c32016-10-28 11:09:23 -07001303 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001304
Yun Park7c4f31b2016-11-30 10:09:21 -08001305 if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) {
1306 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL");
1307 QDF_ASSERT(0);
1308 return;
1309 }
1310
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001311 hdd_ipa->resource_unloading = true;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301312 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW RX PIPE", __func__);
Leo Changfdb45c32016-10-28 11:09:23 -07001313 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, false, false);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301314 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW TX PIPE", __func__);
Leo Changfdb45c32016-10-28 11:09:23 -07001315 cdp_ipa_set_active(soc, cds_ctx->pdev_txrx_ctx, false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001316}
1317
1318/**
1319 * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
1320 * @context: User context registered with TL (the IPA Global context is
1321 * registered
1322 * @rxpkt: Packet containing the notification
1323 * @staid: ID of the station associated with the packet
1324 *
1325 * Return: None
1326 */
1327static void
1328hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event)
1329{
1330 struct hdd_ipa_priv *hdd_ipa = context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301331 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332
1333 /*
1334 * When SSR is going on or driver is unloading, just return.
1335 */
1336 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301337 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001338 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001339
1340 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1341 return;
1342
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301343 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s, event code %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001344 __func__, event);
1345
1346 switch (event) {
1347 case IPA_RM_RESOURCE_GRANTED:
1348 /* Differed RM Granted */
1349 hdd_ipa_uc_enable_pipes(hdd_ipa);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301350 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001351 if ((false == hdd_ipa->resource_unloading) &&
1352 (!hdd_ipa->activated_fw_pipe)) {
1353 hdd_ipa_uc_enable_pipes(hdd_ipa);
1354 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301355 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001356 break;
1357
1358 case IPA_RM_RESOURCE_RELEASED:
1359 /* Differed RM Released */
1360 hdd_ipa->resource_unloading = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001361 break;
1362
1363 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301364 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001365 "%s, invalid event code %d", __func__, event);
1366 break;
1367 }
1368}
1369
1370/**
1371 * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification
1372 * @hdd_ipa: Global HDD IPA context
1373 * @event: IPA resource manager event to be deferred
1374 *
1375 * This function is called when a resource manager event is received
1376 * from firmware in interrupt context. This function will defer the
1377 * handling to the OL RX thread
1378 *
1379 * Return: None
1380 */
1381static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work)
1382{
1383 enum ipa_rm_event event;
1384 struct uc_rm_work_struct *uc_rm_work = container_of(work,
1385 struct uc_rm_work_struct, work);
1386 struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work,
1387 struct hdd_ipa_priv, uc_rm_work);
1388
1389 cds_ssr_protect(__func__);
1390 event = uc_rm_work->event;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301391 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001392 "%s, posted event %d", __func__, event);
1393
1394 hdd_ipa_uc_rm_notify_handler(hdd_ipa, event);
1395 cds_ssr_unprotect(__func__);
1396
1397 return;
1398}
1399
1400/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401 * hdd_ipa_uc_op_cb() - IPA uC operation callback
1402 * @op_msg: operation message received from firmware
1403 * @usr_ctxt: user context registered with TL (we register the HDD Global
1404 * context)
1405 *
1406 * Return: None
1407 */
1408static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
1409{
1410 struct op_msg_type *msg = op_msg;
1411 struct ipa_uc_fw_stats *uc_fw_stat;
1412 struct IpaHwStatsWDIInfoData_t ipa_stat;
1413 struct hdd_ipa_priv *hdd_ipa;
1414 hdd_context_t *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301415 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001416
1417 if (!op_msg || !usr_ctxt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301418 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001419 return;
1420 }
1421
1422 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301423 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001424 "%s, INVALID OPCODE %d", __func__, msg->op_code);
1425 return;
1426 }
1427
1428 hdd_ctx = (hdd_context_t *) usr_ctxt;
1429
1430 /*
1431 * When SSR is going on or driver is unloading, just return.
1432 */
1433 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301434 if (status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301435 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436 return;
1437 }
1438
1439 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1440
Govind Singhb6a89772016-08-12 11:23:35 +05301441 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001442 "%s, OPCODE %s", __func__, op_string[msg->op_code]);
1443
1444 if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) ||
1445 (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301446 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001447 hdd_ipa->activated_fw_pipe++;
1448 if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) {
1449 hdd_ipa->resource_loading = false;
1450 hdd_ipa_uc_proc_pending_event(hdd_ipa);
Yun Parkccc6d7a2015-12-02 14:50:13 -08001451 if (hdd_ipa->pending_cons_req)
1452 ipa_rm_notify_completion(
1453 IPA_RM_RESOURCE_GRANTED,
1454 IPA_RM_RESOURCE_WLAN_CONS);
Yun Park5b635012015-12-02 15:05:01 -08001455 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301457 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001458 } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001459 (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301460 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001461 hdd_ipa->activated_fw_pipe--;
1462 if (!hdd_ipa->activated_fw_pipe) {
1463 hdd_ipa_uc_disable_pipes(hdd_ipa);
Yun Park5b635012015-12-02 15:05:01 -08001464 if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
1465 ipa_rm_release_resource(
1466 IPA_RM_RESOURCE_WLAN_PROD);
1467 /* Sync return success from IPA
1468 * Enable/resume all the PIPEs */
1469 hdd_ipa->resource_unloading = false;
1470 hdd_ipa_uc_proc_pending_event(hdd_ipa);
1471 hdd_ipa->pending_cons_req = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001472 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301473 qdf_mutex_release(&hdd_ipa->ipa_lock);
Yun Park8292dcb2016-10-07 16:46:06 -07001474 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001475 (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) {
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001476 struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001477 /* STATs from host */
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301478 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001479 "==== IPA_UC WLAN_HOST CE ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001480 "CE RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001481 "CE RING SIZE: %d\n"
1482 "CE REG ADDR : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001483 (unsigned long long)res->ce_sr_base_paddr,
1484 res->ce_sr_ring_size,
1485 (unsigned long long)res->ce_reg_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301486 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001487 "==== IPA_UC WLAN_HOST TX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001488 "COMP RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489 "COMP RING SIZE: %d\n"
1490 "NUM ALLOC BUF: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001491 "COMP RING DBELL : 0x%llx",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001492 (unsigned long long)res->tx_comp_ring_base_paddr,
1493 res->tx_comp_ring_size,
1494 res->tx_num_alloc_buffer,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001495 (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301496 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001497 "==== IPA_UC WLAN_HOST RX ====\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001498 "IND RING BASE: 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001499 "IND RING SIZE: %d\n"
Leo Chang3bc8fed2015-11-13 10:59:47 -08001500 "IND RING DBELL : 0x%llx\n"
1501 "PROC DONE IND ADDR : 0x%llx\n"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001502 "NUM EXCP PKT : %llu\n"
1503 "NUM TX BCMC : %llu\n"
1504 "NUM TX BCMC ERR : %llu",
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001505 (unsigned long long)res->rx_rdy_ring_base_paddr,
1506 res->rx_rdy_ring_size,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001507 (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr,
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001508 (unsigned long long)hdd_ipa->ipa_resource.
1509 rx_proc_done_idx_paddr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001510 hdd_ipa->stats.num_rx_excep,
1511 hdd_ipa->stats.num_tx_bcmc,
Manikandan Mohan22b83722015-12-15 15:03:23 -08001512 (unsigned long long)hdd_ipa->stats.num_tx_bcmc_err);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301513 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001514 "==== IPA_UC WLAN_HOST CONTROL ====\n"
1515 "SAP NUM STAs: %d\n"
1516 "STA CONNECTED: %d\n"
1517 "TX PIPE HDL: %d\n"
1518 "RX PIPE HDL : %d\n"
1519 "RSC LOADING : %d\n"
1520 "RSC UNLOADING : %d\n"
1521 "PNDNG CNS RQT : %d",
1522 hdd_ipa->sap_num_connected_sta,
1523 hdd_ipa->sta_connected,
1524 hdd_ipa->tx_pipe_handle,
1525 hdd_ipa->rx_pipe_handle,
1526 (unsigned int)hdd_ipa->resource_loading,
1527 (unsigned int)hdd_ipa->resource_unloading,
1528 (unsigned int)hdd_ipa->pending_cons_req);
1529
1530 /* STATs from FW */
1531 uc_fw_stat = (struct ipa_uc_fw_stats *)
1532 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301533 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001534 "==== IPA_UC WLAN_FW TX ====\n"
1535 "COMP RING BASE: 0x%x\n"
1536 "COMP RING SIZE: %d\n"
1537 "COMP RING DBELL : 0x%x\n"
1538 "COMP RING DBELL IND VAL : %d\n"
1539 "COMP RING DBELL CACHED VAL : %d\n"
1540 "COMP RING DBELL CACHED VAL : %d\n"
1541 "PKTS ENQ : %d\n"
1542 "PKTS COMP : %d\n"
1543 "IS SUSPEND : %d\n"
1544 "RSVD : 0x%x",
1545 uc_fw_stat->tx_comp_ring_base,
1546 uc_fw_stat->tx_comp_ring_size,
1547 uc_fw_stat->tx_comp_ring_dbell_addr,
1548 uc_fw_stat->tx_comp_ring_dbell_ind_val,
1549 uc_fw_stat->tx_comp_ring_dbell_cached_val,
1550 uc_fw_stat->tx_comp_ring_dbell_cached_val,
1551 uc_fw_stat->tx_pkts_enqueued,
1552 uc_fw_stat->tx_pkts_completed,
1553 uc_fw_stat->tx_is_suspend, uc_fw_stat->tx_reserved);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301554 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555 "==== IPA_UC WLAN_FW RX ====\n"
1556 "IND RING BASE: 0x%x\n"
1557 "IND RING SIZE: %d\n"
1558 "IND RING DBELL : 0x%x\n"
1559 "IND RING DBELL IND VAL : %d\n"
1560 "IND RING DBELL CACHED VAL : %d\n"
1561 "RDY IND ADDR : 0x%x\n"
1562 "RDY IND CACHE VAL : %d\n"
1563 "RFIL IND : %d\n"
1564 "NUM PKT INDICAT : %d\n"
1565 "BUF REFIL : %d\n"
1566 "NUM DROP NO SPC : %d\n"
1567 "NUM DROP NO BUF : %d\n"
1568 "IS SUSPND : %d\n"
1569 "RSVD : 0x%x\n",
1570 uc_fw_stat->rx_ind_ring_base,
1571 uc_fw_stat->rx_ind_ring_size,
1572 uc_fw_stat->rx_ind_ring_dbell_addr,
1573 uc_fw_stat->rx_ind_ring_dbell_ind_val,
1574 uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
1575 uc_fw_stat->rx_ind_ring_rdidx_addr,
1576 uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
1577 uc_fw_stat->rx_refill_idx,
1578 uc_fw_stat->rx_num_pkts_indicated,
1579 uc_fw_stat->rx_buf_refilled,
1580 uc_fw_stat->rx_num_ind_drop_no_space,
1581 uc_fw_stat->rx_num_ind_drop_no_buf,
1582 uc_fw_stat->rx_is_suspend, uc_fw_stat->rx_reserved);
1583 /* STATs from IPA */
1584 ipa_get_wdi_stats(&ipa_stat);
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301585 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586 "==== IPA_UC IPA TX ====\n"
1587 "NUM PROCD : %d\n"
1588 "CE DBELL : 0x%x\n"
1589 "NUM DBELL FIRED : %d\n"
1590 "COMP RNG FULL : %d\n"
1591 "COMP RNG EMPT : %d\n"
1592 "COMP RNG USE HGH : %d\n"
1593 "COMP RNG USE LOW : %d\n"
1594 "BAM FIFO FULL : %d\n"
1595 "BAM FIFO EMPT : %d\n"
1596 "BAM FIFO USE HGH : %d\n"
1597 "BAM FIFO USE LOW : %d\n"
1598 "NUM DBELL : %d\n"
1599 "NUM UNEXP DBELL : %d\n"
1600 "NUM BAM INT HDL : 0x%x\n"
1601 "NUM BAM INT NON-RUN : 0x%x\n"
1602 "NUM QMB INT HDL : 0x%x",
1603 ipa_stat.tx_ch_stats.num_pkts_processed,
1604 ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
1605 ipa_stat.tx_ch_stats.num_db_fired,
1606 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
1607 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
1608 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
1609 ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
1610 ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
1611 ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
1612 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
1613 ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
1614 ipa_stat.tx_ch_stats.num_db,
1615 ipa_stat.tx_ch_stats.num_unexpected_db,
1616 ipa_stat.tx_ch_stats.num_bam_int_handled,
1617 ipa_stat.tx_ch_stats.
1618 num_bam_int_in_non_runnning_state,
1619 ipa_stat.tx_ch_stats.num_qmb_int_handled);
1620
Anurag Chouhandf2b2682016-02-29 14:15:27 +05301621 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622 "==== IPA_UC IPA RX ====\n"
1623 "MAX OST PKT : %d\n"
1624 "NUM PKT PRCSD : %d\n"
1625 "RNG RP : 0x%x\n"
1626 "COMP RNG FULL : %d\n"
1627 "COMP RNG EMPT : %d\n"
1628 "COMP RNG USE HGH : %d\n"
1629 "COMP RNG USE LOW : %d\n"
1630 "BAM FIFO FULL : %d\n"
1631 "BAM FIFO EMPT : %d\n"
1632 "BAM FIFO USE HGH : %d\n"
1633 "BAM FIFO USE LOW : %d\n"
1634 "NUM DB : %d\n"
1635 "NUM UNEXP DB : %d\n"
1636 "NUM BAM INT HNDL : 0x%x\n",
1637 ipa_stat.rx_ch_stats.max_outstanding_pkts,
1638 ipa_stat.rx_ch_stats.num_pkts_processed,
1639 ipa_stat.rx_ch_stats.rx_ring_rp_value,
1640 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
1641 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
1642 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
1643 ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
1644 ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
1645 ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
1646 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
1647 ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
1648 ipa_stat.rx_ch_stats.num_db,
1649 ipa_stat.rx_ch_stats.num_unexpected_db,
1650 ipa_stat.rx_ch_stats.num_bam_int_handled);
1651 } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) &&
1652 (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) {
1653 /* STATs from FW */
1654 uc_fw_stat = (struct ipa_uc_fw_stats *)
1655 ((uint8_t *)op_msg + sizeof(struct op_msg_type));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301656 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001657 hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF(
1658 uc_fw_stat->tx_pkts_completed,
1659 hdd_ipa->ipa_p_tx_packets);
1660 hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF(
1661 (uc_fw_stat->rx_num_ind_drop_no_space +
1662 uc_fw_stat->rx_num_ind_drop_no_buf +
1663 uc_fw_stat->rx_num_pkts_indicated),
1664 hdd_ipa->ipa_p_rx_packets);
1665
1666 hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
1667 hdd_ipa->ipa_p_rx_packets =
1668 (uc_fw_stat->rx_num_ind_drop_no_space +
1669 uc_fw_stat->rx_num_ind_drop_no_buf +
1670 uc_fw_stat->rx_num_pkts_indicated);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301671 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 } else {
Yun Park8292dcb2016-10-07 16:46:06 -07001673 HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d",
1674 msg->op_code, hdd_ipa->stat_req_reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301676 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001677}
1678
1679
1680/**
1681 * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
1682 * @adapter: device adapter instance
1683 * @offload_type: MCC or SCC
1684 * @enable: TX offload enable or disable
1685 *
1686 * Return: none
1687 */
1688static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001689 uint32_t offload_type, bool enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001690{
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001691 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692 struct sir_ipa_offload_enable_disable ipa_offload_enable_disable;
Yun Park8292dcb2016-10-07 16:46:06 -07001693 struct hdd_ipa_iface_context *iface_context = NULL;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001694 uint8_t session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001696 if (!adapter || !hdd_ipa)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 return;
1698
Yun Park8292dcb2016-10-07 16:46:06 -07001699 iface_context = adapter->ipa_context;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001700 session_id = adapter->sessionId;
Yun Park8292dcb2016-10-07 16:46:06 -07001701
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001702 if (!iface_context) {
1703 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1704 "Interface context is NULL");
1705 return;
1706 }
1707
1708 if (enable == hdd_ipa->vdev_offload_enabled[session_id]) {
Yun Park8292dcb2016-10-07 16:46:06 -07001709 /* IPA offload status is already set as desired */
1710 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001711 "%s: (offload_type=%d, vdev_id=%d, enable=%d)",
1712 "IPA offload status is already set",
1713 offload_type, session_id, enable);
Yun Park8292dcb2016-10-07 16:46:06 -07001714 return;
1715 }
1716
Yun Park4540e862016-11-10 16:30:06 -08001717 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1718 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
1719 "invalid session id: %d, offload_type=%d, enable=%d",
1720 adapter->sessionId, offload_type, enable);
1721 return;
1722 }
1723
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301724 qdf_mem_zero(&ipa_offload_enable_disable,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725 sizeof(ipa_offload_enable_disable));
1726 ipa_offload_enable_disable.offload_type = offload_type;
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001727 ipa_offload_enable_disable.vdev_id = session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728 ipa_offload_enable_disable.enable = enable;
1729
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301730 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Yun Park8292dcb2016-10-07 16:46:06 -07001731 "offload_type=%d, vdev_id=%d, enable=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732 ipa_offload_enable_disable.offload_type,
1733 ipa_offload_enable_disable.vdev_id,
1734 ipa_offload_enable_disable.enable);
1735
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301736 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001737 sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter),
1738 adapter->sessionId, &ipa_offload_enable_disable)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301739 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Jeff Johnsona8a4f542016-11-08 10:56:53 -08001740 "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)",
1741 __func__,
1742 ipa_offload_enable_disable.offload_type,
1743 ipa_offload_enable_disable.vdev_id,
1744 ipa_offload_enable_disable.enable);
Yun Park8292dcb2016-10-07 16:46:06 -07001745 } else {
1746 /* Update the IPA offload status */
Prakash Dhavali89d406d2016-11-23 11:11:00 -08001747 hdd_ipa->vdev_offload_enabled[session_id] =
Yun Park8292dcb2016-10-07 16:46:06 -07001748 ipa_offload_enable_disable.enable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749 }
1750}
1751
1752/**
1753 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
1754 * @work: uC OP work
1755 *
1756 * Return: None
1757 */
1758static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work)
1759{
1760 struct op_msg_type *msg;
1761 struct uc_op_work_struct *uc_op_work = container_of(work,
1762 struct uc_op_work_struct, work);
1763 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
1764
1765 cds_ssr_protect(__func__);
1766
1767 msg = uc_op_work->msg;
1768 uc_op_work->msg = NULL;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301769 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770 "%s, posted msg %d", __func__, msg->op_code);
1771
1772 hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx);
1773
1774 cds_ssr_unprotect(__func__);
1775
1776 return;
1777}
1778
1779/**
1780 * hdd_ipa_uc_op_event_handler() - Adapter lookup
1781 * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
1782 * @op_msg: operation message received from firmware
1783 * @hdd_ctx: Global HDD context
1784 *
1785 * Return: None
1786 */
1787static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx)
1788{
1789 struct hdd_ipa_priv *hdd_ipa;
1790 struct op_msg_type *msg;
1791 struct uc_op_work_struct *uc_op_work;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301792 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793
1794 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301795 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001796 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001797
1798 msg = (struct op_msg_type *)op_msg;
1799 hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa;
1800
1801 if (unlikely(!hdd_ipa))
1802 goto end;
1803
1804 if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301805 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806 __func__, msg->op_code);
1807 goto end;
1808 }
1809
1810 uc_op_work = &hdd_ipa->uc_op_work[msg->op_code];
1811 if (uc_op_work->msg)
1812 /* When the same uC OPCODE is already pended, just return */
1813 goto end;
1814
1815 uc_op_work->msg = msg;
1816 schedule_work(&uc_op_work->work);
1817 return;
1818
1819end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301820 qdf_mem_free(op_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821}
1822
1823/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08001824 * hdd_ipa_init_uc_op_work - init ipa uc op work
1825 * @work: struct work_struct
1826 * @work_handler: work_handler
1827 *
1828 * Return: none
1829 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08001830static void hdd_ipa_init_uc_op_work(struct work_struct *work,
1831 work_func_t work_handler)
1832{
1833 INIT_WORK(work, work_handler);
1834}
Rajeev Kumar217f2172016-01-06 18:11:55 -08001835
1836
1837/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001838 * hdd_ipa_uc_ol_init() - Initialize IPA uC offload
1839 * @hdd_ctx: Global HDD context
1840 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301841 * Return: QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001842 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301843static QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844{
1845 struct ipa_wdi_in_params pipe_in;
1846 struct ipa_wdi_out_params pipe_out;
1847 struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1848 p_cds_contextType cds_ctx = hdd_ctx->pcds_context;
1849 uint8_t i;
Leo Changfdb45c32016-10-28 11:09:23 -07001850 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001851
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301852 qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params));
1853 qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854
Anurag Chouhanffb21542016-02-17 14:33:03 +05301855 qdf_list_create(&ipa_ctxt->pending_event, 1000);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301856 qdf_mutex_create(&ipa_ctxt->event_lock);
1857 qdf_mutex_create(&ipa_ctxt->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858
1859 /* TX PIPE */
1860 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
1861 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
1862 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
1863 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
1864 pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len =
1865 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
1866 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
1867 pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS;
1868 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize;
1869 pipe_in.sys.priv = hdd_ctx->hdd_ipa;
1870 pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
1871 pipe_in.sys.notify = hdd_ipa_i2w_cb;
1872 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301873 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001874 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
1875 pipe_in.sys.keep_ipa_awake = true;
1876 }
1877
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001878 pipe_in.u.dl.comp_ring_base_pa =
1879 ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08001880 pipe_in.u.dl.comp_ring_size =
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001881 ipa_ctxt->ipa_resource.tx_comp_ring_size *
1882 sizeof(qdf_dma_addr_t);
1883 pipe_in.u.dl.ce_ring_base_pa =
1884 ipa_ctxt->ipa_resource.ce_sr_base_paddr;
1885 pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr;
1886 pipe_in.u.dl.ce_ring_size =
1887 ipa_ctxt->ipa_resource.ce_sr_ring_size;
1888 pipe_in.u.dl.num_tx_buffers =
1889 ipa_ctxt->ipa_resource.tx_num_alloc_buffer;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001890
1891 /* Connect WDI IPA PIPE */
1892 ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
1893 /* Micro Controller Doorbell register */
Govind Singh0487bf22016-08-24 23:08:57 +05301894 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
1895 "%s CONS DB pipe out 0x%x TX PIPE Handle 0x%x",
1896 __func__, (unsigned int)pipe_out.uc_door_bell_pa,
1897 ipa_ctxt->tx_pipe_handle);
Leo Chang3bc8fed2015-11-13 10:59:47 -08001898 ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001899 /* WLAN TX PIPE Handle */
1900 ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301901 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001902 "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x,"
1903 " CERZ %d, NB %d, CDBPAD 0x%x",
1904 (unsigned int)pipe_in.u.dl.comp_ring_base_pa,
1905 pipe_in.u.dl.comp_ring_size,
1906 (unsigned int)pipe_in.u.dl.ce_ring_base_pa,
1907 (unsigned int)pipe_in.u.dl.ce_door_bell_pa,
1908 pipe_in.u.dl.ce_ring_size,
1909 pipe_in.u.dl.num_tx_buffers,
Leo Chang3bc8fed2015-11-13 10:59:47 -08001910 (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911
1912 /* RX PIPE */
1913 pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
1914 pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN;
1915 pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0;
1916 pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1;
1917 pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC;
1918 pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD;
1919 pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize +
1920 sizeof(struct sps_iovec);
1921 pipe_in.sys.notify = hdd_ipa_w2i_cb;
1922 if (!hdd_ipa_is_rm_enabled(hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301923 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001924 "%s: IPA RM DISABLED, IPA AWAKE", __func__);
1925 pipe_in.sys.keep_ipa_awake = true;
1926 }
1927
Dhanashri Atreb08959a2016-03-01 17:28:03 -08001928 pipe_in.u.ul.rdy_ring_base_pa =
1929 ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr;
1930 pipe_in.u.ul.rdy_ring_size =
1931 ipa_ctxt->ipa_resource.rx_rdy_ring_size;
1932 pipe_in.u.ul.rdy_ring_rp_pa =
1933 ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr;
Leo Chang3bc8fed2015-11-13 10:59:47 -08001934 HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001935 ipa_connect_wdi_pipe(&pipe_in, &pipe_out);
Leo Chang3bc8fed2015-11-13 10:59:47 -08001936 ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001937 ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301938 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001939 "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x",
1940 (unsigned int)pipe_in.u.ul.rdy_ring_base_pa,
1941 pipe_in.u.ul.rdy_ring_size,
1942 (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa,
Leo Chang3bc8fed2015-11-13 10:59:47 -08001943 (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001944
Leo Changfdb45c32016-10-28 11:09:23 -07001945 cdp_ipa_set_doorbell_paddr(soc, cds_ctx->pdev_txrx_ctx,
1946 ipa_ctxt->tx_comp_doorbell_paddr,
1947 ipa_ctxt->rx_ready_doorbell_paddr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948
Leo Changfdb45c32016-10-28 11:09:23 -07001949 cdp_ipa_register_op_cb(soc, cds_ctx->pdev_txrx_ctx,
1950 hdd_ipa_uc_op_event_handler, (void *)hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001951
1952 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
Rajeev Kumar217f2172016-01-06 18:11:55 -08001953 hdd_ipa_init_uc_op_work(&ipa_ctxt->uc_op_work[i].work,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 hdd_ipa_uc_fw_op_event_handler);
1955 ipa_ctxt->uc_op_work[i].msg = NULL;
1956 }
1957
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301958 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001959}
1960
Leo Change3e49442015-10-26 20:07:13 -07001961/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001962 * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
Leo Change3e49442015-10-26 20:07:13 -07001963 * @hdd_ctx: hdd main context
1964 *
1965 * Force shutdown IPA pipe
1966 * Independent of FW pipe status, IPA pipe shutdonw progress
1967 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
1968 * independent from FW pipe status
1969 *
1970 * Return: NONE
1971 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001972static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
Leo Change3e49442015-10-26 20:07:13 -07001973{
1974 struct hdd_ipa_priv *hdd_ipa;
1975
1976 if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
1977 return;
1978
1979 hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
1980 if (false == hdd_ipa->ipa_pipes_down) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301981 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Leo Change3e49442015-10-26 20:07:13 -07001982 "IPA pipes are not down yet, force shutdown");
1983 hdd_ipa_uc_disable_pipes(hdd_ipa);
1984 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301985 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Leo Change3e49442015-10-26 20:07:13 -07001986 "IPA pipes are down, do nothing");
1987 }
1988
1989 return;
1990}
1991
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001992/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07001993 * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for
1994 * __hdd_ipa_uc_force_pipe_shutdown
1995 * @hdd_ctx: hdd main context
1996 *
1997 * Force shutdown IPA pipe
1998 * Independent of FW pipe status, IPA pipe shutdonw progress
1999 * in case, any STA does not leave properly, IPA HW pipe should cleaned up
2000 * independent from FW pipe status
2001 *
2002 * Return: NONE
2003 */
2004void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
2005{
2006 cds_ssr_protect(__func__);
2007 __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
2008 cds_ssr_unprotect(__func__);
2009}
2010
2011/**
Govind Singh9c58eba2016-09-02 16:23:06 +05302012 * hdd_ipa_msg_free_fn() - Free an IPA message
2013 * @buff: pointer to the IPA message
2014 * @len: length of the IPA message
2015 * @type: type of IPA message
2016 *
2017 * Return: None
2018 */
2019static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
2020{
2021 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len);
2022 ghdd_ipa->stats.num_free_msg++;
2023 qdf_mem_free(buff);
2024}
2025
2026
2027/**
2028 * hdd_ipa_send_disconnect() - ipa send disconnect clients
2029 * adapter: pointer to hdd adapter
2030 * Send disconnect evnt to IPA driver during SSR
2031 *
2032 * Return: 0 - Success
2033 */
2034static int hdd_ipa_send_disconnect(hdd_adapter_t *adapter)
2035{
2036 struct ipa_msg_meta meta;
2037 struct ipa_wlan_msg *msg;
2038 int ret = 0;
2039 int i;
2040
2041 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
2042 if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA))
2043 continue;
2044 if ((adapter->aStaInfo[i].isUsed) &&
2045 (!adapter->aStaInfo[i].isDeauthInProgress)) {
2046 meta.msg_len = sizeof(struct ipa_wlan_msg);
2047 msg = qdf_mem_malloc(meta.msg_len);
2048 if (msg == NULL) {
2049 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2050 "msg allocation failed");
2051 return -ENOMEM;
2052 }
2053 meta.msg_type = WLAN_CLIENT_DISCONNECT;
2054 strlcpy(msg->name, adapter->dev->name,
2055 IPA_RESOURCE_NAME_MAX);
2056 memcpy(msg->mac_addr, adapter->aStaInfo[i].macAddrSTA.bytes,
2057 ETH_ALEN);
2058 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
2059 msg->name, meta.msg_type);
2060 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
2061 if (ret) {
2062 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2063 "%s: Evt: %d fail:%d",
2064 msg->name, meta.msg_type, ret);
2065 qdf_mem_free(msg);
2066 return ret;
2067 }
2068 }
2069 }
2070
2071 return ret;
2072}
2073
2074/**
2075 * hdd_ipa_uc_disconnect_client() - disconnect ipa sap clients
2076 * hdd_ctx: pointer to hdd context
2077 * Send disconnect evnt to IPA driver during SSR
2078 *
2079 * Return: 0 - Success
2080 */
2081static int hdd_ipa_uc_disconnect_client(hdd_context_t *hdd_ctx)
2082{
2083 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2084 QDF_STATUS status;
2085 hdd_adapter_t *adapter;
2086 int ret = 0;
2087
2088
2089 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
2090 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
2091 adapter = adapter_node->pAdapter;
2092 if (adapter->device_mode == QDF_SAP_MODE)
2093 hdd_ipa_send_disconnect(adapter);
2094 status = hdd_get_next_adapter(
2095 hdd_ctx, adapter_node, &next);
2096 adapter_node = next;
2097 }
2098
2099 return ret;
2100}
2101
2102/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002103 * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002104 *
2105 * Deinit basic IPA UC host side to be in sync reloaded FW during
2106 * SSR
2107 *
2108 * Return: 0 - Success
2109 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002110static int __hdd_ipa_uc_ssr_deinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002111{
2112 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2113 int idx;
2114 struct hdd_ipa_iface_context *iface_context;
2115
Leo Chang3bc8fed2015-11-13 10:59:47 -08002116 if ((!hdd_ipa) || (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002117 return 0;
2118
Govind Singh9c58eba2016-09-02 16:23:06 +05302119 /* send disconnect to ipa driver for connected clients */
2120 hdd_ipa_uc_disconnect_client(hdd_ipa->hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002121 /* Clean up HDD IPA interfaces */
2122 for (idx = 0; (hdd_ipa->num_iface > 0) &&
2123 (idx < HDD_IPA_MAX_IFACE); idx++) {
2124 iface_context = &hdd_ipa->iface_context[idx];
2125 if (iface_context && iface_context->adapter)
2126 hdd_ipa_cleanup_iface(iface_context);
2127 }
2128
2129 /* After SSR, wlan driver reloads FW again. But we need to protect
2130 * IPA submodule during SSR transient state. So deinit basic IPA
2131 * UC host side to be in sync with reloaded FW during SSR
2132 */
Yun Parkf7dc8cd2015-11-17 15:25:12 -08002133 if (!hdd_ipa->ipa_pipes_down)
2134 hdd_ipa_uc_disable_pipes(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002135
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302136 qdf_mutex_acquire(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002137 for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) {
2138 hdd_ipa->assoc_stas_map[idx].is_reserved = false;
2139 hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF;
2140 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302141 qdf_mutex_release(&hdd_ipa->ipa_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002142
Guolei Bianca144d82016-11-10 11:07:42 +08002143 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
2144 hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa);
2145
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146 /* Full IPA driver cleanup not required since wlan driver is now
2147 * unloaded and reloaded after SSR.
2148 */
2149 return 0;
2150}
2151
2152/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002153 * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit
2154 *
2155 * Deinit basic IPA UC host side to be in sync reloaded FW during
2156 * SSR
2157 *
2158 * Return: 0 - Success
2159 */
2160int hdd_ipa_uc_ssr_deinit(void)
2161{
2162 int ret;
2163
2164 cds_ssr_protect(__func__);
2165 ret = __hdd_ipa_uc_ssr_deinit();
2166 cds_ssr_unprotect(__func__);
2167
2168 return ret;
2169}
2170
2171/**
2172 * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002173 *
2174 * Init basic IPA UC host side to be in sync with reloaded FW after
2175 * SSR to resume IPA UC operations
2176 *
2177 * Return: 0 - Success
2178 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002179static int __hdd_ipa_uc_ssr_reinit(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002180{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002181
2182 /* After SSR is complete, IPA UC can resume operation. But now wlan
2183 * driver will be unloaded and reloaded, which takes care of IPA cleanup
2184 * and initialization. This is a placeholder func if IPA has to resume
2185 * operations without driver reload.
2186 */
2187 return 0;
2188}
Leo Chang3bc8fed2015-11-13 10:59:47 -08002189
2190/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002191 * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit
2192 *
2193 * Init basic IPA UC host side to be in sync with reloaded FW after
2194 * SSR to resume IPA UC operations
2195 *
2196 * Return: 0 - Success
2197 */
2198int hdd_ipa_uc_ssr_reinit(void)
2199{
2200 int ret;
2201
2202 cds_ssr_protect(__func__);
2203 ret = __hdd_ipa_uc_ssr_reinit();
2204 cds_ssr_unprotect(__func__);
2205
2206 return ret;
2207}
2208
2209/**
2210 * __hdd_ipa_tx_packet_ipa() - send packet to IPA
Leo Chang3bc8fed2015-11-13 10:59:47 -08002211 * @hdd_ctx: Global HDD context
2212 * @skb: skb sent to IPA
2213 * @session_id: send packet instance session id
2214 *
2215 * Send TX packet which generated by system to IPA.
2216 * This routine only will be used for function verification
2217 *
2218 * Return: NULL packet sent to IPA properly
2219 * NULL invalid packet drop
2220 * skb packet not sent to IPA. legacy data path should handle
2221 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002222static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
Leo Chang3bc8fed2015-11-13 10:59:47 -08002223 struct sk_buff *skb, uint8_t session_id)
Leo Change3e49442015-10-26 20:07:13 -07002224{
Leo Chang3bc8fed2015-11-13 10:59:47 -08002225 struct ipa_header *ipa_header;
2226 struct frag_header *frag_header;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002227 struct hdd_ipa_priv *hdd_ipa;
2228
2229 if (wlan_hdd_validate_context(hdd_ctx))
2230 return skb;
2231
2232 hdd_ipa = hdd_ctx->hdd_ipa;
Leo Chang3bc8fed2015-11-13 10:59:47 -08002233
2234 if (!hdd_ipa_uc_is_enabled(hdd_ctx))
2235 return skb;
2236
Leo Chang07b28f62016-05-11 12:29:22 -07002237 if (!hdd_ipa)
2238 return skb;
2239
2240 if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe)
2241 return skb;
2242
Leo Changcc923e22016-06-16 15:29:03 -07002243 if (skb_headroom(skb) <
2244 (sizeof(struct ipa_header) + sizeof(struct frag_header)))
Leo Chang07b28f62016-05-11 12:29:22 -07002245 return skb;
2246
Leo Chang3bc8fed2015-11-13 10:59:47 -08002247 ipa_header = (struct ipa_header *) skb_push(skb,
2248 sizeof(struct ipa_header));
2249 if (!ipa_header) {
2250 /* No headroom, legacy */
2251 return skb;
2252 }
2253 memset(ipa_header, 0, sizeof(*ipa_header));
2254 ipa_header->vdev_id = 0;
2255
2256 frag_header = (struct frag_header *) skb_push(skb,
2257 sizeof(struct frag_header));
2258 if (!frag_header) {
2259 /* No headroom, drop */
2260 kfree_skb(skb);
2261 return NULL;
2262 }
2263 memset(frag_header, 0, sizeof(*frag_header));
2264 frag_header->length = skb->len - sizeof(struct frag_header)
2265 - sizeof(struct ipa_header);
2266
2267 ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL);
2268 return NULL;
Leo Change3e49442015-10-26 20:07:13 -07002269}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002270
2271/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002272 * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa
2273 * @hdd_ctx: Global HDD context
2274 * @skb: skb sent to IPA
2275 * @session_id: send packet instance session id
2276 *
2277 * Send TX packet which generated by system to IPA.
2278 * This routine only will be used for function verification
2279 *
2280 * Return: NULL packet sent to IPA properly
2281 * NULL invalid packet drop
2282 * skb packet not sent to IPA. legacy data path should handle
2283 */
2284struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx,
2285 struct sk_buff *skb, uint8_t session_id)
2286{
2287 struct sk_buff *ret;
2288
2289 cds_ssr_protect(__func__);
2290 ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id);
2291 cds_ssr_unprotect(__func__);
2292
2293 return ret;
2294}
2295
2296/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002297 * hdd_ipa_wake_lock_timer_func() - Wake lock work handler
2298 * @work: scheduled work
2299 *
2300 * When IPA resources are released in hdd_ipa_rm_try_release() we do
2301 * not want to immediately release the wake lock since the system
2302 * would then potentially try to suspend when there is a healthy data
2303 * rate. Deferred work is scheduled and this function handles the
2304 * work. When this function is called, if the IPA resource is still
2305 * released then we release the wake lock.
2306 *
2307 * Return: None
2308 */
2309static void hdd_ipa_wake_lock_timer_func(struct work_struct *work)
2310{
2311 struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work),
2312 struct hdd_ipa_priv,
2313 wake_lock_work);
2314
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302315 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002316
2317 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED)
2318 goto end;
2319
2320 hdd_ipa->wake_lock_released = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302321 qdf_wake_lock_release(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322 WIFI_POWER_EVENT_WAKELOCK_IPA);
2323
2324end:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302325 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002326}
2327
2328/**
2329 * hdd_ipa_rm_request() - Request resource from IPA
2330 * @hdd_ipa: Global HDD IPA context
2331 *
2332 * Return: 0 on success, negative errno on error
2333 */
2334static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa)
2335{
2336 int ret = 0;
2337
2338 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2339 return 0;
2340
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302341 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002342
2343 switch (hdd_ipa->rm_state) {
2344 case HDD_IPA_RM_GRANTED:
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 0;
2347 case HDD_IPA_RM_GRANT_PENDING:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302348 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002349 return -EINPROGRESS;
2350 case HDD_IPA_RM_RELEASED:
2351 hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING;
2352 break;
2353 }
2354
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302355 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002356
2357 ret = ipa_rm_inactivity_timer_request_resource(
2358 IPA_RM_RESOURCE_WLAN_PROD);
2359
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302360 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002361 if (ret == 0) {
2362 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
2363 hdd_ipa->stats.num_rm_grant_imm++;
2364 }
2365
2366 cancel_delayed_work(&hdd_ipa->wake_lock_work);
2367 if (hdd_ipa->wake_lock_released) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302368 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002369 WIFI_POWER_EVENT_WAKELOCK_IPA);
2370 hdd_ipa->wake_lock_released = false;
2371 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302372 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373
2374 return ret;
2375}
2376
2377/**
2378 * hdd_ipa_rm_try_release() - Attempt to release IPA resource
2379 * @hdd_ipa: Global HDD IPA context
2380 *
2381 * Return: 0 if resources released, negative errno otherwise
2382 */
2383static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
2384{
2385 int ret = 0;
2386
2387 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2388 return 0;
2389
2390 if (atomic_read(&hdd_ipa->tx_ref_cnt))
2391 return -EAGAIN;
2392
2393 spin_lock_bh(&hdd_ipa->q_lock);
2394 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
2395 (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
2396 spin_unlock_bh(&hdd_ipa->q_lock);
2397 return -EAGAIN;
2398 }
2399 spin_unlock_bh(&hdd_ipa->q_lock);
2400
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302401 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002402
Nirav Shahcbc6d722016-03-01 16:24:53 +05302403 if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302404 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002405 return -EAGAIN;
2406 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302407 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002408
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302409 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002410 switch (hdd_ipa->rm_state) {
2411 case HDD_IPA_RM_GRANTED:
2412 break;
2413 case HDD_IPA_RM_GRANT_PENDING:
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 -EINPROGRESS;
2416 case HDD_IPA_RM_RELEASED:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302417 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002418 return 0;
2419 }
2420
2421 /* IPA driver returns immediately so set the state here to avoid any
2422 * race condition.
2423 */
2424 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
2425 hdd_ipa->stats.num_rm_release++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302426 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002427
2428 ret =
2429 ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
2430
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302431 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 if (unlikely(ret != 0)) {
2433 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
2434 WARN_ON(1);
2435 }
2436
2437 /*
2438 * If wake_lock is released immediately, kernel would try to suspend
2439 * immediately as well, Just avoid ping-pong between suspend-resume
2440 * while there is healthy amount of data transfer going on by
2441 * releasing the wake_lock after some delay.
2442 */
2443 schedule_delayed_work(&hdd_ipa->wake_lock_work,
2444 msecs_to_jiffies
2445 (HDD_IPA_RX_INACTIVITY_MSEC_DELAY));
2446
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302447 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002448
2449 return ret;
2450}
2451
2452/**
2453 * hdd_ipa_rm_notify() - IPA resource manager notifier callback
2454 * @user_data: user data registered with IPA
2455 * @event: the IPA resource manager event that occurred
2456 * @data: the data associated with the event
2457 *
2458 * Return: None
2459 */
2460static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
2461 unsigned long data)
2462{
2463 struct hdd_ipa_priv *hdd_ipa = user_data;
2464
2465 if (unlikely(!hdd_ipa))
2466 return;
2467
2468 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2469 return;
2470
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302471 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002472
2473 switch (event) {
2474 case IPA_RM_RESOURCE_GRANTED:
2475 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2476 /* RM Notification comes with ISR context
2477 * it should be serialized into work queue to avoid
2478 * ISR sleep problem
2479 */
2480 hdd_ipa->uc_rm_work.event = event;
2481 schedule_work(&hdd_ipa->uc_rm_work.work);
2482 break;
2483 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302484 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002485 hdd_ipa->rm_state = HDD_IPA_RM_GRANTED;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302486 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002487 hdd_ipa->stats.num_rm_grant++;
2488 break;
2489
2490 case IPA_RM_RESOURCE_RELEASED:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302491 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002492 hdd_ipa->resource_unloading = false;
2493 break;
2494
2495 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302496 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002497 break;
2498 }
2499}
2500
2501/**
2502 * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler
2503 *
2504 * Callback function registered with IPA that is called when IPA wants
2505 * to release the WLAN consumer resource
2506 *
2507 * Return: 0 if the request is granted, negative errno otherwise
2508 */
2509static int hdd_ipa_rm_cons_release(void)
2510{
2511 return 0;
2512}
2513
2514/**
2515 * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler
2516 *
2517 * Callback function registered with IPA that is called when IPA wants
2518 * to access the WLAN consumer resource
2519 *
2520 * Return: 0 if the request is granted, negative errno otherwise
2521 */
2522static int hdd_ipa_rm_cons_request(void)
2523{
Yun Park4d8b60a2015-10-22 13:59:32 -07002524 int ret = 0;
2525
2526 if (ghdd_ipa->resource_loading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302527 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07002528 "%s: IPA resource loading in progress",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002529 __func__);
2530 ghdd_ipa->pending_cons_req = true;
Yun Park4d8b60a2015-10-22 13:59:32 -07002531 ret = -EINPROGRESS;
2532 } else if (ghdd_ipa->resource_unloading) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302533 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Yun Park4d8b60a2015-10-22 13:59:32 -07002534 "%s: IPA resource unloading in progress",
2535 __func__);
2536 ghdd_ipa->pending_cons_req = true;
2537 ret = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002538 }
Yun Park4d8b60a2015-10-22 13:59:32 -07002539
2540 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002541}
2542
2543/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002544 * __hdd_ipa_set_perf_level() - Set IPA performance level
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002545 * @hdd_ctx: Global HDD context
2546 * @tx_packets: Number of packets transmitted in the last sample period
2547 * @rx_packets: Number of packets received in the last sample period
2548 *
2549 * Return: 0 on success, negative errno on error
2550 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002551static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002552 uint64_t rx_packets)
2553{
2554 uint32_t next_cons_bw, next_prod_bw;
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002555 struct hdd_ipa_priv *hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002556 struct ipa_rm_perf_profile profile;
2557 int ret;
2558
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002559 if (wlan_hdd_validate_context(hdd_ctx))
2560 return 0;
2561
2562 hdd_ipa = hdd_ctx->hdd_ipa;
2563
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002564 if ((!hdd_ipa_is_enabled(hdd_ctx)) ||
2565 (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)))
2566 return 0;
2567
2568 memset(&profile, 0, sizeof(profile));
2569
2570 if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
2571 next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps;
2572 else if (tx_packets >
2573 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
2574 next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
2575 else
2576 next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps;
2577
2578 if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2))
2579 next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps;
2580 else if (rx_packets >
2581 (hdd_ctx->config->busBandwidthMediumThreshold / 2))
2582 next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps;
2583 else
2584 next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps;
2585
Yun Park8f289c82016-10-18 16:38:21 -07002586 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002587 "CONS perf curr: %d, next: %d",
2588 hdd_ipa->curr_cons_bw, next_cons_bw);
Yun Park8f289c82016-10-18 16:38:21 -07002589 HDD_IPA_LOG(LOGOFF,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002590 "PROD perf curr: %d, next: %d",
2591 hdd_ipa->curr_prod_bw, next_prod_bw);
2592
2593 if (hdd_ipa->curr_cons_bw != next_cons_bw) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302594 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002595 "Requesting CONS perf curr: %d, next: %d",
2596 hdd_ipa->curr_cons_bw, next_cons_bw);
2597 profile.max_supported_bandwidth_mbps = next_cons_bw;
2598 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS,
2599 &profile);
2600 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302601 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002602 "RM CONS set perf profile failed: %d", ret);
2603
2604 return ret;
2605 }
2606 hdd_ipa->curr_cons_bw = next_cons_bw;
2607 hdd_ipa->stats.num_cons_perf_req++;
2608 }
2609
2610 if (hdd_ipa->curr_prod_bw != next_prod_bw) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302611 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612 "Requesting PROD perf curr: %d, next: %d",
2613 hdd_ipa->curr_prod_bw, next_prod_bw);
2614 profile.max_supported_bandwidth_mbps = next_prod_bw;
2615 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD,
2616 &profile);
2617 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302618 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002619 "RM PROD set perf profile failed: %d", ret);
2620 return ret;
2621 }
2622 hdd_ipa->curr_prod_bw = next_prod_bw;
2623 hdd_ipa->stats.num_prod_perf_req++;
2624 }
2625
2626 return 0;
2627}
2628
2629/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07002630 * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level
2631 * @hdd_ctx: Global HDD context
2632 * @tx_packets: Number of packets transmitted in the last sample period
2633 * @rx_packets: Number of packets received in the last sample period
2634 *
2635 * Return: 0 on success, negative errno on error
2636 */
2637int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets,
2638 uint64_t rx_packets)
2639{
2640 int ret;
2641
2642 cds_ssr_protect(__func__);
2643 ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets);
2644 cds_ssr_unprotect(__func__);
2645
2646 return ret;
2647}
2648
2649/**
Rajeev Kumar217f2172016-01-06 18:11:55 -08002650 * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work
2651 * @work: struct work_struct
2652 * @work_handler: work_handler
2653 *
2654 * Return: none
2655 */
Rajeev Kumar217f2172016-01-06 18:11:55 -08002656static void hdd_ipa_init_uc_rm_work(struct work_struct *work,
2657 work_func_t work_handler)
2658{
2659 INIT_WORK(work, work_handler);
2660}
Rajeev Kumar217f2172016-01-06 18:11:55 -08002661
2662/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663 * hdd_ipa_setup_rm() - Setup IPA resource management
2664 * @hdd_ipa: Global HDD IPA context
2665 *
2666 * Return: 0 on success, negative errno on error
2667 */
2668static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa)
2669{
2670 struct ipa_rm_create_params create_params = { 0 };
2671 int ret;
2672
2673 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2674 return 0;
2675
Rajeev Kumar217f2172016-01-06 18:11:55 -08002676 hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work,
2677 hdd_ipa_uc_rm_notify_defer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002678 memset(&create_params, 0, sizeof(create_params));
2679 create_params.name = IPA_RM_RESOURCE_WLAN_PROD;
2680 create_params.reg_params.user_data = hdd_ipa;
2681 create_params.reg_params.notify_cb = hdd_ipa_rm_notify;
2682 create_params.floor_voltage = IPA_VOLTAGE_SVS;
2683
2684 ret = ipa_rm_create_resource(&create_params);
2685 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302686 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002687 "Create RM resource failed: %d", ret);
2688 goto setup_rm_fail;
2689 }
2690
2691 memset(&create_params, 0, sizeof(create_params));
2692 create_params.name = IPA_RM_RESOURCE_WLAN_CONS;
2693 create_params.request_resource = hdd_ipa_rm_cons_request;
2694 create_params.release_resource = hdd_ipa_rm_cons_release;
2695 create_params.floor_voltage = IPA_VOLTAGE_SVS;
2696
2697 ret = ipa_rm_create_resource(&create_params);
2698 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302699 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002700 "Create RM CONS resource failed: %d", ret);
2701 goto delete_prod;
2702 }
2703
2704 ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
2705 IPA_RM_RESOURCE_APPS_CONS);
2706
2707 ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD,
2708 HDD_IPA_RX_INACTIVITY_MSEC_DELAY);
2709 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302710 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002711 ret);
2712 goto timer_init_failed;
2713 }
2714
2715 /* Set the lowest bandwidth to start with */
2716 ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0);
2717
2718 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302719 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720 "Set perf level failed: %d", ret);
2721 goto set_perf_failed;
2722 }
2723
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302724 qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002725 INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work,
2726 hdd_ipa_wake_lock_timer_func);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302727 qdf_spinlock_create(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002728 hdd_ipa->rm_state = HDD_IPA_RM_RELEASED;
2729 hdd_ipa->wake_lock_released = true;
2730 atomic_set(&hdd_ipa->tx_ref_cnt, 0);
2731
2732 return ret;
2733
2734set_perf_failed:
2735 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
2736
2737timer_init_failed:
2738 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
2739
2740delete_prod:
2741 ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
2742
2743setup_rm_fail:
2744 return ret;
2745}
2746
2747/**
2748 * hdd_ipa_destroy_rm_resource() - Destroy IPA resources
2749 * @hdd_ipa: Global HDD IPA context
2750 *
2751 * Destroys all resources associated with the IPA resource manager
2752 *
2753 * Return: None
2754 */
2755static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa)
2756{
2757 int ret;
2758
2759 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
2760 return;
2761
2762 cancel_delayed_work_sync(&hdd_ipa->wake_lock_work);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302763 qdf_wake_lock_destroy(&hdd_ipa->wake_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002764
2765#ifdef WLAN_OPEN_SOURCE
2766 cancel_work_sync(&hdd_ipa->uc_rm_work.work);
2767#endif
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302768 qdf_spinlock_destroy(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002769
2770 ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD);
2771
2772 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
2773 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302774 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002775 "RM PROD resource delete failed %d", ret);
2776
2777 ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
2778 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302779 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002780 "RM CONS resource delete failed %d", ret);
2781}
2782
2783/**
2784 * hdd_ipa_send_skb_to_network() - Send skb to kernel
2785 * @skb: network buffer
2786 * @adapter: network adapter
2787 *
2788 * Called when a network buffer is received which should not be routed
2789 * to the IPA module.
2790 *
2791 * Return: None
2792 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05302793static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002794 hdd_adapter_t *adapter)
2795{
2796 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
2797 unsigned int cpu_index;
2798
2799 if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302800 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002801 adapter);
2802 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07002803 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002804 return;
2805 }
2806
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002807 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002808 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07002809 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002810 return;
2811 }
2812
2813 skb->destructor = hdd_ipa_uc_rt_debug_destructor;
2814 skb->dev = adapter->dev;
2815 skb->protocol = eth_type_trans(skb, skb->dev);
2816 skb->ip_summed = CHECKSUM_NONE;
2817
2818 cpu_index = wlan_hdd_get_cpu();
2819
2820 ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];
2821 if (netif_rx_ni(skb) == NET_RX_SUCCESS)
2822 ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index];
2823 else
2824 ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index];
2825
2826 HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa);
2827 adapter->dev->last_rx = jiffies;
2828}
2829
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002830/**
Leo Chang69c39692016-10-12 20:11:12 -07002831 * hdd_ipa_forward() - handle packet forwarding to wlan tx
2832 * @hdd_ipa: pointer to hdd ipa context
2833 * @adapter: network adapter
2834 * @skb: data pointer
2835 *
2836 * if exception packet has set forward bit, copied new packet should be
2837 * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
2838 * put into pm queue and tx procedure will be differed
2839 *
2840 * Return: None
2841 */
Jeff Johnson414f7ea2016-10-19 18:50:02 -07002842static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa,
2843 hdd_adapter_t *adapter, qdf_nbuf_t skb)
Leo Chang69c39692016-10-12 20:11:12 -07002844{
Leo Chang69c39692016-10-12 20:11:12 -07002845 struct hdd_ipa_pm_tx_cb *pm_tx_cb;
2846
Leo Chang69c39692016-10-12 20:11:12 -07002847 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
2848 /* WLAN subsystem is in suspend, put int queue */
2849 if (hdd_ipa->suspended) {
2850 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
2851 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2852 "TX in SUSPEND PUT QUEUE");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002853 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
2854 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Leo Chang69c39692016-10-12 20:11:12 -07002855 pm_tx_cb->exception = true;
2856 pm_tx_cb->adapter = adapter;
2857 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002858 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Leo Chang69c39692016-10-12 20:11:12 -07002859 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
2860 hdd_ipa->stats.num_tx_queued++;
2861 } else {
2862 /* Resume, put packet into WLAN TX */
2863 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002864 if (hdd_softap_hard_start_xmit(skb, adapter->dev)) {
Leo Chang69c39692016-10-12 20:11:12 -07002865 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2866 "packet tx fail");
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002867 hdd_ipa->stats.num_tx_bcmc_err++;
Leo Chang69c39692016-10-12 20:11:12 -07002868 } else {
2869 hdd_ipa->stats.num_tx_bcmc++;
2870 hdd_ipa->ipa_tx_forward++;
2871 }
2872 }
2873}
2874
2875/**
Prakash Dhavali87b38e32016-11-14 16:22:53 -08002876 * hdd_ipa_intrabss_forward() - Forward intra bss packets.
2877 * @hdd_ipa: pointer to HDD IPA struct
2878 * @adapter: hdd adapter pointer
2879 * @desc: Firmware descriptor
2880 * @skb: Data buffer
2881 *
2882 * Return:
2883 * HDD_IPA_FORWARD_PKT_NONE
2884 * HDD_IPA_FORWARD_PKT_DISCARD
2885 * HDD_IPA_FORWARD_PKT_LOCAL_STACK
2886 *
2887 */
2888
2889static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward(
2890 struct hdd_ipa_priv *hdd_ipa,
2891 hdd_adapter_t *adapter,
2892 uint8_t desc,
2893 qdf_nbuf_t skb)
2894{
2895 int ret = HDD_IPA_FORWARD_PKT_NONE;
2896
2897 if ((desc & FW_RX_DESC_FORWARD_M)) {
2898 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
2899 "Forward packet to Tx (fw_desc=%d)", desc);
2900 hdd_ipa->ipa_tx_forward++;
2901
2902 if ((desc & FW_RX_DESC_DISCARD_M)) {
2903 hdd_ipa_forward(hdd_ipa, adapter, skb);
2904 hdd_ipa->ipa_rx_internel_drop_count++;
2905 hdd_ipa->ipa_rx_discard++;
2906 ret = HDD_IPA_FORWARD_PKT_DISCARD;
2907 } else {
2908 struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
2909 if (cloned_skb)
2910 hdd_ipa_forward(hdd_ipa, adapter, cloned_skb);
2911 else
2912 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2913 "%s: tx skb alloc failed",
2914 __func__);
2915 ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK;
2916 }
2917 }
2918
2919 return ret;
2920}
2921
2922/**
Leo Chang69c39692016-10-12 20:11:12 -07002923 * hdd_ipa_w2i_cb() - WLAN to IPA callback handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002924 * @priv: pointer to private data registered with IPA (we register a
2925 * pointer to the global IPA context)
2926 * @evt: the IPA event which triggered the callback
2927 * @data: data associated with the event
2928 *
2929 * Return: None
2930 */
Yun Parkf8d6a122016-10-11 15:49:43 -07002931static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002932 unsigned long data)
2933{
2934 struct hdd_ipa_priv *hdd_ipa = NULL;
2935 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05302936 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002937 uint8_t iface_id;
2938 uint8_t session_id;
2939 struct hdd_ipa_iface_context *iface_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002940 uint8_t fw_desc;
Yun Parkf8d6a122016-10-11 15:49:43 -07002941 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002942
2943 hdd_ipa = (struct hdd_ipa_priv *)priv;
2944
Prakash Dhavali63f8fd62016-11-14 14:40:42 -08002945 if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx))
2946 return;
2947
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002948 switch (evt) {
2949 case IPA_RECEIVE:
Nirav Shahcbc6d722016-03-01 16:24:53 +05302950 skb = (qdf_nbuf_t) data;
Yun Parkf8d6a122016-10-11 15:49:43 -07002951
2952 /*
2953 * When SSR is going on or driver is unloading,
2954 * just drop the packets.
2955 */
2956 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
2957 if (0 != status) {
2958 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
2959 "Invalid context: drop packet");
2960 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
2961 kfree_skb(skb);
2962 return;
2963 }
2964
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002965 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2966 session_id = (uint8_t)skb->cb[0];
Prakash Dhavali89d406d2016-11-23 11:11:00 -08002967 iface_id = hdd_ipa->vdev_to_iface[session_id];
Govind Singhb6a89772016-08-12 11:23:35 +05302968 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002969 "IPA_RECEIVE: session_id=%u, iface_id=%u",
2970 session_id, iface_id);
2971 } else {
2972 iface_id = HDD_IPA_GET_IFACE_ID(skb->data);
2973 }
2974
2975 if (iface_id >= HDD_IPA_MAX_IFACE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302976 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002977 "IPA_RECEIVE: Invalid iface_id: %u",
2978 iface_id);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302979 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002980 "w2i -- skb", skb->data, 8);
2981 HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa);
Yun Parkf8d6a122016-10-11 15:49:43 -07002982 kfree_skb(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002983 return;
2984 }
2985
2986 iface_context = &hdd_ipa->iface_context[iface_id];
2987 adapter = iface_context->adapter;
2988
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302989 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002990 "w2i -- skb", skb->data, 8);
2991 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
2992 hdd_ipa->stats.num_rx_excep++;
2993 skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN);
2994 } else {
2995 skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN);
2996 }
2997
2998 iface_context->stats.num_rx_ipa_excep++;
2999
3000 /* Disable to forward Intra-BSS Rx packets when
3001 * ap_isolate=1 in hostapd.conf
3002 */
Yun Park046101c2016-09-02 15:32:14 -07003003 if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003004 /*
3005 * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send
3006 * all Rx packets to IPA uC, which need to be forwarded
3007 * to other interface.
3008 * And, IPA driver will send back to WLAN host driver
3009 * through exception pipe with fw_desc field set by FW.
3010 * Here we are checking fw_desc field for FORWARD bit
3011 * set, and forward to Tx. Then copy to kernel stack
3012 * only when DISCARD bit is not set.
3013 */
3014 fw_desc = (uint8_t)skb->cb[1];
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003015 if (HDD_IPA_FORWARD_PKT_DISCARD ==
3016 hdd_ipa_intrabss_forward(hdd_ipa, adapter,
3017 fw_desc, skb))
Mahesh Kumar Kalikot Veetil221dc672015-11-06 14:27:28 -08003018 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003019 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303020 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003021 "Intra-BSS FWD is disabled-skip forward to Tx");
3022 }
3023
3024 hdd_ipa_send_skb_to_network(skb, adapter);
3025 break;
3026
3027 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303028 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003029 "w2i cb wrong event: 0x%x", evt);
3030 return;
3031 }
3032}
3033
3034/**
Yun Parkf8d6a122016-10-11 15:49:43 -07003035 * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb
3036 * @priv: pointer to private data registered with IPA (we register a
3037 * pointer to the global IPA context)
3038 * @evt: the IPA event which triggered the callback
3039 * @data: data associated with the event
3040 *
3041 * Return: None
3042 */
3043static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
3044 unsigned long data)
3045{
3046 cds_ssr_protect(__func__);
3047 __hdd_ipa_w2i_cb(priv, evt, data);
3048 cds_ssr_unprotect(__func__);
3049}
3050
3051/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003052 * hdd_ipa_nbuf_cb() - IPA TX complete callback
3053 * @skb: packet buffer which was transmitted
3054 *
3055 * Return: None
3056 */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303057void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003058{
3059 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3060
Govind Singhb6a89772016-08-12 11:23:35 +05303061 HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
Nirav Shahcbc6d722016-03-01 16:24:53 +05303062 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003063 /* FIXME: This is broken; PRIV_DATA is now 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303064 ipa_free_skb((struct ipa_rx_data *)
3065 wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003066
3067 hdd_ipa->stats.num_tx_comp_cnt++;
3068
3069 atomic_dec(&hdd_ipa->tx_ref_cnt);
3070
3071 hdd_ipa_rm_try_release(hdd_ipa);
3072}
3073
3074/**
3075 * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL
3076 * @iface_context: interface-specific IPA context
3077 * @ipa_tx_desc: packet data descriptor
3078 *
3079 * Return: None
3080 */
3081static void hdd_ipa_send_pkt_to_tl(
3082 struct hdd_ipa_iface_context *iface_context,
3083 struct ipa_rx_data *ipa_tx_desc)
3084{
3085 struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003086 hdd_adapter_t *adapter = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303087 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003088
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303089 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090 adapter = iface_context->adapter;
3091 if (!adapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303092 HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003093 ipa_free_skb(ipa_tx_desc);
3094 iface_context->stats.num_tx_drop++;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303095 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003096 hdd_ipa_rm_try_release(hdd_ipa);
3097 return;
3098 }
3099
3100 /*
3101 * During CAC period, data packets shouldn't be sent over the air so
3102 * drop all the packets here
3103 */
3104 if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) {
3105 ipa_free_skb(ipa_tx_desc);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303106 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003107 iface_context->stats.num_tx_cac_drop++;
3108 hdd_ipa_rm_try_release(hdd_ipa);
3109 return;
3110 }
3111
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003112 ++adapter->stats.tx_packets;
3113
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303114 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115
3116 skb = ipa_tx_desc->skb;
3117
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303118 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303119 qdf_nbuf_ipa_owned_set(skb);
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003120 /* FIXME: This is broken. No such field in cb any more:
3121 NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb; */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003122 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
Nirav Shahcbc6d722016-03-01 16:24:53 +05303123 qdf_nbuf_mapped_paddr_set(skb,
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003124 ipa_tx_desc->dma_addr
3125 + HDD_IPA_WLAN_FRAG_HEADER
3126 + HDD_IPA_WLAN_IPA_HEADER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003127 ipa_tx_desc->skb->len -=
3128 HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER;
3129 } else
Nirav Shahcbc6d722016-03-01 16:24:53 +05303130 qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003131
Houston Hoffman43d47fa2016-02-24 16:34:30 -08003132 /* FIXME: This is broken: priv_data is 31 bits */
Nirav Shahcbc6d722016-03-01 16:24:53 +05303133 qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003134
3135 adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
3136
Leo Changfdb45c32016-10-28 11:09:23 -07003137 skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC),
3138 iface_context->tl_context, ipa_tx_desc->skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003139 if (skb) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303140 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003141 ipa_free_skb(ipa_tx_desc);
3142 iface_context->stats.num_tx_err++;
3143 hdd_ipa_rm_try_release(hdd_ipa);
3144 return;
3145 }
3146
3147 atomic_inc(&hdd_ipa->tx_ref_cnt);
3148
3149 iface_context->stats.num_tx++;
3150
3151}
3152
3153/**
Leo Chang11545d62016-10-17 14:53:50 -07003154 * hdd_ipa_is_present() - get IPA hw status
3155 * @hdd_ctx: pointer to hdd context
3156 *
3157 * ipa_uc_reg_rdyCB is not directly designed to check
3158 * ipa hw status. This is an undocumented function which
3159 * has confirmed with IPA team.
3160 *
3161 * Return: true - ipa hw present
3162 * false - ipa hw not present
3163 */
3164bool hdd_ipa_is_present(hdd_context_t *hdd_ctx)
3165{
3166 /* Check if ipa hw is enabled */
Leo Chang63d73612016-10-18 18:09:43 -07003167 if (HDD_IPA_CHECK_HW() != -EPERM)
Leo Chang11545d62016-10-17 14:53:50 -07003168 return true;
3169 else
3170 return false;
3171}
3172
3173/**
Leo Chang69c39692016-10-12 20:11:12 -07003174 * hdd_ipa_pm_flush() - flush queued packets
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003175 * @work: pointer to the scheduled work
3176 *
3177 * Called during PM resume to send packets to TL which were queued
3178 * while host was in the process of suspending.
3179 *
3180 * Return: None
3181 */
Leo Chang69c39692016-10-12 20:11:12 -07003182static void hdd_ipa_pm_flush(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003183{
3184 struct hdd_ipa_priv *hdd_ipa = container_of(work,
3185 struct hdd_ipa_priv,
3186 pm_work);
3187 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303188 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003189 uint32_t dequeued = 0;
3190
Leo Chang69c39692016-10-12 20:11:12 -07003191 qdf_wake_lock_acquire(&hdd_ipa->wake_lock,
3192 WIFI_POWER_EVENT_WAKELOCK_IPA);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303193 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05303194 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
3195 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303196 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003197
3198 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003199 dequeued++;
Leo Chang69c39692016-10-12 20:11:12 -07003200 if (pm_tx_cb->exception) {
3201 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
3202 "FLUSH EXCEPTION");
3203 hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev);
3204 } else {
3205 hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003206 pm_tx_cb->ipa_tx_desc);
Leo Chang69c39692016-10-12 20:11:12 -07003207 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303208 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003209 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303210 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Leo Chang69c39692016-10-12 20:11:12 -07003211 qdf_wake_lock_release(&hdd_ipa->wake_lock,
3212 WIFI_POWER_EVENT_WAKELOCK_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003213
3214 hdd_ipa->stats.num_tx_dequeued += dequeued;
3215 if (dequeued > hdd_ipa->stats.num_max_pm_queue)
3216 hdd_ipa->stats.num_max_pm_queue = dequeued;
3217}
3218
3219/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003220 * __hdd_ipa_i2w_cb() - IPA to WLAN callback
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003221 * @priv: pointer to private data registered with IPA (we register a
3222 * pointer to the interface-specific IPA context)
3223 * @evt: the IPA event which triggered the callback
3224 * @data: data associated with the event
3225 *
3226 * Return: None
3227 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003228static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003229 unsigned long data)
3230{
3231 struct hdd_ipa_priv *hdd_ipa = NULL;
3232 struct ipa_rx_data *ipa_tx_desc;
3233 struct hdd_ipa_iface_context *iface_context;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303234 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003235 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303236 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003237
Mukul Sharma81661ae2015-10-30 20:26:02 +05303238 iface_context = (struct hdd_ipa_iface_context *)priv;
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003239 ipa_tx_desc = (struct ipa_rx_data *)data;
3240 hdd_ipa = iface_context->hdd_ipa;
3241
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003242 if (evt != IPA_RECEIVE) {
Prakash Dhavali87b38e32016-11-14 16:22:53 -08003243 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE");
3244 ipa_free_skb(ipa_tx_desc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003245 iface_context->stats.num_tx_drop++;
3246 return;
3247 }
3248
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003249 /*
3250 * When SSR is going on or driver is unloading, just drop the packets.
3251 * During SSR, there is no use in queueing the packets as STA has to
3252 * connect back any way
3253 */
3254 status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303255 if (status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003256 ipa_free_skb(ipa_tx_desc);
3257 iface_context->stats.num_tx_drop++;
3258 return;
3259 }
3260
3261 skb = ipa_tx_desc->skb;
3262
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303263 HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, "i2w", skb->data, 8);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003264
3265 /*
3266 * If PROD resource is not requested here then there may be cases where
3267 * IPA hardware may be clocked down because of not having proper
3268 * dependency graph between WLAN CONS and modem PROD pipes. Adding the
3269 * workaround to request PROD resource while data is going over CONS
3270 * pipe to prevent the IPA hardware clockdown.
3271 */
3272 hdd_ipa_rm_request(hdd_ipa);
3273
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303274 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003275 /*
3276 * If host is still suspended then queue the packets and these will be
3277 * drained later when resume completes. When packet is arrived here and
3278 * host is suspended, this means that there is already resume is in
3279 * progress.
3280 */
3281 if (hdd_ipa->suspended) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303282 qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
3284 pm_tx_cb->iface_context = iface_context;
3285 pm_tx_cb->ipa_tx_desc = ipa_tx_desc;
Nirav Shahcbc6d722016-03-01 16:24:53 +05303286 qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003287 hdd_ipa->stats.num_tx_queued++;
3288
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303289 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003290 return;
3291 }
3292
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303293 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003294
3295 /*
3296 * If we are here means, host is not suspended, wait for the work queue
3297 * to finish.
3298 */
3299#ifdef WLAN_OPEN_SOURCE
3300 flush_work(&hdd_ipa->pm_work);
3301#endif
3302
3303 return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
3304}
3305
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003306/*
3307 * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb
3308 * @priv: pointer to private data registered with IPA (we register a
3309 * pointer to the interface-specific IPA context)
3310 * @evt: the IPA event which triggered the callback
3311 * @data: data associated with the event
3312 *
3313 * Return: None
3314 */
3315static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt,
3316 unsigned long data)
3317{
3318 cds_ssr_protect(__func__);
3319 __hdd_ipa_i2w_cb(priv, evt, data);
3320 cds_ssr_unprotect(__func__);
3321}
3322
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003323/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003324 * __hdd_ipa_suspend() - Suspend IPA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003325 * @hdd_ctx: Global HDD context
3326 *
3327 * Return: 0 on success, negativer errno on error
3328 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003329static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003330{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003331 struct hdd_ipa_priv *hdd_ipa;
3332
3333 if (wlan_hdd_validate_context(hdd_ctx))
3334 return 0;
3335
3336 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003337
3338 if (!hdd_ipa_is_enabled(hdd_ctx))
3339 return 0;
3340
3341 /*
3342 * Check if IPA is ready for suspend, If we are here means, there is
3343 * high chance that suspend would go through but just to avoid any race
3344 * condition after suspend started, these checks are conducted before
3345 * allowing to suspend.
3346 */
3347 if (atomic_read(&hdd_ipa->tx_ref_cnt))
3348 return -EAGAIN;
3349
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303350 qdf_spin_lock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003351
3352 if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303353 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003354 return -EAGAIN;
3355 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303356 qdf_spin_unlock_bh(&hdd_ipa->rm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003357
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303358 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003359 hdd_ipa->suspended = true;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303360 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003361
3362 return 0;
3363}
3364
3365/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003366 * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend
3367 * @hdd_ctx: Global HDD context
3368 *
3369 * Return: 0 on success, negativer errno on error
3370 */
3371int hdd_ipa_suspend(hdd_context_t *hdd_ctx)
3372{
3373 int ret;
3374
3375 cds_ssr_protect(__func__);
3376 ret = __hdd_ipa_suspend(hdd_ctx);
3377 cds_ssr_unprotect(__func__);
3378
3379 return ret;
3380}
3381
3382/**
3383 * __hdd_ipa_resume() - Resume IPA following suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003384 * hdd_ctx: Global HDD context
3385 *
3386 * Return: 0 on success, negative errno on error
3387 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003388static int __hdd_ipa_resume(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003389{
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003390 struct hdd_ipa_priv *hdd_ipa;
3391
3392 if (wlan_hdd_validate_context(hdd_ctx))
3393 return 0;
3394
3395 hdd_ipa = hdd_ctx->hdd_ipa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003396
3397 if (!hdd_ipa_is_enabled(hdd_ctx))
3398 return 0;
3399
3400 schedule_work(&hdd_ipa->pm_work);
3401
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303402 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003403 hdd_ipa->suspended = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303404 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003405
3406 return 0;
3407}
3408
3409/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003410 * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume
3411 * hdd_ctx: Global HDD context
3412 *
3413 * Return: 0 on success, negative errno on error
3414 */
3415int hdd_ipa_resume(hdd_context_t *hdd_ctx)
3416{
3417 int ret;
3418
3419 cds_ssr_protect(__func__);
3420 ret = __hdd_ipa_resume(hdd_ctx);
3421 cds_ssr_unprotect(__func__);
3422
3423 return ret;
3424}
3425
3426/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003427 * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
3428 * @hdd_ipa: Global HDD IPA context
3429 *
3430 * Return: 0 on success, negative errno on error
3431 */
3432static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
3433{
3434 int i, ret = 0;
3435 struct ipa_sys_connect_params *ipa;
3436 uint32_t desc_fifo_sz;
3437
3438 /* The maximum number of descriptors that can be provided to a BAM at
3439 * once is one less than the total number of descriptors that the buffer
3440 * can contain.
3441 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
3442 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
3443 * be provided at once.
3444 * Because of above requirement, one extra descriptor will be added to
3445 * make sure hardware always has one descriptor.
3446 */
3447 desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize
3448 + sizeof(struct sps_iovec);
3449
3450 /*setup TX pipes */
3451 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3452 ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params;
3453
3454 ipa->client = hdd_ipa_adapter_2_client[i].cons_client;
3455 ipa->desc_fifo_sz = desc_fifo_sz;
3456 ipa->priv = &hdd_ipa->iface_context[i];
3457 ipa->notify = hdd_ipa_i2w_cb;
3458
3459 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
3460 ipa->ipa_ep_cfg.hdr.hdr_len =
3461 HDD_IPA_UC_WLAN_TX_HDR_LEN;
3462 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3463 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
3464 ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
3465 ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
3466 HDD_IPA_UC_WLAN_8023_HDR_SIZE;
3467 ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
3468 } else {
3469 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
3470 }
3471 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
3472
3473 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3474 ipa->keep_ipa_awake = 1;
3475
3476 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
3477 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303478 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479 " ret: %d", i, ret);
3480 goto setup_sys_pipe_fail;
3481 }
3482 hdd_ipa->sys_pipe[i].conn_hdl_valid = 1;
3483 }
3484
3485 if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
3486 /*
3487 * Hard code it here, this can be extended if in case
3488 * PROD pipe is also per interface.
3489 * Right now there is no advantage of doing this.
3490 */
3491 hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD;
3492
3493 ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params;
3494
3495 ipa->client = hdd_ipa->prod_client;
3496
3497 ipa->desc_fifo_sz = desc_fifo_sz;
3498 ipa->priv = hdd_ipa;
3499 ipa->notify = hdd_ipa_w2i_cb;
3500
3501 ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
3502 ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN;
3503 ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
3504 ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
3505
3506 if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
3507 ipa->keep_ipa_awake = 1;
3508
3509 ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl));
3510 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303511 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003512 "Failed for RX pipe: %d", ret);
3513 goto setup_sys_pipe_fail;
3514 }
3515 hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
3516 }
3517
3518 return ret;
3519
3520setup_sys_pipe_fail:
3521
3522 while (--i >= 0) {
3523 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303524 qdf_mem_zero(&hdd_ipa->sys_pipe[i],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003525 sizeof(struct hdd_ipa_sys_pipe));
3526 }
3527
3528 return ret;
3529}
3530
3531/**
3532 * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
3533 * @hdd_ipa: Global HDD IPA context
3534 *
3535 * Return: None
3536 */
3537static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
3538{
3539 int ret = 0, i;
3540 for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
3541 if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
3542 ret =
3543 ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].
3544 conn_hdl);
3545 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303546 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003547 ret);
3548
3549 hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
3550 }
3551 }
3552}
3553
3554/**
3555 * hdd_ipa_register_interface() - register IPA interface
3556 * @hdd_ipa: Global IPA context
3557 * @iface_context: Per-interface IPA context
3558 *
3559 * Return: 0 on success, negative errno on error
3560 */
3561static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
3562 struct hdd_ipa_iface_context
3563 *iface_context)
3564{
3565 struct ipa_tx_intf tx_intf;
3566 struct ipa_rx_intf rx_intf;
3567 struct ipa_ioc_tx_intf_prop *tx_prop = NULL;
3568 struct ipa_ioc_rx_intf_prop *rx_prop = NULL;
3569 char *ifname = iface_context->adapter->dev->name;
3570
3571 char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX];
3572 char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX];
3573
3574 int num_prop = 1;
3575 int ret = 0;
3576
3577 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx))
3578 num_prop++;
3579
3580 /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */
3581 tx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303582 qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003583 if (!tx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303584 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003585 goto register_interface_fail;
3586 }
3587
3588 /* Allocate RX properties, 1 each for IPv4 & IPv6 */
3589 rx_prop =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303590 qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003591 if (!rx_prop) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303592 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003593 goto register_interface_fail;
3594 }
3595
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303596 qdf_mem_zero(&tx_intf, sizeof(tx_intf));
3597 qdf_mem_zero(&rx_intf, sizeof(rx_intf));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003598
3599 snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
3600 ifname, HDD_IPA_IPV4_NAME_EXT);
3601 snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s",
3602 ifname, HDD_IPA_IPV6_NAME_EXT);
3603
3604 rx_prop[IPA_IP_v4].ip = IPA_IP_v4;
3605 rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client;
3606 rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3607 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
3608
3609 /*
3610 * Interface ID is 3rd byte in the CLD header. Add the meta data and
3611 * mask to identify the interface in IPA hardware
3612 */
3613 rx_prop[IPA_IP_v4].attrib.meta_data =
3614 htonl(iface_context->adapter->sessionId << 16);
3615 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
3616
3617 rx_intf.num_props++;
3618 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3619 rx_prop[IPA_IP_v6].ip = IPA_IP_v6;
3620 rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client;
3621 rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3622 rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA;
3623 rx_prop[IPA_IP_v4].attrib.meta_data =
3624 htonl(iface_context->adapter->sessionId << 16);
3625 rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000);
3626
3627 rx_intf.num_props++;
3628 }
3629
3630 tx_prop[IPA_IP_v4].ip = IPA_IP_v4;
3631 tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3632 tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS;
3633 tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client;
3634 strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name,
3635 IPA_RESOURCE_NAME_MAX);
3636 tx_intf.num_props++;
3637
3638 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3639 tx_prop[IPA_IP_v6].ip = IPA_IP_v6;
3640 tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
3641 tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS;
3642 tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client;
3643 strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name,
3644 IPA_RESOURCE_NAME_MAX);
3645 tx_intf.num_props++;
3646 }
3647
3648 tx_intf.prop = tx_prop;
3649 rx_intf.prop = rx_prop;
3650
3651 /* Call the ipa api to register interface */
3652 ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
3653
3654register_interface_fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303655 qdf_mem_free(tx_prop);
3656 qdf_mem_free(rx_prop);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003657 return ret;
3658}
3659
3660/**
3661 * hdd_remove_ipa_header() - Remove a specific header from IPA
3662 * @name: Name of the header to be removed
3663 *
3664 * Return: None
3665 */
3666static void hdd_ipa_remove_header(char *name)
3667{
3668 struct ipa_ioc_get_hdr hdrlookup;
3669 int ret = 0, len;
3670 struct ipa_ioc_del_hdr *ipa_hdr;
3671
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303672 qdf_mem_zero(&hdrlookup, sizeof(hdrlookup));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003673 strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name));
3674 ret = ipa_get_hdr(&hdrlookup);
3675 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303676 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003677 name, ret);
3678 return;
3679 }
3680
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303681 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003682 len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303683 ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003684 if (ipa_hdr == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303685 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003686 return;
3687 }
3688 ipa_hdr->num_hdls = 1;
3689 ipa_hdr->commit = 0;
3690 ipa_hdr->hdl[0].hdl = hdrlookup.hdl;
3691 ipa_hdr->hdl[0].status = -1;
3692 ret = ipa_del_hdr(ipa_hdr);
3693 if (ret != 0)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303694 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003695 ret);
3696
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303697 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003698}
3699
3700/**
3701 * hdd_ipa_add_header_info() - Add IPA header for a given interface
3702 * @hdd_ipa: Global HDD IPA context
3703 * @iface_context: Interface-specific HDD IPA context
3704 * @mac_addr: Interface MAC address
3705 *
3706 * Return: 0 on success, negativer errno value on error
3707 */
3708static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa,
3709 struct hdd_ipa_iface_context *iface_context,
3710 uint8_t *mac_addr)
3711{
3712 hdd_adapter_t *adapter = iface_context->adapter;
3713 char *ifname;
3714 struct ipa_ioc_add_hdr *ipa_hdr = NULL;
3715 int ret = -EINVAL;
3716 struct hdd_ipa_tx_hdr *tx_hdr = NULL;
3717 struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL;
3718
3719 ifname = adapter->dev->name;
3720
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303721 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003722 ifname, mac_addr);
3723
3724 /* dynamically allocate the memory to add the hdrs */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303725 ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003726 + sizeof(struct ipa_hdr_add));
3727 if (!ipa_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303728 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003729 "%s: ipa_hdr allocation failed", ifname);
3730 ret = -ENOMEM;
3731 goto end;
3732 }
3733
3734 ipa_hdr->commit = 0;
3735 ipa_hdr->num_hdrs = 1;
3736
3737 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3738 uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
3739 memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN);
3740 memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
3741 uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303742 HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003743 "ifname=%s, vdev_id=%d",
3744 ifname, uc_tx_hdr->ipa_hd.vdev_id);
3745 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
3746 ifname, HDD_IPA_IPV4_NAME_EXT);
3747 ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN;
3748 ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II;
3749 ipa_hdr->hdr[0].is_partial = 1;
3750 ipa_hdr->hdr[0].hdr_hdl = 0;
3751 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
3752 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
3753
3754 ret = ipa_add_hdr(ipa_hdr);
3755 } else {
3756 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
3757
3758 /* Set the Source MAC */
3759 memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN);
3760 memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN);
3761
3762 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
3763 ifname, HDD_IPA_IPV4_NAME_EXT);
3764 ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN;
3765 ipa_hdr->hdr[0].is_partial = 1;
3766 ipa_hdr->hdr[0].hdr_hdl = 0;
3767 ipa_hdr->hdr[0].is_eth2_ofst_valid = 1;
3768 ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
3769
3770 /* Set the type to IPV4 in the header */
3771 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP);
3772
3773 ret = ipa_add_hdr(ipa_hdr);
3774 }
3775 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303776 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003777 ifname, ret);
3778 goto end;
3779 }
3780
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303781 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
3783
3784 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3785 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
3786 ifname, HDD_IPA_IPV6_NAME_EXT);
3787
3788 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
3789 uc_tx_hdr =
3790 (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr;
3791 uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6);
3792 } else {
3793 /* Set the type to IPV6 in the header */
3794 tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr;
3795 tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6);
3796 }
3797
3798 ret = ipa_add_hdr(ipa_hdr);
3799 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303800 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003801 "%s: IPv6 add hdr failed: %d", ifname, ret);
3802 goto clean_ipv4_hdr;
3803 }
3804
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303805 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003806 ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl);
3807 }
3808
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303809 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003810
3811 return ret;
3812
3813clean_ipv4_hdr:
3814 snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s",
3815 ifname, HDD_IPA_IPV4_NAME_EXT);
3816 hdd_ipa_remove_header(ipa_hdr->hdr[0].name);
3817end:
3818 if (ipa_hdr)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303819 qdf_mem_free(ipa_hdr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003820
3821 return ret;
3822}
3823
3824/**
3825 * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter
3826 * @adapter: Adapter upon which IPA was previously configured
3827 *
3828 * Return: None
3829 */
3830static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter)
3831{
3832 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
3833 int ret;
3834 char name_ipa[IPA_RESOURCE_NAME_MAX];
3835
3836 /* Remove the headers */
3837 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
3838 adapter->dev->name, HDD_IPA_IPV4_NAME_EXT);
3839 hdd_ipa_remove_header(name_ipa);
3840
3841 if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) {
3842 snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s",
3843 adapter->dev->name, HDD_IPA_IPV6_NAME_EXT);
3844 hdd_ipa_remove_header(name_ipa);
3845 }
3846 /* unregister the interface with IPA */
3847 ret = ipa_deregister_intf(adapter->dev->name);
3848 if (ret)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303849 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003850 "%s: ipa_deregister_intf fail: %d",
3851 adapter->dev->name, ret);
3852}
3853
3854/**
3855 * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface
3856 * @iface_context: interface-specific IPA context
3857 *
3858 * Return: None
3859 */
3860static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context)
3861{
3862 if (iface_context == NULL)
3863 return;
3864
3865 hdd_ipa_clean_hdr(iface_context->adapter);
3866
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303867 qdf_spin_lock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003868 iface_context->adapter->ipa_context = NULL;
3869 iface_context->adapter = NULL;
3870 iface_context->tl_context = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303871 qdf_spin_unlock_bh(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003872 iface_context->ifa_address = 0;
3873 if (!iface_context->hdd_ipa->num_iface) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303874 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003875 "NUM INTF 0, Invalid");
Anurag Chouhandf2b2682016-02-29 14:15:27 +05303876 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003877 }
3878 iface_context->hdd_ipa->num_iface--;
3879}
3880
3881/**
3882 * hdd_ipa_setup_iface() - Setup IPA on a given interface
3883 * @hdd_ipa: HDD IPA global context
3884 * @adapter: Interface upon which IPA is being setup
3885 * @sta_id: Station ID of the API instance
3886 *
3887 * Return: 0 on success, negative errno value on error
3888 */
3889static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa,
3890 hdd_adapter_t *adapter, uint8_t sta_id)
3891{
3892 struct hdd_ipa_iface_context *iface_context = NULL;
3893 void *tl_context = NULL;
3894 int i, ret = 0;
3895
3896 /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
3897 * channel change indication. Since these indications are sent by lower
3898 * layer as SAP updates and IPA doesn't have to do anything for these
3899 * updates so ignoring!
3900 */
Krunal Sonibe766b02016-03-10 13:00:44 -08003901 if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003902 return 0;
3903
3904 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
3905 if (hdd_ipa->iface_context[i].adapter == NULL) {
3906 iface_context = &(hdd_ipa->iface_context[i]);
3907 break;
3908 }
3909 }
3910
3911 if (iface_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303912 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003913 "All the IPA interfaces are in use");
3914 ret = -ENOMEM;
3915 goto end;
3916 }
3917
3918 adapter->ipa_context = iface_context;
3919 iface_context->adapter = adapter;
3920 iface_context->sta_id = sta_id;
Leo Changfdb45c32016-10-28 11:09:23 -07003921 tl_context = cdp_peer_get_vdev_by_sta_id(
3922 cds_get_context(QDF_MODULE_ID_SOC), sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923 if (tl_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303924 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003925 "Not able to get TL context sta_id: %d", sta_id);
3926 ret = -EINVAL;
3927 goto end;
3928 }
3929
3930 iface_context->tl_context = tl_context;
3931
3932 ret = hdd_ipa_add_header_info(hdd_ipa, iface_context,
3933 adapter->dev->dev_addr);
3934
3935 if (ret)
3936 goto end;
3937
3938 /* Configure the TX and RX pipes filter rules */
3939 ret = hdd_ipa_register_interface(hdd_ipa, iface_context);
3940 if (ret)
3941 goto cleanup_header;
3942
3943 hdd_ipa->num_iface++;
3944 return ret;
3945
3946cleanup_header:
3947
3948 hdd_ipa_clean_hdr(adapter);
3949end:
3950 if (iface_context)
3951 hdd_ipa_cleanup_iface(iface_context);
3952 return ret;
3953}
3954
Yun Parka27049a2016-10-11 12:30:49 -07003955#ifndef QCA_LL_TX_FLOW_CONTROL_V2
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003956/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003957 * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003958 * @mcc_mode: 0=MCC/1=SCC
3959 *
3960 * Return: 0 on success, negative errno value on error
3961 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003962static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003963{
3964 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303965 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003966 hdd_adapter_t *pAdapter;
3967 struct ipa_msg_meta meta;
3968 struct ipa_wlan_msg *msg;
3969 int ret;
3970
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003971 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003972 return -EINVAL;
3973
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003974 if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx))
3975 return -EINVAL;
3976
3977 if (!hdd_ctx->mcc_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003978 /* Flush TxRx queue for each adapter before switch to SCC */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003979 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303980 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003981 pAdapter = adapter_node->pAdapter;
Krunal Sonibe766b02016-03-10 13:00:44 -08003982 if (pAdapter->device_mode == QDF_STA_MODE ||
Jeff Johnsonab2cd402016-12-05 13:54:28 -08003983 pAdapter->device_mode == QDF_SAP_MODE) {
3984 hdd_info("MCC->SCC: Flush TxRx queue(d_mode=%d)",
3985 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003986 hdd_deinit_tx_rx(pAdapter);
3987 }
3988 status = hdd_get_next_adapter(
Prakash Dhavali412cdb02016-10-20 21:19:31 -07003989 hdd_ctx, adapter_node, &next);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003990 adapter_node = next;
3991 }
3992 }
3993
3994 /* Send SCC/MCC Switching event to IPA */
3995 meta.msg_len = sizeof(*msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303996 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003997 if (msg == NULL) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08003998 hdd_err("msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003999 return -ENOMEM;
4000 }
4001
4002 meta.msg_type = mcc_mode ?
4003 WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004004 hdd_info("ipa_send_msg(Evt:%d)", meta.msg_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004005
4006 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4007
4008 if (ret) {
Jeff Johnsonab2cd402016-12-05 13:54:28 -08004009 hdd_err("ipa_send_msg(Evt:%d) - fail=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004010 meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304011 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004012 }
4013
4014 return ret;
4015}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004016
4017/**
4018 * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg
4019 * @mcc_mode: 0=MCC/1=SCC
4020 *
4021 * Return: 0 on success, negative errno value on error
4022 */
4023int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode)
4024{
4025 int ret;
4026
4027 cds_ssr_protect(__func__);
4028 ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode);
4029 cds_ssr_unprotect(__func__);
4030
4031 return ret;
4032}
Yun Parka27049a2016-10-11 12:30:49 -07004033#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004034
4035/**
4036 * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string
4037 * @event: IPA WLAN event to be converted to a string
4038 *
4039 * Return: ASCII string representing the IPA WLAN event
4040 */
4041static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event)
4042{
4043 switch (event) {
4044 case WLAN_CLIENT_CONNECT:
4045 return "WLAN_CLIENT_CONNECT";
4046 case WLAN_CLIENT_DISCONNECT:
4047 return "WLAN_CLIENT_DISCONNECT";
4048 case WLAN_CLIENT_POWER_SAVE_MODE:
4049 return "WLAN_CLIENT_POWER_SAVE_MODE";
4050 case WLAN_CLIENT_NORMAL_MODE:
4051 return "WLAN_CLIENT_NORMAL_MODE";
4052 case SW_ROUTING_ENABLE:
4053 return "SW_ROUTING_ENABLE";
4054 case SW_ROUTING_DISABLE:
4055 return "SW_ROUTING_DISABLE";
4056 case WLAN_AP_CONNECT:
4057 return "WLAN_AP_CONNECT";
4058 case WLAN_AP_DISCONNECT:
4059 return "WLAN_AP_DISCONNECT";
4060 case WLAN_STA_CONNECT:
4061 return "WLAN_STA_CONNECT";
4062 case WLAN_STA_DISCONNECT:
4063 return "WLAN_STA_DISCONNECT";
4064 case WLAN_CLIENT_CONNECT_EX:
4065 return "WLAN_CLIENT_CONNECT_EX";
4066
4067 case IPA_WLAN_EVENT_MAX:
4068 default:
4069 return "UNKNOWN";
4070 }
4071}
4072
4073/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07004074 * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event
4075 * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event
4076 *
4077 * Return: ipa_wlan_event representing the hdd_ipa_wlan_event
4078 */
4079static enum ipa_wlan_event
4080hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type)
4081{
4082 enum ipa_wlan_event ipa_event;
4083
4084 switch (hdd_ipa_event_type) {
4085 case HDD_IPA_CLIENT_CONNECT:
4086 ipa_event = WLAN_CLIENT_CONNECT;
4087 break;
4088 case HDD_IPA_CLIENT_DISCONNECT:
4089 ipa_event = WLAN_CLIENT_DISCONNECT;
4090 break;
4091 case HDD_IPA_AP_CONNECT:
4092 ipa_event = WLAN_AP_CONNECT;
4093 break;
4094 case HDD_IPA_AP_DISCONNECT:
4095 ipa_event = WLAN_AP_DISCONNECT;
4096 break;
4097 case HDD_IPA_STA_CONNECT:
4098 ipa_event = WLAN_STA_CONNECT;
4099 break;
4100 case HDD_IPA_STA_DISCONNECT:
4101 ipa_event = WLAN_STA_DISCONNECT;
4102 break;
4103 case HDD_IPA_CLIENT_CONNECT_EX:
4104 ipa_event = WLAN_CLIENT_CONNECT_EX;
4105 break;
4106 case HDD_IPA_WLAN_EVENT_MAX:
4107 default:
4108 ipa_event = IPA_WLAN_EVENT_MAX;
4109 break;
4110 }
4111 return ipa_event;
4112
4113}
4114
4115/**
4116 * __hdd_ipa_wlan_evt() - IPA event handler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004117 * @adapter: adapter upon which the event was received
4118 * @sta_id: station id for the event
Mohit Khannafa99aea2016-05-12 21:43:13 -07004119 * @type: event enum of type ipa_wlan_event
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004120 * @mac_address: MAC address associated with the event
4121 *
Mohit Khannafa99aea2016-05-12 21:43:13 -07004122 * This function is meant to be called from within wlan_hdd_ipa.c
4123 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004124 * Return: 0 on success, negative errno value on error
4125 */
Mohit Khannafa99aea2016-05-12 21:43:13 -07004126static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004127 enum ipa_wlan_event type, uint8_t *mac_addr)
4128{
4129 struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
4130 struct ipa_msg_meta meta;
4131 struct ipa_wlan_msg *msg;
4132 struct ipa_wlan_msg_ex *msg_ex = NULL;
4133 int ret;
4134
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304135 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004136 adapter->dev->name, hdd_ipa_wlan_event_to_str(type),
4137 mac_addr, sta_id);
4138
4139 if (type >= IPA_WLAN_EVENT_MAX)
4140 return -EINVAL;
4141
4142 if (WARN_ON(is_zero_ether_addr(mac_addr)))
4143 return -EINVAL;
4144
4145 if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304146 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004147 return -EINVAL;
4148 }
4149
4150 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) &&
4151 !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Krunal Sonibe766b02016-03-10 13:00:44 -08004152 (QDF_SAP_MODE != adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004153 return 0;
4154 }
4155
4156 /*
4157 * During IPA UC resource loading/unloading new events can be issued.
4158 * Store the events separately and handle them later.
4159 */
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004160 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4161 if (hdd_ipa->resource_loading) {
4162 unsigned int pending_event_count;
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004163 struct ipa_uc_pending_event *pending_event = NULL;
Yun Parkf19e07d2015-11-20 11:34:27 -08004164
Yun Park7c4f31b2016-11-30 10:09:21 -08004165 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA resource %s inprogress",
4166 hdd_ipa->resource_loading ? "load":"unload");
4167
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004168 hdd_err("IPA resource %s inprogress",
4169 hdd_ipa->resource_loading ? "load":"unload");
Yun Parkf19e07d2015-11-20 11:34:27 -08004170
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004171 qdf_mutex_acquire(&hdd_ipa->event_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004172
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004173 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4174 if (pending_event_count >= HDD_IPA_MAX_PENDING_EVENT_COUNT) {
4175 hdd_notice("Reached max pending event count");
4176 qdf_list_remove_front(&hdd_ipa->pending_event,
4177 (qdf_list_node_t **)&pending_event);
4178 } else {
4179 pending_event =
4180 (struct ipa_uc_pending_event *)qdf_mem_malloc(
4181 sizeof(struct ipa_uc_pending_event));
4182 }
4183
4184 if (!pending_event) {
Yun Park7c4f31b2016-11-30 10:09:21 -08004185 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
4186 "Pending event memory alloc fail");
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004187 qdf_mutex_release(&hdd_ipa->event_lock);
4188 return -ENOMEM;
4189 }
4190
4191 pending_event->adapter = adapter;
4192 pending_event->sta_id = sta_id;
4193 pending_event->type = type;
4194 qdf_mem_copy(pending_event->mac_addr,
4195 mac_addr,
4196 QDF_MAC_ADDR_SIZE);
4197 qdf_list_insert_back(&hdd_ipa->pending_event,
4198 &pending_event->node);
4199
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304200 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavalibf6d5d22016-08-17 10:17:46 -07004201 return 0;
4202 } else if (hdd_ipa->resource_unloading) {
4203 hdd_err("%s: IPA resource unload inprogress", __func__);
4204 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004205 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004206 }
4207
4208 hdd_ipa->stats.event[type]++;
4209
Leo Chang3bc8fed2015-11-13 10:59:47 -08004210 meta.msg_type = type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004211 switch (type) {
4212 case WLAN_STA_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004213 qdf_mutex_acquire(&hdd_ipa->event_lock);
4214
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004215 /* STA already connected and without disconnect, connect again
4216 * This is Roaming scenario
4217 */
4218 if (hdd_ipa->sta_connected)
4219 hdd_ipa_cleanup_iface(adapter->ipa_context);
4220
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004221 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4222 if (ret) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304223 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004224 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004225 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004226
Yun Park8f289c82016-10-18 16:38:21 -07004227 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4228 (hdd_ipa->sap_num_connected_sta > 0) &&
4229 !hdd_ipa->sta_connected) {
4230 qdf_mutex_release(&hdd_ipa->event_lock);
4231 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004232 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004233 qdf_mutex_acquire(&hdd_ipa->event_lock);
4234 }
4235
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004236 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004237 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004238 (adapter->ipa_context))->iface_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004239
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240 hdd_ipa->sta_connected = 1;
Yun Park8f289c82016-10-18 16:38:21 -07004241
4242 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004243 break;
4244
4245 case WLAN_AP_CONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004246 qdf_mutex_acquire(&hdd_ipa->event_lock);
4247
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248 /* For DFS channel we get two start_bss event (before and after
4249 * CAC). Also when ACS range includes both DFS and non DFS
4250 * channels, we could possibly change channel many times due to
4251 * RADAR detection and chosen channel may not be a DFS channels.
4252 * So dont return error here. Just discard the event.
4253 */
Yun Park8f289c82016-10-18 16:38:21 -07004254 if (adapter->ipa_context) {
4255 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004256 return 0;
Yun Park8f289c82016-10-18 16:38:21 -07004257 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004258
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004259 ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id);
4260 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304261 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004262 "%s: Evt: %d, Interface setup failed",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304263 adapter->dev->name, type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304264 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004265 goto end;
Yun Parka37592b2016-06-11 17:10:28 -07004266 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004267
Yun Park8f289c82016-10-18 16:38:21 -07004268 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4269 qdf_mutex_release(&hdd_ipa->event_lock);
4270 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004271 SIR_AP_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004272 qdf_mutex_acquire(&hdd_ipa->event_lock);
4273 }
4274
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004275 hdd_ipa->vdev_to_iface[adapter->sessionId] =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004276 ((struct hdd_ipa_iface_context *)
Yun Parka37592b2016-06-11 17:10:28 -07004277 (adapter->ipa_context))->iface_id;
4278
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304279 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 break;
4281
4282 case WLAN_STA_DISCONNECT:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304283 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004284
4285 if (!hdd_ipa->sta_connected) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304286 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004287 "%s: Evt: %d, STA already disconnected",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304288 adapter->dev->name, type);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304289 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004290 return -EINVAL;
4291 }
Yun Parka37592b2016-06-11 17:10:28 -07004292
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293 hdd_ipa->sta_connected = 0;
Yun Parka37592b2016-06-11 17:10:28 -07004294
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004295 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304296 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004297 "%s: IPA UC OFFLOAD NOT ENABLED",
4298 msg_ex->name);
4299 } else {
4300 /* Disable IPA UC TX PIPE when STA disconnected */
Yun Parka37592b2016-06-11 17:10:28 -07004301 if (!hdd_ipa->num_iface &&
4302 (HDD_IPA_UC_NUM_WDI_PIPE ==
4303 hdd_ipa->activated_fw_pipe))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004304 hdd_ipa_uc_handle_last_discon(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004305 }
4306
Yun Park74127cf2016-09-18 11:22:41 -07004307 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4308 (hdd_ipa->sap_num_connected_sta > 0)) {
Yun Park8f289c82016-10-18 16:38:21 -07004309 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004310 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004311 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004312 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004313 hdd_ipa->vdev_to_iface[adapter->sessionId] =
4314 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004315 }
4316
Yun Park8f289c82016-10-18 16:38:21 -07004317 hdd_ipa_cleanup_iface(adapter->ipa_context);
4318
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304319 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004320 break;
4321
4322 case WLAN_AP_DISCONNECT:
Yun Park8f289c82016-10-18 16:38:21 -07004323 qdf_mutex_acquire(&hdd_ipa->event_lock);
4324
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004325 if (!adapter->ipa_context) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304326 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327 "%s: Evt: %d, SAP already disconnected",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304328 adapter->dev->name, type);
Yun Park8f289c82016-10-18 16:38:21 -07004329 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004330 return -EINVAL;
4331 }
4332
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333 if ((!hdd_ipa->num_iface) &&
4334 (HDD_IPA_UC_NUM_WDI_PIPE ==
4335 hdd_ipa->activated_fw_pipe)) {
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004336 if (cds_is_driver_unloading()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004337 /*
4338 * We disable WDI pipes directly here since
4339 * IPA_OPCODE_TX/RX_SUSPEND message will not be
4340 * processed when unloading WLAN driver is in
4341 * progress
4342 */
4343 hdd_ipa_uc_disable_pipes(hdd_ipa);
4344 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304345 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004346 "NO INTF left but still pipe clean up");
4347 hdd_ipa_uc_handle_last_discon(hdd_ipa);
4348 }
4349 }
4350
4351 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Yun Park8f289c82016-10-18 16:38:21 -07004352 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004353 hdd_ipa_uc_offload_enable_disable(adapter,
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004354 SIR_AP_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004355 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004356 hdd_ipa->vdev_to_iface[adapter->sessionId] =
4357 CSR_ROAM_SESSION_MAX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004358 }
Yun Parka37592b2016-06-11 17:10:28 -07004359
Yun Park8f289c82016-10-18 16:38:21 -07004360 hdd_ipa_cleanup_iface(adapter->ipa_context);
4361
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304362 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363 break;
4364
4365 case WLAN_CLIENT_CONNECT_EX:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004366 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304367 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004368 "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304369 adapter->dev->name, type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370 return 0;
4371 }
4372
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304373 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004374 if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa,
4375 true, sta_id)) {
Yun Park8f289c82016-10-18 16:38:21 -07004376 qdf_mutex_release(&hdd_ipa->event_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304377 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004378 "%s: STA ID %d found, not valid",
4379 adapter->dev->name, sta_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004380 return 0;
4381 }
Yun Park312f71a2015-12-08 10:22:42 -08004382
4383 /* Enable IPA UC Data PIPEs when first STA connected */
Yun Parka37592b2016-06-11 17:10:28 -07004384 if (0 == hdd_ipa->sap_num_connected_sta) {
4385 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07004386 hdd_ipa->sta_connected) {
4387 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07004388 hdd_ipa_uc_offload_enable_disable(
4389 hdd_get_adapter(hdd_ipa->hdd_ctx,
4390 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004391 SIR_STA_RX_DATA_OFFLOAD, true);
Yun Park8f289c82016-10-18 16:38:21 -07004392 qdf_mutex_acquire(&hdd_ipa->event_lock);
4393 }
Yun Parka37592b2016-06-11 17:10:28 -07004394
Yun Park312f71a2015-12-08 10:22:42 -08004395 ret = hdd_ipa_uc_handle_first_con(hdd_ipa);
4396 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304397 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Yun Park312f71a2015-12-08 10:22:42 -08004398 "%s: handle 1st con ret %d",
4399 adapter->dev->name, ret);
Yun Parka37592b2016-06-11 17:10:28 -07004400
4401 if (hdd_ipa_uc_sta_is_enabled(
4402 hdd_ipa->hdd_ctx) &&
Yun Park8f289c82016-10-18 16:38:21 -07004403 hdd_ipa->sta_connected) {
4404 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Parka37592b2016-06-11 17:10:28 -07004405 hdd_ipa_uc_offload_enable_disable(
4406 hdd_get_adapter(
4407 hdd_ipa->hdd_ctx,
4408 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004409 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004410 } else {
4411 qdf_mutex_release(&hdd_ipa->event_lock);
4412 }
Yun Parka37592b2016-06-11 17:10:28 -07004413
Yun Park312f71a2015-12-08 10:22:42 -08004414 return ret;
4415 }
4416 }
4417
4418 hdd_ipa->sap_num_connected_sta++;
Yun Park312f71a2015-12-08 10:22:42 -08004419
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304420 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004421
4422 meta.msg_type = type;
4423 meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) +
4424 sizeof(struct ipa_wlan_hdr_attrib_val));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304425 msg_ex = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004426
4427 if (msg_ex == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304428 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004429 "msg_ex allocation failed");
4430 return -ENOMEM;
4431 }
4432 strlcpy(msg_ex->name, adapter->dev->name,
4433 IPA_RESOURCE_NAME_MAX);
4434 msg_ex->num_of_attribs = 1;
4435 msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
4436 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4437 msg_ex->attribs[0].offset =
4438 HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
4439 } else {
4440 msg_ex->attribs[0].offset =
4441 HDD_IPA_WLAN_HDR_DES_MAC_OFFSET;
4442 }
4443 memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
4444 IPA_MAC_ADDR_SIZE);
4445
4446 ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn);
4447
4448 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304449 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d",
Manjeet Singhfd51d8f2016-11-09 15:58:26 +05304450 adapter->dev->name, type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304451 qdf_mem_free(msg_ex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004452 return ret;
4453 }
4454 hdd_ipa->stats.num_send_msg++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004455 return ret;
4456
4457 case WLAN_CLIENT_DISCONNECT:
4458 if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304459 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004460 "%s: IPA UC OFFLOAD NOT ENABLED",
4461 msg_ex->name);
4462 return 0;
4463 }
4464
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304465 qdf_mutex_acquire(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004466 if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304467 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004468 "%s: STA ID %d NOT found, not valid",
4469 msg_ex->name, sta_id);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304470 qdf_mutex_release(&hdd_ipa->event_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471 return 0;
4472 }
4473 hdd_ipa->sap_num_connected_sta--;
Yun Parka37592b2016-06-11 17:10:28 -07004474
Yun Park9b5030f2016-11-08 12:02:37 -08004475 /* Disable IPA UC TX PIPE when last STA disconnected */
4476 if (!hdd_ipa->sap_num_connected_sta) {
4477 if ((false == hdd_ipa->resource_unloading)
4478 && (HDD_IPA_UC_NUM_WDI_PIPE ==
4479 hdd_ipa->activated_fw_pipe)) {
4480 hdd_ipa_uc_handle_last_discon(hdd_ipa);
4481 }
4482
Yun Park8f289c82016-10-18 16:38:21 -07004483 qdf_mutex_release(&hdd_ipa->event_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08004484
4485 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
4486 hdd_ipa->sta_connected)
4487 hdd_ipa_uc_offload_enable_disable(
4488 hdd_get_adapter(hdd_ipa->hdd_ctx,
4489 QDF_STA_MODE),
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004490 SIR_STA_RX_DATA_OFFLOAD, false);
Yun Park8f289c82016-10-18 16:38:21 -07004491 } else {
4492 qdf_mutex_release(&hdd_ipa->event_lock);
4493 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494 break;
4495
4496 default:
4497 return 0;
4498 }
4499
4500 meta.msg_len = sizeof(struct ipa_wlan_msg);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304501 msg = qdf_mem_malloc(meta.msg_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004502 if (msg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304503 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004504 return -ENOMEM;
4505 }
4506
4507 meta.msg_type = type;
4508 strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX);
4509 memcpy(msg->mac_addr, mac_addr, ETH_ALEN);
4510
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304511 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512 msg->name, meta.msg_type);
4513
4514 ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn);
4515
4516 if (ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304517 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d fail:%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004518 msg->name, meta.msg_type, ret);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304519 qdf_mem_free(msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004520 return ret;
4521 }
4522
4523 hdd_ipa->stats.num_send_msg++;
4524
4525end:
4526 return ret;
4527}
4528
4529/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004530 * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt
Mohit Khannafa99aea2016-05-12 21:43:13 -07004531 * @adapter: adapter upon which the event was received
4532 * @sta_id: station id for the event
4533 * @hdd_event_type: event enum of type hdd_ipa_wlan_event
4534 * @mac_address: MAC address associated with the event
4535 *
4536 * This function is meant to be called from outside of wlan_hdd_ipa.c.
4537 *
4538 * Return: 0 on success, negative errno value on error
4539 */
4540int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id,
4541 enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr)
4542{
4543 enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type);
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004544 int ret = 0;
4545
4546 cds_ssr_protect(__func__);
Mohit Khannafa99aea2016-05-12 21:43:13 -07004547
Leo Changa202b522016-10-14 16:13:50 -07004548 /* Data path offload only support for STA and SAP mode */
4549 if ((QDF_STA_MODE == adapter->device_mode) ||
4550 (QDF_SAP_MODE == adapter->device_mode))
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004551 ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr);
Leo Changa202b522016-10-14 16:13:50 -07004552
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004553 cds_ssr_unprotect(__func__);
4554
4555 return ret;
Mohit Khannafa99aea2016-05-12 21:43:13 -07004556}
4557
4558/**
4559 * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
4560 * @hdd_ipa: Global HDD IPA context
4561 *
4562 * Return: None
4563 */
4564static void
4565hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
4566{
4567 unsigned int pending_event_count;
4568 struct ipa_uc_pending_event *pending_event = NULL;
4569
4570 pending_event_count = qdf_list_size(&hdd_ipa->pending_event);
4571 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4572 "%s, Pending Event Count %d", __func__, pending_event_count);
4573 if (!pending_event_count) {
4574 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
4575 "%s, No Pending Event", __func__);
4576 return;
4577 }
4578
4579 qdf_list_remove_front(&hdd_ipa->pending_event,
4580 (qdf_list_node_t **)&pending_event);
4581 while (pending_event != NULL) {
4582 __hdd_ipa_wlan_evt(pending_event->adapter,
4583 pending_event->type,
4584 pending_event->sta_id,
4585 pending_event->mac_addr);
4586 qdf_mem_free(pending_event);
4587 pending_event = NULL;
4588 qdf_list_remove_front(&hdd_ipa->pending_event,
4589 (qdf_list_node_t **)&pending_event);
4590 }
4591}
4592
4593/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594 * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string
4595 * @state: IPA RM state value
4596 *
4597 * Return: ASCII string representing the IPA RM state
4598 */
4599static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state)
4600{
4601 switch (state) {
4602 case HDD_IPA_RM_RELEASED:
4603 return "RELEASED";
4604 case HDD_IPA_RM_GRANT_PENDING:
4605 return "GRANT_PENDING";
4606 case HDD_IPA_RM_GRANTED:
4607 return "GRANTED";
4608 }
4609
4610 return "UNKNOWN";
4611}
4612
4613/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004614 * __hdd_ipa_init() - IPA initialization function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 * @hdd_ctx: HDD global context
4616 *
4617 * Allocate hdd_ipa resources, ipa pipe resource and register
4618 * wlan interface with IPA module.
4619 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304620 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004621 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004622static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623{
4624 struct hdd_ipa_priv *hdd_ipa = NULL;
4625 int ret, i;
4626 struct hdd_ipa_iface_context *iface_context = NULL;
Yun Park7f171ab2016-07-29 15:44:22 -07004627 struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004628
4629 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304630 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004631
Yun Park7f171ab2016-07-29 15:44:22 -07004632 if (!pdev) {
4633 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL");
4634 goto fail_return;
4635 }
4636
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304637 hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004638 if (!hdd_ipa) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304639 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed");
Leo Chang3bc8fed2015-11-13 10:59:47 -08004640 goto fail_return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641 }
4642
4643 hdd_ctx->hdd_ipa = hdd_ipa;
4644 ghdd_ipa = hdd_ipa;
4645 hdd_ipa->hdd_ctx = hdd_ctx;
4646 hdd_ipa->num_iface = 0;
Leo Changfdb45c32016-10-28 11:09:23 -07004647 cdp_ipa_get_resource(cds_get_context(QDF_MODULE_ID_SOC),
4648 cds_get_context(QDF_MODULE_ID_TXRX),
4649 &hdd_ipa->ipa_resource);
Dhanashri Atreb08959a2016-03-01 17:28:03 -08004650 if ((0 == hdd_ipa->ipa_resource.ce_sr_base_paddr) ||
4651 (0 == hdd_ipa->ipa_resource.tx_comp_ring_base_paddr) ||
4652 (0 == hdd_ipa->ipa_resource.rx_rdy_ring_base_paddr) ||
4653 (0 == hdd_ipa->ipa_resource.rx2_rdy_ring_base_paddr)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304654 HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
Leo Chang3bc8fed2015-11-13 10:59:47 -08004655 "IPA UC resource alloc fail");
4656 goto fail_get_resource;
4657 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658
4659 /* Create the interface context */
4660 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4661 iface_context = &hdd_ipa->iface_context[i];
4662 iface_context->hdd_ipa = hdd_ipa;
4663 iface_context->cons_client =
4664 hdd_ipa_adapter_2_client[i].cons_client;
4665 iface_context->prod_client =
4666 hdd_ipa_adapter_2_client[i].prod_client;
4667 iface_context->iface_id = i;
4668 iface_context->adapter = NULL;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304669 qdf_spinlock_create(&iface_context->interface_lock);
Yun Park9b5030f2016-11-08 12:02:37 -08004670 }
4671 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
Prakash Dhavali89d406d2016-11-23 11:11:00 -08004672 hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
4673 hdd_ipa->vdev_offload_enabled[i] = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004674 }
4675
Leo Chang69c39692016-10-12 20:11:12 -07004676 INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304677 qdf_spinlock_create(&hdd_ipa->pm_lock);
Nirav Shahcbc6d722016-03-01 16:24:53 +05304678 qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004679
4680 ret = hdd_ipa_setup_rm(hdd_ipa);
4681 if (ret)
4682 goto fail_setup_rm;
4683
4684 if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
4685 hdd_ipa_uc_rt_debug_init(hdd_ctx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304686 qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004687 hdd_ipa->sap_num_connected_sta = 0;
4688 hdd_ipa->ipa_tx_packets_diff = 0;
4689 hdd_ipa->ipa_rx_packets_diff = 0;
4690 hdd_ipa->ipa_p_tx_packets = 0;
4691 hdd_ipa->ipa_p_rx_packets = 0;
4692 hdd_ipa->resource_loading = false;
4693 hdd_ipa->resource_unloading = false;
4694 hdd_ipa->sta_connected = 0;
Leo Change3e49442015-10-26 20:07:13 -07004695 hdd_ipa->ipa_pipes_down = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004696 /* Setup IPA sys_pipe for MCC */
4697 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
4698 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
4699 if (ret)
4700 goto fail_create_sys_pipe;
4701 }
4702 hdd_ipa_uc_ol_init(hdd_ctx);
4703 } else {
4704 ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
4705 if (ret)
4706 goto fail_create_sys_pipe;
4707 }
4708
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304709 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004710
4711fail_create_sys_pipe:
4712 hdd_ipa_destroy_rm_resource(hdd_ipa);
4713fail_setup_rm:
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304714 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Leo Chang3bc8fed2015-11-13 10:59:47 -08004715fail_get_resource:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304716 qdf_mem_free(hdd_ipa);
Leo Chang3bc8fed2015-11-13 10:59:47 -08004717 hdd_ctx->hdd_ipa = NULL;
4718 ghdd_ipa = NULL;
4719fail_return:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304720 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004721}
4722
4723/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004724 * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init
4725 * @hdd_ctx: HDD global context
4726 *
4727 * Allocate hdd_ipa resources, ipa pipe resource and register
4728 * wlan interface with IPA module.
4729 *
4730 * Return: QDF_STATUS enumeration
4731 */
4732QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
4733{
4734 QDF_STATUS ret;
4735
4736 cds_ssr_protect(__func__);
4737 ret = __hdd_ipa_init(hdd_ctx);
4738 cds_ssr_unprotect(__func__);
4739
4740 return ret;
4741}
4742
4743/**
Yun Parkf19e07d2015-11-20 11:34:27 -08004744 * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list
4745 * @hdd_ipa: pointer to HDD IPA struct
4746 *
4747 * Return: none
4748 */
Jeff Johnsond7720632016-10-05 16:04:32 -07004749static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
Yun Parkf19e07d2015-11-20 11:34:27 -08004750{
4751 struct ipa_uc_pending_event *pending_event = NULL;
4752
Anurag Chouhanffb21542016-02-17 14:33:03 +05304753 while (qdf_list_remove_front(&hdd_ipa->pending_event,
4754 (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304755 qdf_mem_free(pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08004756 }
4757
Anurag Chouhanffb21542016-02-17 14:33:03 +05304758 qdf_list_destroy(&hdd_ipa->pending_event);
Yun Parkf19e07d2015-11-20 11:34:27 -08004759}
4760
4761/**
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004762 * __hdd_ipa_cleanup - IPA cleanup function
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004763 * @hdd_ctx: HDD global context
4764 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304765 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004766 */
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004767static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004768{
4769 struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
4770 int i;
4771 struct hdd_ipa_iface_context *iface_context = NULL;
Nirav Shahcbc6d722016-03-01 16:24:53 +05304772 qdf_nbuf_t skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004773 struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL;
4774
4775 if (!hdd_ipa_is_enabled(hdd_ctx))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304776 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004777
4778 if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
4779 unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
4780 hdd_ipa_teardown_sys_pipe(hdd_ipa);
4781 }
4782
4783 /* Teardown IPA sys_pipe for MCC */
4784 if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
4785 hdd_ipa_teardown_sys_pipe(hdd_ipa);
4786
4787 hdd_ipa_destroy_rm_resource(hdd_ipa);
4788
4789#ifdef WLAN_OPEN_SOURCE
4790 cancel_work_sync(&hdd_ipa->pm_work);
4791#endif
4792
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304793 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004794
Nirav Shahcbc6d722016-03-01 16:24:53 +05304795 while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head))
4796 != NULL)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304797 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004798
4799 pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb;
4800 ipa_free_skb(pm_tx_cb->ipa_tx_desc);
4801
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304802 qdf_spin_lock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004803 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304804 qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004805
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304806 qdf_spinlock_destroy(&hdd_ipa->pm_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004807
4808 /* destory the interface lock */
4809 for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
4810 iface_context = &hdd_ipa->iface_context[i];
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304811 qdf_spinlock_destroy(&iface_context->interface_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004812 }
4813
4814 /* This should never hit but still make sure that there are no pending
4815 * descriptor in IPA hardware
4816 */
4817 if (hdd_ipa->pending_hw_desc_cnt != 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304818 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004819 "IPA Pending write done: %d Waiting!",
4820 hdd_ipa->pending_hw_desc_cnt);
4821
4822 for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
4823 usleep_range(100, 100);
4824 }
4825
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304826 HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004827 "IPA Pending write done: desc: %d %s(%d)!",
4828 hdd_ipa->pending_hw_desc_cnt,
4829 hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
4830 : "leak", i);
4831 }
4832 if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
4833 hdd_ipa_uc_rt_debug_deinit(hdd_ctx);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304834 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05304835 "%s: Disconnect TX PIPE tx_pipe_handle=0x%x",
4836 __func__, hdd_ipa->tx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004837 ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304838 HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
Govind Singh0487bf22016-08-24 23:08:57 +05304839 "%s: Disconnect RX PIPE rx_pipe_handle=0x%x",
4840 __func__, hdd_ipa->rx_pipe_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004841 ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05304842 qdf_mutex_destroy(&hdd_ipa->event_lock);
4843 qdf_mutex_destroy(&hdd_ipa->ipa_lock);
Yun Parkf19e07d2015-11-20 11:34:27 -08004844 hdd_ipa_cleanup_pending_event(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004845
4846#ifdef WLAN_OPEN_SOURCE
4847 for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
4848 cancel_work_sync(&hdd_ipa->uc_op_work[i].work);
4849 hdd_ipa->uc_op_work[i].msg = NULL;
4850 }
4851#endif
4852 }
4853
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304854 qdf_mem_free(hdd_ipa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004855 hdd_ctx->hdd_ipa = NULL;
4856
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304857 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004858}
Prakash Dhavali412cdb02016-10-20 21:19:31 -07004859
4860/**
4861 * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup
4862 * @hdd_ctx: HDD global context
4863 *
4864 * Return: QDF_STATUS enumeration
4865 */
4866QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
4867{
4868 QDF_STATUS ret;
4869
4870 cds_ssr_protect(__func__);
4871 ret = __hdd_ipa_cleanup(hdd_ctx);
4872 cds_ssr_unprotect(__func__);
4873
4874 return ret;
4875}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004876#endif /* IPA_OFFLOAD */